bt2c::Logger: remove unused cLevel() method master
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Thu, 25 Apr 2024 19:27:02 +0000 (15:27 -0400)
committerPhilippe Proulx <eeppeliteloop@gmail.com>
Fri, 26 Apr 2024 04:58:13 +0000 (00:58 -0400)
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Change-Id: I59fb2fd48bb2166b725d8236bbf113f2fe993f99
Reviewed-on: https://review.lttng.org/c/babeltrace/+/12485
Tested-by: jenkins <jenkins@lttng.org>
159 files changed:
.clang-tidy
.gitignore
.reuse/dep5
CONTRIBUTING.adoc
README.adoc
configure.ac
doc/api/libbabeltrace2/.gitignore [deleted file]
doc/man/.gitignore [deleted file]
include/babeltrace2/value.h
src/Makefile.am
src/bindings/python/bt2/.gitignore [deleted file]
src/bindings/python/bt2/setup.py.in
src/clock-correlation-validator/clock-correlation-validator.cpp
src/clock-correlation-validator/clock-correlation-validator.hpp
src/common/macros.h
src/compat/socket.h [deleted file]
src/compat/socket.hpp [new file with mode: 0644]
src/cpp-common/bt2/component-class-dev.hpp
src/cpp-common/bt2/component-class.hpp
src/cpp-common/bt2/error.hpp
src/cpp-common/bt2/field-class.hpp
src/cpp-common/bt2/field-path.hpp
src/cpp-common/bt2/graph.hpp
src/cpp-common/bt2/logging.hpp
src/cpp-common/bt2/message.hpp
src/cpp-common/bt2/trace-ir.hpp
src/cpp-common/bt2/value.hpp
src/cpp-common/bt2c/c-string-view.hpp
src/cpp-common/bt2c/data-len.hpp [new file with mode: 0644]
src/cpp-common/bt2c/dummy.cpp [deleted file]
src/cpp-common/bt2c/exc.hpp
src/cpp-common/bt2c/file-utils.cpp [new file with mode: 0644]
src/cpp-common/bt2c/file-utils.hpp [new file with mode: 0644]
src/cpp-common/bt2c/fmt.hpp
src/cpp-common/bt2c/logging.hpp
src/cpp-common/bt2c/make-span.hpp [new file with mode: 0644]
src/cpp-common/bt2c/span.hpp [deleted file]
src/cpp-common/vendor/wise-enum/optional.h [new file with mode: 0644]
src/cpp-common/vendor/wise-enum/optional_common.h [new file with mode: 0644]
src/cpp-common/vendor/wise-enum/wise_enum.h [new file with mode: 0644]
src/cpp-common/vendor/wise-enum/wise_enum_detail.h [new file with mode: 0644]
src/cpp-common/vendor/wise-enum/wise_enum_generated.h [new file with mode: 0644]
src/plugins/ctf/common/bfcr/bfcr.cpp [deleted file]
src/plugins/ctf/common/bfcr/bfcr.hpp [deleted file]
src/plugins/ctf/common/metadata/ast.hpp [deleted file]
src/plugins/ctf/common/metadata/ctf-meta-configure-ir-trace.cpp [deleted file]
src/plugins/ctf/common/metadata/ctf-meta-configure-ir-trace.hpp [deleted file]
src/plugins/ctf/common/metadata/ctf-meta-resolve.cpp [deleted file]
src/plugins/ctf/common/metadata/ctf-meta-translate.cpp [deleted file]
src/plugins/ctf/common/metadata/ctf-meta-update-alignments.cpp [deleted file]
src/plugins/ctf/common/metadata/ctf-meta-update-default-clock-classes.cpp [deleted file]
src/plugins/ctf/common/metadata/ctf-meta-update-in-ir.cpp [deleted file]
src/plugins/ctf/common/metadata/ctf-meta-update-meanings.cpp [deleted file]
src/plugins/ctf/common/metadata/ctf-meta-update-stream-class-config.cpp [deleted file]
src/plugins/ctf/common/metadata/ctf-meta-update-text-array-sequence.cpp [deleted file]
src/plugins/ctf/common/metadata/ctf-meta-update-value-storing-indexes.cpp [deleted file]
src/plugins/ctf/common/metadata/ctf-meta-validate.cpp [deleted file]
src/plugins/ctf/common/metadata/ctf-meta-visitors.hpp [deleted file]
src/plugins/ctf/common/metadata/ctf-meta-warn-meaningless-header-fields.cpp [deleted file]
src/plugins/ctf/common/metadata/ctf-meta.hpp [deleted file]
src/plugins/ctf/common/metadata/decoder-packetized-file-stream-to-buf.cpp [deleted file]
src/plugins/ctf/common/metadata/decoder-packetized-file-stream-to-buf.hpp [deleted file]
src/plugins/ctf/common/metadata/decoder.cpp [deleted file]
src/plugins/ctf/common/metadata/decoder.hpp [deleted file]
src/plugins/ctf/common/metadata/lexer.lpp [deleted file]
src/plugins/ctf/common/metadata/logging.cpp [deleted file]
src/plugins/ctf/common/metadata/logging.hpp [deleted file]
src/plugins/ctf/common/metadata/objstack.cpp [deleted file]
src/plugins/ctf/common/metadata/objstack.hpp [deleted file]
src/plugins/ctf/common/metadata/parser-wrap.hpp [deleted file]
src/plugins/ctf/common/metadata/parser.ypp [deleted file]
src/plugins/ctf/common/metadata/scanner-symbols.hpp [deleted file]
src/plugins/ctf/common/metadata/scanner.hpp [deleted file]
src/plugins/ctf/common/metadata/visitor-generate-ir.cpp [deleted file]
src/plugins/ctf/common/metadata/visitor-parent-links.cpp [deleted file]
src/plugins/ctf/common/metadata/visitor-semantic-validator.cpp [deleted file]
src/plugins/ctf/common/msg-iter/msg-iter.cpp [deleted file]
src/plugins/ctf/common/msg-iter/msg-iter.hpp [deleted file]
src/plugins/ctf/common/print.hpp [deleted file]
src/plugins/ctf/common/src/bfcr/bfcr.cpp [new file with mode: 0644]
src/plugins/ctf/common/src/bfcr/bfcr.hpp [new file with mode: 0644]
src/plugins/ctf/common/src/clk-cls-cfg.hpp [new file with mode: 0644]
src/plugins/ctf/common/src/metadata/tsdl/ast.hpp [new file with mode: 0644]
src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-configure-ir-trace.cpp [new file with mode: 0644]
src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-configure-ir-trace.hpp [new file with mode: 0644]
src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-resolve.cpp [new file with mode: 0644]
src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-translate.cpp [new file with mode: 0644]
src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-alignments.cpp [new file with mode: 0644]
src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-default-clock-classes.cpp [new file with mode: 0644]
src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-in-ir.cpp [new file with mode: 0644]
src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-meanings.cpp [new file with mode: 0644]
src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-stream-class-config.cpp [new file with mode: 0644]
src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-text-array-sequence.cpp [new file with mode: 0644]
src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-value-storing-indexes.cpp [new file with mode: 0644]
src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-validate.cpp [new file with mode: 0644]
src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-visitors.hpp [new file with mode: 0644]
src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-warn-meaningless-header-fields.cpp [new file with mode: 0644]
src/plugins/ctf/common/src/metadata/tsdl/ctf-meta.hpp [new file with mode: 0644]
src/plugins/ctf/common/src/metadata/tsdl/decoder-packetized-file-stream-to-buf.cpp [new file with mode: 0644]
src/plugins/ctf/common/src/metadata/tsdl/decoder-packetized-file-stream-to-buf.hpp [new file with mode: 0644]
src/plugins/ctf/common/src/metadata/tsdl/decoder.cpp [new file with mode: 0644]
src/plugins/ctf/common/src/metadata/tsdl/decoder.hpp [new file with mode: 0644]
src/plugins/ctf/common/src/metadata/tsdl/lexer.lpp [new file with mode: 0644]
src/plugins/ctf/common/src/metadata/tsdl/logging.hpp [new file with mode: 0644]
src/plugins/ctf/common/src/metadata/tsdl/objstack.cpp [new file with mode: 0644]
src/plugins/ctf/common/src/metadata/tsdl/objstack.hpp [new file with mode: 0644]
src/plugins/ctf/common/src/metadata/tsdl/parser-wrap.hpp [new file with mode: 0644]
src/plugins/ctf/common/src/metadata/tsdl/parser.ypp [new file with mode: 0644]
src/plugins/ctf/common/src/metadata/tsdl/scanner-symbols.hpp [new file with mode: 0644]
src/plugins/ctf/common/src/metadata/tsdl/scanner.hpp [new file with mode: 0644]
src/plugins/ctf/common/src/metadata/tsdl/visitor-generate-ir.cpp [new file with mode: 0644]
src/plugins/ctf/common/src/metadata/tsdl/visitor-parent-links.cpp [new file with mode: 0644]
src/plugins/ctf/common/src/metadata/tsdl/visitor-semantic-validator.cpp [new file with mode: 0644]
src/plugins/ctf/common/src/msg-iter/msg-iter.cpp [new file with mode: 0644]
src/plugins/ctf/common/src/msg-iter/msg-iter.hpp [new file with mode: 0644]
src/plugins/ctf/fs-sink/fs-sink-ctf-meta.hpp
src/plugins/ctf/fs-sink/fs-sink-stream.cpp
src/plugins/ctf/fs-sink/fs-sink-stream.hpp
src/plugins/ctf/fs-sink/fs-sink-trace.cpp
src/plugins/ctf/fs-sink/fs-sink-trace.hpp
src/plugins/ctf/fs-sink/fs-sink.cpp
src/plugins/ctf/fs-sink/fs-sink.hpp
src/plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.cpp
src/plugins/ctf/fs-sink/translate-trace-ir-to-ctf-ir.cpp
src/plugins/ctf/fs-src/data-stream-file.cpp
src/plugins/ctf/fs-src/data-stream-file.hpp
src/plugins/ctf/fs-src/file.cpp
src/plugins/ctf/fs-src/file.hpp
src/plugins/ctf/fs-src/fs.cpp
src/plugins/ctf/fs-src/fs.hpp
src/plugins/ctf/fs-src/metadata.cpp
src/plugins/ctf/fs-src/metadata.hpp
src/plugins/ctf/fs-src/query.cpp
src/plugins/ctf/fs-src/query.hpp
src/plugins/ctf/lttng-live/data-stream.cpp
src/plugins/ctf/lttng-live/data-stream.hpp
src/plugins/ctf/lttng-live/lttng-live.cpp
src/plugins/ctf/lttng-live/lttng-live.hpp
src/plugins/ctf/lttng-live/lttng-viewer-abi.hpp
src/plugins/ctf/lttng-live/metadata.cpp
src/plugins/ctf/lttng-live/metadata.hpp
src/plugins/ctf/lttng-live/viewer-connection.cpp
src/plugins/ctf/lttng-live/viewer-connection.hpp
src/plugins/text/details/write.c
src/plugins/text/pretty/print.c
src/plugins/utils/muxer/comp.cpp
src/plugins/utils/muxer/msg-iter.cpp
src/plugins/utils/muxer/upstream-msg-iter.cpp
src/plugins/utils/muxer/upstream-msg-iter.hpp
tests/bindings/python/bt2/.gitignore [deleted file]
tests/data/plugins/src.ctf.lttng-live/cli-multi-domains.expect
tests/lib/conds/clk-cls-compat-postconds-triggers.cpp
tests/lib/conds/conds-triggers.cpp
tests/lib/conds/utils.cpp
tests/lib/conds/utils.hpp
tests/plugins/flt.lttng-utils.debug-info/test-dwarf.c
tests/plugins/flt.utils.muxer/test-clock-compatibility.cpp
tests/python-plugin-provider/.gitignore [deleted file]
tests/utils/utils.sh

index acbb1421c55ea6c46f74ba1033ed57d869e94692..a9d4ceb822d1d653cf322bba503d9e8e155631de 100644 (file)
@@ -66,8 +66,10 @@ Checks:          '-*,
                   misc-misleading-identifier,
                   misc-non-copyable-objects,
                   misc-throw-by-value-catch-by-reference,
+                  misc-unused-alias-decls,
                   misc-unused-parameters,
                   misc-unused-using-decls,
+                  misc-use-anonymous-namespace,
                   modernize-avoid-bind,
                   modernize-concat-nested-namespaces,
                   modernize-loop-convert,
index c63fcaf05cd4635a45910c8deb8c4f7ab5d99d43..904372ce0b567c0dc3f0c8ca094d891d06ba8b9b 100644 (file)
@@ -1,74 +1,89 @@
-/tests/bitfield/test-bitfield
-/tests/argpar/test-argpar
-/tests/ctf-writer/ctf-writer
-/tests/lib/plugin
-/tests/lib/test-bt-uuid
-/tests/lib/test-bt-values
-/tests/lib/test-fields-bin
-/tests/lib/test-graph-topo
-/tests/lib/test-trace-ir-ref
-/tests/lib/test-simple-sink
-/tests/lib/test-remove-destruction-listener-in-destruction-listener
-/tests/lib/conds/conds-triggers
-/tests/param-validation/test-param-validation
-/tests/plugins/flt.lttng-utils.debug-info/test-bin-info
-/tests/plugins/flt.lttng-utils.debug-info/test-dwarf
-/tests/plugins/src.ctf.fs/succeed/gen-trace-simple
-/tests/plugins/sink.ctf.fs/succeed/gen-trace-float
-/tests/plugins/sink.ctf.fs/succeed/gen-trace-double
-/tests/utils/env.sh
-*~
-*.o
+# Generated build files
 *.a
+*.exe
 *.la
 *.lo
-*.exe
-.libs
-.deps
-*.bkp
+*.o
 *.trs
+.deps
+.libs
+
+# Generated Autotools files
 .dirstamp
-/src/plugins/ctf/common/metadata/lexer.cpp
-/src/plugins/ctf/common/metadata/parser.cpp
-/src/plugins/ctf/common/metadata/parser.hpp
-/src/plugins/ctf/common/metadata/parser.output
-/src/bindings/python/bt2/bt2.egg-info
-/src/bindings/python/bt2/dist
-/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
+/autom4te.cache/
+/config.status
+/config/
+/configure
+libtool
 /m4/libtool.m4
-/m4/lt~obsolete.m4
 /m4/ltoptions.m4
 /m4/ltsugar.m4
 /m4/ltversion.m4
-libtool
-/configure
+/m4/lt~obsolete.m4
 Makefile
 Makefile.in
-autom4te.cache/
-config/
-core
 stamp-h1
+
+# Generated Python files
+*.egg-info
 __pycache__
-/src/babeltrace2.pc
+/src/bindings/python/bt2/dist
+
+# Generated pkg-config files
 /src/babeltrace2-ctf-writer.pc
-TAGS
-cscope*
-*.gcno
+/src/babeltrace2.pc
+
+# Generated configuration/version header files
+/src/common/config.h
+/src/common/config.h.in
+/src/common/version.i
+/src/common/version.i.tmp
+
+# Generated CLI binaries
+/src/cli/*.bin
+/src/cli/babeltrace2
+/src/cli/babeltrace2-log
+
+# Generated `ctf` plugin lexer/parser files
+/src/plugins/ctf/common/src/metadata/tsdl/lexer.cpp
+/src/plugins/ctf/common/src/metadata/tsdl/parser.*pp
+/src/plugins/ctf/common/src/metadata/tsdl/parser.output
+
+# Generated test files
+/tests/**/test-*
+!/tests/**/test-*.sh
+!/tests/**/test-*.[hc]
+!/tests/**/test-*.[hc]pp
+/tests/ctf-writer/ctf-writer
+/tests/lib/conds/conds-triggers
+/tests/lib/plugin
+/tests/plugins/sink.ctf.fs/succeed/gen-trace-double
+/tests/plugins/sink.ctf.fs/succeed/gen-trace-float
+/tests/plugins/src.ctf.fs/succeed/gen-trace-simple
+/tests/utils/env.sh
+
+# Version extra information
+/version
+
+# IDE, editor, development tool, and other files
+*.bkp
 *.gcda
+*.gcno
 *.gcov
 *.html
+*.ide
+*.log
 *.stamp
+*.sublime-project
+*.sublime-workspace
 *.swp
+*~
+.cache/
+.coverage
 .theia
 compile_commands.json
-/version
+cscope*
+htmlcov/
+/install/
+TAGS
index f880aacc89c0c2928f823ceb53b4b8ba90b98908..2f272d84e58d8957e8e2e61fb2a7483968e206ad 100644 (file)
@@ -5,3 +5,8 @@ Files:
   src/cpp-common/vendor/fmt/*.cc
 Copyright: 2012 - present, Victor Zverovich
 License: MIT
+
+Files:
+  src/cpp-common/vendor/wise-enum/*.h
+Copyright: 2017 - present, Nir Friedman
+License: BSL-1.0
index 431a16691418bed00a20c174d2982b394b605125..171fcb14a6b41eb991f9d3f0569738e69105aeb5 100644 (file)
@@ -1728,6 +1728,11 @@ When possible, prefer using this over the C{nbsp}logging API.
 One important benefit is that this API uses {fmt} to format the logging
 message instead of `vsnprintf()`.
 
+`make-span.hpp`::
+    The function template `bt2c::makeSpan()` which is an alternative to
+    https://en.cppreference.com/w/cpp/language/class_template_argument_deduction[CTAD]
+    (a {cpp}17 feature).
+
 `prio-heap.hpp`::
     The `bt2c::PrioHeap` class template: an efficient heap data
     structure.
@@ -1777,7 +1782,7 @@ Also provides conversion to `bt2c::Uuid`.
 Everything under the `bt2s` namespace has its equivalent under the `std`
 namespace, but in {cpp} versions we don't yet have access to, namely:
 
-`make_unique.hpp`::
+`make-unique.hpp`::
     `bt2s::make_unique()`, a drop-in replacement of `std::make_unique()`
     ({cpp}14).
 
@@ -1814,6 +1819,11 @@ the `bt2s` namespace, instead of using this directly.
 +
 IMPORTANT: Use the symbols of `src/cpp-common/bt2s/span.hpp`, under the
 `bt2s` namespace, instead of using this directly.
++
+TIP: `src/cpp-common/bt2c/make-span.hpp` offers `bt2c::makeSpan()` which
+is an alternative to
+https://en.cppreference.com/w/cpp/language/class_template_argument_deduction[CTAD]
+(a {cpp}17 feature).
 
 `string-view-lite`::
     https://github.com/martinmoene/string-view-lite[string_view lite].
@@ -1821,6 +1831,9 @@ IMPORTANT: Use the symbols of `src/cpp-common/bt2s/span.hpp`, under the
 IMPORTANT: Use the symbols of `src/cpp-common/bt2s/string-view.hpp`,
 under the `bt2s` namespace, instead of using this directly.
 
+`wise_enum`::
+    https://github.com/quicknir/wise_enum[wise_enum].
+
 === Automake/Libtool requirements
 
 To add a {cpp} source file to a part of the project, use the `.cpp`
@@ -1897,10 +1910,10 @@ $ FORMATTER='my-clang-format-15 -i' ./tools/format-cpp.sh
 * Use camel case with an uppercase first letter for:
 ** Types: `Pistachio`, `NutManager`.
 ** Template parameters: `PlanetT`, `TotalSize`.
+** Enumerators: `Type::SignedInt`, `Scope::Function`.
 
 * Use snake case with uppercase letters for:
 ** Definition/macro names: `MARK_AS_UNUSED()`, `SOME_FEATURE_EXISTS`.
-** Enumerators: `Type::SIGNED_INT`, `Scope::FUNCTION`.
 
 * Use only lowercase letters and digits for namespaces: `mylib`, `bt2`.
 
@@ -2222,9 +2235,9 @@ public:
 
     enum class Gender
     {
-        MALE,
-        FEMALE,
-        OTHER,
+        Male,
+        Female,
+        Other,
     };
 
     explicit Baby() = default;
index b47dd1d846ccba2da3ba5173cd6cea8e7db183ae..5c7c48e46b2cce3d6692d77d1c86c01c5ee4e737 100644 (file)
@@ -138,6 +138,7 @@ embedded into the {bt2} source tree:
 * https://github.com/martinmoene/optional-lite[optional lite]
 * https://github.com/martinmoene/span-lite[span lite]
 * https://github.com/martinmoene/string-view-lite[string_view lite]
+* https://github.com/quicknir/wise_enum[wise_enum]
 * https://github.com/wonder-mice/zf_log[zf_log]
 ====
 
index fa21a8813509bb698b18457bb28b27d24b127830..799df2f79857250c8d57775b870bd2d06618d3f1 100644 (file)
@@ -798,6 +798,11 @@ AC_SUBST(AM_CPPFLAGS)
 # Add glib to global link libs
 LIBS="$LIBS $GLIB_LIBS"
 
+# Disable exceptions for the {fmt} library.  This means, for example, that a
+# format error will result in an assertion failure (instead of throwing an
+# `fmt::format_error` exception).
+AC_DEFINE_UNQUOTED([FMT_EXCEPTIONS], 0, [Disable {fmt} exceptions.])
+
 # Abuse autoconf's AC_ARG_PROGRAM output variable 'program_transform_name'
 # to rename babeltrace2.bin to babeltrace2 at install time.
 program_transform_name="s&babeltrace2\.bin&babeltrace2&;$program_transform_name"
diff --git a/doc/api/libbabeltrace2/.gitignore b/doc/api/libbabeltrace2/.gitignore
deleted file mode 100644 (file)
index 15523a7..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-output
-Doxyfile
-README.html
diff --git a/doc/man/.gitignore b/doc/man/.gitignore
deleted file mode 100644 (file)
index f54189a..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-*.1
-*.7
-*.xml
-*.html
-asciidoc-attrs.conf
index f6bdbee4cc802d47444f3ba9e3332def0d67eca8..10638bd6c0209a213eacaf90e51739543e2eba3a 100644 (file)
@@ -1837,7 +1837,7 @@ returns \c NULL.
     @endparblock
 
 @bt_pre_not_null{value}
-@bt_pre_is_array_val{value}
+@bt_pre_is_map_val{value}
 @bt_pre_not_null{key}
 
 @sa bt_value_map_borrow_entry_value_const() &mdash;
index 2d18268ce6699c767200180c1b2faa93471b19b3..72a714639917b72780ee75115de709bb1ad39237 100644 (file)
@@ -109,7 +109,7 @@ compat_libcompat_la_SOURCES = \
        compat/memstream.h \
        compat/mman.c \
        compat/mman.h \
-       compat/socket.h \
+       compat/socket.hpp \
        compat/stdio.h \
        compat/stdlib.h \
        compat/string.h \
@@ -161,17 +161,19 @@ cpp_common_libcpp_common_la_SOURCES = \
        cpp-common/bt2c/c-string-view.hpp \
        cpp-common/bt2c/call.hpp \
        cpp-common/bt2c/contains.hpp \
-       cpp-common/bt2c/dummy.cpp \
+       cpp-common/bt2c/data-len.hpp \
        cpp-common/bt2c/endian.hpp \
        cpp-common/bt2c/exc.hpp \
+       cpp-common/bt2c/file-utils.cpp \
+       cpp-common/bt2c/file-utils.hpp \
        cpp-common/bt2c/fmt.hpp \
        cpp-common/bt2c/glib-up.hpp \
        cpp-common/bt2c/libc-up.hpp \
        cpp-common/bt2c/logging.hpp \
+       cpp-common/bt2c/make-span.hpp \
        cpp-common/bt2c/prio-heap.hpp \
        cpp-common/bt2c/read-fixed-len-int.hpp \
        cpp-common/bt2c/safe-ops.hpp \
-       cpp-common/bt2c/span.hpp \
        cpp-common/bt2c/std-int.hpp \
        cpp-common/bt2c/type-traits.hpp \
        cpp-common/bt2c/uuid.hpp \
@@ -183,7 +185,12 @@ cpp_common_libcpp_common_la_SOURCES = \
        cpp-common/vendor/nlohmann/json.hpp \
        cpp-common/vendor/optional-lite/optional.hpp \
        cpp-common/vendor/span-lite/span.hpp \
-       cpp-common/vendor/string-view-lite/string_view.hpp
+       cpp-common/vendor/string-view-lite/string_view.hpp \
+       cpp-common/vendor/wise-enum/optional.h \
+       cpp-common/vendor/wise-enum/optional_common.h \
+       cpp-common/vendor/wise-enum/wise_enum.h \
+       cpp-common/vendor/wise-enum/wise_enum_detail.h \
+       cpp-common/vendor/wise-enum/wise_enum_generated.h
 
 cpp_common_vendor_fmt_libfmt_la_SOURCES = \
        cpp-common/vendor/fmt/args.h \
@@ -202,6 +209,9 @@ cpp_common_vendor_fmt_libfmt_la_SOURCES = \
        cpp-common/vendor/fmt/std.h \
        cpp-common/vendor/fmt/xchar.h
 
+cpp_common_vendor_fmt_libfmt_la_CXXFLAGS = \
+       $(AM_CXXFLAGS) -Wno-missing-noreturn
+
 ctfser_libctfser_la_SOURCES = \
        ctfser/ctfser.c \
        ctfser/ctfser.h
@@ -243,14 +253,14 @@ AM_YFLAGS = \
        -t -d -v -Wno-yacc
 
 plugins_ctf_common_metadata_libctf_parser_la_SOURCES = \
-       plugins/ctf/common/metadata/lexer.lpp \
-       plugins/ctf/common/metadata/parser.ypp \
-       plugins/ctf/common/metadata/objstack.cpp
+       plugins/ctf/common/src/metadata/tsdl/lexer.lpp \
+       plugins/ctf/common/src/metadata/tsdl/parser.ypp \
+       plugins/ctf/common/src/metadata/tsdl/objstack.cpp
 
 # scanner-symbols.h is included to prefix generated yy_* symbols with bt_.
 plugins_ctf_common_metadata_libctf_parser_la_CPPFLAGS = \
        $(AM_CPPFLAGS) \
-       -include $(srcdir)/plugins/ctf/common/metadata/scanner-symbols.hpp
+       -include $(srcdir)/plugins/ctf/common/src/metadata/tsdl/scanner-symbols.hpp
 
 # This library contains (mostly) generated code, silence some warnings that it
 # produces.
@@ -262,52 +272,51 @@ plugins_ctf_common_metadata_libctf_parser_la_CXXFLAGS = \
        -Wno-unused-parameter
 
 plugins_ctf_common_metadata_libctf_ast_la_SOURCES = \
-       plugins/ctf/common/metadata/visitor-generate-ir.cpp \
-       plugins/ctf/common/metadata/visitor-semantic-validator.cpp \
-       plugins/ctf/common/metadata/visitor-parent-links.cpp \
-       plugins/ctf/common/metadata/ast.hpp \
-       plugins/ctf/common/metadata/objstack.hpp \
-       plugins/ctf/common/metadata/parser.hpp \
-       plugins/ctf/common/metadata/parser-wrap.hpp \
-       plugins/ctf/common/metadata/scanner.hpp \
-       plugins/ctf/common/metadata/scanner-symbols.hpp \
-       plugins/ctf/common/metadata/decoder.cpp \
-       plugins/ctf/common/metadata/decoder.hpp \
-       plugins/ctf/common/metadata/decoder-packetized-file-stream-to-buf.cpp \
-       plugins/ctf/common/metadata/decoder-packetized-file-stream-to-buf.hpp \
-       plugins/ctf/common/metadata/logging.cpp \
-       plugins/ctf/common/metadata/logging.hpp \
-       plugins/ctf/common/metadata/ctf-meta.hpp \
-       plugins/ctf/common/metadata/ctf-meta-visitors.hpp \
-       plugins/ctf/common/metadata/ctf-meta-validate.cpp \
-       plugins/ctf/common/metadata/ctf-meta-update-meanings.cpp \
-       plugins/ctf/common/metadata/ctf-meta-update-in-ir.cpp \
-       plugins/ctf/common/metadata/ctf-meta-update-default-clock-classes.cpp \
-       plugins/ctf/common/metadata/ctf-meta-update-text-array-sequence.cpp \
-       plugins/ctf/common/metadata/ctf-meta-update-alignments.cpp \
-       plugins/ctf/common/metadata/ctf-meta-update-value-storing-indexes.cpp \
-       plugins/ctf/common/metadata/ctf-meta-update-stream-class-config.cpp \
-       plugins/ctf/common/metadata/ctf-meta-warn-meaningless-header-fields.cpp \
-       plugins/ctf/common/metadata/ctf-meta-translate.cpp \
-       plugins/ctf/common/metadata/ctf-meta-resolve.cpp \
-       plugins/ctf/common/metadata/ctf-meta-configure-ir-trace.cpp \
-       plugins/ctf/common/metadata/ctf-meta-configure-ir-trace.hpp
+       plugins/ctf/common/src/metadata/tsdl/visitor-generate-ir.cpp \
+       plugins/ctf/common/src/metadata/tsdl/visitor-semantic-validator.cpp \
+       plugins/ctf/common/src/metadata/tsdl/visitor-parent-links.cpp \
+       plugins/ctf/common/src/metadata/tsdl/ast.hpp \
+       plugins/ctf/common/src/metadata/tsdl/objstack.hpp \
+       plugins/ctf/common/src/metadata/tsdl/parser.hpp \
+       plugins/ctf/common/src/metadata/tsdl/parser-wrap.hpp \
+       plugins/ctf/common/src/metadata/tsdl/scanner.hpp \
+       plugins/ctf/common/src/metadata/tsdl/scanner-symbols.hpp \
+       plugins/ctf/common/src/metadata/tsdl/decoder.cpp \
+       plugins/ctf/common/src/metadata/tsdl/decoder.hpp \
+       plugins/ctf/common/src/metadata/tsdl/decoder-packetized-file-stream-to-buf.cpp \
+       plugins/ctf/common/src/metadata/tsdl/decoder-packetized-file-stream-to-buf.hpp \
+       plugins/ctf/common/src/metadata/tsdl/logging.hpp \
+       plugins/ctf/common/src/metadata/tsdl/ctf-meta.hpp \
+       plugins/ctf/common/src/metadata/tsdl/ctf-meta-visitors.hpp \
+       plugins/ctf/common/src/metadata/tsdl/ctf-meta-validate.cpp \
+       plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-meanings.cpp \
+       plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-in-ir.cpp \
+       plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-default-clock-classes.cpp \
+       plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-text-array-sequence.cpp \
+       plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-alignments.cpp \
+       plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-value-storing-indexes.cpp \
+       plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-stream-class-config.cpp \
+       plugins/ctf/common/src/metadata/tsdl/ctf-meta-warn-meaningless-header-fields.cpp \
+       plugins/ctf/common/src/metadata/tsdl/ctf-meta-translate.cpp \
+       plugins/ctf/common/src/metadata/tsdl/ctf-meta-resolve.cpp \
+       plugins/ctf/common/src/metadata/tsdl/ctf-meta-configure-ir-trace.cpp \
+       plugins/ctf/common/src/metadata/tsdl/ctf-meta-configure-ir-trace.hpp
 
 if BABELTRACE_BUILD_WITH_MINGW
 plugins_ctf_common_metadata_libctf_ast_la_LIBADD = -lintl -liconv -lole32
 endif
 
 BUILT_SOURCES += \
-       plugins/ctf/common/metadata/parser.hpp
+       plugins/ctf/common/src/metadata/tsdl/parser.hpp
 
 ALL_LOCAL =
 
 if HAVE_BISON
 # We have bison: we can clean the generated parser files
 CLEANFILES += \
-       plugins/ctf/common/metadata/parser.cpp \
-       plugins/ctf/common/metadata/parser.hpp \
-       plugins/ctf/common/metadata/parser.output
+       plugins/ctf/common/src/metadata/tsdl/parser.cpp \
+       plugins/ctf/common/src/metadata/tsdl/parser.hpp \
+       plugins/ctf/common/src/metadata/tsdl/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
@@ -648,11 +657,11 @@ endif
 
 # ctf plugin
 plugins_ctf_babeltrace_plugin_ctf_la_SOURCES = \
-       plugins/ctf/common/bfcr/bfcr.cpp \
-       plugins/ctf/common/bfcr/bfcr.hpp \
-       plugins/ctf/common/msg-iter/msg-iter.cpp \
-       plugins/ctf/common/msg-iter/msg-iter.hpp \
-       plugins/ctf/common/print.hpp \
+       plugins/ctf/common/src/bfcr/bfcr.cpp \
+       plugins/ctf/common/src/bfcr/bfcr.hpp \
+       plugins/ctf/common/src/clk-cls-cfg.hpp \
+       plugins/ctf/common/src/msg-iter/msg-iter.cpp \
+       plugins/ctf/common/src/msg-iter/msg-iter.hpp \
        plugins/ctf/fs-sink/fs-sink.cpp \
        plugins/ctf/fs-sink/fs-sink-ctf-meta.hpp \
        plugins/ctf/fs-sink/fs-sink.hpp \
@@ -706,7 +715,8 @@ plugins_ctf_babeltrace_plugin_ctf_la_LIBADD += \
        logging/liblogging.la \
        plugins/common/muxing/libmuxing.la \
        common/libcommon.la \
-       ctfser/libctfser.la
+       ctfser/libctfser.la \
+       cpp-common/vendor/fmt/libfmt.la
 endif
 
 # text plugin
diff --git a/src/bindings/python/bt2/.gitignore b/src/bindings/python/bt2/.gitignore
deleted file mode 100644 (file)
index fc7a23f..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-# SPDX-FileCopyrightText: 2019-2020 EfficiOS, Inc.
-# SPDX-License-Identifier: MIT
-
-bt2/native_bt.py
-bt2/native_bt.c
-bt2/native_bt.d
-bt2/version.py
-build
-build-python-bindings.stamp
-installed_files.txt
-setup.py
index 0d1ca724c38f910b43bb0f805bc9bb68238da148..3c81447ea80a2d8dd928f43aba69feea2bf7f980 100644 (file)
@@ -5,6 +5,8 @@
 
 import sys
 import os
+import shutil
+import subprocess
 
 # Distutils was removed in Python 3.12, use setuptools as an alternative.
 if sys.version_info >= (3, 12):
@@ -114,10 +116,44 @@ def our_get_config_vars(*args):
 sysconfig.get_config_vars = our_get_config_vars
 
 
+# Returns 'True' when running on a MinGW system.
+def is_mingw():
+    return sys.platform == "win32" and shutil.which("cygpath") != None
+
+
+# On MinGW systems run 'cygpath -m' on 'path', on other systems return 'path' as-is.
+def cygpath_m(path: str):
+    if is_mingw():
+        return subprocess.check_output(
+            'cygpath -m "{}"'.format(path), shell=True, encoding="utf-8"
+        ).strip("\n")
+
+    return path
+
+
+# On MinGW systems, check CFLAGS and CPPFLAGS for absolute include paths
+# (starts with '-I/') and convert them to valid Windows paths using cygpath.
+if is_mingw():
+    for flagvar in ["CFLAGS", "CPPFLAGS"]:
+        cur_flags = os.getenv(flagvar)
+        if cur_flags != None:
+            new_flags = ""
+            for flag in cur_flags.split():
+                if flag.startswith("-I/"):
+                    flag = "-I{}".format(cygpath_m(flag[2:]))
+
+                new_flags += " {}".format(flag)
+
+            os.environ[flagvar] = new_flags
+
+
 def main():
     babeltrace_ext = Extension(
         "bt2._native_bt",
-        sources=["bt2/native_bt.c", "@srcdir@/bt2/logging.c"],
+        sources=[
+            "bt2/native_bt.c",
+            cygpath_m("@srcdir@/bt2/logging.c"),
+        ],
         libraries=["babeltrace2", "glib-2.0"],
         extra_objects=[
             "@top_builddir@/src/autodisc/.libs/libautodisc.a",
index a116c364ccdbd6af5ca17eed6fb853f9dcf20913..4bb1a725bcddf4a4c85d4f008e9585301bb200f5 100644 (file)
@@ -19,12 +19,12 @@ void ClockCorrelationValidator::_validate(const bt2::ConstMessage msg)
     bt2::OptionalBorrowedObject<bt2::ConstStreamClass> streamCls;
 
     switch (msg.type()) {
-    case bt2::MessageType::STREAM_BEGINNING:
+    case bt2::MessageType::StreamBeginning:
         streamCls = msg.asStreamBeginning().stream().cls();
         clockCls = streamCls->defaultClockClass();
         break;
 
-    case bt2::MessageType::MESSAGE_ITERATOR_INACTIVITY:
+    case bt2::MessageType::MessageIteratorInactivity:
         clockCls = msg.asMessageIteratorInactivity().clockSnapshot().clockClass();
         break;
 
@@ -33,93 +33,87 @@ void ClockCorrelationValidator::_validate(const bt2::ConstMessage msg)
     }
 
     switch (_mExpectation) {
-    case PropsExpectation::UNSET:
+    case PropsExpectation::Unset:
         /*
          * This is the first analysis of a message with a clock
          * snapshot: record the properties of that clock, against which
          * we'll compare the clock properties of the following messages.
          */
         if (!clockCls) {
-            _mExpectation = PropsExpectation::NONE;
+            _mExpectation = PropsExpectation::None;
         } else if (clockCls->originIsUnixEpoch()) {
-            _mExpectation = PropsExpectation::ORIGIN_UNIX;
+            _mExpectation = PropsExpectation::OriginUnix;
         } else if (const auto uuid = clockCls->uuid()) {
-            _mExpectation = PropsExpectation::ORIGIN_OTHER_UUID;
+            _mExpectation = PropsExpectation::OriginOtherUuid;
             _mUuid = *uuid;
         } else {
-            _mExpectation = PropsExpectation::ORIGIN_OTHER_NO_UUID;
+            _mExpectation = PropsExpectation::OriginOtherNoUuid;
             _mClockClass = clockCls->shared();
         }
 
         break;
 
-    case PropsExpectation::NONE:
+    case PropsExpectation::None:
         if (clockCls) {
-            throw ClockCorrelationError {
-                ClockCorrelationError::Type::EXPECTING_NO_CLOCK_CLASS_GOT_ONE,
-                bt2s::nullopt,
-                *clockCls,
-                {},
-                streamCls};
+            throw ClockCorrelationError {ClockCorrelationError::Type::ExpectingNoClockClassGotOne,
+                                         bt2s::nullopt,
+                                         *clockCls,
+                                         {},
+                                         streamCls};
         }
 
         break;
 
-    case PropsExpectation::ORIGIN_UNIX:
+    case PropsExpectation::OriginUnix:
         if (!clockCls) {
-            throw ClockCorrelationError {
-                ClockCorrelationError::Type::EXPECTING_ORIGIN_UNIX_GOT_NONE,
-                bt2s::nullopt,
-                {},
-                {},
-                streamCls};
+            throw ClockCorrelationError {ClockCorrelationError::Type::ExpectingOriginUnixGotNone,
+                                         bt2s::nullopt,
+                                         {},
+                                         {},
+                                         streamCls};
         }
 
         if (!clockCls->originIsUnixEpoch()) {
-            throw ClockCorrelationError {
-                ClockCorrelationError::Type::EXPECTING_ORIGIN_UNIX_GOT_OTHER,
-                bt2s::nullopt,
-                *clockCls,
-                {},
-                streamCls};
+            throw ClockCorrelationError {ClockCorrelationError::Type::ExpectingOriginUnixGotOther,
+                                         bt2s::nullopt,
+                                         *clockCls,
+                                         {},
+                                         streamCls};
         }
 
         break;
 
-    case PropsExpectation::ORIGIN_OTHER_UUID:
+    case PropsExpectation::OriginOtherUuid:
     {
         if (!clockCls) {
-            throw ClockCorrelationError {
-                ClockCorrelationError::Type::EXPECTING_ORIGIN_UUID_GOT_NONE,
-                bt2s::nullopt,
-                {},
-                {},
-                streamCls};
+            throw ClockCorrelationError {ClockCorrelationError::Type::ExpectingOriginUuidGotNone,
+                                         bt2s::nullopt,
+                                         {},
+                                         {},
+                                         streamCls};
         }
 
         if (clockCls->originIsUnixEpoch()) {
-            throw ClockCorrelationError {
-                ClockCorrelationError::Type::EXPECTING_ORIGIN_UUID_GOT_UNIX,
-                bt2s::nullopt,
-                *clockCls,
-                {},
-                streamCls};
+            throw ClockCorrelationError {ClockCorrelationError::Type::ExpectingOriginUuidGotUnix,
+                                         bt2s::nullopt,
+                                         *clockCls,
+                                         {},
+                                         streamCls};
         }
 
         const auto uuid = clockCls->uuid();
 
         if (!uuid) {
-            throw ClockCorrelationError {
-                ClockCorrelationError::Type::EXPECTING_ORIGIN_UUID_GOT_NO_UUID,
-                bt2s::nullopt,
-                *clockCls,
-                {},
-                streamCls};
+            throw ClockCorrelationError {ClockCorrelationError::Type::ExpectingOriginUuidGotNoUuid,
+                                         bt2s::nullopt,
+                                         *clockCls,
+                                         {},
+                                         streamCls};
         }
 
         if (*uuid != _mUuid) {
             throw ClockCorrelationError {
-                ClockCorrelationError::Type::EXPECTING_ORIGIN_UUID_GOT_OTHER_UUID,
+                ClockCorrelationError::Type::ExpectingOriginUuidGotOtherUuid,
                 _mUuid,
                 *clockCls,
                 {},
@@ -129,20 +123,18 @@ void ClockCorrelationValidator::_validate(const bt2::ConstMessage msg)
         break;
     }
 
-    case PropsExpectation::ORIGIN_OTHER_NO_UUID:
+    case PropsExpectation::OriginOtherNoUuid:
         if (!clockCls) {
-            throw ClockCorrelationError {
-                ClockCorrelationError::Type::EXPECTING_ORIGIN_NO_UUID_GOT_NONE,
-                bt2s::nullopt,
-                {},
-                {},
-                streamCls};
+            throw ClockCorrelationError {ClockCorrelationError::Type::ExpectingOriginNoUuidGotNone,
+                                         bt2s::nullopt,
+                                         {},
+                                         {},
+                                         streamCls};
         }
 
         if (clockCls->libObjPtr() != _mClockClass->libObjPtr()) {
-            throw ClockCorrelationError {
-                ClockCorrelationError::Type::EXPECTING_ORIGIN_NO_UUID_GOT_OTHER, bt2s::nullopt,
-                *clockCls, *_mClockClass, streamCls};
+            throw ClockCorrelationError {ClockCorrelationError::Type::ExpectingOriginNoUuidGotOther,
+                                         bt2s::nullopt, *clockCls, *_mClockClass, streamCls};
         }
 
         break;
index 773c97cba00647d84db2e0e403fdfffed96b3fcb..314551c3cd7cee53cd4b749a5397ced606fb2d59 100644 (file)
@@ -18,23 +18,23 @@ class ClockCorrelationError final : public std::runtime_error
 public:
     enum class Type
     {
-        EXPECTING_NO_CLOCK_CLASS_GOT_ONE =
+        ExpectingNoClockClassGotOne =
             BT_CLOCK_CORRELATION_VALIDATOR_ERROR_TYPE_EXPECTING_NO_CLOCK_CLASS_GOT_ONE,
-        EXPECTING_ORIGIN_UNIX_GOT_NONE =
+        ExpectingOriginUnixGotNone =
             BT_CLOCK_CORRELATION_VALIDATOR_ERROR_TYPE_EXPECTING_ORIGIN_UNIX_GOT_NONE,
-        EXPECTING_ORIGIN_UNIX_GOT_OTHER =
+        ExpectingOriginUnixGotOther =
             BT_CLOCK_CORRELATION_VALIDATOR_ERROR_TYPE_EXPECTING_ORIGIN_UNIX_GOT_OTHER,
-        EXPECTING_ORIGIN_UUID_GOT_NONE =
+        ExpectingOriginUuidGotNone =
             BT_CLOCK_CORRELATION_VALIDATOR_ERROR_TYPE_EXPECTING_ORIGIN_UUID_GOT_NONE,
-        EXPECTING_ORIGIN_UUID_GOT_UNIX =
+        ExpectingOriginUuidGotUnix =
             BT_CLOCK_CORRELATION_VALIDATOR_ERROR_TYPE_EXPECTING_ORIGIN_UUID_GOT_UNIX,
-        EXPECTING_ORIGIN_UUID_GOT_NO_UUID =
+        ExpectingOriginUuidGotNoUuid =
             BT_CLOCK_CORRELATION_VALIDATOR_ERROR_TYPE_EXPECTING_ORIGIN_UUID_GOT_NO_UUID,
-        EXPECTING_ORIGIN_UUID_GOT_OTHER_UUID =
+        ExpectingOriginUuidGotOtherUuid =
             BT_CLOCK_CORRELATION_VALIDATOR_ERROR_TYPE_EXPECTING_ORIGIN_UUID_GOT_OTHER_UUID,
-        EXPECTING_ORIGIN_NO_UUID_GOT_NONE =
+        ExpectingOriginNoUuidGotNone =
             BT_CLOCK_CORRELATION_VALIDATOR_ERROR_TYPE_EXPECTING_ORIGIN_NO_UUID_GOT_NONE,
-        EXPECTING_ORIGIN_NO_UUID_GOT_OTHER =
+        ExpectingOriginNoUuidGotOther =
             BT_CLOCK_CORRELATION_VALIDATOR_ERROR_TYPE_EXPECTING_ORIGIN_NO_UUID_GOT_OTHER,
     };
 
@@ -89,19 +89,19 @@ private:
     enum class PropsExpectation
     {
         /* We haven't recorded clock properties yet. */
-        UNSET,
+        Unset,
 
         /* Expect to have no clock. */
-        NONE,
+        None,
 
         /* Expect a clock with a Unix epoch origin. */
-        ORIGIN_UNIX,
+        OriginUnix,
 
         /* Expect a clock without a Unix epoch origin, but with a UUID. */
-        ORIGIN_OTHER_UUID,
+        OriginOtherUuid,
 
         /* Expect a clock without a Unix epoch origin and without a UUID. */
-        ORIGIN_OTHER_NO_UUID,
+        OriginOtherNoUuid,
     };
 
 public:
@@ -117,7 +117,7 @@ public:
 private:
     void _validate(const bt2::ConstMessage msg);
 
-    PropsExpectation _mExpectation = PropsExpectation::UNSET;
+    PropsExpectation _mExpectation = PropsExpectation::Unset;
 
     /*
      * Expected UUID of the clock, if `_mExpectation` is
index 13ba2d3628c1abf4b36239838be6e00146224da5..8120515c63fe5bbcd81672f8c7b4cf1df89d9ce8 100644 (file)
@@ -99,6 +99,11 @@ extern "C" {
        ((void) sizeof((void) (_expr1), (void) (_expr2),                \
                (void) (_expr3), (void) (_expr4), (void) (_expr5), 0))
 
+#define BT_DIAG_PUSH _Pragma ("GCC diagnostic push")
+#define BT_DIAG_POP _Pragma ("GCC diagnostic push")
+
+#define BT_DIAG_IGNORE_SHADOW _Pragma("GCC diagnostic ignored \"-Wshadow\"")
+
 #if defined __clang__
 #  if __has_warning("-Wunused-but-set-variable")
 #    define BT_DIAG_IGNORE_UNUSED_BUT_SET_VARIABLE \
diff --git a/src/compat/socket.h b/src/compat/socket.h
deleted file mode 100644 (file)
index 4715677..0000000
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright (C) 2015-2017 Michael Jeanson <mjeanson@efficios.com>
- * Copyright (C) 2015 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- */
-
-#ifndef _BABELTRACE_COMPAT_SOCKET_H
-#define _BABELTRACE_COMPAT_SOCKET_H
-
-#include <stdbool.h>
-
-#ifdef __MINGW32__
-
-#include <winsock2.h>
-
-#define BT_INVALID_SOCKET INVALID_SOCKET
-#define BT_SOCKET_ERROR SOCKET_ERROR
-#define BT_SOCKET SOCKET
-
-#ifndef BT_LOG_WRITE_CUR_LVL
-#define BT_SOCKET_LOG_LEVEL_UNUSED_ATTR __attribute__((unused))
-#else
-#define BT_SOCKET_LOG_LEVEL_UNUSED_ATTR
-#endif
-
-static inline
-int bt_socket_init(int log_level BT_SOCKET_LOG_LEVEL_UNUSED_ATTR)
-{
-       WORD verreq;
-       WSADATA wsa;
-       int ret;
-
-       /* Request winsock 2.2 support */
-       verreq = MAKEWORD(2, 2);
-
-       ret = WSAStartup(verreq, &wsa);
-       if (ret != 0) {
-#ifdef BT_LOG_WRITE_PRINTF_CUR_LVL
-               BT_LOG_WRITE_PRINTF_CUR_LVL(BT_LOG_ERROR, log_level, BT_LOG_TAG,
-                               "Winsock init failed with error: %d", ret);
-#endif
-               goto end;
-       }
-
-       if (LOBYTE(wsa.wVersion) != 2 || HIBYTE(wsa.wVersion) != 2) {
-#ifdef BT_LOG_WRITE_CUR_LVL
-               BT_LOG_WRITE_CUR_LVL(BT_LOG_ERROR, log_level, BT_LOG_TAG,
-                               "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, (const char *) buf, len, flags);
-}
-
-static inline
-int bt_socket_recv(int sockfd, void *buf, size_t len, int flags)
-{
-       return recv(sockfd, (char *) 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 <errno.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <unistd.h>
-
-#include <glib.h>
-
-#define BT_INVALID_SOCKET -1
-#define BT_SOCKET_ERROR -1
-#define BT_SOCKET int
-
-static inline
-int bt_socket_init(int log_level __attribute__((unused)))
-{
-       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/socket.hpp b/src/compat/socket.hpp
new file mode 100644 (file)
index 0000000..972f692
--- /dev/null
@@ -0,0 +1,386 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright (C) 2015-2017 Michael Jeanson <mjeanson@efficios.com>
+ * Copyright (C) 2015 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ */
+
+#ifndef BABELTRACE_COMPAT_SOCKET_HPP
+#define BABELTRACE_COMPAT_SOCKET_HPP
+
+#include <stdbool.h>
+
+#include "cpp-common/bt2c/logging.hpp"
+
+#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(const bt2c::Logger& logger)
+{
+    WORD verreq;
+    WSADATA wsa;
+    int ret;
+
+    /* Request winsock 2.2 support */
+    verreq = MAKEWORD(2, 2);
+
+    ret = WSAStartup(verreq, &wsa);
+    if (ret != 0) {
+        BT_CPPLOGE_SPEC(logger, "Winsock init failed with error: {}", ret);
+        goto end;
+    }
+
+    if (LOBYTE(wsa.wVersion) != 2 || HIBYTE(wsa.wVersion) != 2) {
+        BT_CPPLOGE_SPEC(logger, "Could not init winsock 2.2 support");
+        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, (const char *) buf, len, flags);
+}
+
+static inline int bt_socket_recv(int sockfd, void *buf, size_t len, int flags)
+{
+    return recv(sockfd, (char *) 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 <errno.h>
+#    include <glib.h>
+#    include <netdb.h>
+#    include <netinet/in.h>
+#    include <sys/socket.h>
+#    include <unistd.h>
+
+#    define BT_INVALID_SOCKET -1
+#    define BT_SOCKET_ERROR   -1
+#    define BT_SOCKET         int
+
+static inline int bt_socket_init(const bt2c::Logger&)
+{
+    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_HPP */
index b89ac6b24305fa95b6eda6339138acff04d317c4..e0d45d6b7e20f0347dbbba67c473ee60f2a504e0 100644 (file)
@@ -471,9 +471,9 @@ private:
     /* Type of `_mExcToThrowType` */
     enum class _ExcToThrowType
     {
-        NONE,
-        ERROR,
-        MEM_ERROR,
+        None,
+        Error,
+        MemError,
     };
 
 protected:
@@ -489,17 +489,17 @@ public:
     void next(ConstMessageArray& messages)
     {
         /* Any saved error? Now is the time to throw */
-        if (G_UNLIKELY(_mExcToThrowType != _ExcToThrowType::NONE)) {
+        if (G_UNLIKELY(_mExcToThrowType != _ExcToThrowType::None)) {
             /* Move `_mSavedLibError`, if any, as current thread error */
             if (_mSavedLibError) {
                 bt_current_thread_move_error(_mSavedLibError.release());
             }
 
             /* Throw the corresponding exception */
-            if (_mExcToThrowType == _ExcToThrowType::ERROR) {
+            if (_mExcToThrowType == _ExcToThrowType::Error) {
                 throw Error {};
             } else {
-                BT_ASSERT(_mExcToThrowType == _ExcToThrowType::MEM_ERROR);
+                BT_ASSERT(_mExcToThrowType == _ExcToThrowType::MemError);
                 throw MemoryError {};
             }
         }
@@ -513,7 +513,7 @@ public:
          * if any, so that we can restore it later (see the beginning of
          * this method).
          */
-        BT_ASSERT_DBG(_mExcToThrowType == _ExcToThrowType::NONE);
+        BT_ASSERT_DBG(_mExcToThrowType == _ExcToThrowType::None);
 
         try {
             this->_userObj()._next(messages);
@@ -529,16 +529,16 @@ public:
                 throw;
             }
 
-            _mExcToThrowType = _ExcToThrowType::MEM_ERROR;
+            _mExcToThrowType = _ExcToThrowType::MemError;
         } catch (const Error&) {
             if (messages.isEmpty()) {
                 throw;
             }
 
-            _mExcToThrowType = _ExcToThrowType::ERROR;
+            _mExcToThrowType = _ExcToThrowType::Error;
         }
 
-        if (_mExcToThrowType != _ExcToThrowType::NONE) {
+        if (_mExcToThrowType != _ExcToThrowType::None) {
             BT_CPPLOGE(
                 "An error occurred, but there are {} messages to return: delaying the error reporting.",
                 messages.length());
@@ -716,7 +716,7 @@ private:
 
     void _resetError() noexcept
     {
-        _mExcToThrowType = _ExcToThrowType::NONE;
+        _mExcToThrowType = _ExcToThrowType::None;
         _mSavedLibError.reset();
     }
 
@@ -730,7 +730,7 @@ private:
      *
      * It also saves the type of the exception to throw the next time.
      */
-    _ExcToThrowType _mExcToThrowType = _ExcToThrowType::NONE;
+    _ExcToThrowType _mExcToThrowType = _ExcToThrowType::None;
 
     struct LibErrorDeleter final
     {
index e32ba34ae6811be0558401ce3f3f05de0b91b057..2933d74f737fd6d6e56d13f672549029579cd8f6 100644 (file)
@@ -33,6 +33,13 @@ struct ComponentClassRefFuncs final
 
 } /* namespace internal */
 
+enum class ComponentClassType
+{
+    Source = BT_COMPONENT_CLASS_TYPE_SOURCE,
+    Filter = BT_COMPONENT_CLASS_TYPE_FILTER,
+    Sink = BT_COMPONENT_CLASS_TYPE_SINK,
+};
+
 template <typename LibObjT>
 class CommonSourceComponentClass;
 
@@ -52,13 +59,6 @@ public:
     using typename _ThisBorrowedObject::LibObjPtr;
     using Shared = SharedObject<CommonComponentClass, LibObjT, internal::ComponentClassRefFuncs>;
 
-    enum class Type
-    {
-        SOURCE = BT_COMPONENT_CLASS_TYPE_SOURCE,
-        FILTER = BT_COMPONENT_CLASS_TYPE_FILTER,
-        SINK = BT_COMPONENT_CLASS_TYPE_SINK,
-    };
-
     explicit CommonComponentClass(const LibObjPtr libObjPtr) noexcept :
         _ThisBorrowedObject {libObjPtr}
     {
index 7daaaf6b4b17c41c05ac88c204ee80110a39075e..d4dfeaac25807e75f8ee8febac5d0dc3f31dde3f 100644 (file)
@@ -25,39 +25,39 @@ class ConstComponentClassErrorCause;
 class ConstComponentErrorCause;
 class ConstMessageIteratorErrorCause;
 
+enum class ErrorCauseActorType
+{
+    Unknown = BT_ERROR_CAUSE_ACTOR_TYPE_UNKNOWN,
+    Component = BT_ERROR_CAUSE_ACTOR_TYPE_COMPONENT,
+    ComponentClass = BT_ERROR_CAUSE_ACTOR_TYPE_COMPONENT_CLASS,
+    MessageIterator = BT_ERROR_CAUSE_ACTOR_TYPE_MESSAGE_ITERATOR,
+};
+
 class ConstErrorCause : public BorrowedObject<const bt_error_cause>
 {
 public:
-    enum class ActorType
-    {
-        UNKNOWN = BT_ERROR_CAUSE_ACTOR_TYPE_UNKNOWN,
-        COMPONENT = BT_ERROR_CAUSE_ACTOR_TYPE_COMPONENT,
-        COMPONENT_CLASS = BT_ERROR_CAUSE_ACTOR_TYPE_COMPONENT_CLASS,
-        MESSAGE_ITERATOR = BT_ERROR_CAUSE_ACTOR_TYPE_MESSAGE_ITERATOR,
-    };
-
     explicit ConstErrorCause(const LibObjPtr libObjPtr) noexcept : _ThisBorrowedObject {libObjPtr}
     {
     }
 
-    ActorType actorType() const noexcept
+    ErrorCauseActorType actorType() const noexcept
     {
-        return static_cast<ActorType>(bt_error_cause_get_actor_type(this->libObjPtr()));
+        return static_cast<ErrorCauseActorType>(bt_error_cause_get_actor_type(this->libObjPtr()));
     }
 
     bool actorTypeIsComponentClass() const noexcept
     {
-        return this->actorType() == ActorType::COMPONENT_CLASS;
+        return this->actorType() == ErrorCauseActorType::ComponentClass;
     }
 
     bool actorTypeIsComponent() const noexcept
     {
-        return this->actorType() == ActorType::COMPONENT;
+        return this->actorType() == ErrorCauseActorType::Component;
     }
 
     bool actorTypeIsMessageIterator() const noexcept
     {
-        return this->actorType() == ActorType::MESSAGE_ITERATOR;
+        return this->actorType() == ErrorCauseActorType::MessageIterator;
     }
 
     ConstComponentClassErrorCause asComponentClass() const noexcept;
@@ -93,9 +93,9 @@ public:
         BT_ASSERT(this->actorTypeIsComponentClass());
     }
 
-    bt2::ComponentClass::Type componentClassType() const noexcept
+    bt2::ComponentClassType componentClassType() const noexcept
     {
-        return static_cast<bt2::ComponentClass::Type>(
+        return static_cast<bt2::ComponentClassType>(
             bt_error_cause_component_class_actor_get_component_class_type(this->libObjPtr()));
     }
 
@@ -128,9 +128,9 @@ public:
         return bt_error_cause_component_actor_get_component_name(this->libObjPtr());
     }
 
-    bt2::ComponentClass::Type componentClassType() const noexcept
+    bt2::ComponentClassType componentClassType() const noexcept
     {
-        return static_cast<bt2::ComponentClass::Type>(
+        return static_cast<bt2::ComponentClassType>(
             bt_error_cause_component_actor_get_component_class_type(this->libObjPtr()));
     }
 
@@ -168,9 +168,9 @@ public:
         return bt_error_cause_message_iterator_actor_get_component_name(this->libObjPtr());
     }
 
-    bt2::ComponentClass::Type componentClassType() const noexcept
+    bt2::ComponentClassType componentClassType() const noexcept
     {
-        return static_cast<bt2::ComponentClass::Type>(
+        return static_cast<bt2::ComponentClassType>(
             bt_error_cause_message_iterator_actor_get_component_class_type(this->libObjPtr()));
     }
 
@@ -219,7 +219,7 @@ class ConstErrorIterator final
 
 private:
     explicit ConstErrorIterator(const UniqueConstError& error, const std::uint64_t index) noexcept :
-        _mError {error}, _mIndex {index}
+        _mError {&error}, _mIndex {index}
     {
     }
 
@@ -257,7 +257,7 @@ public:
     }
 
 private:
-    const UniqueConstError_mError;
+    const UniqueConstError *_mError;
     std::uint64_t _mIndex;
 };
 
@@ -321,7 +321,7 @@ private:
 
 inline ConstErrorCause ConstErrorIterator::operator*() const noexcept
 {
-    return _mError[_mIndex];
+    return (*_mError)[_mIndex];
 }
 
 inline UniqueConstError takeCurrentThreadError() noexcept
index 411cf6690a1798355b2bcc2341a5621f203acc01..71e32e411d2d43cb5d19ed411b41383aa82488bc 100644 (file)
@@ -135,29 +135,28 @@ class CommonTraceClass;
 
 enum class FieldClassType
 {
-    BOOL = BT_FIELD_CLASS_TYPE_BOOL,
-    BIT_ARRAY = BT_FIELD_CLASS_TYPE_BIT_ARRAY,
-    UNSIGNED_INTEGER = BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER,
-    SIGNED_INTEGER = BT_FIELD_CLASS_TYPE_SIGNED_INTEGER,
-    UNSIGNED_ENUMERATION = BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION,
-    SIGNED_ENUMERATION = BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION,
-    SINGLE_PRECISION_REAL = BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL,
-    DOUBLE_PRECISION_REAL = BT_FIELD_CLASS_TYPE_DOUBLE_PRECISION_REAL,
-    STRING = BT_FIELD_CLASS_TYPE_STRING,
-    STRUCTURE = BT_FIELD_CLASS_TYPE_STRUCTURE,
-    STATIC_ARRAY = BT_FIELD_CLASS_TYPE_STATIC_ARRAY,
-    DYNAMIC_ARRAY_WITHOUT_LENGTH = BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITHOUT_LENGTH_FIELD,
-    DYNAMIC_ARRAY_WITH_LENGTH = BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD,
-    OPTION_WITHOUT_SELECTOR = BT_FIELD_CLASS_TYPE_OPTION_WITHOUT_SELECTOR_FIELD,
-    OPTION_WITH_BOOL_SELECTOR = BT_FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR_FIELD,
-    OPTION_WITH_UNSIGNED_INTEGER_SELECTOR =
+    Bool = BT_FIELD_CLASS_TYPE_BOOL,
+    BitArray = BT_FIELD_CLASS_TYPE_BIT_ARRAY,
+    UnsignedInteger = BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER,
+    SignedInteger = BT_FIELD_CLASS_TYPE_SIGNED_INTEGER,
+    UnsignedEnumeration = BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION,
+    SignedEnumeration = BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION,
+    SinglePrecisionReal = BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL,
+    DoublePrecisionReal = BT_FIELD_CLASS_TYPE_DOUBLE_PRECISION_REAL,
+    String = BT_FIELD_CLASS_TYPE_STRING,
+    Structure = BT_FIELD_CLASS_TYPE_STRUCTURE,
+    StaticArray = BT_FIELD_CLASS_TYPE_STATIC_ARRAY,
+    DynamicArrayWithoutLength = BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITHOUT_LENGTH_FIELD,
+    DynamicArrayWithLength = BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD,
+    OptionWithoutSelector = BT_FIELD_CLASS_TYPE_OPTION_WITHOUT_SELECTOR_FIELD,
+    OptionWithBoolSelector = BT_FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR_FIELD,
+    OptionWithUnsignedIntegerSelector =
         BT_FIELD_CLASS_TYPE_OPTION_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD,
-    OPTION_WITH_SIGNED_INTEGER_SELECTOR =
-        BT_FIELD_CLASS_TYPE_OPTION_WITH_SIGNED_INTEGER_SELECTOR_FIELD,
-    VARIANT_WITHOUT_SELECTOR = BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR_FIELD,
-    VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR =
+    OptionWithSignedIntegerSelector = BT_FIELD_CLASS_TYPE_OPTION_WITH_SIGNED_INTEGER_SELECTOR_FIELD,
+    VariantWithoutSelector = BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR_FIELD,
+    VariantWithUnsignedIntegerSelector =
         BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD,
-    VARIANT_WITH_SIGNED_INTEGER_SELECTOR =
+    VariantWithSignedIntegerSelector =
         BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR_FIELD,
 };
 
@@ -522,10 +521,10 @@ struct TypeDescr<ConstBitArrayFieldClass> : public BitArrayFieldClassTypeDescr
 
 enum class DisplayBase
 {
-    BINARY = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY,
-    OCTAL = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL,
-    DECIMAL = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
-    HEXADECIMAL = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL,
+    Binary = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY,
+    Octal = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL,
+    Decimal = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
+    Hexadecimal = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL,
 };
 
 template <typename LibObjT>
@@ -865,6 +864,9 @@ public:
     CommonEnumerationFieldClass addMapping(const bt2c::CStringView label,
                                            const typename Mapping::RangeSet ranges) const
     {
+        static_assert(!std::is_const<LibObjT>::value,
+                      "Not available with `bt2::Const*EnumerationFieldClass`.");
+
         const auto status = internal::CommonEnumerationFieldClassSpec<MappingT>::addMapping(
             this->libObjPtr(), label, ranges.libObjPtr());
 
index fc087593b881ecbaef878ccdea4642c4c3884de4..ed44ad4bda9a25a099c6645dd5f2a4020d178e06 100644 (file)
@@ -12,6 +12,7 @@
 #include <babeltrace2/babeltrace.h>
 
 #include "common/assert.h"
+#include "cpp-common/vendor/wise-enum/wise_enum.h"
 
 #include "borrowed-object-iterator.hpp"
 #include "borrowed-object.hpp"
@@ -23,9 +24,9 @@ class ConstIndexFieldPathItem;
 
 enum class FieldPathItemType
 {
-    INDEX = BT_FIELD_PATH_ITEM_TYPE_INDEX,
-    CURRENT_ARRAY_ELEMENT = BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT,
-    CURRENT_OPTION_CONTENT = BT_FIELD_PATH_ITEM_TYPE_CURRENT_OPTION_CONTENT,
+    Index = BT_FIELD_PATH_ITEM_TYPE_INDEX,
+    CurrentArrayElement = BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT,
+    CurrentOptionContent = BT_FIELD_PATH_ITEM_TYPE_CURRENT_OPTION_CONTENT,
 };
 
 class ConstFieldPathItem : public BorrowedObject<const bt_field_path_item>
@@ -102,27 +103,29 @@ struct FieldPathRefFuncs final
 
 } /* namespace internal */
 
+/* clang-format off */
+
+WISE_ENUM_CLASS(FieldPathScope,
+    (PacketContext, BT_FIELD_PATH_SCOPE_PACKET_CONTEXT),
+    (EventCommonContext, BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT),
+    (EventSpecificContext, BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT),
+    (EventPayload, BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD))
+
+/* clang-format on */
+
 class ConstFieldPath final : public BorrowedObject<const bt_field_path>
 {
 public:
     using Shared = SharedObject<ConstFieldPath, const bt_field_path, internal::FieldPathRefFuncs>;
     using Iterator = BorrowedObjectIterator<ConstFieldPath>;
 
-    enum class Scope
-    {
-        PACKET_CONTEXT = BT_FIELD_PATH_SCOPE_PACKET_CONTEXT,
-        EVENT_COMMON_CONTEXT = BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT,
-        EVENT_SPECIFIC_CONTEXT = BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT,
-        EVENT_PAYLOAD = BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD,
-    };
-
     explicit ConstFieldPath(const LibObjPtr libObjPtr) noexcept : _ThisBorrowedObject {libObjPtr}
     {
     }
 
-    Scope rootScope() const noexcept
+    FieldPathScope rootScope() const noexcept
     {
-        return static_cast<Scope>(bt_field_path_get_root_scope(this->libObjPtr()));
+        return static_cast<FieldPathScope>(bt_field_path_get_root_scope(this->libObjPtr()));
     }
 
     std::uint64_t length() const noexcept
index 0927cd30a0f2483aa22363dcd835844b9239c2f5..e2bcf77ce5ced33692f25c807b3f5f60c619b808 100644 (file)
@@ -57,7 +57,7 @@ public:
     ConstSourceComponent addComponent(const ConstSourceComponentClass componentClass,
                                       const bt2c::CStringView name,
                                       const OptionalBorrowedObject<ConstMapValue> params = {},
-                                      const LoggingLevel loggingLevel = LoggingLevel::NONE) const
+                                      const LoggingLevel loggingLevel = LoggingLevel::None) const
     {
         return this->_addComponent<ConstSourceComponent>(
             componentClass, name, params, static_cast<void *>(nullptr), loggingLevel,
@@ -68,7 +68,7 @@ public:
     ConstSourceComponent addComponent(const ConstSourceComponentClass componentClass,
                                       const bt2c::CStringView name, InitDataT&& initData,
                                       const OptionalBorrowedObject<ConstMapValue> params = {},
-                                      const LoggingLevel loggingLevel = LoggingLevel::NONE) const
+                                      const LoggingLevel loggingLevel = LoggingLevel::None) const
     {
         return this->_addComponent<ConstSourceComponent>(
             componentClass, name, params, &initData, loggingLevel,
@@ -78,7 +78,7 @@ public:
     ConstFilterComponent addComponent(const ConstFilterComponentClass componentClass,
                                       const bt2c::CStringView name,
                                       const OptionalBorrowedObject<ConstMapValue> params = {},
-                                      const LoggingLevel loggingLevel = LoggingLevel::NONE) const
+                                      const LoggingLevel loggingLevel = LoggingLevel::None) const
     {
         return this->_addComponent<ConstFilterComponent>(
             componentClass, name, params, static_cast<void *>(nullptr), loggingLevel,
@@ -89,7 +89,7 @@ public:
     ConstFilterComponent addComponent(const ConstFilterComponentClass componentClass,
                                       const bt2c::CStringView name, InitDataT&& initData,
                                       const OptionalBorrowedObject<ConstMapValue> params = {},
-                                      const LoggingLevel loggingLevel = LoggingLevel::NONE) const
+                                      const LoggingLevel loggingLevel = LoggingLevel::None) const
     {
         return this->_addComponent<ConstFilterComponent>(
             componentClass, name, params, &initData, loggingLevel,
@@ -99,7 +99,7 @@ public:
     ConstSinkComponent addComponent(const ConstSinkComponentClass componentClass,
                                     const bt2c::CStringView name,
                                     const OptionalBorrowedObject<ConstMapValue> params = {},
-                                    const LoggingLevel loggingLevel = LoggingLevel::NONE) const
+                                    const LoggingLevel loggingLevel = LoggingLevel::None) const
     {
         return this->_addComponent<ConstSinkComponent>(
             componentClass, name, params, static_cast<void *>(nullptr), loggingLevel,
@@ -110,7 +110,7 @@ public:
     ConstSinkComponent addComponent(const ConstSinkComponentClass componentClass,
                                     const bt2c::CStringView name, InitDataT&& initData,
                                     const OptionalBorrowedObject<ConstMapValue> params = {},
-                                    const LoggingLevel loggingLevel = LoggingLevel::NONE) const
+                                    const LoggingLevel loggingLevel = LoggingLevel::None) const
     {
         return this->_addComponent<ConstSinkComponent>(
             componentClass, name, params, &initData, loggingLevel,
index 10e1ee3a9fe83c9b222fb87c20eaeb35e84563fe..d8c8a480b5751c18dd8035d090e51cb7a068d596 100644 (file)
@@ -9,19 +9,27 @@
 
 #include <babeltrace2/babeltrace.h>
 
+#include "common/macros.h"
+
 namespace bt2 {
 
+/* Avoid `-Wshadow` error on GCC, conflicting with `bt2::Error` */
+BT_DIAG_PUSH
+BT_DIAG_IGNORE_SHADOW
+
 enum class LoggingLevel
 {
-    TRACE = BT_LOGGING_LEVEL_TRACE,
-    DEBUG = BT_LOGGING_LEVEL_DEBUG,
-    INFO = BT_LOGGING_LEVEL_INFO,
-    WARNING = BT_LOGGING_LEVEL_WARNING,
-    ERROR = BT_LOGGING_LEVEL_ERROR,
-    FATAL = BT_LOGGING_LEVEL_FATAL,
-    NONE = BT_LOGGING_LEVEL_NONE,
+    Trace = BT_LOGGING_LEVEL_TRACE,
+    Debug = BT_LOGGING_LEVEL_DEBUG,
+    Info = BT_LOGGING_LEVEL_INFO,
+    Warning = BT_LOGGING_LEVEL_WARNING,
+    Error = BT_LOGGING_LEVEL_ERROR,
+    Fatal = BT_LOGGING_LEVEL_FATAL,
+    None = BT_LOGGING_LEVEL_NONE,
 };
 
+BT_DIAG_POP
+
 } /* namespace bt2 */
 
 #endif /* BABELTRACE_CPP_COMMON_BT2_LOGGING_HPP */
index be9be1184587d23bc5f1c4e117d3e16b7803170c..77321778ad0394e6e81482400219a8f0731524e5 100644 (file)
@@ -16,6 +16,7 @@
 #include "cpp-common/bt2/clock-snapshot.hpp"
 #include "cpp-common/bt2/trace-ir.hpp"
 #include "cpp-common/bt2s/optional.hpp"
+#include "cpp-common/vendor/wise-enum/wise_enum.h"
 
 #include "borrowed-object.hpp"
 #include "internal/utils.hpp"
@@ -68,17 +69,19 @@ class CommonDiscardedPacketsMessage;
 template <typename LibObjT>
 class CommonMessageIteratorInactivityMessage;
 
-enum class MessageType
-{
-    STREAM_BEGINNING = BT_MESSAGE_TYPE_STREAM_BEGINNING,
-    STREAM_END = BT_MESSAGE_TYPE_STREAM_END,
-    EVENT = BT_MESSAGE_TYPE_EVENT,
-    PACKET_BEGINNING = BT_MESSAGE_TYPE_PACKET_BEGINNING,
-    PACKET_END = BT_MESSAGE_TYPE_PACKET_END,
-    DISCARDED_EVENTS = BT_MESSAGE_TYPE_DISCARDED_EVENTS,
-    DISCARDED_PACKETS = BT_MESSAGE_TYPE_DISCARDED_PACKETS,
-    MESSAGE_ITERATOR_INACTIVITY = BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY,
-};
+/* clang-format off */
+
+WISE_ENUM_CLASS(MessageType,
+    (StreamBeginning, BT_MESSAGE_TYPE_STREAM_BEGINNING),
+    (StreamEnd, BT_MESSAGE_TYPE_STREAM_END),
+    (Event, BT_MESSAGE_TYPE_EVENT),
+    (PacketBeginning, BT_MESSAGE_TYPE_PACKET_BEGINNING),
+    (PacketEnd, BT_MESSAGE_TYPE_PACKET_END),
+    (DiscardedEvents, BT_MESSAGE_TYPE_DISCARDED_EVENTS),
+    (DiscardedPackets, BT_MESSAGE_TYPE_DISCARDED_PACKETS),
+    (MessageIteratorInactivity, BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY));
+
+/* clang-format on */
 
 template <typename LibObjT>
 class CommonMessage : public BorrowedObject<LibObjT>
@@ -121,42 +124,42 @@ public:
 
     bool isStreamBeginning() const noexcept
     {
-        return this->type() == MessageType::STREAM_BEGINNING;
+        return this->type() == MessageType::StreamBeginning;
     }
 
     bool isStreamEnd() const noexcept
     {
-        return this->type() == MessageType::STREAM_END;
+        return this->type() == MessageType::StreamEnd;
     }
 
     bool isEvent() const noexcept
     {
-        return this->type() == MessageType::EVENT;
+        return this->type() == MessageType::Event;
     }
 
     bool isPacketBeginning() const noexcept
     {
-        return this->type() == MessageType::PACKET_BEGINNING;
+        return this->type() == MessageType::PacketBeginning;
     }
 
     bool isPacketEnd() const noexcept
     {
-        return this->type() == MessageType::PACKET_END;
+        return this->type() == MessageType::PacketEnd;
     }
 
     bool isDiscardedEvents() const noexcept
     {
-        return this->type() == MessageType::DISCARDED_EVENTS;
+        return this->type() == MessageType::DiscardedEvents;
     }
 
     bool isDiscardedPackets() const noexcept
     {
-        return this->type() == MessageType::DISCARDED_PACKETS;
+        return this->type() == MessageType::DiscardedPackets;
     }
 
     bool isMessageIteratorInactivity() const noexcept
     {
-        return this->type() == MessageType::MESSAGE_ITERATOR_INACTIVITY;
+        return this->type() == MessageType::MessageIteratorInactivity;
     }
 
     Shared shared() const noexcept
index f2678f89e95efedef5c6a0c24893989fffd40707..07c65924d931b4a27dd3d7da6402b8dbe10fccdd 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <babeltrace2/babeltrace.h>
 
+#include "common/macros.h"
 #include "cpp-common/bt2c/c-string-view.hpp"
 #include "cpp-common/bt2s/optional.hpp"
 
@@ -854,6 +855,31 @@ using DepStructFc = DepType<LibObjT, StructureFieldClass, ConstStructureFieldCla
 
 } /* namespace internal */
 
+/* Avoid `-Wshadow` error on GCC, conflicting with `bt2::Error` */
+BT_DIAG_PUSH
+BT_DIAG_IGNORE_SHADOW
+
+enum class EventClassLogLevel
+{
+    Emergency = BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY,
+    Alert = BT_EVENT_CLASS_LOG_LEVEL_ALERT,
+    Critical = BT_EVENT_CLASS_LOG_LEVEL_CRITICAL,
+    Error = BT_EVENT_CLASS_LOG_LEVEL_ERROR,
+    Warning = BT_EVENT_CLASS_LOG_LEVEL_WARNING,
+    Notice = BT_EVENT_CLASS_LOG_LEVEL_NOTICE,
+    Info = BT_EVENT_CLASS_LOG_LEVEL_INFO,
+    DebugSystem = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM,
+    DebugProgram = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM,
+    DebugProcess = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS,
+    DebugModule = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE,
+    DebugUnit = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT,
+    DebugFunction = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION,
+    DebugLine = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE,
+    Debug = BT_EVENT_CLASS_LOG_LEVEL_DEBUG,
+};
+
+BT_DIAG_POP
+
 template <typename LibObjT>
 class CommonEventClass final : public BorrowedObject<LibObjT>
 {
@@ -870,25 +896,6 @@ public:
     using Shared = SharedObject<CommonEventClass, LibObjT, internal::EventClassRefFuncs>;
     using UserAttributes = internal::DepUserAttrs<LibObjT>;
 
-    enum class LogLevel
-    {
-        EMERGENCY = BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY,
-        ALERT = BT_EVENT_CLASS_LOG_LEVEL_ALERT,
-        CRITICAL = BT_EVENT_CLASS_LOG_LEVEL_CRITICAL,
-        ERR = BT_EVENT_CLASS_LOG_LEVEL_ERROR,
-        WARNING = BT_EVENT_CLASS_LOG_LEVEL_WARNING,
-        NOTICE = BT_EVENT_CLASS_LOG_LEVEL_NOTICE,
-        INFO = BT_EVENT_CLASS_LOG_LEVEL_INFO,
-        DEBUG_SYSTEM = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM,
-        DEBUG_PROGRAM = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM,
-        DEBUG_PROC = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS,
-        DEBUG_MODULE = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE,
-        DEBUG_UNIT = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT,
-        DEBUG_FUNCTION = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION,
-        DEBUG_LINE = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE,
-        DEBUG = BT_EVENT_CLASS_LOG_LEVEL_DEBUG,
-    };
-
     explicit CommonEventClass(const LibObjPtr libObjPtr) noexcept : _ThisBorrowedObject {libObjPtr}
     {
     }
@@ -936,7 +943,7 @@ public:
         return bt_event_class_get_name(this->libObjPtr());
     }
 
-    CommonEventClass logLevel(const LogLevel logLevel) const noexcept
+    CommonEventClass logLevel(const EventClassLogLevel logLevel) const noexcept
     {
         static_assert(!std::is_const<LibObjT>::value, "Not available with `bt2::ConstEventClass`.");
 
@@ -945,12 +952,12 @@ public:
         return *this;
     }
 
-    bt2s::optional<LogLevel> logLevel() const noexcept
+    bt2s::optional<EventClassLogLevel> logLevel() const noexcept
     {
         bt_event_class_log_level libLogLevel;
 
         if (bt_event_class_get_log_level(this->libObjPtr(), &libLogLevel)) {
-            return static_cast<LogLevel>(libLogLevel);
+            return static_cast<EventClassLogLevel>(libLogLevel);
         }
 
         return bt2s::nullopt;
index 80e17dea2fda6ef2fa94925f98fe543ed9a83d72..9f7fdff5cc883b312e8fc71cf495d369a54507ca 100644 (file)
@@ -16,6 +16,7 @@
 #include "common/assert.h"
 #include "common/common.h"
 #include "cpp-common/bt2c/c-string-view.hpp"
+#include "cpp-common/vendor/wise-enum/wise_enum.h"
 
 #include "borrowed-object-iterator.hpp"
 #include "borrowed-object.hpp"
@@ -70,17 +71,19 @@ class CommonArrayValue;
 template <typename LibObjT>
 class CommonMapValue;
 
-enum class ValueType
-{
-    NUL = BT_VALUE_TYPE_NULL,
-    BOOL = BT_VALUE_TYPE_BOOL,
-    UNSIGNED_INTEGER = BT_VALUE_TYPE_UNSIGNED_INTEGER,
-    SIGNED_INTEGER = BT_VALUE_TYPE_SIGNED_INTEGER,
-    REAL = BT_VALUE_TYPE_REAL,
-    STRING = BT_VALUE_TYPE_STRING,
-    ARRAY = BT_VALUE_TYPE_ARRAY,
-    MAP = BT_VALUE_TYPE_MAP,
-};
+/* clang-format off */
+
+WISE_ENUM_CLASS(ValueType,
+    (Null, BT_VALUE_TYPE_NULL),
+    (Bool, BT_VALUE_TYPE_BOOL),
+    (UnsignedInteger, BT_VALUE_TYPE_UNSIGNED_INTEGER),
+    (SignedInteger, BT_VALUE_TYPE_SIGNED_INTEGER),
+    (Real, BT_VALUE_TYPE_REAL),
+    (String, BT_VALUE_TYPE_STRING),
+    (Array, BT_VALUE_TYPE_ARRAY),
+    (Map, BT_VALUE_TYPE_MAP));
+
+/* clang-format on */
 
 template <typename ValueObjT>
 class CommonValueRawValueProxy final
index 0437cd65c4d87458ebe8eca1029d74e728201649..771954c1a0f9119365a63af1b18120580b9ae9e6 100644 (file)
@@ -258,4 +258,12 @@ bool operator!=(LhsT&& lhs, RhsT&& rhs) noexcept
 
 } /* namespace bt2c */
 
+/*
+ * Appends `rhs` to `lhs`.
+ */
+inline void operator+=(std::string& lhs, bt2c::CStringView rhs)
+{
+    lhs += rhs.data();
+}
+
 #endif /* BABELTRACE_CPP_COMMON_BT2C_C_STRING_VIEW_HPP */
diff --git a/src/cpp-common/bt2c/data-len.hpp b/src/cpp-common/bt2c/data-len.hpp
new file mode 100644 (file)
index 0000000..55760f4
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2022 Philippe Proulx <pproulx@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#ifndef BABELTRACE_CPP_COMMON_BT2C_DATA_LEN_HPP
+#define BABELTRACE_CPP_COMMON_BT2C_DATA_LEN_HPP
+
+#include "safe-ops.hpp"
+
+namespace bt2c {
+
+/*
+ * A data length is a quantity of binary data (bits).
+ *
+ * This class can make some code clearer and safer because its
+ * constructor is private so that you need to call DataLen::fromBits()
+ * or DataLen::fromBytes() to create an instance.
+ *
+ * With a `DataLen` instance `len`, use `*len` or `len.bits()` to get
+ * the quantity in bits and `len.bytes()` to get it in bytes (floored).
+ *
+ * You can add, subtract, and compare data lengths.
+ */
+class DataLen final
+{
+private:
+    constexpr explicit DataLen(const unsigned long long lenBits) noexcept : _mLenBits {lenBits}
+    {
+    }
+
+public:
+    /*
+     * Creates and returns a data length instance representing `lenBits`
+     * bits.
+     */
+    static constexpr DataLen fromBits(const unsigned long long lenBits) noexcept
+    {
+        return DataLen {lenBits};
+    }
+
+    /*
+     * Creates and returns a data length instance representing
+     * `lenBytes` bytes.
+     */
+    static DataLen fromBytes(const unsigned long long lenBytes) noexcept
+    {
+        return DataLen {safeMul(lenBytes, 8ULL)};
+    }
+
+    /*
+     * Number of bits of this data length.
+     */
+    constexpr unsigned long long operator*() const noexcept
+    {
+        return _mLenBits;
+    }
+
+    /*
+     * Number of bits of this data length.
+     */
+    constexpr unsigned long long bits() const noexcept
+    {
+        return _mLenBits;
+    }
+
+    /*
+     * Number of bytes (floor) of this data length.
+     */
+    constexpr unsigned long long bytes() const noexcept
+    {
+        return _mLenBits / 8;
+    }
+
+    /*
+     * Whether or not this data length represents a multiple of eight
+     * bits.
+     */
+    constexpr bool hasExtraBits() const noexcept
+    {
+        return this->extraBitCount() > 0;
+    }
+
+    /*
+     * Remainder of this data length, in bits, divided by eight.
+     */
+    constexpr unsigned int extraBitCount() const noexcept
+    {
+        return _mLenBits & 7;
+    }
+
+    /*
+     * Returns whether or not this data length is a power of two bits.
+     */
+    constexpr bool isPowOfTwo() const noexcept
+    {
+        return ((_mLenBits & (_mLenBits - 1)) == 0) && _mLenBits > 0;
+    }
+
+    constexpr bool operator==(const DataLen& other) const noexcept
+    {
+        return _mLenBits == other._mLenBits;
+    }
+
+    constexpr bool operator!=(const DataLen& other) const noexcept
+    {
+        return !(*this == other);
+    }
+
+    constexpr bool operator<(const DataLen& other) const noexcept
+    {
+        return _mLenBits < other._mLenBits;
+    }
+
+    constexpr bool operator<=(const DataLen& other) const noexcept
+    {
+        return (*this == other) || (*this < other);
+    }
+
+    constexpr bool operator>(const DataLen& other) const noexcept
+    {
+        return !(*this <= other);
+    }
+
+    constexpr bool operator>=(const DataLen& other) const noexcept
+    {
+        return (*this > other) || (*this == other);
+    }
+
+    DataLen& operator+=(const DataLen len) noexcept
+    {
+        _mLenBits = safeAdd(_mLenBits, len._mLenBits);
+        return *this;
+    }
+
+    DataLen& operator-=(const DataLen len) noexcept
+    {
+        _mLenBits = safeSub(_mLenBits, len._mLenBits);
+        return *this;
+    }
+
+    DataLen& operator*=(const unsigned long long mul) noexcept
+    {
+        _mLenBits = safeMul(_mLenBits, mul);
+        return *this;
+    }
+
+private:
+    unsigned long long _mLenBits = 0;
+};
+
+static inline DataLen operator+(const DataLen lenA, const DataLen lenB) noexcept
+{
+    return DataLen::fromBits(safeAdd(*lenA, *lenB));
+}
+
+static inline DataLen operator-(const DataLen lenA, const DataLen lenB) noexcept
+{
+    return DataLen::fromBits(safeSub(*lenA, *lenB));
+}
+
+static inline DataLen operator*(const DataLen len, const unsigned long long mul) noexcept
+{
+    return DataLen::fromBits(safeMul(*len, mul));
+}
+
+/*
+ * Use this namespace to access handy data length user literals, for
+ * example:
+ *
+ *     using namespace bt2c::literals::datalen;
+ *
+ *     const auto bufSize = 64_MiBytes + 8_KiBits;
+ */
+namespace literals {
+namespace datalen {
+
+static inline DataLen operator""_bits(const unsigned long long val) noexcept
+{
+    return DataLen::fromBits(val);
+}
+
+static inline DataLen operator""_KiBits(const unsigned long long val) noexcept
+{
+    return DataLen::fromBits(safeMul(val, 1024ULL));
+}
+
+static inline DataLen operator""_MiBits(const unsigned long long val) noexcept
+{
+    return DataLen::fromBits(safeMul(val, 1024ULL * 1024));
+}
+
+static inline DataLen operator""_GiBits(const unsigned long long val) noexcept
+{
+    return DataLen::fromBits(safeMul(val, 1024ULL * 1024 * 1024));
+}
+
+static inline DataLen operator""_bytes(const unsigned long long val) noexcept
+{
+    return DataLen::fromBytes(val);
+}
+
+static inline DataLen operator""_KiBytes(const unsigned long long val) noexcept
+{
+    return DataLen::fromBytes(safeMul(val, 1024ULL));
+}
+
+static inline DataLen operator""_MiBytes(const unsigned long long val) noexcept
+{
+    return DataLen::fromBytes(safeMul(val, 1024ULL * 1024));
+}
+
+static inline DataLen operator""_GiBytes(const unsigned long long val) noexcept
+{
+    return DataLen::fromBytes(safeMul(val, 1024ULL * 1024 * 1024));
+}
+
+} /* namespace datalen */
+} /* namespace literals */
+} /* namespace bt2c */
+
+#endif /* BABELTRACE_CPP_COMMON_BT2C_DATA_LEN_HPP */
diff --git a/src/cpp-common/bt2c/dummy.cpp b/src/cpp-common/bt2c/dummy.cpp
deleted file mode 100644 (file)
index e69de29..0000000
index 3138fdbcd44060d36b8afa67f8f9be205151dcd1..3400dfafffe1d3d24981481a0b04486c83374d38 100644 (file)
@@ -69,6 +69,17 @@ public:
     }
 };
 
+/*
+ * No such file or directory.
+ */
+class NoSuchFileOrDirectoryError : public Error
+{
+public:
+    explicit NoSuchFileOrDirectoryError() noexcept : Error {"No such file or directory"}
+    {
+    }
+};
+
 } /* namespace bt2c */
 
 #endif /* BABELTRACE_CPP_COMMON_BT2C_EXC_HPP */
diff --git a/src/cpp-common/bt2c/file-utils.cpp b/src/cpp-common/bt2c/file-utils.cpp
new file mode 100644 (file)
index 0000000..9352018
--- /dev/null
@@ -0,0 +1,38 @@
+
+/*
+ * Copyright (c) 2022 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ */
+#include <fstream>
+
+#include "exc.hpp"
+#include "file-utils.hpp"
+
+namespace bt2c {
+
+std::vector<std::uint8_t> dataFromFile(const char * const filePath)
+{
+    /*
+     * Open a file stream and seek to the end of the stream to compute the size
+     * of the buffer required.
+    */
+    std::ifstream file {filePath, std::ios::binary | std::ios::ate};
+
+    if (!file) {
+        throw NoSuchFileOrDirectoryError {};
+    }
+
+    const auto size = file.tellg();
+    std::vector<uint8_t> buffer(static_cast<std::size_t>(size));
+
+    /*
+     * Seek the reading head back at the beginning of the stream to actually
+     * read the content.
+     */
+    file.seekg(0, std::ios::beg);
+    file.read(reinterpret_cast<char *>(buffer.data()), size);
+    return buffer;
+}
+
+} /* namespace bt2c */
diff --git a/src/cpp-common/bt2c/file-utils.hpp b/src/cpp-common/bt2c/file-utils.hpp
new file mode 100644 (file)
index 0000000..9890f0a
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2022 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#ifndef BABELTRACE_CPP_COMMON_FILE_UTILS_HPP
+#define BABELTRACE_CPP_COMMON_FILE_UTILS_HPP
+
+#include <cstdint>
+#include <vector>
+
+namespace bt2c {
+
+/*
+ * Returns a vector of all the bytes contained in `path`.
+ */
+std::vector<std::uint8_t> dataFromFile(const char *path);
+
+} /* namespace bt2c */
+
+#endif /* BABELTRACE_CPP_COMMON_FILE_UTILS_HPP */
index 8af3d71e49ca84f0205fb6f20e112ea84e5a5aed..a78d7a61af83f37bb7f5b4c96c0035b568401908 100644 (file)
@@ -4,22 +4,37 @@
  * SPDX-License-Identifier: MIT
  */
 
-#include "common/common.h"
-#include "cpp-common/bt2/message.hpp"
-#include "cpp-common/bt2c/uuid.hpp"
 #include "cpp-common/vendor/fmt/format.h" /* IWYU pragma: keep */
+#include "cpp-common/vendor/wise-enum/wise_enum.h"
+
+#include "uuid.hpp"
+
+namespace internal {
+
+template <typename T>
+using EnableIfIsWiseEnum =
+    typename std::enable_if<wise_enum::is_wise_enum<T>::value, const char *>::type;
+
+} /* namespace internal */
 
 namespace bt2 {
 
-inline const char *format_as(const MessageType type)
+template <typename T>
+::internal::EnableIfIsWiseEnum<T> format_as(const T val) noexcept
 {
-    return bt_common_message_type_string(static_cast<bt_message_type>(type));
+    return wise_enum::to_string<T>(val);
 }
 
 } /* namespace bt2 */
 
 namespace bt2c {
 
+template <typename T>
+::internal::EnableIfIsWiseEnum<T> format_as(const T val) noexcept
+{
+    return wise_enum::to_string<T>(val);
+}
+
 inline std::string format_as(const UuidView uuid)
 {
     return uuid.str();
index 159e909bb66e48150f57e4b9e1da48808f6616e8..a1fc583f83a26aba272f652efab5fb0657f29ea3 100644 (file)
@@ -22,7 +22,9 @@
 #include "cpp-common/bt2/self-component-port.hpp"
 #include "cpp-common/bt2/self-message-iterator.hpp"
 #include "cpp-common/bt2s/optional.hpp"
+#include "cpp-common/bt2s/span.hpp"
 #include "cpp-common/vendor/fmt/core.h"
+#include "cpp-common/vendor/wise-enum/wise_enum.h"
 #include "logging/log-api.h"
 
 namespace bt2c {
@@ -32,9 +34,9 @@ namespace bt2c {
  * self message iterator, or simple module name), a current logging
  * level, and a logging tag.
  *
- * It offers the logNoThrow(), logMemNoThrow(), logErrnoNoThrow(),
- * logErrorAndThrow(), logErrorAndRethrow(), logErrorErrnoAndThrow(),
- * and logErrorErrnoAndRethrow() method templates to log using a given
+ * It offers the log(), logMem(), logErrno(), logErrorAndThrow(),
+ * logErrorAndRethrow(), logErrorErrnoAndThrow(), and
+ * logErrorErrnoAndRethrow() method templates to log using a given
  * level, optionally append a cause to the error of the current thread
  * using the correct actor, and optionally throw or rethrow.
  *
@@ -44,17 +46,22 @@ namespace bt2c {
 class Logger final
 {
 public:
+    using MemData = bt2s::span<const std::uint8_t>;
+
+    /* clang-format off */
+
     /* Available log levels */
-    enum class Level
-    {
-        TRACE = BT_LOG_TRACE,
-        DEBUG = BT_LOG_DEBUG,
-        INFO = BT_LOG_INFO,
-        WARNING = BT_LOG_WARNING,
-        ERROR = BT_LOG_ERROR,
-        FATAL = BT_LOG_FATAL,
-        NONE = BT_LOG_NONE,
-    };
+    WISE_ENUM_CLASS_MEMBER(Level,
+        (Trace,     BT_LOG_TRACE),
+        (Debug,     BT_LOG_DEBUG),
+        (Info,      BT_LOG_INFO),
+        (Warning,   BT_LOG_WARNING),
+        (Error,     BT_LOG_ERROR),
+        (Fatal,     BT_LOG_FATAL),
+        (None,      BT_LOG_NONE)
+    )
+
+    /* clang-format on */
 
     /*
      * Builds a logger from the self component class `selfCompCls` using
@@ -115,9 +122,9 @@ public:
      * using the tag `tag`.
      */
     explicit Logger(const bt2::SelfMessageIterator selfMsgIter, std::string tag) noexcept :
-        Logger {selfMsgIter.component(), std::move(tag)}
+        _mSelfMsgIter {selfMsgIter},
+        _mLevel {static_cast<Level>(selfMsgIter.component().loggingLevel())}, _mTag {std::move(tag)}
     {
-        _mSelfMsgIter = selfMsgIter;
     }
 
     /*
@@ -134,7 +141,8 @@ public:
      * `newTag`.
      */
     explicit Logger(const Logger& other, std::string newTag) :
-        _mSelfComp {other._mSelfComp}, _mSelfMsgIter {other._mSelfMsgIter},
+        _mSelfCompCls {other._mSelfCompCls}, _mSelfComp {other._mSelfComp},
+        _mSelfMsgIter {other._mSelfMsgIter},
         _mModuleName {other._mModuleName}, _mLevel {other._mLevel}, _mTag {std::move(newTag)}
     {
     }
@@ -147,16 +155,6 @@ public:
         return _mLevel;
     }
 
-    /*
-     * Current logging level converted to a `bt_log_level` value.
-     *
-     * For legacy code.
-     */
-    bt_log_level cLevel() const noexcept
-    {
-        return static_cast<bt_log_level>(_mLevel);
-    }
-
     /*
      * Whether or not this logger would log at the level `level`.
      */
@@ -170,7 +168,7 @@ public:
      */
     bool wouldLogT() const noexcept
     {
-        return this->wouldLog(Level::TRACE);
+        return this->wouldLog(Level::Trace);
     }
 
     /*
@@ -178,7 +176,7 @@ public:
      */
     bool wouldLogD() const noexcept
     {
-        return this->wouldLog(Level::DEBUG);
+        return this->wouldLog(Level::Debug);
     }
 
     /*
@@ -186,7 +184,7 @@ public:
      */
     bool wouldLogI() const noexcept
     {
-        return this->wouldLog(Level::INFO);
+        return this->wouldLog(Level::Info);
     }
 
     /*
@@ -194,7 +192,7 @@ public:
      */
     bool wouldLogW() const noexcept
     {
-        return this->wouldLog(Level::WARNING);
+        return this->wouldLog(Level::Warning);
     }
 
     /*
@@ -202,7 +200,7 @@ public:
      */
     bool wouldLogE() const noexcept
     {
-        return this->wouldLog(Level::ERROR);
+        return this->wouldLog(Level::Error);
     }
 
     /*
@@ -210,7 +208,7 @@ public:
      */
     bool wouldLogF() const noexcept
     {
-        return this->wouldLog(Level::FATAL);
+        return this->wouldLog(Level::Fatal);
     }
 
     /*
@@ -257,9 +255,8 @@ private:
     struct _StdLogWriter final
     {
         static void write(const char * const fileName, const char * const funcName,
-                          const unsigned lineNo, const Level level, const char * const tag,
-                          const void *, unsigned int, const char * const initMsg,
-                          const char * const msg) noexcept
+                          const unsigned lineNo, const Level level, const char * const tag, MemData,
+                          const char * const initMsg, const char * const msg) noexcept
         {
             BT_ASSERT_DBG(initMsg && std::strcmp(initMsg, "") == 0);
             bt_log_write(fileName, funcName, lineNo, static_cast<bt_log_level>(level), tag, msg);
@@ -277,77 +274,37 @@ public:
      * the error of the current thread using the same message.
      */
     template <Level LevelV, bool AppendCauseV, typename... ArgTs>
-    void logNoThrow(const char * const fileName, const char * const funcName,
-                    const unsigned int lineNo, const char * const fmt, ArgTs&&...args) const
-    {
-        this->_logNoThrow<_StdLogWriter, LevelV, AppendCauseV>(
-            fileName, funcName, lineNo, nullptr, 0, "", fmt, std::forward<ArgTs>(args)...);
-    }
-
-    /*
-     * Logs `msg` using the level `LevelV`.
-     *
-     * If `AppendCauseV` is true, this method also appends a cause to
-     * the error of the current thread using the same message.
-     */
-    template <Level LevelV, bool AppendCauseV>
-    void logStrNoThrow(const char * const fileName, const char * const funcName,
-                       const unsigned int lineNo, const char * const msg) const
+    void log(const char * const fileName, const char * const funcName, const unsigned int lineNo,
+             const char * const fmt, ArgTs&&...args) const
     {
-        this->_logStrNoThrow<_StdLogWriter, LevelV, AppendCauseV>(fileName, funcName, lineNo,
-                                                                  nullptr, 0, "", msg);
+        this->_log<_StdLogWriter, LevelV, AppendCauseV>(fileName, funcName, lineNo, {}, "", fmt,
+                                                        std::forward<ArgTs>(args)...);
     }
 
     /*
-     * Like logAndNoThrow() with the `Level::ERROR` level, but also
-     * throws a default-constructed instance of `ExcT`.
+     * Like log() with the `Level::Error` level, but also throws a
+     * default-constructed instance of `ExcT`.
      */
     template <bool AppendCauseV, typename ExcT, typename... ArgTs>
     [[noreturn]] void logErrorAndThrow(const char * const fileName, const char * const funcName,
                                        const unsigned int lineNo, const char * const fmt,
                                        ArgTs&&...args) const
     {
-        this->logNoThrow<Level::ERROR, AppendCauseV>(fileName, funcName, lineNo, fmt,
-                                                     std::forward<ArgTs>(args)...);
-        throw ExcT {};
-    }
-
-    /*
-     * Like logStrAndNoThrow() with the `Level::ERROR` level, but also
-     * throws a default-constructed instance of `ExcT`.
-     */
-    template <bool AppendCauseV, typename ExcT>
-    [[noreturn]] void logErrorStrAndThrow(const char * const fileName, const char * const funcName,
-                                          const unsigned int lineNo, const char * const msg) const
-    {
-        this->logStrNoThrow<Level::ERROR, AppendCauseV>(fileName, funcName, lineNo, msg);
+        this->log<Level::Error, AppendCauseV>(fileName, funcName, lineNo, fmt,
+                                              std::forward<ArgTs>(args)...);
         throw ExcT {};
     }
 
     /*
-     * Like logAndNoThrow() with the `Level::ERROR` level, but also
-     * rethrows.
+     * Like log() with the `Level::Error` level, but also rethrows.
      */
     template <bool AppendCauseV, typename... ArgTs>
     [[noreturn]] void logErrorAndRethrow(const char * const fileName, const char * const funcName,
                                          const unsigned int lineNo, const char * const fmt,
                                          ArgTs&&...args) const
     {
-        this->logNoThrow<Level::ERROR, AppendCauseV>(fileName, funcName, lineNo, fmt,
-                                                     std::forward<ArgTs>(args)...);
-        throw;
-    }
-
-    /*
-     * Like logStrAndNoThrow() with the `Level::ERROR` level, but also
-     * rethrows.
-     */
-    template <bool AppendCauseV>
-    [[noreturn]] void logErrorStrAndRethrow(const char * const fileName,
-                                            const char * const funcName, const unsigned int lineNo,
-                                            const char * const msg) const
-    {
-        this->logStrNoThrow<Level::ERROR, AppendCauseV>(fileName, funcName, lineNo, msg);
+        this->log<Level::Error, AppendCauseV>(fileName, funcName, lineNo, fmt,
+                                              std::forward<ArgTs>(args)...);
         throw;
     }
 
@@ -355,9 +312,8 @@ private:
     struct _InitMsgLogWriter final
     {
         static void write(const char * const fileName, const char * const funcName,
-                          const unsigned lineNo, const Level level, const char * const tag,
-                          const void *, unsigned int, const char * const initMsg,
-                          const char * const msg) noexcept
+                          const unsigned lineNo, const Level level, const char * const tag, MemData,
+                          const char * const initMsg, const char * const msg) noexcept
         {
             bt_log_write_printf(funcName, fileName, lineNo, static_cast<bt_log_level>(level), tag,
                                 "%s%s", initMsg, msg);
@@ -376,36 +332,18 @@ public:
      * the error of the current thread using the same message.
      */
     template <Level LevelV, bool AppendCauseV, typename... ArgTs>
-    void logErrnoNoThrow(const char * const fileName, const char * const funcName,
-                         const unsigned int lineNo, const char * const initMsg,
-                         const char * const fmt, ArgTs&&...args) const
-    {
-        this->_logNoThrow<_InitMsgLogWriter, LevelV, AppendCauseV>(
-            fileName, funcName, lineNo, nullptr, 0, this->_errnoIntroStr(initMsg).c_str(), fmt,
-            std::forward<ArgTs>(args)...);
-    }
-
-    /*
-     * Logs the message of `errno` using the level `LevelV`.
-     *
-     * The log message starts with `initMsg`, is followed with the
-     * message for `errno`, and then with `msg`.
-     *
-     * If `AppendCauseV` is true, this method also appends a cause to
-     * the error of the current thread using the same message.
-     */
-    template <Level LevelV, bool AppendCauseV>
-    void logErrnoStrNoThrow(const char * const fileName, const char * const funcName,
-                            const unsigned int lineNo, const char * const initMsg,
-                            const char * const msg) const
+    void logErrno(const char * const fileName, const char * const funcName,
+                  const unsigned int lineNo, const char * const initMsg, const char * const fmt,
+                  ArgTs&&...args) const
     {
-        this->_logStrNoThrow<_InitMsgLogWriter, LevelV, AppendCauseV>(
-            fileName, funcName, lineNo, nullptr, 0, this->_errnoIntroStr(initMsg).c_str(), msg);
+        this->_log<_InitMsgLogWriter, LevelV, AppendCauseV>(fileName, funcName, lineNo, {},
+                                                            this->_errnoIntroStr(initMsg).c_str(),
+                                                            fmt, std::forward<ArgTs>(args)...);
     }
 
     /*
-     * Like logErrnoNoThrow() with the `Level::ERROR` level, but also
-     * throws a default-constructed instance of `ExcT`.
+     * Like logErrno() with the `Level::Error` level, but also throws a
+     * default-constructed instance of `ExcT`.
      */
     template <bool AppendCauseV, typename ExcT, typename... ArgTs>
     [[noreturn]] void logErrorErrnoAndThrow(const char * const fileName,
@@ -413,29 +351,13 @@ public:
                                             const char * const initMsg, const char * const fmt,
                                             ArgTs&&...args) const
     {
-        this->logErrnoNoThrow<Level::ERROR, AppendCauseV>(fileName, funcName, lineNo, initMsg, fmt,
-                                                          std::forward<ArgTs>(args)...);
-        throw ExcT {};
-    }
-
-    /*
-     * Like logErrnoStrNoThrow() with the `Level::ERROR` level, but also
-     * throws a default-constructed instance of `ExcT`.
-     */
-    template <bool AppendCauseV, typename ExcT>
-    [[noreturn]] void
-    logErrorErrnoStrAndThrow(const char * const fileName, const char * const funcName,
-                             const unsigned int lineNo, const char * const initMsg,
-                             const char * const msg) const
-    {
-        this->logErrnoStrNoThrow<Level::ERROR, AppendCauseV>(fileName, funcName, lineNo, initMsg,
-                                                             msg);
+        this->logErrno<Level::Error, AppendCauseV>(fileName, funcName, lineNo, initMsg, fmt,
+                                                   std::forward<ArgTs>(args)...);
         throw ExcT {};
     }
 
     /*
-     * Like logErrnoNoThrow() with the `Level::ERROR` level, but also
-     * rethrows.
+     * Like logErrno() with the `Level::Error` level, but also rethrows.
      */
     template <bool AppendCauseV, typename... ArgTs>
     [[noreturn]] void logErrorErrnoAndRethrow(const char * const fileName,
@@ -443,23 +365,8 @@ public:
                                               const unsigned int lineNo, const char * const initMsg,
                                               const char * const fmt, ArgTs&&...args) const
     {
-        this->logErrnoNoThrow<Level::ERROR, AppendCauseV>(fileName, funcName, lineNo, initMsg, fmt,
-                                                          std::forward<ArgTs>(args)...);
-        throw;
-    }
-
-    /*
-     * Like logErrnoStrNoThrow() with the `Level::ERROR` level, but also
-     * rethrows.
-     */
-    template <bool AppendCauseV>
-    [[noreturn]] void
-    logErrorErrnoStrAndRethrow(const char * const fileName, const char * const funcName,
-                               const unsigned int lineNo, const char * const initMsg,
-                               const char * const msg) const
-    {
-        this->logErrnoStrNoThrow<Level::ERROR, AppendCauseV>(fileName, funcName, lineNo, initMsg,
-                                                             msg);
+        this->logErrno<Level::Error, AppendCauseV>(fileName, funcName, lineNo, initMsg, fmt,
+                                                   std::forward<ArgTs>(args)...);
         throw;
     }
 
@@ -468,11 +375,10 @@ private:
     {
         static void write(const char * const fileName, const char * const funcName,
                           const unsigned lineNo, const Level level, const char * const tag,
-                          const void * const memData, const unsigned int memLen, const char *,
-                          const char * const msg) noexcept
+                          const MemData memData, const char *, const char * const msg) noexcept
         {
             bt_log_write_mem(funcName, fileName, lineNo, static_cast<bt_log_level>(level), tag,
-                             memData, memLen, msg);
+                             memData.data(), memData.size(), msg);
         }
     };
 
@@ -484,92 +390,68 @@ public:
      * the log message.
      */
     template <Level LevelV, typename... ArgTs>
-    void logMemNoThrow(const char * const fileName, const char * const funcName,
-                       const unsigned int lineNo, const void * const memData,
-                       const unsigned int memLen, const char * const fmt, ArgTs&&...args) const
-    {
-        this->_logNoThrow<_MemLogWriter, LevelV, false>(fileName, funcName, lineNo, memData, memLen,
-                                                        "", fmt, std::forward<ArgTs>(args)...);
-    }
-
-    /*
-     * Logs memory data using the level `LevelV`, starting with the
-     * message `msg`.
-     */
-    template <Level LevelV>
-    void logMemStrNoThrow(const char * const fileName, const char * const funcName,
-                          const unsigned int lineNo, const void * const memData,
-                          const unsigned int memLen, const char * const msg) const
+    void logMem(const char * const fileName, const char * const funcName, const unsigned int lineNo,
+                const MemData memData, const char * const fmt, ArgTs&&...args) const
     {
-        this->_logStrNoThrow<_MemLogWriter, LevelV, false>(fileName, funcName, lineNo, memData,
-                                                           memLen, "", msg);
+        this->_log<_MemLogWriter, LevelV, false>(fileName, funcName, lineNo, memData, "", fmt,
+                                                 std::forward<ArgTs>(args)...);
     }
 
 private:
     /*
      * Formats a log message with fmt::format() given `fmt` and `args`,
-     * and then forwards everything to _logStrNoThrow().
+     * and then:
+     *
+     * 1. Calls LogWriterT::write() with its arguments to log using the
+     *    level `LevelV`.
+     *
+     * 2. If `AppendCauseV` is true, this method also appends a cause to
+     *    the error of the current thread using the concatenation of
+     *    `initMsg` and `msg` as the message.
      */
     template <typename LogWriterT, Level LevelV, bool AppendCauseV, typename... ArgTs>
-    void _logNoThrow(const char * const fileName, const char * const funcName,
-                     const unsigned int lineNo, const void * const memData,
-                     const std::size_t memLen, const char * const initMsg, const char * const fmt,
-                     ArgTs&&...args) const
+    void _log(const char * const fileName, const char * const funcName, const unsigned int lineNo,
+              const MemData memData, const char * const initMsg, const char * const fmt,
+              ArgTs&&...args) const
     {
+        const auto wouldLog = this->wouldLog(LevelV);
+
         /* Only format arguments if logging or appending an error cause */
-        if (G_UNLIKELY(this->wouldLog(LevelV) || AppendCauseV)) {
+        if (G_UNLIKELY(wouldLog || AppendCauseV)) {
             /*
              * Format arguments to our buffer (fmt::format_to() doesn't
              * append a null character).
              */
             _mBuf.clear();
+            BT_ASSERT(fmt);
             fmt::format_to(std::back_inserter(_mBuf), fmt, std::forward<ArgTs>(args)...);
             _mBuf.push_back('\0');
         }
 
-        this->_logStrNoThrow<LogWriterT, LevelV, AppendCauseV>(fileName, funcName, lineNo, memData,
-                                                               memLen, initMsg, _mBuf.data());
-    }
-
-    /*
-     * Calls LogWriterT::write() with its arguments to log using the
-     * level `LevelV`.
-     *
-     * If `AppendCauseV` is true, this method also appends a cause to
-     * the error of the current thread using the concatenation of
-     * `initMsg` and `msg` as the message.
-     */
-    template <typename LogWriterT, Level LevelV, bool AppendCauseV>
-    void _logStrNoThrow(const char * const fileName, const char * const funcName,
-                        const unsigned int lineNo, const void * const memData,
-                        const std::size_t memLen, const char * const initMsg,
-                        const char * const msg) const
-    {
-        /* Initial message and main message are required */
+        /* Initial message is required */
         BT_ASSERT(initMsg);
-        BT_ASSERT(msg);
 
         /* Log if needed */
-        if (this->wouldLog(LevelV)) {
-            LogWriterT::write(fileName, funcName, lineNo, LevelV, _mTag.data(), memData, memLen,
-                              initMsg, msg);
+        if (wouldLog) {
+            LogWriterT::write(fileName, funcName, lineNo, LevelV, _mTag.data(), memData, initMsg,
+                              _mBuf.data());
         }
 
         /* Append an error cause if needed */
         if (AppendCauseV) {
             if (_mSelfMsgIter) {
                 bt_current_thread_error_append_cause_from_message_iterator(
-                    _mSelfMsgIter->libObjPtr(), fileName, lineNo, "%s%s", initMsg, msg);
+                    _mSelfMsgIter->libObjPtr(), fileName, lineNo, "%s%s", initMsg, _mBuf.data());
             } else if (_mSelfComp) {
                 bt_current_thread_error_append_cause_from_component(
-                    _mSelfComp->libObjPtr(), fileName, lineNo, "%s%s", initMsg, msg);
+                    _mSelfComp->libObjPtr(), fileName, lineNo, "%s%s", initMsg, _mBuf.data());
             } else if (_mSelfCompCls) {
                 bt_current_thread_error_append_cause_from_component_class(
-                    _mSelfCompCls->libObjPtr(), fileName, lineNo, "%s%s", initMsg, msg);
+                    _mSelfCompCls->libObjPtr(), fileName, lineNo, "%s%s", initMsg, _mBuf.data());
             } else {
                 BT_ASSERT(_mModuleName);
-                bt_current_thread_error_append_cause_from_unknown(_mModuleName->data(), fileName,
-                                                                  lineNo, "%s%s", initMsg, msg);
+                bt_current_thread_error_append_cause_from_unknown(
+                    _mModuleName->data(), fileName, lineNo, "%s%s", initMsg, _mBuf.data());
             }
         }
     }
@@ -580,7 +462,7 @@ private:
         return fmt::format("{}: {}", initMsg, g_strerror(errno));
     }
 
-    /* At least one of the following four members has a value */
+    /* Exactly one of the following four members has a value */
     bt2s::optional<bt2::SelfComponentClass> _mSelfCompCls;
     bt2s::optional<bt2::SelfComponent> _mSelfComp;
     bt2s::optional<bt2::SelfMessageIterator> _mSelfMsgIter;
@@ -596,20 +478,27 @@ private:
     mutable std::vector<char> _mBuf;
 };
 
+/*
+ * Returns `s` if it's not `nullptr`, or the `(null)` string otherwise.
+ */
+inline const char *maybeNull(const char * const s) noexcept
+{
+    return s ? s : "(null)";
+}
+
 } /* namespace bt2c */
 
 /* Internal: default logger name */
 #define _BT_CPPLOG_DEF_LOGGER _mLogger
 
 /*
- * Calls logNoThrow() on `_logger` to log using the level `_lvl` without
- * appending nor throwing.
+ * Calls log() on `_logger` to log using the level `_lvl`.
  */
 #define BT_CPPLOG_EX(_lvl, _logger, _fmt, ...)                                                     \
     do {                                                                                           \
         if (G_UNLIKELY((_logger).wouldLog(_lvl))) {                                                \
-            (_logger).logNoThrow<(_lvl), false>(__FILE__, __func__, __LINE__, (_fmt),              \
-                                                ##__VA_ARGS__);                                    \
+            (_logger).template log<(_lvl), false>(__FILE__, __func__, __LINE__, (_fmt),            \
+                                                  ##__VA_ARGS__);                                  \
         }                                                                                          \
     } while (0)
 
@@ -617,17 +506,17 @@ private:
  * BT_CPPLOG_EX() with specific logging levels.
  */
 #define BT_CPPLOGT_SPEC(_logger, _fmt, ...)                                                        \
-    BT_CPPLOG_EX(bt2c::Logger::Level::TRACE, (_logger), (_fmt), ##__VA_ARGS__)
+    BT_CPPLOG_EX(bt2c::Logger::Level::Trace, (_logger), (_fmt), ##__VA_ARGS__)
 #define BT_CPPLOGD_SPEC(_logger, _fmt, ...)                                                        \
-    BT_CPPLOG_EX(bt2c::Logger::Level::DEBUG, (_logger), (_fmt), ##__VA_ARGS__)
+    BT_CPPLOG_EX(bt2c::Logger::Level::Debug, (_logger), (_fmt), ##__VA_ARGS__)
 #define BT_CPPLOGI_SPEC(_logger, _fmt, ...)                                                        \
-    BT_CPPLOG_EX(bt2c::Logger::Level::INFO, (_logger), (_fmt), ##__VA_ARGS__)
+    BT_CPPLOG_EX(bt2c::Logger::Level::Info, (_logger), (_fmt), ##__VA_ARGS__)
 #define BT_CPPLOGW_SPEC(_logger, _fmt, ...)                                                        \
-    BT_CPPLOG_EX(bt2c::Logger::Level::WARNING, (_logger), (_fmt), ##__VA_ARGS__)
+    BT_CPPLOG_EX(bt2c::Logger::Level::Warning, (_logger), (_fmt), ##__VA_ARGS__)
 #define BT_CPPLOGE_SPEC(_logger, _fmt, ...)                                                        \
-    BT_CPPLOG_EX(bt2c::Logger::Level::ERROR, (_logger), (_fmt), ##__VA_ARGS__)
+    BT_CPPLOG_EX(bt2c::Logger::Level::Error, (_logger), (_fmt), ##__VA_ARGS__)
 #define BT_CPPLOGF_SPEC(_logger, _fmt, ...)                                                        \
-    BT_CPPLOG_EX(bt2c::Logger::Level::FATAL, (_logger), (_fmt), ##__VA_ARGS__)
+    BT_CPPLOG_EX(bt2c::Logger::Level::Fatal, (_logger), (_fmt), ##__VA_ARGS__)
 
 /*
  * BT_CPPLOG_EX() with specific logging levels and using the default
@@ -641,260 +530,130 @@ private:
 #define BT_CPPLOGF(_fmt, ...) BT_CPPLOGF_SPEC(_BT_CPPLOG_DEF_LOGGER, (_fmt), ##__VA_ARGS__)
 
 /*
- * Calls logStrNoThrow() on `_logger` to log using the level `_lvl`
- * without appending nor throwing.
- */
-#define BT_CPPLOG_STR_EX(_lvl, _logger, _msg)                                                      \
-    (_logger).logStrNoThrow<(_lvl), false>(__FILE__, __func__, __LINE__, (_msg))
-
-/*
- * BT_CPPLOG_STR_EX() with specific logging levels.
- */
-#define BT_CPPLOGT_STR_SPEC(_logger, _msg)                                                         \
-    BT_CPPLOG_STR_EX(bt2c::Logger::Level::TRACE, (_logger), (_msg))
-#define BT_CPPLOGD_STR_SPEC(_logger, _msg)                                                         \
-    BT_CPPLOG_STR_EX(bt2c::Logger::Level::DEBUG, (_logger), (_msg))
-#define BT_CPPLOGI_STR_SPEC(_logger, _msg)                                                         \
-    BT_CPPLOG_STR_EX(bt2c::Logger::Level::INFO, (_logger), (_msg))
-#define BT_CPPLOGW_STR_SPEC(_logger, _msg)                                                         \
-    BT_CPPLOG_STR_EX(bt2c::Logger::Level::WARNING, (_logger), (_msg))
-#define BT_CPPLOGE_STR_SPEC(_logger, _msg)                                                         \
-    BT_CPPLOG_STR_EX(bt2c::Logger::Level::ERROR, (_logger), (_msg))
-#define BT_CPPLOGF_STR_SPEC(_logger, _msg)                                                         \
-    BT_CPPLOG_STR_EX(bt2c::Logger::Level::FATAL, (_logger), (_msg))
-
-/*
- * BT_CPPLOG_STR_EX() with specific logging levels and using the default
- * logger.
- */
-#define BT_CPPLOGT_STR(_msg) BT_CPPLOGT_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_msg))
-#define BT_CPPLOGD_STR(_msg) BT_CPPLOGD_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_msg))
-#define BT_CPPLOGI_STR(_msg) BT_CPPLOGI_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_msg))
-#define BT_CPPLOGW_STR(_msg) BT_CPPLOGW_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_msg))
-#define BT_CPPLOGE_STR(_msg) BT_CPPLOGE_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_msg))
-#define BT_CPPLOGF_STR(_msg) BT_CPPLOGF_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_msg))
-
-/*
- * Calls logMemNoThrow() on `_logger` to log using the level `_lvl`
- * without appending nor throwing.
+ * Calls logMem() on `_logger` to log using the level `_lvl`.
  */
-#define BT_CPPLOG_MEM_EX(_lvl, _logger, _mem_data, _mem_len, _fmt, ...)                            \
+#define BT_CPPLOG_MEM_EX(_lvl, _logger, _memData, _fmt, ...)                                       \
     do {                                                                                           \
         if (G_UNLIKELY((_logger).wouldLog(_lvl))) {                                                \
-            (_logger).logMemNoThrow<(_lvl)>(__FILE__, __func__, __LINE__, (_mem_data), (_mem_len), \
-                                            (_fmt), ##__VA_ARGS__);                                \
+            (_logger).template logMem<(_lvl)>(__FILE__, __func__, __LINE__, (_memData), (_fmt),    \
+                                              ##__VA_ARGS__);                                      \
         }                                                                                          \
     } while (0)
 
 /*
  * BT_CPPLOG_MEM_EX() with specific logging levels.
  */
-#define BT_CPPLOGT_MEM_SPEC(_logger, _mem_data, _mem_len, _fmt, ...)                               \
-    BT_CPPLOG_MEM_EX(bt2c::Logger::Level::TRACE, (_logger), (_mem_data), (_mem_len), (_fmt),       \
-                     ##__VA_ARGS__)
-#define BT_CPPLOGD_MEM_SPEC(_logger, _mem_data, _mem_len, _fmt, ...)                               \
-    BT_CPPLOG_MEM_EX(bt2c::Logger::Level::DEBUG, (_logger), (_mem_data), (_mem_len), (_fmt),       \
-                     ##__VA_ARGS__)
-#define BT_CPPLOGI_MEM_SPEC(_logger, _mem_data, _mem_len, _fmt, ...)                               \
-    BT_CPPLOG_MEM_EX(bt2c::Logger::Level::INFO, (_logger), (_mem_data), (_mem_len), (_fmt),        \
-                     ##__VA_ARGS__)
-#define BT_CPPLOGW_MEM_SPEC(_logger, _mem_data, _mem_len, _fmt, ...)                               \
-    BT_CPPLOG_MEM_EX(bt2c::Logger::Level::WARNING, (_logger), (_mem_data), (_mem_len), (_fmt),     \
-                     ##__VA_ARGS__)
-#define BT_CPPLOGE_MEM_SPEC(_logger, _mem_data, _mem_len, _fmt, ...)                               \
-    BT_CPPLOG_MEM_EX(bt2c::Logger::Level::ERROR, (_logger), (_mem_data), (_mem_len), (_fmt),       \
-                     ##__VA_ARGS__)
-#define BT_CPPLOGF_MEM_SPEC(_logger, _mem_data, _mem_len, _fmt, ...)                               \
-    BT_CPPLOG_MEM_EX(bt2c::Logger::Level::FATAL, (_logger), (_mem_data), (_mem_len), (_fmt),       \
-                     ##__VA_ARGS__)
+#define BT_CPPLOGT_MEM_SPEC(_logger, _memData, _fmt, ...)                                          \
+    BT_CPPLOG_MEM_EX(bt2c::Logger::Level::Trace, (_logger), (_memData), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGD_MEM_SPEC(_logger, _memData, _fmt, ...)                                          \
+    BT_CPPLOG_MEM_EX(bt2c::Logger::Level::Debug, (_logger), (_memData), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGI_MEM_SPEC(_logger, _memData, _fmt, ...)                                          \
+    BT_CPPLOG_MEM_EX(bt2c::Logger::Level::Info, (_logger), (_memData), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGW_MEM_SPEC(_logger, _memData, _fmt, ...)                                          \
+    BT_CPPLOG_MEM_EX(bt2c::Logger::Level::Warning, (_logger), (_memData), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGE_MEM_SPEC(_logger, _memData, _fmt, ...)                                          \
+    BT_CPPLOG_MEM_EX(bt2c::Logger::Level::Error, (_logger), (_memData), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGF_MEM_SPEC(_logger, _memData, _fmt, ...)                                          \
+    BT_CPPLOG_MEM_EX(bt2c::Logger::Level::Fatal, (_logger), (_memData), (_fmt), ##__VA_ARGS__)
 
 /*
  * BT_CPPLOG_MEM_EX() with specific logging levels and using the default
  * logger.
  */
-#define BT_CPPLOGT_MEM(_mem_data, _mem_len, _fmt, ...)                                             \
-    BT_CPPLOGT_MEM_SPEC(_BT_CPPLOG_DEF_LOGGER, (_mem_data), (_mem_len), (_fmt), ##__VA_ARGS__)
-#define BT_CPPLOGD_MEM(_mem_data, _mem_len, _fmt, ...)                                             \
-    BT_CPPLOGD_MEM_SPEC(_BT_CPPLOG_DEF_LOGGER, (_mem_data), (_mem_len), (_fmt), ##__VA_ARGS__)
-#define BT_CPPLOGI_MEM(_mem_data, _mem_len, _fmt, ...)                                             \
-    BT_CPPLOGI_MEM_SPEC(_BT_CPPLOG_DEF_LOGGER, (_mem_data), (_mem_len), (_fmt), ##__VA_ARGS__)
-#define BT_CPPLOGW_MEM(_mem_data, _mem_len, _fmt, ...)                                             \
-    BT_CPPLOGW_MEM_SPEC(_BT_CPPLOG_DEF_LOGGER, (_mem_data), (_mem_len), (_fmt), ##__VA_ARGS__)
-#define BT_CPPLOGE_MEM(_mem_data, _mem_len, _fmt, ...)                                             \
-    BT_CPPLOGE_MEM_SPEC(_BT_CPPLOG_DEF_LOGGER, (_mem_data), (_mem_len), (_fmt), ##__VA_ARGS__)
-#define BT_CPPLOGF_MEM(_mem_data, _mem_len, _fmt, ...)                                             \
-    BT_CPPLOGF_MEM_SPEC(_BT_CPPLOG_DEF_LOGGER, (_mem_data), (_mem_len), (_fmt), ##__VA_ARGS__)
-
-/*
- * Calls logMemStrNoThrow() on `_logger` to log using the level `_lvl`
- * without appending nor throwing.
- */
-#define BT_CPPLOG_MEM_STR_EX(_lvl, _logger, _mem_data, _mem_len, _msg)                             \
-    (_logger).logMemStrNoThrow<(_lvl)>(__FILE__, __func__, __LINE__, (_mem_data), (_mem_len),      \
-                                       (_msg))
-
-/*
- * BT_CPPLOG_MEM_STR_EX() with specific logging levels.
- */
-#define BT_CPPLOGT_MEM_STR_SPEC(_logger, _mem_data, _mem_len, _msg)                                \
-    BT_CPPLOG_MEM_STR_EX(bt2c::Logger::Level::TRACE, (_logger), (_mem_data), (_mem_len), (_msg))
-#define BT_CPPLOGD_MEM_STR_SPEC(_logger, _mem_data, _mem_len, _msg)                                \
-    BT_CPPLOG_MEM_STR_EX(bt2c::Logger::Level::DEBUG, (_logger), (_mem_data), (_mem_len), (_msg))
-#define BT_CPPLOGI_MEM_STR_SPEC(_logger, _mem_data, _mem_len, _msg)                                \
-    BT_CPPLOG_MEM_STR_EX(bt2c::Logger::Level::INFO, (_logger), (_mem_data), (_mem_len), (_msg))
-#define BT_CPPLOGW_MEM_STR_SPEC(_logger, _mem_data, _mem_len, _msg)                                \
-    BT_CPPLOG_MEM_STR_EX(bt2c::Logger::Level::WARNING, (_logger), (_mem_data), (_mem_len), (_msg))
-#define BT_CPPLOGE_MEM_STR_SPEC(_logger, _mem_data, _mem_len, _msg)                                \
-    BT_CPPLOG_MEM_STR_EX(bt2c::Logger::Level::ERROR, (_logger), (_mem_data), (_mem_len), (_msg))
-#define BT_CPPLOGF_MEM_STR_SPEC(_logger, _mem_data, _mem_len, _msg)                                \
-    BT_CPPLOG_MEM_STR_EX(bt2c::Logger::Level::FATAL, (_logger), (_mem_data), (_mem_len), (_msg))
-
-/*
- * BT_CPPLOG_MEM_STR_EX() with specific logging levels and using the
- * default logger.
- */
-#define BT_CPPLOGT_MEM_STR(_mem_data, _mem_len, _msg)                                              \
-    BT_CPPLOGT_MEM_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_mem_data), (_mem_len), (_msg))
-#define BT_CPPLOGD_MEM_STR(_mem_data, _mem_len, _msg)                                              \
-    BT_CPPLOGD_MEM_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_mem_data), (_mem_len), (_msg))
-#define BT_CPPLOGI_MEM_STR(_mem_data, _mem_len, _msg)                                              \
-    BT_CPPLOGI_MEM_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_mem_data), (_mem_len), (_msg))
-#define BT_CPPLOGW_MEM_STR(_mem_data, _mem_len, _msg)                                              \
-    BT_CPPLOGW_MEM_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_mem_data), (_mem_len), (_msg))
-#define BT_CPPLOGE_MEM_STR(_mem_data, _mem_len, _msg)                                              \
-    BT_CPPLOGE_MEM_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_mem_data), (_mem_len), (_msg))
-#define BT_CPPLOGF_MEM_STR(_mem_data, _mem_len, _msg)                                              \
-    BT_CPPLOGF_MEM_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_mem_data), (_mem_len), (_msg))
+#define BT_CPPLOGT_MEM(_memData, _fmt, ...)                                                        \
+    BT_CPPLOGT_MEM_SPEC(_BT_CPPLOG_DEF_LOGGER, (_memData), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGD_MEM(_memData, _fmt, ...)                                                        \
+    BT_CPPLOGD_MEM_SPEC(_BT_CPPLOG_DEF_LOGGER, (_memData), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGI_MEM(_memData, _fmt, ...)                                                        \
+    BT_CPPLOGI_MEM_SPEC(_BT_CPPLOG_DEF_LOGGER, (_memData), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGW_MEM(_memData, _fmt, ...)                                                        \
+    BT_CPPLOGW_MEM_SPEC(_BT_CPPLOG_DEF_LOGGER, (_memData), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGE_MEM(_memData, _fmt, ...)                                                        \
+    BT_CPPLOGE_MEM_SPEC(_BT_CPPLOG_DEF_LOGGER, (_memData), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGF_MEM(_memData, _fmt, ...)                                                        \
+    BT_CPPLOGF_MEM_SPEC(_BT_CPPLOG_DEF_LOGGER, (_memData), (_fmt), ##__VA_ARGS__)
 
 /*
- * Calls logErrnoNoThrow() on `_logger` to log using the level `_lvl`
- * and initial message `_init_msg` without appending nor throwing.
+ * Calls logErrno() on `_logger` to log using the level `_lvl` and
+ * initial message `_initMsg`.
  */
-#define BT_CPPLOG_ERRNO_EX(_lvl, _logger, _init_msg, _fmt, ...)                                    \
+#define BT_CPPLOG_ERRNO_EX(_lvl, _logger, _initMsg, _fmt, ...)                                     \
     do {                                                                                           \
         if (G_UNLIKELY((_logger).wouldLog(_lvl))) {                                                \
-            (_logger).logErrnoNoThrow<(_lvl), false>(__FILE__, __func__, __LINE__, (_init_msg),    \
-                                                     (_fmt), ##__VA_ARGS__);                       \
+            (_logger).template logErrno<(_lvl), false>(__FILE__, __func__, __LINE__, (_initMsg),   \
+                                                       (_fmt), ##__VA_ARGS__);                     \
         }                                                                                          \
     } while (0)
 
 /*
  * BT_CPPLOG_ERRNO_EX() with specific logging levels.
  */
-#define BT_CPPLOGT_ERRNO_SPEC(_logger, _init_msg, _fmt, ...)                                       \
-    BT_CPPLOG_ERRNO_EX(bt2c::Logger::Level::TRACE, (_logger), (_init_msg), (_fmt), ##__VA_ARGS__)
-#define BT_CPPLOGD_ERRNO_SPEC(_logger, _init_msg, _fmt, ...)                                       \
-    BT_CPPLOG_ERRNO_EX(bt2c::Logger::Level::DEBUG, (_logger), (_init_msg), (_fmt), ##__VA_ARGS__)
-#define BT_CPPLOGI_ERRNO_SPEC(_logger, _init_msg, _fmt, ...)                                       \
-    BT_CPPLOG_ERRNO_EX(bt2c::Logger::Level::INFO, (_logger), (_init_msg), (_fmt), ##__VA_ARGS__)
-#define BT_CPPLOGW_ERRNO_SPEC(_logger, _init_msg, _fmt, ...)                                       \
-    BT_CPPLOG_ERRNO_EX(bt2c::Logger::Level::WARNING, (_logger), (_init_msg), (_fmt), ##__VA_ARGS__)
-#define BT_CPPLOGE_ERRNO_SPEC(_logger, _init_msg, _fmt, ...)                                       \
-    BT_CPPLOG_ERRNO_EX(bt2c::Logger::Level::ERROR, (_logger), (_init_msg), (_fmt), ##__VA_ARGS__)
-#define BT_CPPLOGF_ERRNO_SPEC(_logger, _init_msg, _fmt, ...)                                       \
-    BT_CPPLOG_ERRNO_EX(bt2c::Logger::Level::FATAL, (_logger), (_init_msg), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGT_ERRNO_SPEC(_logger, _initMsg, _fmt, ...)                                        \
+    BT_CPPLOG_ERRNO_EX(bt2c::Logger::Level::Trace, (_logger), (_initMsg), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGD_ERRNO_SPEC(_logger, _initMsg, _fmt, ...)                                        \
+    BT_CPPLOG_ERRNO_EX(bt2c::Logger::Level::Debug, (_logger), (_initMsg), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGI_ERRNO_SPEC(_logger, _initMsg, _fmt, ...)                                        \
+    BT_CPPLOG_ERRNO_EX(bt2c::Logger::Level::Info, (_logger), (_initMsg), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGW_ERRNO_SPEC(_logger, _initMsg, _fmt, ...)                                        \
+    BT_CPPLOG_ERRNO_EX(bt2c::Logger::Level::Warning, (_logger), (_initMsg), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGE_ERRNO_SPEC(_logger, _initMsg, _fmt, ...)                                        \
+    BT_CPPLOG_ERRNO_EX(bt2c::Logger::Level::Error, (_logger), (_initMsg), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGF_ERRNO_SPEC(_logger, _initMsg, _fmt, ...)                                        \
+    BT_CPPLOG_ERRNO_EX(bt2c::Logger::Level::Fatal, (_logger), (_initMsg), (_fmt), ##__VA_ARGS__)
 
 /*
  * BT_CPPLOG_ERRNO_EX() with specific logging levels and using the
  * default logger.
  */
-#define BT_CPPLOGT_ERRNO(_init_msg, _fmt, ...)                                                     \
-    BT_CPPLOGT_ERRNO_SPEC(_BT_CPPLOG_DEF_LOGGER, (_init_msg), (_fmt), ##__VA_ARGS__)
-#define BT_CPPLOGD_ERRNO(_init_msg, _fmt, ...)                                                     \
-    BT_CPPLOGD_ERRNO_SPEC(_BT_CPPLOG_DEF_LOGGER, (_init_msg), (_fmt), ##__VA_ARGS__)
-#define BT_CPPLOGI_ERRNO(_init_msg, _fmt, ...)                                                     \
-    BT_CPPLOGI_ERRNO_SPEC(_BT_CPPLOG_DEF_LOGGER, (_init_msg), (_fmt), ##__VA_ARGS__)
-#define BT_CPPLOGW_ERRNO(_init_msg, _fmt, ...)                                                     \
-    BT_CPPLOGW_ERRNO_SPEC(_BT_CPPLOG_DEF_LOGGER, (_init_msg), (_fmt), ##__VA_ARGS__)
-#define BT_CPPLOGE_ERRNO(_init_msg, _fmt, ...)                                                     \
-    BT_CPPLOGE_ERRNO_SPEC(_BT_CPPLOG_DEF_LOGGER, (_init_msg), (_fmt), ##__VA_ARGS__)
-#define BT_CPPLOGF_ERRNO(_init_msg, _fmt, ...)                                                     \
-    BT_CPPLOGF_ERRNO_SPEC(_BT_CPPLOG_DEF_LOGGER, (_init_msg), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGT_ERRNO(_initMsg, _fmt, ...)                                                      \
+    BT_CPPLOGT_ERRNO_SPEC(_BT_CPPLOG_DEF_LOGGER, (_initMsg), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGD_ERRNO(_initMsg, _fmt, ...)                                                      \
+    BT_CPPLOGD_ERRNO_SPEC(_BT_CPPLOG_DEF_LOGGER, (_initMsg), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGI_ERRNO(_initMsg, _fmt, ...)                                                      \
+    BT_CPPLOGI_ERRNO_SPEC(_BT_CPPLOG_DEF_LOGGER, (_initMsg), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGW_ERRNO(_initMsg, _fmt, ...)                                                      \
+    BT_CPPLOGW_ERRNO_SPEC(_BT_CPPLOG_DEF_LOGGER, (_initMsg), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGE_ERRNO(_initMsg, _fmt, ...)                                                      \
+    BT_CPPLOGE_ERRNO_SPEC(_BT_CPPLOG_DEF_LOGGER, (_initMsg), (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGF_ERRNO(_initMsg, _fmt, ...)                                                      \
+    BT_CPPLOGF_ERRNO_SPEC(_BT_CPPLOG_DEF_LOGGER, (_initMsg), (_fmt), ##__VA_ARGS__)
 
 /*
- * Calls logErrnoStrNoThrow() on `_logger` to log using the level `_lvl`
- * and initial message `_init_msg` without appending nor throwing.
+ * Calls log() on `_logger` with the `Error` level to log an error and
+ * append a cause to the error of the current thread.
  */
-#define BT_CPPLOG_ERRNO_STR_EX(_lvl, _logger, _init_msg, _msg)                                     \
-    (_logger).logErrnoStrNoThrow<(_lvl), false>(__FILE__, __func__, __LINE__, (_init_msg), (_msg))
+#define BT_CPPLOGE_APPEND_CAUSE_SPEC(_logger, _fmt, ...)                                           \
+    (_logger).template log<bt2c::Logger::Level::Error, true>(__FILE__, __func__, __LINE__, (_fmt), \
+                                                             ##__VA_ARGS__)
 
 /*
- * BT_CPPLOG_ERRNO_STR_EX() with specific logging levels.
+ * BT_CPPLOGE_APPEND_CAUSE_SPEC() using the default logger.
  */
-#define BT_CPPLOGT_ERRNO_STR_SPEC(_logger, _init_msg, _msg)                                        \
-    BT_CPPLOG_ERRNO_STR_EX(bt2c::Logger::Level::TRACE, (_logger), (_init_msg), (_msg))
-#define BT_CPPLOGD_ERRNO_STR_SPEC(_logger, _init_msg, _msg)                                        \
-    BT_CPPLOG_ERRNO_STR_EX(bt2c::Logger::Level::DEBUG, (_logger), (_init_msg), (_msg))
-#define BT_CPPLOGI_ERRNO_STR_SPEC(_logger, _init_msg, _msg)                                        \
-    BT_CPPLOG_ERRNO_STR_EX(bt2c::Logger::Level::INFO, (_logger), (_init_msg), (_msg))
-#define BT_CPPLOGW_ERRNO_STR_SPEC(_logger, _init_msg, _msg)                                        \
-    BT_CPPLOG_ERRNO_STR_EX(bt2c::Logger::Level::WARNING, (_logger), (_init_msg), (_msg))
-#define BT_CPPLOGE_ERRNO_STR_SPEC(_logger, _init_msg, _msg)                                        \
-    BT_CPPLOG_ERRNO_STR_EX(bt2c::Logger::Level::ERROR, (_logger), (_init_msg), (_msg))
-#define BT_CPPLOGF_ERRNO_STR_SPEC(_logger, _init_msg, _msg)                                        \
-    BT_CPPLOG_ERRNO_STR_EX(bt2c::Logger::Level::FATAL, (_logger), (_init_msg), (_msg))
-
-/*
- * BT_CPPLOG_ERRNO_STR_EX() with specific logging levels and using the
- * default logger.
- */
-#define BT_CPPLOGT_ERRNO_STR(_init_msg, _msg)                                                      \
-    BT_CPPLOGT_ERRNO_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_init_msg), (_msg))
-#define BT_CPPLOGD_ERRNO_STR(_init_msg, _msg)                                                      \
-    BT_CPPLOGD_ERRNO_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_init_msg), (_msg))
-#define BT_CPPLOGI_ERRNO_STR(_init_msg, _msg)                                                      \
-    BT_CPPLOGI_ERRNO_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_init_msg), (_msg))
-#define BT_CPPLOGW_ERRNO_STR(_init_msg, _msg)                                                      \
-    BT_CPPLOGW_ERRNO_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_init_msg), (_msg))
-#define BT_CPPLOGE_ERRNO_STR(_init_msg, _msg)                                                      \
-    BT_CPPLOGE_ERRNO_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_init_msg), (_msg))
-#define BT_CPPLOGF_ERRNO_STR(_init_msg, _msg)                                                      \
-    BT_CPPLOGF_ERRNO_STR_SPEC(_BT_CPPLOG_DEF_LOGGER, (_init_msg), (_msg))
-
-/*
- * Calls logErrorAndThrow() on `_logger` to log an error, append a cause
- * to the error of the current thread, and throw an instance of
- * `_exc_cls`.
- */
-#define BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(_logger, _exc_cls, _fmt, ...)                       \
-    (_logger).logErrorAndThrow<true, _exc_cls>(__FILE__, __func__, __LINE__, (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGE_APPEND_CAUSE(_fmt, ...)                                                         \
+    BT_CPPLOGE_APPEND_CAUSE_SPEC(_BT_CPPLOG_DEF_LOGGER, (_fmt), ##__VA_ARGS__)
 
 /*
  * Calls logErrorAndThrow() on `_logger` to log an error, append a cause
  * to the error of the current thread, and throw an instance of
- * `_exc_cls`.
+ * `_excCls`.
  */
-#define BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(_logger, _exc_cls, _fmt, ...)                       \
-    (_logger).logErrorAndThrow<true, _exc_cls>(__FILE__, __func__, __LINE__, (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(_logger, _excCls, _fmt, ...)                        \
+    (_logger).template logErrorAndThrow<true, _excCls>(__FILE__, __func__, __LINE__, (_fmt),       \
+                                                       ##__VA_ARGS__)
 
 /*
  * BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC() using the default logger.
  */
-#define BT_CPPLOGE_APPEND_CAUSE_AND_THROW(_exc_cls, _fmt, ...)                                     \
-    BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(_BT_CPPLOG_DEF_LOGGER, _exc_cls, (_fmt), ##__VA_ARGS__)
-
-/*
- * Calls logErrorStrAndThrow() on `_logger` to log an error, append a
- * cause to the error of the current thread, and throw an instance of
- * `_exc_cls`.
- */
-#define BT_CPPLOGE_STR_APPEND_CAUSE_AND_THROW_SPEC(_logger, _exc_cls, _msg)                        \
-    (_logger).logErrorStrAndThrow<true, _exc_cls>(__FILE__, __func__, __LINE__, (_msg))
-
-/*
- * BT_CPPLOGE_STR_APPEND_CAUSE_AND_THROW_SPEC() using the default
- * logger.
- */
-#define BT_CPPLOGE_STR_APPEND_CAUSE_AND_THROW(_exc_cls, _msg)                                      \
-    BT_CPPLOGE_STR_APPEND_CAUSE_AND_THROW_SPEC(_BT_CPPLOG_DEF_LOGGER, _exc_cls, (_msg))
+#define BT_CPPLOGE_APPEND_CAUSE_AND_THROW(_excCls, _fmt, ...)                                      \
+    BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(_BT_CPPLOG_DEF_LOGGER, _excCls, (_fmt), ##__VA_ARGS__)
 
 /*
  * Calls logErrorAndRethrow() on `_logger` to log an error, append a
  * cause to the error of the current thread, and throw an instance of
- * `_exc_cls`.
+ * `_excCls`.
  */
 #define BT_CPPLOGE_APPEND_CAUSE_AND_RETHROW_SPEC(_logger, _fmt, ...)                               \
-    (_logger).logErrorAndRethrow<true>(__FILE__, __func__, __LINE__, (_fmt), ##__VA_ARGS__)
+    (_logger).template logErrorAndRethrow<true>(__FILE__, __func__, __LINE__, (_fmt), ##__VA_ARGS__)
 
 /*
  * BT_CPPLOGE_APPEND_CAUSE_AND_RETHROW_SPEC() using the default logger.
@@ -903,84 +662,51 @@ private:
     BT_CPPLOGE_APPEND_CAUSE_AND_RETHROW_SPEC(_BT_CPPLOG_DEF_LOGGER, (_fmt), ##__VA_ARGS__)
 
 /*
- * Calls logErrorStrAndRethrow() on `_logger` to log an error, append a
- * cause to the error of the current thread, and throw an instance of
- * `_exc_cls`.
+ * Calls logErrno() on `_logger` with the `Level::Error` level to log an
+ * error and append a cause to the error of the current thread.
  */
-#define BT_CPPLOGE_STR_APPEND_CAUSE_AND_RETHROW_SPEC(_logger, _msg)                                \
-    (_logger).logErrorStrAndRethrow<true>(__FILE__, __func__, __LINE__, (_msg))
+#define BT_CPPLOGE_ERRNO_APPEND_CAUSE_SPEC(_logger, _initMsg, _fmt, ...)                           \
+    (_logger).template logErrno<bt2c::Logger::Level::Error, true>(                                 \
+        __FILE__, __func__, __LINE__, (_initMsg), (_fmt), ##__VA_ARGS__)
 
 /*
- * BT_CPPLOGE_STR_APPEND_CAUSE_AND_RETHROW_SPEC() using the default
- * logger.
+ * BT_CPPLOGE_ERRNO_APPEND_CAUSE_SPEC() using the default logger.
  */
-#define BT_CPPLOGE_STR_APPEND_CAUSE_AND_RETHROW(_msg)                                              \
-    BT_CPPLOGE_STR_APPEND_CAUSE_AND_RETHROW_SPEC(_BT_CPPLOG_DEF_LOGGER, (_msg))
+#define BT_CPPLOGE_ERRNO_APPEND_CAUSE(_initMsg, _fmt, ...)                                         \
+    BT_CPPLOGE_ERRNO_APPEND_CAUSE_SPEC(_BT_CPPLOG_DEF_LOGGER, (_initMsg), (_fmt), ##__VA_ARGS__)
 
 /*
  * Calls logErrorErrnoAndThrow() on `_logger` to log an error, append a
  * cause to the error of the current thread, and throw an instance of
- * `_exc_cls`.
+ * `_excCls`.
  */
-#define BT_CPPLOGE_ERRNO_APPEND_CAUSE_AND_THROW_SPEC(_logger, _exc_cls, _init_msg, _fmt, ...)      \
-    (_logger).logErrorErrnoAndThrow<true, _exc_cls>(__FILE__, __func__, __LINE__, (_init_msg),     \
-                                                    (_fmt), ##__VA_ARGS__)
+#define BT_CPPLOGE_ERRNO_APPEND_CAUSE_AND_THROW_SPEC(_logger, _excCls, _initMsg, _fmt, ...)        \
+    (_logger).template logErrorErrnoAndThrow<true, _excCls>(__FILE__, __func__, __LINE__,          \
+                                                            (_initMsg), (_fmt), ##__VA_ARGS__)
 
 /*
  * BT_CPPLOGE_ERRNO_APPEND_CAUSE_AND_THROW_SPEC() using the default
  * logger.
  */
-#define BT_CPPLOGE_ERRNO_APPEND_CAUSE_AND_THROW(_exc_cls, _init_msg, _fmt, ...)                    \
-    BT_CPPLOGE_ERRNO_APPEND_CAUSE_AND_THROW_SPEC(_BT_CPPLOG_DEF_LOGGER, _exc_cls, (_init_msg),     \
+#define BT_CPPLOGE_ERRNO_APPEND_CAUSE_AND_THROW(_excCls, _initMsg, _fmt, ...)                      \
+    BT_CPPLOGE_ERRNO_APPEND_CAUSE_AND_THROW_SPEC(_BT_CPPLOG_DEF_LOGGER, _excCls, (_initMsg),       \
                                                  (_fmt), ##__VA_ARGS__)
 
-/*
- * Calls logErrorErrnoStrAndThrow() on `_logger` to log an error, append
- * a cause to the error of the current thread, and throw an instance of
- * `_exc_cls`.
- */
-#define BT_CPPLOGE_ERRNO_STR_APPEND_CAUSE_AND_THROW_SPEC(_logger, _exc_cls, _init_msg, _msg)       \
-    (_logger).logErrorErrnoStrAndThrow<true, _exc_cls>(__FILE__, __func__, __LINE__, (_init_msg),  \
-                                                       (_msg))
-
-/*
- * BT_CPPLOGE_ERRNO_STR_APPEND_CAUSE_AND_THROW_SPEC() using the default
- * logger.
- */
-#define BT_CPPLOGE_ERRNO_STR_APPEND_CAUSE_AND_THROW(_exc_cls, _init_msg, _msg)                     \
-    BT_CPPLOGE_ERRNO_STR_APPEND_CAUSE_AND_THROW_SPEC(_BT_CPPLOG_DEF_LOGGER, _exc_cls, (_init_msg), \
-                                                     (_msg))
-
 /*
  * Calls logErrorErrnoAndRethrow() on `_logger` to log an error, append
  * a cause to the error of the current thread, and throw an instance of
- * `_exc_cls`.
+ * `_excCls`.
  */
-#define BT_CPPLOGE_ERRNO_APPEND_CAUSE_AND_RETHROW_SPEC(_logger, _init_msg, _fmt, ...)              \
-    (_logger).logErrorErrnoAndRethrow<true>(__FILE__, __func__, __LINE__, (_init_msg), (_fmt),     \
-                                            ##__VA_ARGS__)
+#define BT_CPPLOGE_ERRNO_APPEND_CAUSE_AND_RETHROW_SPEC(_logger, _initMsg, _fmt, ...)               \
+    (_logger).template logErrorErrnoAndRethrow<true>(__FILE__, __func__, __LINE__, (_initMsg),     \
+                                                     (_fmt), ##__VA_ARGS__)
 
 /*
  * BT_CPPLOGE_ERRNO_APPEND_CAUSE_AND_RETHROW_SPEC() using the default
  * logger.
  */
-#define BT_CPPLOGE_ERRNO_APPEND_CAUSE_AND_RETHROW(_init_msg, _fmt, ...)                            \
-    BT_CPPLOGE_ERRNO_APPEND_CAUSE_AND_RETHROW_SPEC(_BT_CPPLOG_DEF_LOGGER, (_init_msg), (_fmt),     \
+#define BT_CPPLOGE_ERRNO_APPEND_CAUSE_AND_RETHROW(_initMsg, _fmt, ...)                             \
+    BT_CPPLOGE_ERRNO_APPEND_CAUSE_AND_RETHROW_SPEC(_BT_CPPLOG_DEF_LOGGER, (_initMsg), (_fmt),      \
                                                    ##__VA_ARGS__)
 
-/*
- * Calls logErrorErrnoStrAndRethrow() on `_logger` to log an error,
- * append a cause to the error of the current thread, and throw an
- * instance of `_exc_cls`.
- */
-#define BT_CPPLOGE_ERRNO_STR_APPEND_CAUSE_AND_RETHROW_SPEC(_logger, _init_msg, _msg)               \
-    (_logger).logErrorErrnoStrAndRethrow<true>(__FILE__, __func__, __LINE__, (_init_msg), (_msg))
-
-/*
- * BT_CPPLOGE_ERRNO_STR_APPEND_CAUSE_AND_RETHROW_SPEC() using the
- * default logger.
- */
-#define BT_CPPLOGE_ERRNO_STR_APPEND_CAUSE_AND_RETHROW(_init_msg, _msg)                             \
-    BT_CPPLOGE_ERRNO_STR_APPEND_CAUSE_AND_RETHROW_SPEC(_BT_CPPLOG_DEF_LOGGER, (_init_msg), (_msg))
-
 #endif /* BABELTRACE_CPP_COMMON_BT2C_LOGGING_HPP */
diff --git a/src/cpp-common/bt2c/make-span.hpp b/src/cpp-common/bt2c/make-span.hpp
new file mode 100644 (file)
index 0000000..2270a8f
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2024 EfficiOS Inc.
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#ifndef BABELTRACE_CPP_COMMON_BT2C_MAKE_SPAN_HPP
+#define BABELTRACE_CPP_COMMON_BT2C_MAKE_SPAN_HPP
+
+#include "cpp-common/bt2s/span.hpp"
+
+namespace bt2c {
+
+template <class T>
+inline constexpr bt2s::span<T> makeSpan(T * const ptr, const size_t count) noexcept
+{
+    return nonstd::make_span(ptr, count);
+}
+
+} /* namespace bt2c */
+
+#endif /* BABELTRACE_CPP_COMMON_BT2C_MAKE_SPAN_HPP */
diff --git a/src/cpp-common/bt2c/span.hpp b/src/cpp-common/bt2c/span.hpp
deleted file mode 100644 (file)
index 05ab3d7..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (c) 2024 EfficiOS Inc.
- *
- * SPDX-License-Identifier: MIT
- */
-
-#ifndef BABELTRACE_CPP_COMMON_BT2C_SPAN_HPP
-#define BABELTRACE_CPP_COMMON_BT2C_SPAN_HPP
-
-#include "cpp-common/bt2s/span.hpp"
-
-namespace bt2c {
-
-template <class T>
-inline constexpr bt2s::span<T> makeSpan(T * const ptr, const size_t count) noexcept
-{
-    return nonstd::make_span(ptr, count);
-}
-
-} /* namespace bt2c */
-
-#endif /* BABELTRACE_CPP_COMMON_BT2C_SPAN_HPP */
diff --git a/src/cpp-common/vendor/wise-enum/optional.h b/src/cpp-common/vendor/wise-enum/optional.h
new file mode 100644 (file)
index 0000000..6b0dab1
--- /dev/null
@@ -0,0 +1,82 @@
+#pragma once
+
+#include "optional_common.h"
+
+#include <stdexcept>
+#include <type_traits>
+
+#if __cplusplus == 201103
+#define WISE_ENUM_CONSTEXPR_14
+#else
+#define WISE_ENUM_CONSTEXPR_14 constexpr
+#endif
+
+namespace wise_enum {
+
+/* A simple, *forward* compatible optional implementation. That is, it does not
+ * provide the full std::optional interface, but all the interface it does
+ * provide is found on std::optional, so it should not be a breaking change to
+ * upgrade to std::optional.
+ */
+template <class T>
+class optional {
+public:
+  static_assert(std::is_enum<T>::value,
+                "wise enum optional is only for enum types");
+  optional() = default;
+  optional(T t) : m_t(t), m_active(true) {}
+
+  WISE_ENUM_CONSTEXPR_14 T &operator*() & { return m_t; }
+  constexpr const T &operator*() const & { return m_t; }
+  WISE_ENUM_CONSTEXPR_14 T &&operator*() && { return m_t; }
+  constexpr const T &&operator*() const && { return m_t; }
+
+  constexpr explicit operator bool() const noexcept { return m_active; }
+  constexpr bool has_value() const noexcept { return m_active; }
+
+  WISE_ENUM_CONSTEXPR_14 T &value() & {
+    if (m_active)
+      return m_t;
+    else
+      WISE_ENUM_OPTIONAL_BAD_ACCESS;
+  }
+  WISE_ENUM_CONSTEXPR_14 const T &value() const & {
+    if (m_active)
+      return m_t;
+    else
+      WISE_ENUM_OPTIONAL_BAD_ACCESS;
+  }
+
+  WISE_ENUM_CONSTEXPR_14 T &&value() && {
+    if (m_active)
+      return m_t;
+    else
+      WISE_ENUM_OPTIONAL_BAD_ACCESS;
+  }
+  WISE_ENUM_CONSTEXPR_14 const T &&value() const && {
+    if (m_active)
+      return m_t;
+    else
+      WISE_ENUM_OPTIONAL_BAD_ACCESS;
+  }
+
+  template <class U>
+  WISE_ENUM_CONSTEXPR_14 T value_or(U &&u) {
+    if (m_active)
+      return m_t;
+    else
+      return std::forward<U>(u);
+  }
+
+  void reset() noexcept { m_active = false; }
+
+  optional(const optional &other) = default;
+  optional(optional &&other) = default;
+  optional &operator=(const optional &other) = default;
+  optional &operator=(optional &&other) = default;
+
+private:
+  T m_t;
+  bool m_active = false;
+};
+} // namespace wise_enum
diff --git a/src/cpp-common/vendor/wise-enum/optional_common.h b/src/cpp-common/vendor/wise-enum/optional_common.h
new file mode 100644 (file)
index 0000000..c8f7b4f
--- /dev/null
@@ -0,0 +1,23 @@
+#pragma once
+
+#ifdef WISE_ENUM_NO_EXCEPT
+
+#include <cstdlib>
+#define WISE_ENUM_OPTIONAL_BAD_ACCESS std::abort()
+
+#else
+
+#include <stdexcept>
+
+namespace wise_enum {
+
+struct bad_optional_access : std::exception {
+  const char *what() const noexcept override {
+    return "Error, attempt to access valueless optional!";
+  }
+};
+} // namespace wise_enum
+
+#define WISE_ENUM_OPTIONAL_BAD_ACCESS throw bad_optional_access{}
+
+#endif
diff --git a/src/cpp-common/vendor/wise-enum/wise_enum.h b/src/cpp-common/vendor/wise-enum/wise_enum.h
new file mode 100644 (file)
index 0000000..db50027
--- /dev/null
@@ -0,0 +1,108 @@
+#pragma once
+
+#include "wise_enum_detail.h"
+#include "wise_enum_generated.h"
+
+#include <algorithm>
+#include <array>
+#include <type_traits>
+#include <utility>
+
+/*
+ Macro interface
+
+ The first argument to any macro enum is either the name of the enum, or a
+ parenthesized pair, (name, storage). The first form results in unfixed
+ underlying type for the enum, while the second form defines it explicitly.
+ After that, the macros take a variadic enumerator list. Each entry in the list
+ can be either a legal identifier name, or it can be a parenthesized pair where
+ the first entry is the identifier and the second entry is the initializer.
+
+ Usage notes:
+   - A semi-colon after the macro invocation is not necessary, and your
+     compiler may warn for it
+*/
+
+// Declare an enum at namespace scope
+#define WISE_ENUM(name, ...) WISE_ENUM_IMPL(enum, name, , __VA_ARGS__)
+
+// Declare an enum class at namespace scope
+#define WISE_ENUM_CLASS(name, ...)                                             \
+  WISE_ENUM_IMPL(enum class, name, , __VA_ARGS__)
+
+// Declare an enum at class scope
+#define WISE_ENUM_MEMBER(name, ...)                                            \
+  WISE_ENUM_IMPL(enum, name, friend, __VA_ARGS__)
+
+// Declare an enum class at class scope
+#define WISE_ENUM_CLASS_MEMBER(name, ...)                                      \
+  WISE_ENUM_IMPL(enum class, name, friend, __VA_ARGS__)
+
+/*
+ Adapt an existing enum into the wise enum API. This macro must be used at
+ global scope. The first argument must be the name of the enum (qualified),
+ followed by all the enumerators of the enum.
+*/
+#define WISE_ENUM_ADAPT(name, ...) WISE_ENUM_IMPL_ADAPT(name, __VA_ARGS__)
+
+namespace wise_enum {
+
+// Returns the string representation of an enumerator
+template <class T>
+constexpr string_type to_string(T t) {
+  return wise_enum_detail_to_string(t, detail::Tag<T>{});
+}
+
+// Enumerators trait class. Each value is also available as a template variable
+// for C++14 and on
+template <class T>
+struct enumerators {
+  // For a given wise enum type, this variable allows iteration over enumerators
+  // and their string names in the declared order. Each iterated object is a
+  // struct with members { T value; string_type name; }
+  static constexpr decltype(wise_enum_detail_array(detail::Tag<T>{})) range =
+      wise_enum_detail_array(detail::Tag<T>{});
+
+  // This variable is equal to the number of enumerators for the wise enum type.
+  static constexpr std::size_t size = range.size();
+};
+
+template <class T>
+constexpr decltype(
+    wise_enum_detail_array(detail::Tag<T>{})) enumerators<T>::range;
+
+template <class T>
+constexpr std::size_t enumerators<T>::size;
+
+#if __cplusplus >= 201402
+template <class T>
+constexpr auto &range = enumerators<T>::range;
+
+template <class T>
+constexpr std::size_t size = enumerators<T>::size;
+#endif
+
+// A type trait; this allows checking if a type is a wise_enum in generic code
+template <class T>
+using is_wise_enum = detail::is_wise_enum<T>;
+
+#if __cplusplus >= 201402
+template <class T>
+static constexpr bool is_wise_enum_v = is_wise_enum<T>::value;
+#endif
+
+// Converts a string literal into a wise enum. Returns an optional<T>; if no
+// enumerator has name matching the string, the optional is returned empty.
+template <class T>
+WISE_ENUM_CONSTEXPR_14 optional_type<T> from_string(string_type s) {
+  auto it =
+      std::find_if(enumerators<T>::range.begin(), enumerators<T>::range.end(),
+                   [=](const detail::value_and_name<T> &x) {
+                     return ::wise_enum::detail::compare(x.name, s);
+                   });
+  if (it == enumerators<T>::range.end())
+    return {};
+
+  return it->value;
+}
+} // namespace wise_enum
diff --git a/src/cpp-common/vendor/wise-enum/wise_enum_detail.h b/src/cpp-common/vendor/wise-enum/wise_enum_detail.h
new file mode 100644 (file)
index 0000000..1accbe7
--- /dev/null
@@ -0,0 +1,208 @@
+#pragma once
+
+#include <array>
+#include <type_traits>
+#include <utility>
+
+// optional type needed for interface
+#ifndef WISE_ENUM_OPTIONAL_TYPE
+#if __cplusplus >= 201703L
+#include <optional>
+namespace wise_enum {
+template <class T>
+using optional_type = std::optional<T>;
+}
+#else
+#include "optional.h"
+namespace wise_enum {
+template <class T>
+using optional_type = wise_enum::optional<T>;
+}
+#endif
+#else
+namespace wise_enum {
+template <class T>
+using optional_type = WISE_ENUM_OPTIONAL_TYPE<T>;
+}
+#endif
+
+// Choice of string_view if type defined, otherwise use string literal
+#ifndef WISE_ENUM_STRING_TYPE
+#if __cplusplus >= 201703L
+#include <string_view>
+namespace wise_enum {
+using string_type = std::string_view;
+}
+#else
+namespace wise_enum {
+using string_type = const char *;
+}
+#endif
+#else
+namespace wise_enum {
+using string_type = WISE_ENUM_STRING_TYPE;
+}
+#endif
+
+#if __cplusplus == 201103
+#define WISE_ENUM_CONSTEXPR_14
+#else
+#define WISE_ENUM_CONSTEXPR_14 constexpr
+#endif
+
+namespace wise_enum {
+namespace detail {
+
+template <class T>
+struct value_and_name {
+  T value;
+  string_type name;
+};
+
+template <class T>
+struct Tag {};
+
+constexpr void wise_enum_detail_array(...);
+
+template <class T>
+struct is_wise_enum
+    : std::integral_constant<
+          bool, !std::is_same<void, decltype(wise_enum_detail_array(
+                                        Tag<T>{}))>::value> {};
+
+WISE_ENUM_CONSTEXPR_14 inline int strcmp(const char *s1, const char *s2) {
+  while (*s1 && (*s1 == *s2))
+    s1++, s2++;
+  if (*s1 < *s2) {
+    return -1;
+  }
+  if (*s1 > *s2) {
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+WISE_ENUM_CONSTEXPR_14 inline bool compare(const char *s1, const char *s2) {
+  return strcmp(s1, s2) == 0;
+}
+
+template <class U, class = typename std::enable_if<
+                       !std::is_same<U, const char *>::value>::type>
+WISE_ENUM_CONSTEXPR_14 bool compare(U u1, U u2) {
+  return u1 == u2;
+}
+} // namespace detail
+} // namespace wise_enum
+
+
+// Needed for expansion of variadic macro arguments in MSVC
+// MSVC expands __VA_ARGS__ after passing it, while gcc expands it before
+#define WISE_ENUM_IMPL_EXPAND(x) x
+
+#define WISE_ENUM_IMPL_NARG(...)                                               \
+  WISE_ENUM_IMPL_NARG_(__VA_ARGS__, WISE_ENUM_IMPL_RSEQ_N())
+#define WISE_ENUM_IMPL_NARG_(...) WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_ARG_N(__VA_ARGS__))
+
+// ARG_N and RSEQ_N defined in wise_enum_generated.h
+
+// Building blocks; credit to:
+// https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms
+
+#define WISE_ENUM_IMPL_COMMA() ,
+#define WISE_ENUM_IMPL_NOTHING()
+
+#define WISE_ENUM_IMPL_CAT(a, ...) WISE_ENUM_IMPL_PRIMITIVE_CAT(a, __VA_ARGS__)
+#define WISE_ENUM_IMPL_PRIMITIVE_CAT(a, ...) a##__VA_ARGS__
+
+#define WISE_ENUM_IMPL_XSTR(s) #s
+#define WISE_ENUM_IMPL_STR(s) WISE_ENUM_IMPL_XSTR(s)
+
+#define WISE_ENUM_IMPL_IIF(c) WISE_ENUM_IMPL_CAT(WISE_ENUM_IMPL_IIF_, c)
+#define WISE_ENUM_IMPL_IIF_0(t, f) f
+#define WISE_ENUM_IMPL_IIF_1(t, f) t
+
+#define WISE_ENUM_IMPL_CHECK_N(x, n, ...) n
+#define WISE_ENUM_IMPL_CHECK(...)                                              \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_CHECK_N(__VA_ARGS__, 0, ))
+#define WISE_ENUM_IMPL_PROBE(x) x, 1,
+
+#define WISE_ENUM_IMPL_IS_PAREN(x)                                             \
+  WISE_ENUM_IMPL_CHECK(WISE_ENUM_IMPL_IS_PAREN_PROBE x)
+#define WISE_ENUM_IMPL_IS_PAREN_PROBE(...) WISE_ENUM_IMPL_PROBE(~)
+
+#define WISE_ENUM_IMPL_FIRST_ARG(x, ...) x
+
+#define WISE_ENUM_IMPL_ONLY_OR_FIRST(x)                                        \
+  WISE_ENUM_IMPL_IIF(WISE_ENUM_IMPL_IS_PAREN(x))                               \
+  (WISE_ENUM_IMPL_FIRST_ARG x, x)
+
+// Use building blocks to conditionally process enumerators; they can either be
+// just an identifier, or (identifier, value)
+#define WISE_ENUM_IMPL_ENUM_INIT_2(x, ...) x = __VA_ARGS__
+#define WISE_ENUM_IMPL_ENUM_INIT(name, x)                                      \
+  WISE_ENUM_IMPL_IIF(WISE_ENUM_IMPL_IS_PAREN(x))                               \
+  (WISE_ENUM_IMPL_ENUM_INIT_2 x, x)
+
+#define WISE_ENUM_IMPL_ENUM_STR(x)                                             \
+  WISE_ENUM_IMPL_STR(WISE_ENUM_IMPL_ONLY_OR_FIRST(x))
+
+#define WISE_ENUM_IMPL_DESC_PAIR(name, x)                                      \
+  { name::WISE_ENUM_IMPL_ONLY_OR_FIRST(x), WISE_ENUM_IMPL_ENUM_STR(x) }
+
+#define WISE_ENUM_IMPL_SWITCH_CASE(name, x)                                    \
+  case name::WISE_ENUM_IMPL_ONLY_OR_FIRST(x):                                  \
+    return WISE_ENUM_IMPL_ENUM_STR(x);
+
+#define WISE_ENUM_IMPL_STORAGE_2(x, y) y
+
+#define WISE_ENUM_IMPL_STORAGE(x)                                              \
+  WISE_ENUM_IMPL_IIF(WISE_ENUM_IMPL_IS_PAREN(x))                               \
+  ( : WISE_ENUM_IMPL_STORAGE_2 x, )
+
+#define WISE_ENUM_IMPL(type, name_storage, friendly, ...)                      \
+  WISE_ENUM_IMPL_2(type, WISE_ENUM_IMPL_ONLY_OR_FIRST(name_storage),           \
+                   WISE_ENUM_IMPL_STORAGE(name_storage), friendly,             \
+                   WISE_ENUM_IMPL_NARG(__VA_ARGS__), __VA_ARGS__)
+
+#define WISE_ENUM_IMPL_2(type, name, storage, friendly, num_enums, ...)        \
+  WISE_ENUM_IMPL_3(type, name, storage, friendly, num_enums,                   \
+                   WISE_ENUM_IMPL_CAT(WISE_ENUM_IMPL_LOOP_, num_enums),        \
+                   __VA_ARGS__)
+
+
+#define WISE_ENUM_IMPL_3(type, name, storage, friendly, num_enums, loop, ...)  \
+  type name storage{                                                           \
+      WISE_ENUM_IMPL_EXPAND(loop(WISE_ENUM_IMPL_ENUM_INIT, _,                  \
+                             WISE_ENUM_IMPL_COMMA, __VA_ARGS__))};             \
+  WISE_ENUM_IMPL_ADAPT_3(name, friendly, num_enums, loop, __VA_ARGS__)
+
+#define WISE_ENUM_IMPL_ADAPT(name, ...)                                        \
+  namespace wise_enum {                                                        \
+  namespace detail {                                                           \
+  WISE_ENUM_IMPL_ADAPT_2(name, WISE_ENUM_IMPL_NARG(__VA_ARGS__), __VA_ARGS__)  \
+  }                                                                            \
+  }
+
+#define WISE_ENUM_IMPL_ADAPT_2(name, num_enums, ...)                           \
+  WISE_ENUM_IMPL_ADAPT_3(name, , num_enums,                                    \
+                         WISE_ENUM_IMPL_CAT(WISE_ENUM_IMPL_LOOP_, num_enums),  \
+                         __VA_ARGS__)
+
+#define WISE_ENUM_IMPL_ADAPT_3(name, friendly, num_enums, loop, ...)           \
+  friendly constexpr std::array<::wise_enum::detail::value_and_name<name>,     \
+                                num_enums>                                     \
+  wise_enum_detail_array(::wise_enum::detail::Tag<name>) {                     \
+    return {{WISE_ENUM_IMPL_EXPAND(loop(WISE_ENUM_IMPL_DESC_PAIR, name,        \
+                  WISE_ENUM_IMPL_COMMA, __VA_ARGS__))}};                       \
+  }                                                                            \
+                                                                               \
+  template <class T>                                                           \
+  friendly WISE_ENUM_CONSTEXPR_14 ::wise_enum::string_type                     \
+  wise_enum_detail_to_string(T e, ::wise_enum::detail::Tag<name>) {            \
+    switch (e) {                                                               \
+      WISE_ENUM_IMPL_EXPAND(loop(WISE_ENUM_IMPL_SWITCH_CASE, name,             \
+           WISE_ENUM_IMPL_NOTHING, __VA_ARGS__))                               \
+    }                                                                          \
+    return {};                                                                 \
+  }
diff --git a/src/cpp-common/vendor/wise-enum/wise_enum_generated.h b/src/cpp-common/vendor/wise-enum/wise_enum_generated.h
new file mode 100644 (file)
index 0000000..f83c8ae
--- /dev/null
@@ -0,0 +1,406 @@
+#define WISE_ENUM_IMPL_ARG_N(                                                           \
+    _1, _2, _3, _4, _5, _6, _7, _8, _9, _10,                                            \
+    _11, _12, _13, _14, _15, _16, _17, _18, _19, _20,                                   \
+    _21, _22, _23, _24, _25, _26, _27, _28, _29, _30,                                   \
+    _31, _32, _33, _34, _35, _36, _37, _38, _39, _40,                                   \
+    _41, _42, _43, _44, _45, _46, _47, _48, _49, _50,                                   \
+    _51, _52, _53, _54, _55, _56, _57, _58, _59, _60,                                   \
+    _61, _62, _63, _64, _65, _66, _67, _68, _69, _70,                                   \
+    _71, _72, _73, _74, _75, _76, _77, _78, _79, _80,                                   \
+    _81, _82, _83, _84, _85, _86, _87, _88, _89, _90,                                   \
+    _91, _92, _93, _94, _95, _96, _97, _98, _99, _100,                                  \
+    _101, _102, _103, _104, _105, _106, _107, _108, _109, _110,                         \
+    _111, _112, _113, _114, _115, _116, _117, _118, _119, _120,                         \
+    _121, _122, _123, _124, _125, N, ...                                                \
+  )                                                                                     \
+  N                                                                                     \
+
+#define WISE_ENUM_IMPL_RSEQ_N()                                                         \
+  125, 124, 123, 122, 121, 120, 119, 118, 117, 116,                                     \
+  115, 114, 113, 112, 111, 110, 109, 108, 107, 106,                                     \
+  105, 104, 103, 102, 101, 100, 99, 98, 97, 96,                                         \
+  95, 94, 93, 92, 91, 90, 89, 88, 87, 86,                                               \
+  85, 84, 83, 82, 81, 80, 79, 78, 77, 76,                                               \
+  75, 74, 73, 72, 71, 70, 69, 68, 67, 66,                                               \
+  65, 64, 63, 62, 61, 60, 59, 58, 57, 56,                                               \
+  55, 54, 53, 52, 51, 50, 49, 48, 47, 46,                                               \
+  45, 44, 43, 42, 41, 40, 39, 38, 37, 36,                                               \
+  35, 34, 33, 32, 31, 30, 29, 28, 27, 26,                                               \
+  25, 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                                                                      \
+
+#define WISE_ENUM_IMPL_LOOP_1(M, C, D, x) M(C, x)
+
+#define WISE_ENUM_IMPL_LOOP_2(M, C, D, x, ...) M(C, x) D()                              \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_1(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_3(M, C, D, x, ...) M(C, x) D()                              \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_2(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_4(M, C, D, x, ...) M(C, x) D()                              \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_3(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_5(M, C, D, x, ...) M(C, x) D()                              \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_4(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_6(M, C, D, x, ...) M(C, x) D()                              \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_5(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_7(M, C, D, x, ...) M(C, x) D()                              \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_6(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_8(M, C, D, x, ...) M(C, x) D()                              \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_7(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_9(M, C, D, x, ...) M(C, x) D()                              \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_8(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_10(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_9(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_11(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_10(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_12(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_11(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_13(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_12(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_14(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_13(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_15(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_14(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_16(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_15(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_17(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_16(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_18(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_17(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_19(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_18(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_20(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_19(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_21(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_20(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_22(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_21(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_23(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_22(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_24(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_23(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_25(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_24(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_26(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_25(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_27(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_26(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_28(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_27(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_29(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_28(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_30(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_29(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_31(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_30(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_32(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_31(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_33(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_32(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_34(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_33(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_35(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_34(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_36(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_35(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_37(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_36(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_38(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_37(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_39(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_38(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_40(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_39(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_41(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_40(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_42(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_41(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_43(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_42(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_44(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_43(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_45(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_44(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_46(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_45(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_47(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_46(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_48(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_47(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_49(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_48(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_50(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_49(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_51(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_50(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_52(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_51(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_53(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_52(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_54(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_53(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_55(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_54(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_56(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_55(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_57(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_56(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_58(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_57(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_59(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_58(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_60(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_59(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_61(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_60(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_62(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_61(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_63(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_62(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_64(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_63(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_65(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_64(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_66(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_65(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_67(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_66(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_68(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_67(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_69(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_68(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_70(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_69(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_71(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_70(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_72(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_71(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_73(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_72(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_74(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_73(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_75(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_74(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_76(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_75(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_77(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_76(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_78(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_77(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_79(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_78(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_80(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_79(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_81(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_80(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_82(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_81(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_83(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_82(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_84(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_83(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_85(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_84(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_86(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_85(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_87(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_86(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_88(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_87(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_89(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_88(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_90(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_89(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_91(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_90(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_92(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_91(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_93(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_92(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_94(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_93(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_95(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_94(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_96(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_95(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_97(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_96(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_98(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_97(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_99(M, C, D, x, ...) M(C, x) D()                             \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_98(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_100(M, C, D, x, ...) M(C, x) D()                            \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_99(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_101(M, C, D, x, ...) M(C, x) D()                            \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_100(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_102(M, C, D, x, ...) M(C, x) D()                            \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_101(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_103(M, C, D, x, ...) M(C, x) D()                            \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_102(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_104(M, C, D, x, ...) M(C, x) D()                            \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_103(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_105(M, C, D, x, ...) M(C, x) D()                            \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_104(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_106(M, C, D, x, ...) M(C, x) D()                            \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_105(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_107(M, C, D, x, ...) M(C, x) D()                            \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_106(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_108(M, C, D, x, ...) M(C, x) D()                            \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_107(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_109(M, C, D, x, ...) M(C, x) D()                            \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_108(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_110(M, C, D, x, ...) M(C, x) D()                            \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_109(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_111(M, C, D, x, ...) M(C, x) D()                            \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_110(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_112(M, C, D, x, ...) M(C, x) D()                            \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_111(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_113(M, C, D, x, ...) M(C, x) D()                            \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_112(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_114(M, C, D, x, ...) M(C, x) D()                            \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_113(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_115(M, C, D, x, ...) M(C, x) D()                            \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_114(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_116(M, C, D, x, ...) M(C, x) D()                            \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_115(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_117(M, C, D, x, ...) M(C, x) D()                            \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_116(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_118(M, C, D, x, ...) M(C, x) D()                            \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_117(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_119(M, C, D, x, ...) M(C, x) D()                            \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_118(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_120(M, C, D, x, ...) M(C, x) D()                            \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_119(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_121(M, C, D, x, ...) M(C, x) D()                            \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_120(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_122(M, C, D, x, ...) M(C, x) D()                            \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_121(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_123(M, C, D, x, ...) M(C, x) D()                            \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_122(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_124(M, C, D, x, ...) M(C, x) D()                            \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_123(M, C, D, __VA_ARGS__))
+
+#define WISE_ENUM_IMPL_LOOP_125(M, C, D, x, ...) M(C, x) D()                            \
+  WISE_ENUM_IMPL_EXPAND(WISE_ENUM_IMPL_LOOP_124(M, C, D, __VA_ARGS__))
+
diff --git a/src/plugins/ctf/common/bfcr/bfcr.cpp b/src/plugins/ctf/common/bfcr/bfcr.cpp
deleted file mode 100644 (file)
index f59f65d..0000000
+++ /dev/null
@@ -1,1264 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2015-2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Babeltrace - CTF binary field class reader (BFCR)
- */
-
-#include <glib.h>
-#include <inttypes.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <string.h>
-
-#include <babeltrace2/babeltrace.h>
-
-#define BT_COMP_LOG_SELF_COMP (bfcr->self_comp)
-#define BT_LOG_OUTPUT_LEVEL   (bfcr->log_level)
-#define BT_LOG_TAG            "PLUGIN/CTF/BFCR"
-#include "logging/comp-logging.h"
-
-#include "common/align.h"
-#include "common/assert.h"
-#include "common/common.h"
-#include "compat/bitfield.h"
-
-#include "../metadata/ctf-meta.hpp"
-#include "bfcr.hpp"
-
-#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
-{
-    struct bt_bfcr *bfcr;
-
-    /* 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
-{
-    bt_logging_level log_level;
-
-    /* Weak */
-    bt_self_component *self_comp;
-
-    /* BFCR 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 CTF_BYTE_ORDER_UNKNOWN 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 "NEXT_FIELD";
-    case BFCR_STATE_ALIGN_BASIC:
-        return "ALIGN_BASIC";
-    case BFCR_STATE_ALIGN_COMPOUND:
-        return "ALIGN_COMPOUND";
-    case BFCR_STATE_READ_BASIC_BEGIN:
-        return "READ_BASIC_BEGIN";
-    case BFCR_STATE_READ_BASIC_CONTINUE:
-        return "READ_BASIC_CONTINUE";
-    case BFCR_STATE_DONE:
-        return "DONE";
-    }
-
-    bt_common_abort();
-}
-
-static struct stack *stack_new(struct bt_bfcr *bfcr)
-{
-    struct stack *stack = NULL;
-
-    stack = g_new0(struct stack, 1);
-    if (!stack) {
-        BT_COMP_LOGE_STR("Failed to allocate one stack.");
-        goto error;
-    }
-
-    stack->bfcr = bfcr;
-    stack->entries = g_array_new(FALSE, TRUE, sizeof(struct stack_entry));
-    if (!stack->entries) {
-        BT_COMP_LOGE_STR("Failed to allocate a GArray.");
-        goto error;
-    }
-
-    BT_COMP_LOGD("Created stack: addr=%p", stack);
-    return stack;
-
-error:
-    g_free(stack);
-    return NULL;
-}
-
-static void stack_destroy(struct stack *stack)
-{
-    struct bt_bfcr *bfcr;
-
-    if (!stack) {
-        return;
-    }
-
-    bfcr = stack->bfcr;
-    BT_COMP_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;
-    struct bt_bfcr *bfcr;
-
-    BT_ASSERT_DBG(stack);
-    BT_ASSERT_DBG(base_class);
-    bfcr = stack->bfcr;
-    BT_COMP_LOGT("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 = &bt_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:
-    {
-        ctf_field_class_struct *struct_fc = ctf_field_class_as_struct(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 = ctf_field_class_as_array(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:
-        bt_common_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_COMP_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_DBG(stack);
-    return stack->size;
-}
-
-static void stack_pop(struct stack *stack)
-{
-    struct bt_bfcr *bfcr;
-
-    BT_ASSERT_DBG(stack);
-    BT_ASSERT_DBG(stack_size(stack));
-    bfcr = stack->bfcr;
-    BT_COMP_LOGT("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_DBG(stack);
-    stack->size = 0;
-}
-
-static inline struct stack_entry *stack_top(struct stack *stack)
-{
-    BT_ASSERT_DBG(stack);
-    BT_ASSERT_DBG(stack_size(stack));
-    return &bt_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_COMP_LOGT("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(struct bt_bfcr *bfcr, 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:
-        bt_common_abort();
-    }
-
-    BT_COMP_LOGT("Read unsigned bit array: cur=%zu, size=%u, "
-                 "bo=%d, val=%" PRIu64,
-                 at, field_size, bo, *v);
-}
-
-static inline void read_signed_bitfield(struct bt_bfcr *bfcr, 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:
-        bt_common_abort();
-    }
-
-    BT_COMP_LOGT("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 == CTF_BYTE_ORDER_UNKNOWN) {
-        goto end;
-    }
-
-    /* Always valid if next byte order is unknown */
-    if (next_bo == CTF_BYTE_ORDER_UNKNOWN) {
-        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_COMP_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;
-    ctf_field_class_float *fc = ctf_field_class_as_float(bfcr->cur_basic_field_class);
-
-    BT_ASSERT_DBG(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(bfcr, 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(bfcr, buf, at, field_size, bo, &f64.u);
-        dblval = f64.d;
-        break;
-    }
-    default:
-        /* Only 32-bit and 64-bit fields are supported currently */
-        bt_common_abort();
-    }
-
-    BT_COMP_LOGT("Read floating point number value: bfcr=%p, cur=%zu, val=%f", bfcr, at, dblval);
-
-    if (bfcr->user.cbs.classes.floating_point) {
-        BT_COMP_LOGT("Calling user function (floating point number).");
-        status = bfcr->user.cbs.classes.floating_point(dblval, bfcr->cur_basic_field_class,
-                                                       bfcr->user.data);
-        BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status));
-        if (status != BT_BFCR_STATUS_OK) {
-            BT_COMP_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;
-    ctf_field_class_int *fc = ctf_field_class_as_int(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(bfcr, buf, at, field_size, bo, &v);
-
-        if (bfcr->user.cbs.classes.signed_int) {
-            BT_COMP_LOGT("Calling user function (signed integer).");
-            status =
-                bfcr->user.cbs.classes.signed_int(v, bfcr->cur_basic_field_class, bfcr->user.data);
-            BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status));
-            if (status != BT_BFCR_STATUS_OK) {
-                BT_COMP_LOGW("User function failed: "
-                             "bfcr-addr=%p, status=%s",
-                             bfcr, bt_bfcr_status_string(status));
-            }
-        }
-    } else {
-        uint64_t v;
-
-        read_unsigned_bitfield(bfcr, buf, at, field_size, bo, &v);
-
-        if (bfcr->user.cbs.classes.unsigned_int) {
-            BT_COMP_LOGT("Calling user function (unsigned integer).");
-            status = bfcr->user.cbs.classes.unsigned_int(v, bfcr->cur_basic_field_class,
-                                                         bfcr->user.data);
-            BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status));
-            if (status != BT_BFCR_STATUS_OK) {
-                BT_COMP_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;
-    ctf_field_class_bit_array *fc = ctf_field_class_as_bit_array(bfcr->cur_basic_field_class);
-
-    if (!at_least_one_bit_left(bfcr)) {
-        BT_COMP_LOGT("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_COMP_LOGT("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_COMP_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_COMP_LOGT_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;
-    ctf_field_class_bit_array *fc = ctf_field_class_as_bit_array(bfcr->cur_basic_field_class);
-
-    if (!at_least_one_bit_left(bfcr)) {
-        BT_COMP_LOGT("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_DBG(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_COMP_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_COMP_LOGT_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_COMP_LOGT("Reached end of data: bfcr-addr=%p", bfcr);
-        status = BT_BFCR_STATUS_EOF;
-        goto end;
-    }
-
-    BT_ASSERT_DBG(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_DBG(bfcr->buf.addr);
-    first_chr = &bfcr->buf.addr[buf_at_bytes];
-    result = (const uint8_t *) memchr(first_chr, '\0', available_bytes);
-
-    if (begin && bfcr->user.cbs.classes.string_begin) {
-        BT_COMP_LOGT("Calling user function (string, beginning).");
-        status = bfcr->user.cbs.classes.string_begin(bfcr->cur_basic_field_class, bfcr->user.data);
-        BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status));
-        if (status != BT_BFCR_STATUS_OK) {
-            BT_COMP_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_COMP_LOGT("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_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status));
-            if (status != BT_BFCR_STATUS_OK) {
-                BT_COMP_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_COMP_LOGT("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_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status));
-            if (status != BT_BFCR_STATUS_OK) {
-                BT_COMP_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_COMP_LOGT("Calling user function (string, end).");
-            status =
-                bfcr->user.cbs.classes.string_end(bfcr->cur_basic_field_class, bfcr->user.data);
-            BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status));
-            if (status != BT_BFCR_STATUS_OK) {
-                BT_COMP_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_DBG(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:
-        bt_common_abort();
-    }
-
-    return status;
-}
-
-static inline enum bt_bfcr_status read_basic_continue_state(struct bt_bfcr *bfcr)
-{
-    enum bt_bfcr_status status;
-
-    BT_ASSERT_DBG(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:
-        bt_common_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 = BT_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_DBG(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_COMP_LOGT("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_COMP_LOGT("Calling user function (compound, end).");
-            status = bfcr->user.cbs.classes.compound_end(top->base_class, bfcr->user.data);
-            BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status));
-            if (status != BT_BFCR_STATUS_OK) {
-                BT_COMP_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(
-                               ctf_field_class_as_struct(top->base_class), (uint64_t) top->index)
-                               ->fc;
-        break;
-    case CTF_FIELD_CLASS_TYPE_ARRAY:
-    case CTF_FIELD_CLASS_TYPE_SEQUENCE:
-    {
-        ctf_field_class_array_base *array_fc = ctf_field_class_as_array_base(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_COMP_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_COMP_LOGT("Calling user function (compound, begin).");
-            status = bfcr->user.cbs.classes.compound_begin(next_field_class, bfcr->user.data);
-            BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status));
-            if (status != BT_BFCR_STATUS_OK) {
-                BT_COMP_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_COMP_LOGT("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_COMP_LOGT("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_COMP_LOGT("Handled state: bfcr-addr=%p, status=%s", bfcr, bt_bfcr_status_string(status));
-    return status;
-}
-
-struct bt_bfcr *bt_bfcr_create(struct bt_bfcr_cbs cbs, void *data, bt_logging_level log_level,
-                               bt_self_component *self_comp)
-{
-    struct bt_bfcr *bfcr;
-
-    BT_COMP_LOG_CUR_LVL(BT_LOG_DEBUG, log_level, self_comp,
-                        "Creating binary field class reader (BFCR).");
-    bfcr = g_new0(struct bt_bfcr, 1);
-    if (!bfcr) {
-        BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_comp,
-                            "Failed to allocate one binary class reader.");
-        goto end;
-    }
-
-    bfcr->log_level = log_level;
-    bfcr->self_comp = self_comp;
-    bfcr->stack = stack_new(bfcr);
-    if (!bfcr->stack) {
-        BT_COMP_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_COMP_LOGD("Created BFCR: addr=%p", bfcr);
-
-end:
-    return bfcr;
-}
-
-void bt_bfcr_destroy(struct bt_bfcr *bfcr)
-{
-    if (bfcr->stack) {
-        stack_destroy(bfcr->stack);
-    }
-
-    BT_COMP_LOGD("Destroying BFCR: addr=%p", bfcr);
-    g_free(bfcr);
-}
-
-static void reset(struct bt_bfcr *bfcr)
-{
-    BT_COMP_LOGD("Resetting BFCR: addr=%p", bfcr);
-    stack_clear(bfcr->stack);
-    stitch_reset(bfcr);
-    bfcr->buf.addr = NULL;
-    bfcr->last_bo = CTF_BYTE_ORDER_UNKNOWN;
-}
-
-static void update_packet_offset(struct bt_bfcr *bfcr)
-{
-    BT_COMP_LOGT("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;
-}
-
-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_DBG(bfcr);
-    BT_ASSERT_DBG(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_COMP_LOGT("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_COMP_LOGT("Calling user function (compound, begin).");
-            *status = bfcr->user.cbs.classes.compound_begin(cls, bfcr->user.data);
-            BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(*status));
-            if (*status != BT_BFCR_STATUS_OK) {
-                BT_COMP_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_COMP_LOGT_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;
-}
-
-size_t bt_bfcr_continue(struct bt_bfcr *bfcr, const uint8_t *buf, size_t sz,
-                        enum bt_bfcr_status *status)
-{
-    BT_ASSERT_DBG(bfcr);
-    BT_ASSERT_DBG(buf);
-    BT_ASSERT_DBG(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_COMP_LOGT("Continuing decoding: bfcr-addr=%p, buf-addr=%p, buf-size=%zu", bfcr, buf, sz);
-
-    /* Continue running the machine */
-    BT_COMP_LOGT_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;
-}
-
-void bt_bfcr_set_unsigned_int_cb(struct bt_bfcr *bfcr, bt_bfcr_unsigned_int_cb_func cb)
-{
-    BT_ASSERT_DBG(bfcr);
-    BT_ASSERT_DBG(cb);
-    bfcr->user.cbs.classes.unsigned_int = cb;
-}
diff --git a/src/plugins/ctf/common/bfcr/bfcr.hpp b/src/plugins/ctf/common/bfcr/bfcr.hpp
deleted file mode 100644 (file)
index f2fe879..0000000
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2015-2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Babeltrace - CTF binary field class reader (BFCR)
- */
-
-#ifndef CTF_BFCR_H
-#define CTF_BFCR_H
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <babeltrace2/babeltrace.h>
-
-#include "common/common.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,
-};
-
-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
- */
-struct bt_bfcr *bt_bfcr_create(struct bt_bfcr_cbs cbs, void *data, bt_logging_level log_level,
-                               bt_self_component *self_comp);
-
-/**
- * Destroys a CTF binary class reader, freeing all internal resources.
- *
- * @param bfcr Binary class reader
- */
-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
- */
-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
- */
-size_t bt_bfcr_continue(struct bt_bfcr *bfcr, const uint8_t *buf, size_t sz,
-                        enum bt_bfcr_status *status);
-
-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 "ENOMEM";
-    case BT_BFCR_STATUS_EOF:
-        return "EOF";
-    case BT_BFCR_STATUS_INVAL:
-        return "INVAL";
-    case BT_BFCR_STATUS_ERROR:
-        return "ERROR";
-    case BT_BFCR_STATUS_OK:
-        return "OK";
-    }
-
-    bt_common_abort();
-}
-
-#endif /* CTF_BFCR_H */
diff --git a/src/plugins/ctf/common/metadata/ast.hpp b/src/plugins/ctf/common/metadata/ast.hpp
deleted file mode 100644 (file)
index a6a7e9f..0000000
+++ /dev/null
@@ -1,458 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright 2011-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- */
-
-#ifndef _CTF_AST_H
-#define _CTF_AST_H
-
-#include <glib.h>
-#include <stdint.h>
-#include <stdio.h>
-
-#include <babeltrace2/babeltrace.h>
-
-#include "common/assert.h"
-#include "common/list.h"
-
-#include "ctf-meta.hpp"
-#include "decoder.hpp"
-
-// 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
-};
-
-enum ctf_unary
-{
-    UNARY_UNKNOWN = 0,
-    UNARY_STRING,
-    UNARY_SIGNED_CONSTANT,
-    UNARY_UNSIGNED_CONSTANT,
-    UNARY_SBRAC,
-};
-
-enum ctf_unary_link
-{
-    UNARY_LINK_UNKNOWN = 0,
-    UNARY_DOTLINK,
-    UNARY_ARROWLINK,
-    UNARY_DOTDOTDOT,
-};
-
-enum ctf_typedec
-{
-    TYPEDEC_UNKNOWN = 0,
-    TYPEDEC_ID,     /* identifier */
-    TYPEDEC_NESTED, /* (), array or sequence */
-};
-
-enum ctf_typespec
-{
-    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,
-};
-
-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
-        {
-            ctf_unary 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;
-            ctf_unary_link 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
-        {
-            ctf_typespec 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;
-            ctf_typedec 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);
-
-struct meta_log_config;
-
-struct ctf_visitor_generate_ir *
-ctf_visitor_generate_ir_create(const struct ctf_metadata_decoder_config *config);
-
-void ctf_visitor_generate_ir_destroy(struct ctf_visitor_generate_ir *visitor);
-
-bt_trace_class *ctf_visitor_generate_ir_get_ir_trace_class(struct ctf_visitor_generate_ir *visitor);
-
-struct ctf_trace_class *
-ctf_visitor_generate_ir_borrow_ctf_trace_class(struct ctf_visitor_generate_ir *visitor);
-
-int ctf_visitor_generate_ir_visit_node(struct ctf_visitor_generate_ir *visitor,
-                                       struct ctf_node *node);
-
-int ctf_visitor_semantic_check(int depth, struct ctf_node *node, struct meta_log_config *log_cfg);
-
-int ctf_visitor_parent_links(int depth, struct ctf_node *node, struct meta_log_config *log_cfg);
-
-static inline char *ctf_ast_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);
-}
-
-#ifndef BT_COMP_LOG_CUR_LVL
-#    define BT_AST_LOG_LEVEL_UNUSED_ATTR __attribute__((unused))
-#else
-#    define BT_AST_LOG_LEVEL_UNUSED_ATTR
-#endif
-
-static inline int ctf_ast_get_unary_uuid(struct bt_list_head *head, bt_uuid_t uuid,
-                                         int log_level BT_AST_LOG_LEVEL_UNUSED_ATTR,
-                                         bt_self_component *self_comp BT_AST_LOG_LEVEL_UNUSED_ATTR)
-{
-    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_from_str(src_string, uuid);
-        if (ret) {
-#ifdef BT_COMP_LOG_CUR_LVL
-            BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_comp,
-                                "Cannot parse UUID: uuid=\"%s\"", src_string);
-#endif
-            goto end;
-        }
-    }
-
-end:
-    return ret;
-}
-
-#endif /* _CTF_AST_H */
diff --git a/src/plugins/ctf/common/metadata/ctf-meta-configure-ir-trace.cpp b/src/plugins/ctf/common/metadata/ctf-meta-configure-ir-trace.cpp
deleted file mode 100644 (file)
index ef178c5..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
- */
-
-#include <babeltrace2/babeltrace.h>
-
-#include "common/assert.h"
-
-#include "ctf-meta-configure-ir-trace.hpp"
-#include "plugins/ctf/common/metadata/ctf-meta.hpp"
-
-int ctf_trace_class_configure_ir_trace(struct ctf_trace_class *tc, bt_trace *ir_trace)
-{
-    int ret = 0;
-    uint64_t i;
-
-    BT_ASSERT(tc);
-    BT_ASSERT(ir_trace);
-
-    if (tc->is_uuid_set) {
-        bt_trace_set_uuid(ir_trace, tc->uuid);
-    }
-
-    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);
-
-        switch (env_entry->type) {
-        case CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT:
-            ret = bt_trace_set_environment_entry_integer(ir_trace, env_entry->name->str,
-                                                         env_entry->value.i);
-            break;
-        case CTF_TRACE_CLASS_ENV_ENTRY_TYPE_STR:
-            ret = bt_trace_set_environment_entry_string(ir_trace, env_entry->name->str,
-                                                        env_entry->value.str->str);
-            break;
-        default:
-            bt_common_abort();
-        }
-
-        if (ret) {
-            goto end;
-        }
-    }
-
-end:
-    return ret;
-}
diff --git a/src/plugins/ctf/common/metadata/ctf-meta-configure-ir-trace.hpp b/src/plugins/ctf/common/metadata/ctf-meta-configure-ir-trace.hpp
deleted file mode 100644 (file)
index f94f19e..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
- */
-
-#ifndef _CTF_META_CONFIGURE_IR_TRACE_H
-#define _CTF_META_CONFIGURE_IR_TRACE_H
-
-#include <babeltrace2/babeltrace.h>
-
-int ctf_trace_class_configure_ir_trace(struct ctf_trace_class *tc, bt_trace *ir_trace);
-
-#endif /* _CTF_META_CONFIGURE_IR_TRACE_H */
diff --git a/src/plugins/ctf/common/metadata/ctf-meta-resolve.cpp b/src/plugins/ctf/common/metadata/ctf-meta-resolve.cpp
deleted file mode 100644 (file)
index 1f7ffe5..0000000
+++ /dev/null
@@ -1,1261 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright 2016-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- */
-
-#include <glib.h>
-#include <inttypes.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <babeltrace2/babeltrace.h>
-
-#define BT_COMP_LOG_SELF_COMP       (ctx->self_comp)
-#define BT_COMP_LOG_SELF_COMP_CLASS (ctx->self_comp_class)
-#define BT_LOG_OUTPUT_LEVEL         ((enum bt_log_level) ctx->log_level)
-#define BT_LOG_TAG                  "PLUGIN/CTF/META/RESOLVE"
-#include "logging.hpp"
-#include "logging/comp-logging.h"
-
-#include "common/assert.h"
-#include "common/common.h"
-
-#include "ctf-meta-visitors.hpp"
-
-using field_class_stack_t = GPtrArray;
-
-/*
- * 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
-{
-    bt_logging_level log_level;
-
-    /* Weak, exactly one of these must be set */
-    bt_self_component *self_comp;
-    bt_self_component_class *self_comp_class;
-
-    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_t *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_t *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_t *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_t *stack, struct ctf_field_class *fc,
-                                  struct resolve_context *ctx)
-{
-    int ret = 0;
-    struct field_class_stack_frame *frame = NULL;
-
-    if (!stack || !fc) {
-        _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-            "Invalid parameter: stack or field class is `NULL`.");
-        ret = -1;
-        goto end;
-    }
-
-    frame = g_new0(struct field_class_stack_frame, 1);
-    if (!frame) {
-        _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Failed to allocate one field class stack frame.");
-        ret = -1;
-        goto end;
-    }
-
-    BT_COMP_LOGD("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_t *stack)
-{
-    return stack->len == 0;
-}
-
-/*
- * Returns the number of frames in `stack`.
- */
-static size_t field_class_stack_size(field_class_stack_t *stack)
-{
-    return stack->len;
-}
-
-/*
- * Returns the top frame of `stack`.
- */
-static struct field_class_stack_frame *field_class_stack_peek(field_class_stack_t *stack)
-{
-    BT_ASSERT(stack);
-    BT_ASSERT(!field_class_stack_empty(stack));
-
-    return (field_class_stack_frame *) g_ptr_array_index(stack, stack->len - 1);
-}
-
-/*
- * Returns the frame at index `index` in `stack`.
- */
-static struct field_class_stack_frame *field_class_stack_at(field_class_stack_t *stack,
-                                                            size_t index)
-{
-    BT_ASSERT(stack);
-    BT_ASSERT(index < stack->len);
-
-    return (field_class_stack_frame *) g_ptr_array_index(stack, index);
-}
-
-/*
- * Removes the top frame of `stack`.
- */
-static void field_class_stack_pop(field_class_stack_t *stack, struct resolve_context *ctx)
-{
-    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_COMP_LOGD("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:
-        bt_common_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,
-                                                           struct resolve_context *ctx)
-{
-    enum ctf_scope scope;
-    enum ctf_scope ret = CTF_SCOPE_PACKET_UNKNOWN;
-    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 = (ctf_scope) (scope + 1)) {
-        /*
-         * Check 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_COMP_LOGD("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_COMP_LOGD("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)
-{
-    g_string_free((GString *) 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, struct resolve_context *ctx)
-{
-    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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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,
-                                 struct resolve_context *ctx)
-{
-    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_COMP_LOGD("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_orig_name(fc, ft_name);
-            if (child_index < 0) {
-                /*
-                 * Error: field name does not exist or
-                 * wrong current class.
-                 */
-                BT_COMP_LOGD("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_COMP_LOGD("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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("No current stream class: "
-                                                     "root-scope=%s",
-                                                     ctf_scope_string(field_path->root));
-            ret = -1;
-            goto end;
-        }
-
-        if (ctx->sc->is_translated) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("No current event class: "
-                                                     "root-scope=%s",
-                                                     ctf_scope_string(field_path->root));
-            ret = -1;
-            goto end;
-        }
-
-        if (ctx->ec->is_translated) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Event class is already translated: "
-                                                     "root-scope=%s",
-                                                     ctf_scope_string(field_path->root));
-            ret = -1;
-            goto end;
-        }
-
-        break;
-
-    default:
-        bt_common_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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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, ctx);
-
-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_COMP_LOGD("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, ctx);
-        if (ret) {
-            /* Not found... yet */
-            BT_COMP_LOGD_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, ctx);
-    if (!ptokens) {
-        _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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, ctx);
-
-    if (root_scope == CTF_SCOPE_PACKET_UNKNOWN) {
-        /* Relative path: start with current root scope */
-        field_path->root = ctx->root_scope;
-        BT_COMP_LOGD("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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                "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_COMP_LOGD("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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                "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_TRACE && 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_COMP_LOGD("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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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.
- */
-static int64_t get_field_paths_lca_index(struct ctf_field_path *field_path1,
-                                         struct ctf_field_path *field_path2,
-                                         struct resolve_context *ctx)
-{
-    int64_t lca_index = 0;
-    uint64_t field_path1_len, field_path2_len;
-
-    if (BT_LOG_ON_TRACE) {
-        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_COMP_LOGD("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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                "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_COMP_LOGD("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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-            "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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-            "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, ctx);
-        if (lca_index < 0) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                "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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                "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:
-    {
-        if (target_fc->type != CTF_FIELD_CLASS_TYPE_INT &&
-            target_fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                "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;
-        }
-
-        ctf_field_class_int *int_fc = ctf_field_class_as_int(target_fc);
-
-        if (int_fc->is_signed) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                "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:
-        bt_common_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 = ctf_field_class_as_sequence(fc);
-        pathstr = seq_fc->length_ref->str;
-        break;
-    }
-    case CTF_FIELD_CLASS_TYPE_VARIANT:
-    {
-        struct ctf_field_class_variant *var_fc = ctf_field_class_as_variant(fc);
-        pathstr = var_fc->tag_ref->str;
-        break;
-    }
-    default:
-        bt_common_abort();
-    }
-
-    if (!pathstr) {
-        _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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:
-    {
-        ctf_field_class_sequence *seq_fc = ctf_field_class_as_sequence(fc);
-
-        ctf_field_path_copy_content(&seq_fc->length_path, &target_field_path);
-        seq_fc->length_fc = ctf_field_class_as_int(target_fc);
-        break;
-    }
-    case CTF_FIELD_CLASS_TYPE_VARIANT:
-    {
-        ctf_field_class_variant *var_fc = ctf_field_class_as_variant(fc);
-
-        ctf_field_path_copy_content(&var_fc->tag_path, &target_field_path);
-        ctf_field_class_variant_set_tag_field_class(var_fc, ctf_field_class_as_enum(target_fc));
-        break;
-    }
-    default:
-        bt_common_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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                "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, ctx);
-        if (ret) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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_COMP_LOGD("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, ctx);
-        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 = CTF_SCOPE_PACKET_UNKNOWN;
-    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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-            "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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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_COMMON_CONTEXT, ctx);
-        if (ret) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                "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++) {
-        ctf_event_class *ec = (ctf_event_class *) sc->event_classes->pdata[i];
-
-        ret = resolve_event_class_field_classes(ctx, ec);
-        if (ret) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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;
-}
-
-int ctf_trace_class_resolve_field_classes(struct ctf_trace_class *tc,
-                                          struct meta_log_config *log_cfg)
-{
-    int ret = 0;
-    uint64_t i;
-
-    resolve_context local_ctx {};
-    local_ctx.log_level = log_cfg->log_level;
-    local_ctx.self_comp = log_cfg->self_comp;
-    local_ctx.self_comp_class = log_cfg->self_comp_class;
-    local_ctx.tc = tc;
-    local_ctx.scopes.packet_header = tc->packet_header_fc;
-    local_ctx.root_scope = CTF_SCOPE_PACKET_HEADER;
-
-    struct resolve_context *ctx = &local_ctx;
-
-    /* Initialize class stack */
-    ctx->field_class_stack = field_class_stack_create();
-    if (!ctx->field_class_stack) {
-        _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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++) {
-        ctf_stream_class *sc = (ctf_stream_class *) tc->stream_classes->pdata[i];
-
-        ret = resolve_stream_class_field_classes(ctx, sc);
-        if (ret) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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.cpp b/src/plugins/ctf/common/metadata/ctf-meta-translate.cpp
deleted file mode 100644 (file)
index e3ecfd0..0000000
+++ /dev/null
@@ -1,651 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
- */
-
-#include <stdint.h>
-#include <string.h>
-
-#include <babeltrace2/babeltrace.h>
-
-#include "common/assert.h"
-
-#include "ctf-meta-visitors.hpp"
-
-struct ctx
-{
-    bt_self_component *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_integer_signed_create(ctx->ir_tc);
-    } else {
-        ir_fc = bt_field_class_integer_unsigned_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_enumeration_signed_create(ctx->ir_tc);
-    } else {
-        ir_fc = bt_field_class_enumeration_unsigned_create(ctx->ir_tc);
-    }
-
-    BT_ASSERT(ir_fc);
-    ctf_field_class_int_set_props(&fc->base, 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);
-        bt_integer_range_set_signed *range_set_signed = NULL;
-        bt_integer_range_set_unsigned *range_set_unsigned = NULL;
-        uint64_t range_i;
-
-        if (fc->base.is_signed) {
-            range_set_signed = bt_integer_range_set_signed_create();
-            BT_ASSERT(range_set_signed);
-        } else {
-            range_set_unsigned = bt_integer_range_set_unsigned_create();
-            BT_ASSERT(range_set_unsigned);
-        }
-
-        for (range_i = 0; range_i < mapping->ranges->len; range_i++) {
-            struct ctf_range *range =
-                ctf_field_class_enum_mapping_borrow_range_by_index(mapping, range_i);
-
-            if (fc->base.is_signed) {
-                ret = bt_integer_range_set_signed_add_range(range_set_signed, range->lower.i,
-                                                            range->upper.i);
-            } else {
-                ret = bt_integer_range_set_unsigned_add_range(range_set_unsigned, range->lower.u,
-                                                              range->upper.u);
-            }
-
-            BT_ASSERT(ret == 0);
-        }
-
-        if (fc->base.is_signed) {
-            ret = bt_field_class_enumeration_signed_add_mapping(ir_fc, mapping->label->str,
-                                                                range_set_signed);
-            BT_INTEGER_RANGE_SET_SIGNED_PUT_REF_AND_RESET(range_set_signed);
-        } else {
-            ret = bt_field_class_enumeration_unsigned_add_mapping(ir_fc, mapping->label->str,
-                                                                  range_set_unsigned);
-            BT_INTEGER_RANGE_SET_UNSIGNED_PUT_REF_AND_RESET(range_set_unsigned);
-        }
-
-        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;
-
-    if (fc->base.size == 32) {
-        ir_fc = bt_field_class_real_single_precision_create(ctx->ir_tc);
-    } else {
-        ir_fc = bt_field_class_real_double_precision_create(ctx->ir_tc);
-    }
-    BT_ASSERT(ir_fc);
-
-    return ir_fc;
-}
-
-static inline bt_field_class *ctf_field_class_string_to_ir(struct ctx *ctx,
-                                                           struct ctf_field_class_string *)
-{
-    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,
-                                                        struct ctf_field_class_struct *)
-{
-    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 const bt_field_class_enumeration_mapping *
-find_ir_enum_field_class_mapping_by_label(const bt_field_class *fc, const char *label,
-                                          bool is_signed)
-{
-    const bt_field_class_enumeration_mapping *mapping = NULL;
-    uint64_t i;
-
-    for (i = 0; i < bt_field_class_enumeration_get_mapping_count(fc); i++) {
-        const bt_field_class_enumeration_mapping *this_mapping;
-        const bt_field_class_enumeration_signed_mapping *signed_this_mapping = NULL;
-        const bt_field_class_enumeration_unsigned_mapping *unsigned_this_mapping = NULL;
-
-        if (is_signed) {
-            signed_this_mapping =
-                bt_field_class_enumeration_signed_borrow_mapping_by_index_const(fc, i);
-            BT_ASSERT(signed_this_mapping);
-            this_mapping =
-                bt_field_class_enumeration_signed_mapping_as_mapping_const(signed_this_mapping);
-        } else {
-            unsigned_this_mapping =
-                bt_field_class_enumeration_unsigned_borrow_mapping_by_index_const(fc, i);
-            BT_ASSERT(unsigned_this_mapping);
-            this_mapping =
-                bt_field_class_enumeration_unsigned_mapping_as_mapping_const(unsigned_this_mapping);
-        }
-
-        BT_ASSERT(this_mapping);
-
-        if (strcmp(bt_field_class_enumeration_mapping_get_label(this_mapping), label) == 0) {
-            mapping = this_mapping;
-            goto end;
-        }
-    }
-
-end:
-    return mapping;
-}
-
-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;
-    uint64_t i;
-    bt_field_class *ir_tag_fc = NULL;
-
-    if (fc->tag_path.root != CTF_SCOPE_PACKET_HEADER &&
-        fc->tag_path.root != CTF_SCOPE_EVENT_HEADER) {
-        ir_tag_fc = borrow_ir_fc_from_field_path(ctx, &fc->tag_path);
-        BT_ASSERT(ir_tag_fc);
-    }
-
-    ir_fc = bt_field_class_variant_create(ctx->ir_tc, ir_tag_fc);
-    BT_ASSERT(ir_fc);
-
-    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);
-
-        if (ir_tag_fc) {
-            /*
-             * At this point the trace IR selector
-             * (enumeration) field class already exists if
-             * the variant is tagged (`ir_tag_fc`). This one
-             * already contains range sets for its mappings,
-             * so we just reuse the same, finding them by
-             * matching a variant field class's option's
-             * _original_ name (with a leading underscore,
-             * possibly) with a selector field class's
-             * mapping name.
-             */
-            if (fc->tag_fc->base.is_signed) {
-                const bt_field_class_enumeration_signed_mapping *mapping =
-                    (bt_field_class_enumeration_signed_mapping *)
-                        find_ir_enum_field_class_mapping_by_label(ir_tag_fc,
-                                                                  named_fc->orig_name->str, true);
-                const bt_integer_range_set_signed *range_set;
-
-                BT_ASSERT(mapping);
-                range_set = bt_field_class_enumeration_signed_mapping_borrow_ranges_const(mapping);
-                BT_ASSERT(range_set);
-                ret = bt_field_class_variant_with_selector_field_integer_signed_append_option(
-                    ir_fc, named_fc->name->str, option_ir_fc, range_set);
-            } else {
-                const bt_field_class_enumeration_unsigned_mapping *mapping =
-                    (bt_field_class_enumeration_unsigned_mapping *)
-                        find_ir_enum_field_class_mapping_by_label(ir_tag_fc,
-                                                                  named_fc->orig_name->str, false);
-                const bt_integer_range_set_unsigned *range_set;
-
-                BT_ASSERT(mapping);
-                range_set =
-                    bt_field_class_enumeration_unsigned_mapping_borrow_ranges_const(mapping);
-                BT_ASSERT(range_set);
-                ret = bt_field_class_variant_with_selector_field_integer_unsigned_append_option(
-                    ir_fc, named_fc->name->str, option_ir_fc, range_set);
-            }
-        } else {
-            ret = bt_field_class_variant_without_selector_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_array_static_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)
-{
-    bt_field_class *ir_fc;
-    bt_field_class *elem_ir_fc;
-    bt_field_class *length_fc = NULL;
-
-    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);
-
-    if (fc->length_path.root != CTF_SCOPE_PACKET_HEADER &&
-        fc->length_path.root != CTF_SCOPE_EVENT_HEADER) {
-        length_fc = borrow_ir_fc_from_field_path(ctx, &fc->length_path);
-        BT_ASSERT(length_fc);
-    }
-
-    ir_fc = bt_field_class_array_dynamic_create(ctx->ir_tc, elem_ir_fc, length_fc);
-    BT_ASSERT(ir_fc);
-    bt_field_class_put_ref(elem_ir_fc);
-    BT_ASSERT(ir_fc);
-
-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, ctf_field_class_as_int(fc));
-        break;
-    case CTF_FIELD_CLASS_TYPE_ENUM:
-        ir_fc = ctf_field_class_enum_to_ir(ctx, ctf_field_class_as_enum(fc));
-        break;
-    case CTF_FIELD_CLASS_TYPE_FLOAT:
-        ir_fc = ctf_field_class_float_to_ir(ctx, ctf_field_class_as_float(fc));
-        break;
-    case CTF_FIELD_CLASS_TYPE_STRING:
-        ir_fc = ctf_field_class_string_to_ir(ctx, ctf_field_class_as_string(fc));
-        break;
-    case CTF_FIELD_CLASS_TYPE_STRUCT:
-        ir_fc = ctf_field_class_struct_to_ir(ctx, ctf_field_class_as_struct(fc));
-        break;
-    case CTF_FIELD_CLASS_TYPE_ARRAY:
-        ir_fc = ctf_field_class_array_to_ir(ctx, ctf_field_class_as_array(fc));
-        break;
-    case CTF_FIELD_CLASS_TYPE_SEQUENCE:
-        ir_fc = ctf_field_class_sequence_to_ir(ctx, ctf_field_class_as_sequence(fc));
-        break;
-    case CTF_FIELD_CLASS_TYPE_VARIANT:
-        ir_fc = ctf_field_class_variant_to_ir(ctx, ctf_field_class_as_variant(fc));
-        break;
-    default:
-        bt_common_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:
-        bt_common_abort();
-    }
-
-    if (fc && ctf_field_class_struct_has_immediate_member_in_ir(ctf_field_class_as_struct(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->is_log_level_set) {
-        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);
-
-    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_supports_packets(ctx->ir_sc, BT_TRUE, ctx->sc->packets_have_ts_begin,
-                                         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->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);
-
-    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;
-    }
-
-    for (i = 0; i < ctx->tc->clock_classes->len; i++) {
-        ctf_clock_class *cc = (ctf_clock_class *) ctx->tc->clock_classes->pdata[i];
-
-        cc->ir_cc = bt_clock_class_create(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;
-}
-
-int ctf_trace_class_translate(bt_self_component *self_comp, bt_trace_class *ir_tc,
-                              struct ctf_trace_class *tc)
-{
-    int ret = 0;
-    uint64_t i;
-    struct ctx ctx = {};
-
-    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 = (ctf_stream_class *) tc->stream_classes->pdata[i];
-
-        ctf_stream_class_to_ir(&ctx);
-
-        for (j = 0; j < ctx.sc->event_classes->len; j++) {
-            ctx.ec = (ctf_event_class *) 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-alignments.cpp b/src/plugins/ctf/common/metadata/ctf-meta-update-alignments.cpp
deleted file mode 100644 (file)
index bea62bf..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright 2020 Philippe Proulx <pproulx@efficios.com>
- */
-
-#include <stdint.h>
-
-#include "ctf-meta-visitors.hpp"
-
-static inline int set_alignments(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 = ctf_field_class_as_struct(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_alignments(named_fc->fc);
-            if (ret) {
-                goto end;
-            }
-
-            if (named_fc->fc->alignment > fc->alignment) {
-                fc->alignment = named_fc->fc->alignment;
-            }
-        }
-
-        break;
-    }
-    case CTF_FIELD_CLASS_TYPE_VARIANT:
-    {
-        struct ctf_field_class_variant *var_fc = ctf_field_class_as_variant(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_alignments(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 = ctf_field_class_as_array_base(fc);
-
-        ret = set_alignments(array_fc->elem_fc);
-        if (ret) {
-            goto end;
-        }
-
-        /*
-         * Use the alignment of the array/sequence field class's
-         * element FC as its own alignment.
-         *
-         * This is especially important when the array/sequence
-         * field's effective length is zero: as per CTF 1.8, the
-         * stream data decoding process still needs to align the
-         * cursor using the element's alignment [1]:
-         *
-         * > Arrays are always aligned on their element
-         * > alignment requirement.
-         *
-         * For example:
-         *
-         *     struct {
-         *         integer { size = 8; } a;
-         *         integer { size = 8; align = 16; } b[0];
-         *         integer { size = 8; } c;
-         *     };
-         *
-         * When using this to decode the bytes 1, 2, and 3, then
-         * the decoded values are:
-         *
-         * `a`: 1
-         * `b`: []
-         * `c`: 3
-         *
-         * [1]: https://diamon.org/ctf/#spec4.2.3
-         */
-        array_fc->base.alignment = array_fc->elem_fc->alignment;
-        break;
-    }
-    default:
-        break;
-    }
-
-end:
-    return ret;
-}
-
-int ctf_trace_class_update_alignments(struct ctf_trace_class *ctf_tc)
-{
-    int ret = 0;
-    uint64_t i;
-
-    if (!ctf_tc->is_translated) {
-        ret = set_alignments(ctf_tc->packet_header_fc);
-        if (ret) {
-            goto end;
-        }
-    }
-
-    for (i = 0; i < ctf_tc->stream_classes->len; i++) {
-        ctf_stream_class *sc = (ctf_stream_class *) ctf_tc->stream_classes->pdata[i];
-        uint64_t j;
-
-        if (!sc->is_translated) {
-            ret = set_alignments(sc->packet_context_fc);
-            if (ret) {
-                goto end;
-            }
-
-            ret = set_alignments(sc->event_header_fc);
-            if (ret) {
-                goto end;
-            }
-
-            ret = set_alignments(sc->event_common_context_fc);
-            if (ret) {
-                goto end;
-            }
-        }
-
-        for (j = 0; j < sc->event_classes->len; j++) {
-            struct ctf_event_class *ec = (ctf_event_class *) sc->event_classes->pdata[j];
-
-            if (ec->is_translated) {
-                continue;
-            }
-
-            ret = set_alignments(ec->spec_context_fc);
-            if (ret) {
-                goto end;
-            }
-
-            ret = set_alignments(ec->payload_fc);
-            if (ret) {
-                goto end;
-            }
-        }
-    }
-
-end:
-    return ret;
-}
diff --git a/src/plugins/ctf/common/metadata/ctf-meta-update-default-clock-classes.cpp b/src/plugins/ctf/common/metadata/ctf-meta-update-default-clock-classes.cpp
deleted file mode 100644 (file)
index ab10dd4..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
- */
-
-#include <inttypes.h>
-#include <string.h>
-
-#define BT_COMP_LOG_SELF_COMP       (log_cfg->self_comp)
-#define BT_COMP_LOG_SELF_COMP_CLASS (log_cfg->self_comp_class)
-#define BT_LOG_OUTPUT_LEVEL         (log_cfg->log_level)
-#define BT_LOG_TAG                  "PLUGIN/CTF/META/UPDATE-DEF-CC"
-#include "logging.hpp"
-
-#include "ctf-meta-visitors.hpp"
-
-static inline int find_mapped_clock_class(struct ctf_field_class *fc,
-                                          struct ctf_clock_class **clock_class,
-                                          struct meta_log_config *log_cfg)
-{
-    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 = ctf_field_class_as_int(fc);
-
-        if (int_fc->mapped_clock_class) {
-            if (*clock_class && *clock_class != int_fc->mapped_clock_class) {
-                _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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 = ctf_field_class_as_struct(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, log_cfg);
-            if (ret) {
-                goto end;
-            }
-        }
-
-        break;
-    }
-    case CTF_FIELD_CLASS_TYPE_VARIANT:
-    {
-        struct ctf_field_class_variant *var_fc = ctf_field_class_as_variant(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, log_cfg);
-            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 = ctf_field_class_as_array_base(fc);
-
-        ret = find_mapped_clock_class(array_fc->elem_fc, clock_class, log_cfg);
-        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,
-                                                          struct meta_log_config *log_cfg)
-{
-    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, log_cfg);
-    if (ret) {
-        goto end;
-    }
-
-    ret = find_mapped_clock_class(stream_class->event_header_fc, &clock_class, log_cfg);
-    if (ret) {
-        goto end;
-    }
-
-    ret = find_mapped_clock_class(stream_class->event_common_context_fc, &clock_class, log_cfg);
-    if (ret) {
-        goto end;
-    }
-
-    for (i = 0; i < stream_class->event_classes->len; i++) {
-        struct ctf_event_class *event_class =
-            (ctf_event_class *) stream_class->event_classes->pdata[i];
-
-        ret = find_mapped_clock_class(event_class->spec_context_fc, &clock_class, log_cfg);
-        if (ret) {
-            goto end;
-        }
-
-        ret = find_mapped_clock_class(event_class->payload_fc, &clock_class, log_cfg);
-        if (ret) {
-            goto end;
-        }
-    }
-
-    if (!stream_class->default_clock_class) {
-        stream_class->default_clock_class = clock_class;
-    }
-
-end:
-    return ret;
-}
-
-int ctf_trace_class_update_default_clock_classes(struct ctf_trace_class *ctf_tc,
-                                                 struct meta_log_config *log_cfg)
-{
-    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, log_cfg);
-    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_stream_class *) ctf_tc->stream_classes->pdata[i];
-
-        ret = update_stream_class_default_clock_class(
-            (ctf_stream_class *) ctf_tc->stream_classes->pdata[i], log_cfg);
-        if (ret) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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.cpp b/src/plugins/ctf/common/metadata/ctf-meta-update-in-ir.cpp
deleted file mode 100644 (file)
index c790238..0000000
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
- */
-
-#include <assert.h>
-#include <glib.h>
-#include <stdint.h>
-
-#include "common/assert.h"
-#include "compat/glib.h"
-
-#include "ctf-meta-visitors.hpp"
-
-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 = ctf_field_class_as_struct(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 = ctf_field_class_as_variant(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 = ctf_field_class_as_array_base(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 = ctf_field_class_as_int(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 = ctf_field_class_as_struct(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 = ctf_field_class_as_variant(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 = ctf_field_class_as_array_base(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 = ctf_field_class_as_array(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 = ctf_field_class_as_sequence(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.
- */
-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++) {
-        ctf_stream_class *sc = (ctf_stream_class *) ctf_tc->stream_classes->pdata[i];
-        uint64_t j;
-
-        for (j = 0; j < sc->event_classes->len; j++) {
-            ctf_event_class *ec = (ctf_event_class *) 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.cpp b/src/plugins/ctf/common/metadata/ctf-meta-update-meanings.cpp
deleted file mode 100644 (file)
index 23c6574..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
- */
-
-#include <stdint.h>
-#include <string.h>
-
-#include "ctf-meta-visitors.hpp"
-
-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 = ctf_field_class_as_int(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 = ctf_field_class_as_struct(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 = ctf_field_class_as_variant(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 = ctf_field_class_as_array_base(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(
-                ctf_field_class_as_struct(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(
-                ctf_field_class_as_struct(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(
-                ctf_field_class_as_struct(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(
-                ctf_field_class_as_struct(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(
-                ctf_field_class_as_struct(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(
-                ctf_field_class_as_struct(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 = (ctf_event_class *) sc->event_classes->pdata[i];
-
-        if (ec->is_translated) {
-            continue;
-        }
-    }
-
-end:
-    return ret;
-}
-
-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(
-            ctf_field_class_as_struct(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(
-            ctf_field_class_as_struct(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(
-            ctf_field_class_as_struct(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(
-            ctf_field_class_as_struct(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 = ctf_field_class_as_array(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_stream_class *) 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.cpp b/src/plugins/ctf/common/metadata/ctf-meta-update-stream-class-config.cpp
deleted file mode 100644 (file)
index a8f5add..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
- */
-
-#include <stdint.h>
-
-#include "ctf-meta-visitors.hpp"
-
-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_stream_class *) 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(
-            ctf_field_class_as_struct(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(
-            ctf_field_class_as_struct(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(
-            ctf_field_class_as_struct(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(
-            ctf_field_class_as_struct(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.cpp b/src/plugins/ctf/common/metadata/ctf-meta-update-text-array-sequence.cpp
deleted file mode 100644 (file)
index 6c3bfc9..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
- */
-
-#include <stdint.h>
-
-#include "ctf-meta-visitors.hpp"
-
-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 = ctf_field_class_as_struct(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 = ctf_field_class_as_variant(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 = ctf_field_class_as_array_base(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 = ctf_field_class_as_int(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;
-}
-
-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++) {
-        ctf_stream_class *sc = (ctf_stream_class *) 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 = (ctf_event_class *) 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.cpp b/src/plugins/ctf/common/metadata/ctf-meta-update-value-storing-indexes.cpp
deleted file mode 100644 (file)
index 65e4c9f..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
- */
-
-#include <stdint.h>
-#include <string.h>
-
-#include "common/assert.h"
-
-#include "ctf-meta-visitors.hpp"
-
-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:
-    {
-        ctf_field_class_variant *var_fc = ctf_field_class_as_variant(fc);
-
-        field_path = &var_fc->tag_path;
-        stored_value_index = &var_fc->stored_tag_index;
-        tgt_fc = &var_fc->tag_fc->base;
-        break;
-    }
-    case CTF_FIELD_CLASS_TYPE_SEQUENCE:
-    {
-        struct ctf_field_class_sequence *seq_fc = ctf_field_class_as_sequence(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 = ctf_field_class_as_struct(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 = ctf_field_class_as_variant(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 = ctf_field_class_as_array_base(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;
-}
-
-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;
-        ctf_stream_class *sc = (ctf_stream_class *) 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 = (ctf_event_class *) 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.cpp b/src/plugins/ctf/common/metadata/ctf-meta-validate.cpp
deleted file mode 100644 (file)
index 9a01c59..0000000
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
- */
-
-#include <inttypes.h>
-
-#define BT_COMP_LOG_SELF_COMP       (log_cfg->self_comp)
-#define BT_COMP_LOG_SELF_COMP_CLASS (log_cfg->self_comp_class)
-#define BT_LOG_OUTPUT_LEVEL         (log_cfg->log_level)
-#define BT_LOG_TAG                  "PLUGIN/CTF/META/VALIDATE"
-#include "logging.hpp"
-
-#include "ctf-meta-visitors.hpp"
-
-static int validate_stream_class(struct ctf_stream_class *sc, struct meta_log_config *log_cfg)
-{
-    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(
-        ctf_field_class_as_struct(sc->packet_context_fc), "timestamp_begin");
-    if (fc) {
-        if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                "Invalid packet context field class: "
-                "`timestamp_begin` member is not an integer field class.");
-            goto invalid;
-        }
-
-        int_fc = ctf_field_class_as_int(fc);
-
-        if (int_fc->is_signed) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet context field class: "
-                                                     "`timestamp_begin` member is signed.");
-            goto invalid;
-        }
-    }
-
-    fc = ctf_field_class_struct_borrow_member_field_class_by_name(
-        ctf_field_class_as_struct(sc->packet_context_fc), "timestamp_end");
-    if (fc) {
-        if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                "Invalid packet context field class: "
-                "`timestamp_end` member is not an integer field class.");
-            goto invalid;
-        }
-
-        int_fc = ctf_field_class_as_int(fc);
-
-        if (int_fc->is_signed) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet context field class: "
-                                                     "`timestamp_end` member is signed.");
-            goto invalid;
-        }
-    }
-
-    fc = ctf_field_class_struct_borrow_member_field_class_by_name(
-        ctf_field_class_as_struct(sc->packet_context_fc), "events_discarded");
-    if (fc) {
-        if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                "Invalid packet context field class: "
-                "`events_discarded` member is not an integer field class.");
-            goto invalid;
-        }
-
-        int_fc = ctf_field_class_as_int(fc);
-
-        if (int_fc->is_signed) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet context field class: "
-                                                     "`events_discarded` member is signed.");
-            goto invalid;
-        }
-    }
-
-    fc = ctf_field_class_struct_borrow_member_field_class_by_name(
-        ctf_field_class_as_struct(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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                "Invalid packet context field class: "
-                "`packet_seq_num` member is not an integer field class.");
-            goto invalid;
-        }
-
-        int_fc = ctf_field_class_as_int(fc);
-
-        if (int_fc->is_signed) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet context field class: "
-                                                     "`packet_seq_num` member is signed.");
-            goto invalid;
-        }
-    }
-
-    fc = ctf_field_class_struct_borrow_member_field_class_by_name(
-        ctf_field_class_as_struct(sc->packet_context_fc), "packet_size");
-    if (fc) {
-        if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                "Invalid packet context field class: "
-                "`packet_size` member is not an integer field class.");
-            goto invalid;
-        }
-
-        int_fc = ctf_field_class_as_int(fc);
-
-        if (int_fc->is_signed) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet context field class: "
-                                                     "`packet_size` member is signed.");
-            goto invalid;
-        }
-    }
-
-    fc = ctf_field_class_struct_borrow_member_field_class_by_name(
-        ctf_field_class_as_struct(sc->packet_context_fc), "content_size");
-    if (fc) {
-        if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                "Invalid packet context field class: "
-                "`content_size` member is not an integer field class.");
-            goto invalid;
-        }
-
-        int_fc = ctf_field_class_as_int(fc);
-
-        if (int_fc->is_signed) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet context field class: "
-                                                     "`content_size` member is signed.");
-            goto invalid;
-        }
-    }
-
-    fc = ctf_field_class_struct_borrow_member_field_class_by_name(
-        ctf_field_class_as_struct(sc->event_header_fc), "id");
-    if (fc) {
-        if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid event header field class: "
-                                                     "`id` member is not an integer field class.");
-            goto invalid;
-        }
-
-        int_fc = ctf_field_class_as_int(fc);
-
-        if (int_fc->is_signed) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid event header field class: "
-                                                     "`id` member is signed.");
-            goto invalid;
-        }
-    } else {
-        if (sc->event_classes->len > 1) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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;
-}
-
-int ctf_trace_class_validate(struct ctf_trace_class *ctf_tc, struct meta_log_config *log_cfg)
-{
-    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(
-            ctf_field_class_as_struct(ctf_tc->packet_header_fc), "magic");
-        if (fc) {
-            struct ctf_named_field_class *named_fc = ctf_field_class_struct_borrow_member_by_index(
-                ctf_field_class_as_struct(ctf_tc->packet_header_fc), 0);
-
-            if (named_fc->fc != fc) {
-                _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                    "Invalid packet header field class: "
-                    "`magic` member is not an integer field class.");
-                goto invalid;
-            }
-
-            int_fc = ctf_field_class_as_int(fc);
-
-            if (int_fc->is_signed) {
-                _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet header field class: "
-                                                         "`magic` member is signed.");
-                goto invalid;
-            }
-
-            if (int_fc->base.size != 32) {
-                _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet header field class: "
-                                                         "`magic` member is not 32-bit.");
-                goto invalid;
-            }
-        }
-
-        fc = ctf_field_class_struct_borrow_member_field_class_by_name(
-            ctf_field_class_as_struct(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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                    "Invalid packet header field class: "
-                    "`stream_id` member is not an integer field class.");
-                goto invalid;
-            }
-
-            int_fc = ctf_field_class_as_int(fc);
-
-            if (int_fc->is_signed) {
-                _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet header field class: "
-                                                         "`stream_id` member is signed.");
-                goto invalid;
-            }
-        } else {
-            if (ctf_tc->stream_classes->len > 1) {
-                _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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(
-            ctf_field_class_as_struct(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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                    "Invalid packet header field class: "
-                    "`stream_instance_id` member is not an integer field class.");
-                goto invalid;
-            }
-
-            int_fc = ctf_field_class_as_int(fc);
-
-            if (int_fc->is_signed) {
-                _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid packet header field class: "
-                                                         "`stream_instance_id` member is signed.");
-                goto invalid;
-            }
-        }
-
-        fc = ctf_field_class_struct_borrow_member_field_class_by_name(
-            ctf_field_class_as_struct(ctf_tc->packet_header_fc), "uuid");
-        if (fc) {
-            if (fc->type != CTF_FIELD_CLASS_TYPE_ARRAY) {
-                _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                    "Invalid packet header field class: "
-                    "`uuid` member is not an array field class.");
-                goto invalid;
-            }
-
-            ctf_field_class_array *array_fc = ctf_field_class_as_array(fc);
-
-            if (array_fc->length != 16) {
-                _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                    "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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                    "Invalid packet header field class: "
-                    "`uuid` member's element field class is not "
-                    "an integer field class.");
-                goto invalid;
-            }
-
-            int_fc = ctf_field_class_as_int(array_fc->base.elem_fc);
-
-            if (int_fc->is_signed) {
-                _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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_stream_class *) ctf_tc->stream_classes->pdata[i];
-
-        ret = validate_stream_class(sc, log_cfg);
-        if (ret) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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.hpp b/src/plugins/ctf/common/metadata/ctf-meta-visitors.hpp
deleted file mode 100644 (file)
index 5294ece..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
- */
-
-#ifndef _CTF_META_VISITORS_H
-#define _CTF_META_VISITORS_H
-
-#include <babeltrace2/babeltrace.h>
-
-#include "ctf-meta.hpp"
-
-struct meta_log_config;
-
-int ctf_trace_class_resolve_field_classes(struct ctf_trace_class *tc,
-                                          struct meta_log_config *log_cfg);
-
-int ctf_trace_class_translate(bt_self_component *self_comp, bt_trace_class *ir_tc,
-                              struct ctf_trace_class *tc);
-
-int ctf_trace_class_update_default_clock_classes(struct ctf_trace_class *ctf_tc,
-                                                 struct meta_log_config *log_cfg);
-
-int ctf_trace_class_update_in_ir(struct ctf_trace_class *ctf_tc);
-
-int ctf_trace_class_update_meanings(struct ctf_trace_class *ctf_tc);
-
-int ctf_trace_class_update_text_array_sequence(struct ctf_trace_class *ctf_tc);
-
-int ctf_trace_class_update_alignments(struct ctf_trace_class *ctf_tc);
-
-int ctf_trace_class_update_value_storing_indexes(struct ctf_trace_class *ctf_tc);
-
-int ctf_trace_class_update_stream_class_config(struct ctf_trace_class *ctf_tc);
-
-int ctf_trace_class_validate(struct ctf_trace_class *ctf_tc, struct meta_log_config *log_cfg);
-
-void ctf_trace_class_warn_meaningless_header_fields(struct ctf_trace_class *ctf_tc,
-                                                    struct meta_log_config *log_cfg);
-
-#endif /* _CTF_META_VISITORS_H */
diff --git a/src/plugins/ctf/common/metadata/ctf-meta-warn-meaningless-header-fields.cpp b/src/plugins/ctf/common/metadata/ctf-meta-warn-meaningless-header-fields.cpp
deleted file mode 100644 (file)
index 6d7e274..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
- */
-
-#include <stdint.h>
-#include <string.h>
-
-#define BT_COMP_LOG_SELF_COMP (log_cfg->self_comp)
-#define BT_LOG_OUTPUT_LEVEL   (log_cfg->log_level)
-#define BT_LOG_TAG            "PLUGIN/CTF/META/WARN-MEANINGLESS-HEADER-FIELDS"
-#include "logging.hpp"
-#include "logging/comp-logging.h"
-
-#include "common/assert.h"
-
-#include "ctf-meta-visitors.hpp"
-
-static inline void warn_meaningless_field(const char *name, const char *scope_name,
-                                          struct meta_log_config *log_cfg)
-{
-    BT_ASSERT(name);
-    BT_COMP_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, struct meta_log_config *log_cfg)
-{
-    uint64_t i;
-
-    if (!fc) {
-        goto end;
-    }
-
-    /*
-     * 'name' is guaranteed to be non-NULL whenever the field class is not a
-     * structure. In the case of a structure field class, its members' names
-     * are used.
-     */
-    switch (fc->type) {
-    case CTF_FIELD_CLASS_TYPE_FLOAT:
-    case CTF_FIELD_CLASS_TYPE_STRING:
-        warn_meaningless_field(name, scope_name, log_cfg);
-        break;
-    case CTF_FIELD_CLASS_TYPE_INT:
-    case CTF_FIELD_CLASS_TYPE_ENUM:
-    {
-        struct ctf_field_class_int *int_fc = ctf_field_class_as_int(fc);
-
-        if (int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE && !int_fc->mapped_clock_class) {
-            warn_meaningless_field(name, scope_name, log_cfg);
-        }
-
-        break;
-    }
-    case CTF_FIELD_CLASS_TYPE_STRUCT:
-    {
-        struct ctf_field_class_struct *struct_fc = ctf_field_class_as_struct(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, log_cfg);
-        }
-
-        break;
-    }
-    case CTF_FIELD_CLASS_TYPE_VARIANT:
-    {
-        struct ctf_field_class_variant *var_fc = ctf_field_class_as_variant(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, log_cfg);
-        }
-
-        break;
-    }
-    case CTF_FIELD_CLASS_TYPE_ARRAY:
-    {
-        struct ctf_field_class_array *array_fc = ctf_field_class_as_array(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 = ctf_field_class_as_array_base(fc);
-
-        warn_meaningless_fields(array_fc->elem_fc, name, scope_name, log_cfg);
-        break;
-    }
-    default:
-        bt_common_abort();
-    }
-
-end:
-    return;
-}
-
-void ctf_trace_class_warn_meaningless_header_fields(struct ctf_trace_class *ctf_tc,
-                                                    struct meta_log_config *log_cfg)
-{
-    uint64_t i;
-
-    if (!ctf_tc->is_translated) {
-        warn_meaningless_fields(ctf_tc->packet_header_fc, NULL, "packet header", log_cfg);
-    }
-
-    for (i = 0; i < ctf_tc->stream_classes->len; i++) {
-        ctf_stream_class *sc = (ctf_stream_class *) ctf_tc->stream_classes->pdata[i];
-
-        if (!sc->is_translated) {
-            warn_meaningless_fields(sc->event_header_fc, NULL, "event header", log_cfg);
-        }
-    }
-}
diff --git a/src/plugins/ctf/common/metadata/ctf-meta.hpp b/src/plugins/ctf/common/metadata/ctf-meta.hpp
deleted file mode 100644 (file)
index 87469d3..0000000
+++ /dev/null
@@ -1,1748 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
- */
-
-#ifndef _CTF_META_H
-#define _CTF_META_H
-
-#include <glib.h>
-#include <stdint.h>
-#include <string.h>
-
-#include <babeltrace2/babeltrace.h>
-
-#include "common/assert.h"
-#include "common/common.h"
-#include "common/uuid.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_UNKNOWN,
-    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_UNKNOWN = -1,
-    CTF_SCOPE_PACKET_HEADER = 0,
-    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;
-    bt_uuid_t uuid;
-    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;
-
-    /* Array of `struct ctf_range` */
-    GArray *ranges;
-};
-
-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
-{
-    /* Original name which can include a leading `_` */
-    GString *orig_name;
-
-    /* Name as translated to trace IR (leading `_` removed) */
-    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;
-    bool is_log_level_set;
-
-    /* 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;
-    bt_uuid_t uuid;
-    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;
-
-    struct
-    {
-        bool lttng_crash;
-        bool lttng_event_after_packet;
-        bool barectf_event_before_packet;
-    } quirks;
-};
-
-static inline ctf_field_class_bit_array *ctf_field_class_as_bit_array(ctf_field_class *fc)
-{
-    BT_ASSERT_DBG(!fc ||
-                  (fc->type == CTF_FIELD_CLASS_TYPE_INT || fc->type == CTF_FIELD_CLASS_TYPE_ENUM ||
-                   fc->type == CTF_FIELD_CLASS_TYPE_FLOAT));
-    return (ctf_field_class_bit_array *) fc;
-}
-
-static inline ctf_field_class_int *ctf_field_class_as_int(ctf_field_class *fc)
-{
-    BT_ASSERT_DBG(!fc ||
-                  (fc->type == CTF_FIELD_CLASS_TYPE_INT || fc->type == CTF_FIELD_CLASS_TYPE_ENUM));
-    return (ctf_field_class_int *) fc;
-}
-
-static inline ctf_field_class_enum *ctf_field_class_as_enum(ctf_field_class *fc)
-{
-    BT_ASSERT_DBG(!fc || fc->type == CTF_FIELD_CLASS_TYPE_ENUM);
-    return (ctf_field_class_enum *) fc;
-}
-
-static inline ctf_field_class_float *ctf_field_class_as_float(ctf_field_class *fc)
-{
-    BT_ASSERT_DBG(!fc || fc->type == CTF_FIELD_CLASS_TYPE_FLOAT);
-    return (ctf_field_class_float *) fc;
-}
-
-static inline ctf_field_class_string *ctf_field_class_as_string(ctf_field_class *fc)
-{
-    BT_ASSERT_DBG(!fc || fc->type == CTF_FIELD_CLASS_TYPE_STRING);
-    return (ctf_field_class_string *) fc;
-}
-
-static inline ctf_field_class_struct *ctf_field_class_as_struct(ctf_field_class *fc)
-{
-    BT_ASSERT_DBG(!fc || fc->type == CTF_FIELD_CLASS_TYPE_STRUCT);
-    return (ctf_field_class_struct *) fc;
-}
-
-static inline ctf_field_class_array_base *ctf_field_class_as_array_base(ctf_field_class *fc)
-{
-    BT_ASSERT_DBG(!fc || (fc->type == CTF_FIELD_CLASS_TYPE_ARRAY ||
-                          fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE));
-    return (ctf_field_class_array_base *) fc;
-}
-
-static inline ctf_field_class_array *ctf_field_class_as_array(ctf_field_class *fc)
-{
-    BT_ASSERT_DBG(!fc || fc->type == CTF_FIELD_CLASS_TYPE_ARRAY);
-    return (ctf_field_class_array *) fc;
-}
-
-static inline ctf_field_class_sequence *ctf_field_class_as_sequence(ctf_field_class *fc)
-{
-    BT_ASSERT_DBG(!fc || fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE);
-    return (ctf_field_class_sequence *) fc;
-}
-
-static inline ctf_field_class_variant *ctf_field_class_as_variant(ctf_field_class *fc)
-{
-    BT_ASSERT_DBG(!fc || fc->type == CTF_FIELD_CLASS_TYPE_VARIANT);
-    return (ctf_field_class_variant *) fc;
-}
-
-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(&fc->base, 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(&fc->base, 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);
-    named_fc->orig_name = g_string_new(NULL);
-    BT_ASSERT(named_fc->orig_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);
-    }
-
-    if (named_fc->orig_name) {
-        g_string_free(named_fc->orig_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);
-    mapping->ranges = g_array_new(FALSE, TRUE, sizeof(struct ctf_range));
-    BT_ASSERT(mapping->ranges);
-}
-
-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);
-    }
-
-    if (mapping->ranges) {
-        g_array_free(mapping->ranges, 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(&fc->base, 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(&fc->base, 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(&fc->base, 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(&fc->base, 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(&fc->base, 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(&fc->base.base, 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(&fc->base.base, 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 =
-                &bt_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 =
-                &bt_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(&fc->base);
-    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(&fc->base);
-
-    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 =
-                &bt_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(ctf_field_class_as_int(fc));
-        break;
-    case CTF_FIELD_CLASS_TYPE_ENUM:
-        _ctf_field_class_enum_destroy(ctf_field_class_as_enum(fc));
-        break;
-    case CTF_FIELD_CLASS_TYPE_FLOAT:
-        _ctf_field_class_float_destroy(ctf_field_class_as_float(fc));
-        break;
-    case CTF_FIELD_CLASS_TYPE_STRING:
-        _ctf_field_class_string_destroy(ctf_field_class_as_string(fc));
-        break;
-    case CTF_FIELD_CLASS_TYPE_STRUCT:
-        _ctf_field_class_struct_destroy(ctf_field_class_as_struct(fc));
-        break;
-    case CTF_FIELD_CLASS_TYPE_ARRAY:
-        _ctf_field_class_array_destroy(ctf_field_class_as_array(fc));
-        break;
-    case CTF_FIELD_CLASS_TYPE_SEQUENCE:
-        _ctf_field_class_sequence_destroy(ctf_field_class_as_sequence(fc));
-        break;
-    case CTF_FIELD_CLASS_TYPE_VARIANT:
-        _ctf_field_class_variant_destroy(ctf_field_class_as_variant(fc));
-        break;
-    default:
-        bt_common_abort();
-    }
-}
-
-static inline struct ctf_range *
-ctf_field_class_enum_mapping_borrow_range_by_index(struct ctf_field_class_enum_mapping *mapping,
-                                                   uint64_t index)
-{
-    BT_ASSERT_DBG(mapping);
-    BT_ASSERT_DBG(index < mapping->ranges->len);
-    return &bt_g_array_index(mapping->ranges, struct ctf_range, index);
-}
-
-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_DBG(fc);
-    BT_ASSERT_DBG(index < fc->mappings->len);
-    return &bt_g_array_index(fc->mappings, struct ctf_field_class_enum_mapping, index);
-}
-
-static inline struct ctf_field_class_enum_mapping *
-ctf_field_class_enum_borrow_mapping_by_label(struct ctf_field_class_enum *fc, const char *label)
-{
-    struct ctf_field_class_enum_mapping *ret_mapping = NULL;
-    uint64_t i;
-
-    BT_ASSERT_DBG(fc);
-    BT_ASSERT_DBG(label);
-
-    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 (strcmp(mapping->label->str, label) == 0) {
-            ret_mapping = mapping;
-            goto end;
-        }
-    }
-
-end:
-    return ret_mapping;
-}
-
-static inline void ctf_field_class_enum_map_range(struct ctf_field_class_enum *fc,
-                                                  const char *label, uint64_t u_lower,
-                                                  uint64_t u_upper)
-{
-    struct ctf_field_class_enum_mapping *mapping = NULL;
-    struct ctf_range range = {
-        .lower =
-            {
-                .u = u_lower,
-            },
-        .upper =
-            {
-                .u = u_upper,
-            },
-    };
-    uint64_t i;
-
-    BT_ASSERT(fc);
-    BT_ASSERT(label);
-
-    for (i = 0; i < fc->mappings->len; i++) {
-        mapping = ctf_field_class_enum_borrow_mapping_by_index(fc, i);
-
-        if (strcmp(mapping->label->str, label) == 0) {
-            break;
-        }
-    }
-
-    if (i == fc->mappings->len) {
-        mapping = NULL;
-    }
-
-    if (!mapping) {
-        g_array_set_size(fc->mappings, fc->mappings->len + 1);
-        mapping = ctf_field_class_enum_borrow_mapping_by_index(fc, fc->mappings->len - 1);
-        _ctf_field_class_enum_mapping_init(mapping);
-        g_string_assign(mapping->label, label);
-    }
-
-    g_array_append_val(mapping->ranges, range);
-}
-
-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_DBG(fc);
-    BT_ASSERT_DBG(index < fc->members->len);
-    return &bt_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_DBG(fc);
-    BT_ASSERT_DBG(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)
-{
-    ctf_field_class *member_fc =
-        ctf_field_class_struct_borrow_member_field_class_by_name(struct_fc, name);
-
-    if (!member_fc) {
-        return nullptr;
-    }
-
-    if (member_fc->type != CTF_FIELD_CLASS_TYPE_INT &&
-        member_fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
-        return nullptr;
-    }
-
-    return ctf_field_class_as_int(member_fc);
-}
-
-static inline void _ctf_named_field_class_unescape_orig_name(struct ctf_named_field_class *named_fc)
-{
-    const char *name = named_fc->orig_name->str;
-
-    if (name[0] == '_') {
-        name++;
-    }
-
-    g_string_assign(named_fc->name, name);
-}
-
-static inline void ctf_field_class_struct_append_member(struct ctf_field_class_struct *fc,
-                                                        const char *orig_name,
-                                                        struct ctf_field_class *member_fc)
-{
-    struct ctf_named_field_class *named_fc;
-
-    BT_ASSERT(fc);
-    BT_ASSERT(orig_name);
-    g_array_set_size(fc->members, fc->members->len + 1);
-
-    named_fc = &bt_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->orig_name, orig_name);
-    _ctf_named_field_class_unescape_orig_name(named_fc);
-    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_DBG(fc);
-    BT_ASSERT_DBG(index < fc->options->len);
-    return &bt_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_DBG(fc);
-    BT_ASSERT_DBG(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_DBG(fc);
-    BT_ASSERT_DBG(index < fc->ranges->len);
-    return &bt_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 *orig_name,
-                                                         struct ctf_field_class *option_fc)
-{
-    struct ctf_named_field_class *named_fc;
-
-    BT_ASSERT(fc);
-    BT_ASSERT(orig_name);
-    g_array_set_size(fc->options, fc->options->len + 1);
-
-    named_fc = &bt_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->orig_name, orig_name);
-    _ctf_named_field_class_unescape_orig_name(named_fc);
-    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 range_i;
-        struct ctf_named_field_class *named_fc =
-            ctf_field_class_variant_borrow_option_by_index(fc, option_i);
-        struct ctf_field_class_enum_mapping *mapping;
-
-        mapping = ctf_field_class_enum_borrow_mapping_by_label(tag_fc, named_fc->orig_name->str);
-        if (!mapping) {
-            continue;
-        }
-
-        for (range_i = 0; range_i < mapping->ranges->len; range_i++) {
-            struct ctf_range *range =
-                ctf_field_class_enum_mapping_borrow_range_by_index(mapping, range_i);
-            struct ctf_field_class_variant_range var_range;
-
-            var_range.range = *range;
-            var_range.option_index = option_i;
-            g_array_append_val(fc->ranges, var_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(
-            (struct ctf_field_class_struct *) comp_fc, index);
-
-        BT_ASSERT_DBG(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(
-            (struct ctf_field_class_variant *) comp_fc, index);
-
-        BT_ASSERT_DBG(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 = (struct ctf_field_class_array_base *) 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 = (struct ctf_field_class_struct *) fc;
-
-        field_count = struct_fc->members->len;
-        break;
-    }
-    case CTF_FIELD_CLASS_TYPE_VARIANT:
-    {
-        struct ctf_field_class_variant *var_fc = (struct ctf_field_class_variant *) 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:
-        bt_common_abort();
-    }
-
-    return field_count;
-}
-
-static inline int64_t
-ctf_field_class_compound_get_field_class_index_from_orig_name(struct ctf_field_class *fc,
-                                                              const char *orig_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 = (struct ctf_field_class_struct *) 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(orig_name, named_fc->orig_name->str) == 0) {
-                ret_index = (int64_t) i;
-                goto end;
-            }
-        }
-
-        break;
-    }
-    case CTF_FIELD_CLASS_TYPE_VARIANT:
-    {
-        struct ctf_field_class_variant *var_fc = (struct ctf_field_class_variant *) 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(orig_name, named_fc->orig_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_DBG(fp);
-    BT_ASSERT_DBG(index < fp->path->len);
-    return bt_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 "PACKET_HEADER";
-    case CTF_SCOPE_PACKET_CONTEXT:
-        return "PACKET_CONTEXT";
-    case CTF_SCOPE_EVENT_HEADER:
-        return "EVENT_HEADER";
-    case CTF_SCOPE_EVENT_COMMON_CONTEXT:
-        return "EVENT_COMMON_CONTEXT";
-    case CTF_SCOPE_EVENT_SPECIFIC_CONTEXT:
-        return "EVENT_SPECIFIC_CONTEXT";
-    case CTF_SCOPE_EVENT_PAYLOAD:
-        return "EVENT_PAYLOAD";
-    default:
-        bt_common_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:
-        bt_common_abort();
-    }
-
-    BT_ASSERT_DBG(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_DBG(child_fc);
-        fc = child_fc;
-    }
-
-    BT_ASSERT_DBG(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(&dst_fc->base, &src_fc->base);
-    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(&copy_fc->base, &fc->base);
-
-    for (i = 0; i < fc->mappings->len; i++) {
-        uint64_t range_i;
-
-        struct ctf_field_class_enum_mapping *mapping =
-            &bt_g_array_index(fc->mappings, struct ctf_field_class_enum_mapping, i);
-
-        for (range_i = 0; range_i < mapping->ranges->len; range_i++) {
-            struct ctf_range *range = &bt_g_array_index(mapping->ranges, struct ctf_range, range_i);
-
-            ctf_field_class_enum_map_range(copy_fc, mapping->label->str, range->lower.u,
-                                           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(&copy_fc->base, &fc->base);
-    return copy_fc;
-}
-
-static inline struct ctf_field_class_string *
-_ctf_field_class_string_copy(struct ctf_field_class_string *)
-{
-    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 =
-            &bt_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 =
-            &bt_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 =
-            &bt_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(&copy_fc->base, &fc->base);
-    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(&copy_fc->base, &fc->base);
-    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 = &_ctf_field_class_int_copy(ctf_field_class_as_int(fc))->base.base;
-        break;
-    case CTF_FIELD_CLASS_TYPE_ENUM:
-        copy_fc = &_ctf_field_class_enum_copy(ctf_field_class_as_enum(fc))->base.base.base;
-        break;
-    case CTF_FIELD_CLASS_TYPE_FLOAT:
-        copy_fc = &_ctf_field_class_float_copy(ctf_field_class_as_float(fc))->base.base;
-        break;
-    case CTF_FIELD_CLASS_TYPE_STRING:
-        copy_fc = &_ctf_field_class_string_copy(ctf_field_class_as_string(fc))->base;
-        break;
-    case CTF_FIELD_CLASS_TYPE_STRUCT:
-        copy_fc = &_ctf_field_class_struct_copy(ctf_field_class_as_struct(fc))->base;
-        break;
-    case CTF_FIELD_CLASS_TYPE_ARRAY:
-        copy_fc = &_ctf_field_class_array_copy(ctf_field_class_as_array(fc))->base.base;
-        break;
-    case CTF_FIELD_CLASS_TYPE_SEQUENCE:
-        copy_fc = &_ctf_field_class_sequence_copy(ctf_field_class_as_sequence(fc))->base.base;
-        break;
-    case CTF_FIELD_CLASS_TYPE_VARIANT:
-        copy_fc = &_ctf_field_class_variant_copy(ctf_field_class_as_variant(fc))->base;
-        break;
-    default:
-        bt_common_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->is_log_level_set = false;
-    return ec;
-}
-
-static inline void ctf_event_class_set_log_level(struct ctf_event_class *ec,
-                                                 enum bt_event_class_log_level log_level)
-{
-    BT_ASSERT(ec);
-    ec->log_level = log_level;
-    ec->is_log_level_set = true;
-}
-
-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_DBG(sc);
-    return (struct ctf_event_class *) 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 = CTF_BYTE_ORDER_UNKNOWN;
-    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 =
-                &bt_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 = &bt_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_DBG(tc);
-
-    for (i = 0; i < tc->stream_classes->len; i++) {
-        struct ctf_stream_class *sc = (struct ctf_stream_class *) 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_DBG(tc);
-    BT_ASSERT_DBG(name);
-
-    for (i = 0; i < tc->clock_classes->len; i++) {
-        struct ctf_clock_class *cc = (struct ctf_clock_class *) tc->clock_classes->pdata[i];
-
-        BT_ASSERT_DBG(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_DBG(tc);
-    BT_ASSERT_DBG(index < tc->env_entries->len);
-    return &bt_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_DBG(tc);
-    BT_ASSERT_DBG(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-packetized-file-stream-to-buf.cpp b/src/plugins/ctf/common/metadata/decoder-packetized-file-stream-to-buf.cpp
deleted file mode 100644 (file)
index 2150465..0000000
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright 2016-2017 Philippe Proulx <pproulx@efficios.com>
- */
-
-#include <glib.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <babeltrace2/babeltrace.h>
-
-#define BT_COMP_LOG_SELF_COMP       self_comp
-#define BT_COMP_LOG_SELF_COMP_CLASS self_comp_class
-#define BT_LOG_OUTPUT_LEVEL         log_level
-#define BT_LOG_TAG                  "PLUGIN/CTF/META/DECODER-DECODE-PACKET"
-#include "logging.hpp"
-#include "logging/comp-logging.h"
-
-#include "common/uuid.h"
-#include "compat/memstream.h"
-
-#include "decoder-packetized-file-stream-to-buf.hpp"
-#include "decoder.hpp"
-
-#define TSDL_MAGIC 0x75d11d57
-
-struct ctf_metadata_decoder
-{
-    struct ctf_visitor_generate_ir *visitor;
-    bt_uuid_t uuid;
-    bool is_uuid_set;
-    int bo;
-    struct ctf_metadata_decoder_config config;
-};
-
-struct packet_header
-{
-    uint32_t magic;
-    bt_uuid_t uuid;
-    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 int decode_packet(FILE *in_fp, FILE *out_fp, int byte_order, bool *is_uuid_set,
-                         uint8_t *uuid, bt_logging_level log_level, bt_self_component *self_comp,
-                         bt_self_component_class *self_comp_class)
-{
-    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_COMP_LOGE_APPEND_CAUSE_ERRNO(BT_COMP_LOG_SELF_COMP,
-                                        "Failed to get current metadata file position", ".");
-        goto error;
-    }
-    BT_COMP_LOGD("Decoding metadata packet: offset=%ld", offset);
-    readlen = fread(&header, sizeof(header), 1, in_fp);
-    if (feof(in_fp) != 0) {
-        BT_COMP_LOGI("Reached end of file: offset=%ld", ftell(in_fp));
-        goto end;
-    }
-    if (readlen < 1) {
-        _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-            "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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-            "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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-            "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 (!ctf_metadata_decoder_is_packet_version_valid(header.major, header.minor)) {
-        _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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 (is_uuid_set) {
-        if (!*is_uuid_set) {
-            bt_uuid_copy(uuid, header.uuid);
-            *is_uuid_set = true;
-        } else if (bt_uuid_compare(header.uuid, uuid)) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                "Metadata UUID mismatch between packets of the same stream: "
-                "packet-uuid=\"" BT_UUID_FMT "\", "
-                "expected-uuid=\"" BT_UUID_FMT "\", "
-                "offset=%ld",
-                BT_UUID_FMT_VALUES(header.uuid), BT_UUID_FMT_VALUES(uuid), offset);
-            goto error;
-        }
-    }
-
-    if ((header.content_size / CHAR_BIT) < sizeof(header)) {
-        _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-            "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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot read metadata packet buffer: "
-                                                     "offset=%ld, read-size=%zu",
-                                                     ftell(in_fp), loop_read);
-            goto error;
-        }
-        if (readlen > loop_read) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                "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_COMP_LOGW_STR("Missing padding at the end of the metadata stream.");
-            }
-            break;
-        }
-    }
-
-    goto end;
-
-error:
-    ret = -1;
-
-end:
-    return ret;
-}
-
-int ctf_metadata_decoder_packetized_file_stream_to_buf(FILE *fp, char **buf, int byte_order,
-                                                       bool *is_uuid_set, uint8_t *uuid,
-                                                       bt_logging_level log_level,
-                                                       bt_self_component *self_comp,
-                                                       bt_self_component_class *self_comp_class)
-{
-    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) {
-        _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot open memory stream: %s.", strerror(errno));
-        goto error;
-    }
-
-    for (;;) {
-        if (feof(fp) != 0) {
-            break;
-        }
-
-        tret = decode_packet(fp, out_fp, byte_order, is_uuid_set, uuid, log_level, self_comp,
-                             self_comp_class);
-        if (tret) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot decode packet: index=%zu",
-                                                     packet_index);
-            goto error;
-        }
-
-        packet_index++;
-    }
-
-    /* Make sure the whole string ends with a null character */
-    tret = fputc('\0', out_fp);
-    if (tret == EOF) {
-        _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-            "Cannot append '\\0' to the decoded metadata buffer.");
-        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_COMP_LOGE_APPEND_CAUSE_ERRNO(BT_COMP_LOG_SELF_COMP, "Cannot close memory stream", ".");
-        goto error;
-    }
-
-    goto end;
-
-error:
-    ret = -1;
-
-    if (out_fp) {
-        if (bt_close_memstream(buf, &size, out_fp)) {
-            BT_COMP_LOGE_ERRNO("Cannot close memory stream", ".");
-        }
-    }
-
-    if (*buf) {
-        free(*buf);
-        *buf = NULL;
-    }
-
-end:
-    return ret;
-}
diff --git a/src/plugins/ctf/common/metadata/decoder-packetized-file-stream-to-buf.hpp b/src/plugins/ctf/common/metadata/decoder-packetized-file-stream-to-buf.hpp
deleted file mode 100644 (file)
index 8d83153..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright 2019 Efficios Inc.
- */
-
-#ifndef SRC_PLUGINS_CTF_COMMON_METADATA_DECODER_PACKETIZED_FILE_STREAM_TO_BUF
-#define SRC_PLUGINS_CTF_COMMON_METADATA_DECODER_PACKETIZED_FILE_STREAM_TO_BUF
-
-#include <cstdio>
-
-#include <stdint.h>
-
-#include <babeltrace2/babeltrace.h>
-
-int ctf_metadata_decoder_packetized_file_stream_to_buf(FILE *fp, char **buf, int byte_order,
-                                                       bool *is_uuid_set, uint8_t *uuid,
-                                                       bt_logging_level log_level,
-                                                       bt_self_component *self_comp,
-                                                       bt_self_component_class *self_comp_class);
-
-#endif /* SRC_PLUGINS_CTF_COMMON_METADATA_DECODER_PACKETIZED_FILE_STREAM_TO_BUF */
diff --git a/src/plugins/ctf/common/metadata/decoder.cpp b/src/plugins/ctf/common/metadata/decoder.cpp
deleted file mode 100644 (file)
index deaeedb..0000000
+++ /dev/null
@@ -1,473 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright 2016-2017 Philippe Proulx <pproulx@efficios.com>
- */
-
-#include <glib.h>
-#include <inttypes.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <babeltrace2/babeltrace.h>
-
-#define BT_COMP_LOG_SELF_COMP       (mdec->config.self_comp)
-#define BT_COMP_LOG_SELF_COMP_CLASS (mdec->config.self_comp_class)
-#define BT_LOG_OUTPUT_LEVEL         ((enum bt_log_level) mdec->config.log_level)
-#define BT_LOG_TAG                  "PLUGIN/CTF/META/DECODER"
-#include "logging.hpp"
-#include "logging/comp-logging.h"
-
-#include "common/assert.h"
-#include "common/uuid.h"
-#include "compat/memstream.h"
-
-#include "ast.hpp"
-#include "decoder-packetized-file-stream-to-buf.hpp"
-#include "decoder.hpp"
-#include "parser-wrap.hpp"
-#include "scanner.hpp"
-
-#define TSDL_MAGIC 0x75d11d57
-
-struct ctf_metadata_decoder
-{
-    struct ctf_scanner *scanner;
-    GString *text;
-    struct ctf_visitor_generate_ir *visitor;
-    bt_uuid_t uuid;
-    bool is_uuid_set;
-    int bo;
-    struct ctf_metadata_decoder_config config;
-    struct meta_log_config log_cfg;
-    bool has_checked_plaintext_signature;
-};
-
-struct packet_header
-{
-    uint32_t magic;
-    bt_uuid_t uuid;
-    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__));
-
-int ctf_metadata_decoder_is_packetized(FILE *fp, bool *is_packetized, int *byte_order,
-                                       bt_logging_level log_level, bt_self_component *self_comp)
-{
-    uint32_t magic;
-    size_t len;
-    int ret = 0;
-
-    *is_packetized = false;
-    len = fread(&magic, sizeof(magic), 1, fp);
-    if (len != 1) {
-        BT_COMP_LOG_CUR_LVL(
-            BT_LOG_INFO, log_level, self_comp,
-            "Cannot read first metadata packet header: assuming the stream is not packetized.");
-        ret = -1;
-        goto end;
-    }
-
-    if (byte_order) {
-        if (magic == TSDL_MAGIC) {
-            *is_packetized = true;
-            *byte_order = BYTE_ORDER;
-        } else if (magic == GUINT32_SWAP_LE_BE(TSDL_MAGIC)) {
-            *is_packetized = true;
-            *byte_order = BYTE_ORDER == BIG_ENDIAN ? LITTLE_ENDIAN : BIG_ENDIAN;
-        }
-    }
-
-end:
-    rewind(fp);
-
-    return ret;
-}
-
-struct ctf_metadata_decoder *
-ctf_metadata_decoder_create(const struct ctf_metadata_decoder_config *config)
-{
-    struct ctf_metadata_decoder *mdec = g_new0(struct ctf_metadata_decoder, 1);
-
-    BT_ASSERT(config);
-    BT_COMP_LOG_CUR_LVL(BT_LOG_DEBUG, config->log_level, config->self_comp,
-                        "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_COMP_LOG_CUR_LVL(BT_LOG_ERROR, config->log_level, config->self_comp,
-                            "Failed to allocate one CTF metadata decoder.");
-        goto end;
-    }
-
-    mdec->log_cfg.log_level = config->log_level;
-    mdec->log_cfg.self_comp = config->self_comp;
-    mdec->log_cfg.self_comp_class = config->self_comp_class;
-    mdec->scanner = ctf_scanner_alloc();
-    if (!mdec->scanner) {
-        _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot allocate a metadata lexical scanner: "
-                                                 "mdec-addr=%p",
-                                                 mdec);
-        goto error;
-    }
-
-    mdec->text = g_string_new(NULL);
-    if (!mdec->text) {
-        _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Failed to allocate one GString: "
-                                                 "mdec-addr=%p",
-                                                 mdec);
-        goto error;
-    }
-
-    mdec->bo = -1;
-    mdec->config = *config;
-    mdec->visitor = ctf_visitor_generate_ir_create(config);
-    if (!mdec->visitor) {
-        _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Failed to create a CTF IR metadata AST visitor: "
-                                                 "mdec-addr=%p",
-                                                 mdec);
-        goto error;
-    }
-
-    BT_COMP_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);
-    goto end;
-
-error:
-    ctf_metadata_decoder_destroy(mdec);
-    mdec = NULL;
-
-end:
-    return mdec;
-}
-
-void ctf_metadata_decoder_destroy(struct ctf_metadata_decoder *mdec)
-{
-    if (!mdec) {
-        return;
-    }
-
-    if (mdec->scanner) {
-        ctf_scanner_free(mdec->scanner);
-    }
-
-    if (mdec->text) {
-        g_string_free(mdec->text, TRUE);
-    }
-
-    BT_COMP_LOGD("Destroying CTF metadata decoder: addr=%p", mdec);
-    ctf_visitor_generate_ir_destroy(mdec->visitor);
-    g_free(mdec);
-}
-
-enum ctf_metadata_decoder_status
-ctf_metadata_decoder_append_content(struct ctf_metadata_decoder *mdec, FILE *fp)
-{
-    enum ctf_metadata_decoder_status status = CTF_METADATA_DECODER_STATUS_OK;
-    int ret;
-    char *buf = NULL;
-    bool close_fp = false;
-    long start_pos = -1;
-    bool is_packetized;
-
-    BT_ASSERT(mdec);
-    ret = ctf_metadata_decoder_is_packetized(fp, &is_packetized, &mdec->bo, mdec->config.log_level,
-                                             mdec->config.self_comp);
-    if (ret) {
-        status = CTF_METADATA_DECODER_STATUS_ERROR;
-        goto end;
-    }
-
-    if (is_packetized) {
-        BT_COMP_LOGI("Metadata stream is packetized: mdec-addr=%p", mdec);
-        ret = ctf_metadata_decoder_packetized_file_stream_to_buf(
-            fp, &buf, mdec->bo, &mdec->is_uuid_set, mdec->uuid, mdec->config.log_level,
-            mdec->config.self_comp, mdec->config.self_comp_class);
-        if (ret) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                "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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot memory-open metadata buffer: %s: "
-                                                     "mdec-addr=%p",
-                                                     strerror(errno), mdec);
-            status = CTF_METADATA_DECODER_STATUS_ERROR;
-            goto end;
-        }
-    } else if (!mdec->has_checked_plaintext_signature) {
-        unsigned int major, minor;
-        ssize_t nr_items;
-        const long init_pos = ftell(fp);
-
-        BT_COMP_LOGI("Metadata stream is plain text: mdec-addr=%p", mdec);
-
-        if (init_pos < 0) {
-            BT_COMP_LOGE_APPEND_CAUSE_ERRNO(BT_COMP_LOG_SELF_COMP,
-                                            "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_COMP_LOGW(
-                "Missing \"/* CTF major.minor\" signature in plain text metadata file stream: "
-                "mdec-addr=%p",
-                mdec);
-        }
-
-        BT_COMP_LOGI("Found metadata stream version in signature: version=%u.%u", major, minor);
-
-        if (!ctf_metadata_decoder_is_packet_version_valid(major, minor)) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                "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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                "Cannot seek metadata file stream to initial position: %s: "
-                "mdec-addr=%p",
-                strerror(errno), mdec);
-            status = CTF_METADATA_DECODER_STATUS_ERROR;
-            goto end;
-        }
-
-        mdec->has_checked_plaintext_signature = true;
-    }
-
-#if YYDEBUG
-    if (BT_LOG_ON_TRACE) {
-        yydebug = 1;
-    }
-#endif
-
-    /* Save the file's position: we'll seek back to append the plain text */
-    BT_ASSERT(fp);
-
-    if (mdec->config.keep_plain_text) {
-        start_pos = ftell(fp);
-    }
-
-    /* Append the metadata text content */
-    ret = ctf_scanner_append_ast(mdec->scanner, fp);
-    if (ret) {
-        _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-            "Cannot create the metadata AST out of the metadata text: "
-            "mdec-addr=%p",
-            mdec);
-        status = CTF_METADATA_DECODER_STATUS_INCOMPLETE;
-        goto end;
-    }
-
-    /* We know it's complete: append plain text */
-    if (mdec->config.keep_plain_text) {
-        BT_ASSERT(start_pos != -1);
-        ret = fseek(fp, start_pos, SEEK_SET);
-        if (ret) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Failed to seek file: ret=%d, mdec-addr=%p",
-                                                     ret, mdec);
-            status = CTF_METADATA_DECODER_STATUS_ERROR;
-            goto end;
-        }
-
-        ret = bt_common_append_file_content_to_g_string(mdec->text, fp);
-        if (ret) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Failed to append to current plain text: "
-                                                     "ret=%d, mdec-addr=%p",
-                                                     ret, mdec);
-            status = CTF_METADATA_DECODER_STATUS_ERROR;
-            goto end;
-        }
-    }
-
-    ret = ctf_visitor_semantic_check(0, &mdec->scanner->ast->root, &mdec->log_cfg);
-    if (ret) {
-        _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Validation of the metadata semantics failed: "
-                                                 "mdec-addr=%p",
-                                                 mdec);
-        status = CTF_METADATA_DECODER_STATUS_ERROR;
-        goto end;
-    }
-
-    if (mdec->config.create_trace_class) {
-        ret = ctf_visitor_generate_ir_visit_node(mdec->visitor, &mdec->scanner->ast->root);
-        switch (ret) {
-        case 0:
-            /* Success */
-            break;
-        case -EINCOMPLETE:
-            BT_COMP_LOGD("While visiting metadata AST: incomplete data: "
-                         "mdec-addr=%p",
-                         mdec);
-            status = CTF_METADATA_DECODER_STATUS_INCOMPLETE;
-            goto end;
-        default:
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                "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 YYDEBUG
-    yydebug = 0;
-#endif
-
-    if (fp && close_fp) {
-        if (fclose(fp)) {
-            BT_COMP_LOGE("Cannot close metadata file stream: "
-                         "mdec-addr=%p",
-                         mdec);
-        }
-    }
-
-    free(buf);
-
-    return status;
-}
-
-bt_trace_class *ctf_metadata_decoder_get_ir_trace_class(struct ctf_metadata_decoder *mdec)
-{
-    BT_ASSERT_DBG(mdec);
-    BT_ASSERT_DBG(mdec->config.create_trace_class);
-    return ctf_visitor_generate_ir_get_ir_trace_class(mdec->visitor);
-}
-
-struct ctf_trace_class *
-ctf_metadata_decoder_borrow_ctf_trace_class(struct ctf_metadata_decoder *mdec)
-{
-    BT_ASSERT_DBG(mdec);
-    BT_ASSERT_DBG(mdec->config.create_trace_class);
-    return ctf_visitor_generate_ir_borrow_ctf_trace_class(mdec->visitor);
-}
-
-const char *ctf_metadata_decoder_get_text(struct ctf_metadata_decoder *mdec)
-{
-    BT_ASSERT_DBG(mdec);
-    BT_ASSERT_DBG(mdec->config.keep_plain_text);
-    return mdec->text->str;
-}
-
-int ctf_metadata_decoder_get_byte_order(struct ctf_metadata_decoder *mdec)
-{
-    BT_ASSERT_DBG(mdec);
-    return mdec->bo;
-}
-
-int ctf_metadata_decoder_get_uuid(struct ctf_metadata_decoder *mdec, bt_uuid_t uuid)
-{
-    int ret = 0;
-
-    BT_ASSERT_DBG(mdec);
-
-    if (!mdec->is_uuid_set) {
-        ret = -1;
-        goto end;
-    }
-
-    bt_uuid_copy(uuid, mdec->uuid);
-
-end:
-    return ret;
-}
-
-static enum ctf_metadata_decoder_status find_uuid_in_trace_decl(struct ctf_metadata_decoder *mdec,
-                                                                struct ctf_node *trace_node,
-                                                                bt_uuid_t uuid)
-{
-    enum ctf_metadata_decoder_status status = CTF_METADATA_DECODER_STATUS_OK;
-    struct ctf_node *entry_node;
-    struct bt_list_head *decl_list = &trace_node->u.trace.declaration_list;
-    char *left = NULL;
-
-    bt_list_for_each_entry (entry_node, decl_list, siblings) {
-        if (entry_node->type == NODE_CTF_EXPRESSION) {
-            int ret;
-
-            left = ctf_ast_concatenate_unary_strings(&entry_node->u.ctf_expression.left);
-            if (!left) {
-                _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot concatenate unary strings.");
-                status = CTF_METADATA_DECODER_STATUS_ERROR;
-                goto end;
-            }
-
-            if (strcmp(left, "uuid") == 0) {
-                ret = ctf_ast_get_unary_uuid(&entry_node->u.ctf_expression.right, uuid,
-                                             mdec->config.log_level, mdec->config.self_comp);
-                if (ret) {
-                    _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Invalid trace's `uuid` attribute.");
-                    status = CTF_METADATA_DECODER_STATUS_ERROR;
-                    goto end;
-                }
-
-                goto end;
-            }
-
-            g_free(left);
-            left = NULL;
-        }
-    }
-
-    status = CTF_METADATA_DECODER_STATUS_NONE;
-
-end:
-    g_free(left);
-    return status;
-}
-
-enum ctf_metadata_decoder_status
-ctf_metadata_decoder_get_trace_class_uuid(struct ctf_metadata_decoder *mdec, bt_uuid_t uuid)
-{
-    enum ctf_metadata_decoder_status status = CTF_METADATA_DECODER_STATUS_INCOMPLETE;
-    struct ctf_node *root_node = &mdec->scanner->ast->root;
-    struct ctf_node *trace_node;
-
-    if (!root_node) {
-        status = CTF_METADATA_DECODER_STATUS_INCOMPLETE;
-        goto end;
-    }
-
-    trace_node = bt_list_entry(root_node->u.root.trace.next, struct ctf_node, siblings);
-    if (!trace_node) {
-        status = CTF_METADATA_DECODER_STATUS_INCOMPLETE;
-        goto end;
-    }
-
-    status = find_uuid_in_trace_decl(mdec, trace_node, uuid);
-
-end:
-    return status;
-}
diff --git a/src/plugins/ctf/common/metadata/decoder.hpp b/src/plugins/ctf/common/metadata/decoder.hpp
deleted file mode 100644 (file)
index d4385f4..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright 2016-2017 Philippe Proulx <pproulx@efficios.com>
- */
-
-#ifndef _METADATA_DECODER_H
-#define _METADATA_DECODER_H
-
-#include <stdint.h>
-#include <stdio.h>
-
-#include <babeltrace2/babeltrace.h>
-
-#include "common/uuid.h"
-
-/* CTF metadata decoder status */
-enum ctf_metadata_decoder_status
-{
-    CTF_METADATA_DECODER_STATUS_OK = 0,
-    CTF_METADATA_DECODER_STATUS_NONE = 1,
-    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
-{
-    /* Active log level to use */
-    bt_logging_level log_level;
-
-    /*
-     * Component or component class to use for logging (exactly one of
-     * them must be non-`NULL`); weak
-     */
-    bt_self_component *self_comp;
-    bt_self_component_class *self_comp_class;
-
-    /* Additional clock class offset to apply */
-    int64_t clock_class_offset_s;
-    int64_t clock_class_offset_ns;
-    bool force_clock_class_origin_unix_epoch;
-
-    /* True to create trace class objects */
-    bool create_trace_class;
-
-    /*
-     * True to keep the plain text when content is appended with
-     * ctf_metadata_decoder_append_content().
-     */
-    bool keep_plain_text;
-};
-
-/*
- * Creates a CTF metadata decoder.
- *
- * Returns `NULL` on error.
- */
-struct ctf_metadata_decoder *
-ctf_metadata_decoder_create(const struct ctf_metadata_decoder_config *config);
-
-/*
- * Destroys a CTF metadata decoder that you created with
- * ctf_metadata_decoder_create().
- */
-void ctf_metadata_decoder_destroy(struct ctf_metadata_decoder *metadata_decoder);
-
-/*
- * Appends content to the metadata decoder.
- *
- * This function reads the metadata from the current position of `fp`
- * until the end of this file stream.
- *
- * The metadata can be packetized or not.
- *
- * The metadata chunk needs to be complete and lexically 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 everything goes as expected, this function returns
- * `CTF_METADATA_DECODER_STATUS_OK`.
- */
-enum ctf_metadata_decoder_status
-ctf_metadata_decoder_append_content(struct ctf_metadata_decoder *metadata_decoder, FILE *fp);
-
-/*
- * Returns the trace IR trace class of this metadata decoder (new
- * reference).
- *
- * Returns `NULL` if there's none yet or if the metadata decoder is not
- * configured to create trace classes.
- */
-bt_trace_class *ctf_metadata_decoder_get_ir_trace_class(struct ctf_metadata_decoder *mdec);
-
-/*
- * Returns the CTF IR trace class of this metadata decoder.
- *
- * Returns `NULL` if there's none yet or if the metadata decoder is not
- * configured to create trace classes.
- */
-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 `fp` is
- * packetized, setting `is_packetized` accordingly on success. On
- * success, also sets `*byte_order` to the byte order of the first
- * packet.
- *
- * This function uses `log_level` and `self_comp` for logging purposes.
- * `self_comp` can be `NULL` if not available.
- */
-int ctf_metadata_decoder_is_packetized(FILE *fp, bool *is_packetized, int *byte_order,
-                                       bt_logging_level log_level, bt_self_component *self_comp);
-
-/*
- * Returns the byte order of the decoder's metadata stream as set by the
- * last call to ctf_metadata_decoder_append_content().
- *
- * Returns -1 if unknown (plain text content).
- */
-int ctf_metadata_decoder_get_byte_order(struct ctf_metadata_decoder *mdec);
-
-/*
- * Returns the UUID of the decoder's metadata stream as set by the last
- * call to ctf_metadata_decoder_append_content().
- */
-int ctf_metadata_decoder_get_uuid(struct ctf_metadata_decoder *mdec, bt_uuid_t uuid);
-
-/*
- * Returns the UUID of the decoder's trace class, if available.
- *
- * Returns:
- *
- * * `CTF_METADATA_DECODER_STATUS_OK`: success.
- * * `CTF_METADATA_DECODER_STATUS_NONE`: no UUID.
- * * `CTF_METADATA_DECODER_STATUS_INCOMPLETE`: missing metadata content.
- */
-enum ctf_metadata_decoder_status
-ctf_metadata_decoder_get_trace_class_uuid(struct ctf_metadata_decoder *mdec, bt_uuid_t uuid);
-
-/*
- * Returns the metadata decoder's current metadata text.
- */
-const char *ctf_metadata_decoder_get_text(struct ctf_metadata_decoder *mdec);
-
-static inline bool ctf_metadata_decoder_is_packet_version_valid(unsigned int major,
-                                                                unsigned int minor)
-{
-    return major == 1 && minor == 8;
-}
-
-#endif /* _METADATA_DECODER_H */
diff --git a/src/plugins/ctf/common/metadata/lexer.lpp b/src/plugins/ctf/common/metadata/lexer.lpp
deleted file mode 100644 (file)
index 7c2d5d3..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-%{
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright 2010 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Common Trace Formal Lexer
- */
-
-#include <ctype.h>
-#include <stdio.h>
-
-#define BT_LOG_OUTPUT_LEVEL ctf_plugin_metadata_log_level
-#define BT_LOG_TAG "PLUGIN-CTF-METADATA-LEXER"
-#include "plugins/ctf/common/metadata/logging.hpp"
-
-#include "plugins/ctf/common/metadata/ast.hpp"
-#include "plugins/ctf/common/metadata/parser-wrap.hpp"
-#include "plugins/ctf/common/metadata/scanner.hpp"
-
-#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_APPEND_CAUSE_LINENO(yylineno,                  \
-                               "Cannot parser constant integer: "      \
-                               "base=%d, text=\"%s\"", base, yytext);  \
-                       return CTF_ERROR;                               \
-               }                                                       \
-       } while (0)
-%}
-
-%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_LOGT("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_APPEND_CAUSE_LINENO(yylineno, "Invalid character: char=\"%c\", val=0x%02x", isprint((unsigned char) yytext[0]) ? yytext[0] : '\0', yytext[0]); return CTF_ERROR;
-%%
diff --git a/src/plugins/ctf/common/metadata/logging.cpp b/src/plugins/ctf/common/metadata/logging.cpp
deleted file mode 100644 (file)
index 058a6b4..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright (c) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- */
-
-#define BT_LOG_OUTPUT_LEVEL ctf_plugin_metadata_log_level
-#include "logging/log-api.h"
-
-BT_LOG_INIT_LOG_LEVEL(ctf_plugin_metadata_log_level, "BABELTRACE_PLUGIN_CTF_METADATA_LOG_LEVEL");
diff --git a/src/plugins/ctf/common/metadata/logging.hpp b/src/plugins/ctf/common/metadata/logging.hpp
deleted file mode 100644 (file)
index 234a1d6..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright (c) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- */
-
-#ifndef CTF_METADATA_LOGGING_H
-#define CTF_METADATA_LOGGING_H
-
-#include <babeltrace2/babeltrace.h>
-
-#include "logging/comp-logging.h"
-#include "logging/log.h"
-
-/*
- * This global log level is for the generated lexer and parser: we can't
- * use a contextual log level for their "tracing", so they rely on this.
- */
-BT_LOG_LEVEL_EXTERN_SYMBOL(ctf_plugin_metadata_log_level);
-
-/*
- * To be used by functions without a context structure to pass all the
- * logging configuration at once.
- */
-struct meta_log_config
-{
-    bt_logging_level log_level;
-
-    /* Weak, exactly one of these must be set */
-    bt_self_component *self_comp;
-    bt_self_component_class *self_comp_class;
-};
-
-#define _BT_LOGT_LINENO(_lineno, _msg, args...)                                                    \
-    BT_LOGT("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_APPEND_CAUSE_LINENO(_lineno, _msg, args...)                                       \
-    do {                                                                                           \
-        BT_LOGE("At line %u in metadata stream: " _msg, _lineno, ##args);                          \
-        (void) BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN(                                  \
-            "CTF metadata parser", "At line %u in metadata stream: " _msg, _lineno, ##args);       \
-    } while (0)
-
-#define _BT_COMP_LOGT_LINENO(_lineno, _msg, args...)                                               \
-    BT_COMP_LOGT("At line %u in metadata stream: " _msg, _lineno, ##args)
-
-#define _BT_COMP_LOGW_LINENO(_lineno, _msg, args...)                                               \
-    BT_COMP_LOGW("At line %u in metadata stream: " _msg, _lineno, ##args)
-
-#define _BT_COMP_LOGE_LINENO(_lineno, _msg, args...)                                               \
-    BT_COMP_LOGE("At line %u in metadata stream: " _msg, _lineno, ##args)
-
-#define _BT_COMP_LOGE_APPEND_CAUSE_LINENO(_lineno, _msg, args...)                                  \
-    BT_COMP_LOGE_APPEND_CAUSE(BT_COMP_LOG_SELF_COMP, "At line %u in metadata stream: " _msg,       \
-                              _lineno, ##args)
-
-#define _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(_msg, args...)                                    \
-    BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(BT_COMP_LOG_SELF_COMP, BT_COMP_LOG_SELF_COMP_CLASS,    \
-                                            _msg, ##args)
-
-#endif /* CTF_METADATA_LOGGING_H */
diff --git a/src/plugins/ctf/common/metadata/objstack.cpp b/src/plugins/ctf/common/metadata/objstack.cpp
deleted file mode 100644 (file)
index bdf31e0..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Common Trace Format Object Stack.
- */
-
-#include <stdlib.h>
-
-#define BT_LOG_OUTPUT_LEVEL ctf_plugin_metadata_log_level
-#define BT_LOG_TAG          "PLUGIN/CTF/META/OBJSTACK"
-#include "logging.hpp"
-
-#include "common/align.h"
-#include "common/list.h"
-
-#include "objstack.hpp"
-
-#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[];
-};
-
-struct objstack *objstack_create(void)
-{
-    struct objstack *objstack;
-    struct objstack_node *node;
-
-    objstack = (struct objstack *) calloc(1, sizeof(*objstack));
-    if (!objstack) {
-        BT_LOGE_STR("Failed to allocate one object stack.");
-        return NULL;
-    }
-    node = (objstack_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);
-}
-
-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 = (objstack_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;
-}
-
-void *objstack_alloc(struct objstack *objstack, size_t len)
-{
-    struct objstack_node *last_node;
-    void *p;
-
-    len = BT_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.hpp b/src/plugins/ctf/common/metadata/objstack.hpp
deleted file mode 100644 (file)
index 2c91e14..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Common Trace Format Object Stack.
- */
-
-#ifndef _OBJSTACK_H
-#define _OBJSTACK_H
-
-#include <cstddef>
-
-struct objstack *objstack_create(void);
-void objstack_destroy(struct objstack *objstack);
-
-/*
- * Allocate len bytes of zeroed memory.
- * Return NULL on error.
- */
-void *objstack_alloc(struct objstack *objstack, size_t len);
-
-#endif /* _OBJSTACK_H */
diff --git a/src/plugins/ctf/common/metadata/parser-wrap.hpp b/src/plugins/ctf/common/metadata/parser-wrap.hpp
deleted file mode 100644 (file)
index e35c362..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright 2019 EfficiOS Inc.
- */
-
-#ifndef BABELTRACE_PLUGINS_CTF_COMMON_METADATA_PARSER_WRAP_H
-#define BABELTRACE_PLUGINS_CTF_COMMON_METADATA_PARSER_WRAP_H
-
-/*
- * Small wrapper around the bison-generated parser.h to conditionally define
- * YYDEBUG (and therefore the yydebug declaration).
- */
-
-#include "logging/log.h"
-
-#if BT_LOG_ENABLED_TRACE
-#    define YYDEBUG                           1
-#    define YYFPRINTF(_stream, _fmt, args...) BT_LOGT(_fmt, ##args)
-#else
-#    define YYDEBUG 0
-#endif
-
-#define ALLOW_INCLUDE_PARSER_H
-#include "plugins/ctf/common/metadata/parser.hpp"
-#undef ALLOW_INCLUDE_PARSER_H
-
-#endif
diff --git a/src/plugins/ctf/common/metadata/parser.ypp b/src/plugins/ctf/common/metadata/parser.ypp
deleted file mode 100644 (file)
index eb6e32c..0000000
+++ /dev/null
@@ -1,2607 +0,0 @@
-%{
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Common Trace Format Metadata Grammar.
- */
-
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <glib.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#define BT_LOG_OUTPUT_LEVEL ctf_plugin_metadata_log_level
-#define BT_LOG_TAG "PLUGIN/CTF/META/PARSER"
-#include "plugins/ctf/common/metadata/logging.hpp"
-
-#include "common/list.h"
-#include "common/assert.h"
-
-#include "plugins/ctf/common/metadata/ast.hpp"
-#include "plugins/ctf/common/metadata/objstack.hpp"
-#include "plugins/ctf/common/metadata/parser-wrap.hpp"
-
-/*
- * Avoid warning about "yynerrs" being unused, seen with bison 3.5.1 + clang 15
- * on Ubuntu 20.04.
- */
-BT_DIAG_IGNORE_UNUSED_BUT_SET_VARIABLE
-
-/* 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;
-       }
-}
-
-int yylex(union YYSTYPE *yyval, yyscan_t yyscanner);
-int yylex_init_extra(struct ctf_scanner *scanner, yyscan_t * ptr_yy_globals);
-int yylex_destroy(yyscan_t yyscanner);
-void yyrestart(FILE * in_str, yyscan_t yyscanner);
-int yyget_lineno(yyscan_t yyscanner);
-char *yyget_text(yyscan_t yyscanner);
-
-/*
- * 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 = {
-       .parent = nullptr,
-       .siblings = {},
-       .tmp_head = {},
-       .lineno = 0,
-       .visited = 0,
-       .type = NODE_ERROR,
-};
-
-const char *node_type(struct ctf_node *node)
-{
-       switch (node->type) {
-#define ENTRY(S) case S: return #S;
-       FOREACH_CTF_NODES(ENTRY)
-#undef ENTRY
-       };
-
-       bt_common_abort();
-}
-
-void setstring(struct ctf_scanner *scanner, YYSTYPE *lvalp, const char *src)
-{
-       lvalp->s = (char *) 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_DBG(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 = (char *) objstack_alloc(scanner->objstack, len);
-       if (src[0] == 'L') {
-               // TODO: import wide string
-               _BT_LOGE_APPEND_CAUSE_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_LOGT("Pushing scope: scanner-addr=%p", scanner);
-       ns = (ctf_scanner_scope *) 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_LOGT("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_LOGT("Looked up type: scanner-addr=%p, id=\"%s\", ret=%d",
-               s, id, ret);
-       return ret;
-}
-
-int is_type(struct ctf_scanner *scanner, const char *id)
-{
-       struct ctf_scanner_scope *it;
-       int ret = 0;
-
-       for (it = scanner->cs; it; it = it->parent) {
-               if (lookup_type(it, id)) {
-                       ret = 1;
-                       break;
-               }
-       }
-       BT_LOGT("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_LOGT("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 = (ctf_node *) objstack_alloc(scanner->objstack, sizeof(*node));
-       if (!node) {
-               _BT_LOGE_APPEND_CAUSE_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;
-}
-
-static
-void yyerror(struct ctf_scanner *scanner, yyscan_t yyscanner, const char *str)
-{
-       _BT_LOGE_APPEND_CAUSE_LINENO(yyget_lineno(scanner->scanner),
-               "%s: token=\"%s\"", str, yyget_text(scanner->scanner));
-}
-
-#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 = (ctf_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 = (ctf_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;
-
-       struct ctf_scanner_scope *scope = scanner->cs;
-
-       do {
-               struct ctf_scanner_scope *parent = scope->parent;
-               finalize_scope(scope);
-
-               /*
-                * The root scope is allocated within the ctf_scanner structure,
-                * do doesn't need freeing.  All others are allocated on their
-                * own.
-                */
-               if (scope != &scanner->root_scope)
-                       free(scope);
-
-               scope = parent;
-       } while (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);
-}
-
-/*
- * The bison-provided version of strlen (yystrlen) generates a benign
- * -Wnull-dereference warning.  That version is used when building on cygwin,
- * for example, but you can also enable it by hand (to test) by removing the
- * preprocessor conditional around it.
- *
- * Define yystrlen such that it will always use strlen.  As far as we know,
- * strlen provided by all the platforms we use is reliable.
- */
-#define yystrlen strlen
-
-%}
-
-/*
- * This ends up in parser.h and makes sure those who want to include it pass
- * through parser-wrap.h.
- */
-%code requires {
-#ifndef ALLOW_INCLUDE_PARSER_H
-# error "Don't include parser.h directly, include parser-wrap.h instead."
-#endif
-
-#include "plugins/ctf/common/metadata/scanner.hpp"
-}
-
-%code provides {
-       void setstring(struct ctf_scanner *scanner, YYSTYPE *lvalp, const char *src);
-
-       int import_string(struct ctf_scanner *scanner, YYSTYPE *lvalp, const char *src, char delim);
-}
-
-%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_SIGNED_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.hpp b/src/plugins/ctf/common/metadata/scanner-symbols.hpp
deleted file mode 100644 (file)
index 1f6f144..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright 2011-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- */
-
-#ifndef _CTF_SCANNER_SYMBOLS
-#define _CTF_SCANNER_SYMBOLS
-
-#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.hpp b/src/plugins/ctf/common/metadata/scanner.hpp
deleted file mode 100644 (file)
index dd16e97..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright 2011-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- */
-
-#ifndef _CTF_SCANNER_H
-#define _CTF_SCANNER_H
-
-#include <stdio.h>
-
-#include "ast.hpp"
-
-#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;
-}
-
-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.cpp b/src/plugins/ctf/common/metadata/visitor-generate-ir.cpp
deleted file mode 100644 (file)
index c53c4d8..0000000
+++ /dev/null
@@ -1,4744 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright 2010 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- * Copyright 2015-2018 Philippe Proulx <philippe.proulx@efficios.com>
- *
- * Common Trace Format metadata visitor (generates CTF IR objects).
- */
-
-#include <string>
-
-#include <errno.h>
-#include <glib.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <babeltrace2/babeltrace.h>
-
-#define BT_COMP_LOG_SELF_COMP       (ctx->log_cfg.self_comp)
-#define BT_COMP_LOG_SELF_COMP_CLASS (ctx->log_cfg.self_comp_class)
-#define BT_LOG_OUTPUT_LEVEL         (ctx->log_cfg.log_level)
-#define BT_LOG_TAG                  "PLUGIN/CTF/META/IR-VISITOR"
-#include "logging.hpp"
-#include "logging/comp-logging.h"
-
-#include "common/assert.h"
-#include "common/common.h"
-#include "common/uuid.h"
-#include "compat/endian.h" /* IWYU pragma: keep  */
-
-#include "ast.hpp"
-#include "ctf-meta-visitors.hpp"
-#include "ctf-meta.hpp"
-#include "decoder.hpp"
-
-/* 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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(_node, _attr, _entity)                                 \
-    _BT_COMP_LOGE_APPEND_CAUSE_LINENO(                                                             \
-        (_node)->lineno, "Duplicate attribute in %s: attr-name=\"%s\"", _entity, _attr)
-
-#define _BT_COMP_LOGE_NODE(_node, _msg, args...) _BT_COMP_LOGE_LINENO((_node)->lineno, _msg, ##args)
-
-#define _BT_COMP_LOGE_APPEND_CAUSE_NODE(_node, _msg, args...)                                      \
-    _BT_COMP_LOGE_APPEND_CAUSE_LINENO((_node)->lineno, _msg, ##args)
-
-#define _BT_COMP_LOGW_NODE(_node, _msg, args...) _BT_COMP_LOGW_LINENO((_node)->lineno, _msg, ##args)
-
-#define _BT_COMP_LOGT_NODE(_node, _msg, args...) _BT_COMP_LOGT_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 ctf_visitor_generate_ir
-{
-    struct meta_log_config log_cfg;
-
-    /* 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 ctf_visitor_generate_ir *ctx,
-                                                    struct ctx_decl_scope *par_scope)
-{
-    struct ctx_decl_scope *scope;
-
-    scope = g_new(struct ctx_decl_scope, 1);
-    if (!scope) {
-        _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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)
-{
-    BT_ASSERT(name);
-    std::string prname = std::string {prefix} + name;
-    return g_quark_from_string(prname.c_str());
-}
-
-/**
- * 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 = (ctf_field_class *) 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 ctf_field_class_as_enum(
-        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 ctf_field_class_as_struct(
-        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 ctf_field_class_as_variant(
-        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, 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, &decl->base.base.base);
-}
-
-/**
- * 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, &decl->base);
-}
-
-/**
- * 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, &decl->base);
-}
-
-/**
- * Destroys a visitor context.
- *
- * @param ctx  Visitor context to destroy
- */
-static void ctx_destroy(struct ctf_visitor_generate_ir *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 ctf_visitor_generate_ir *
-ctx_create(const struct ctf_metadata_decoder_config *decoder_config)
-{
-    struct ctf_visitor_generate_ir *ctx = NULL;
-
-    BT_ASSERT(decoder_config);
-
-    ctx = g_new0(struct ctf_visitor_generate_ir, 1);
-    if (!ctx) {
-        BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, decoder_config->log_level, decoder_config->self_comp,
-                            "Failed to allocate one visitor context.");
-        goto error;
-    }
-
-    ctx->log_cfg.log_level = decoder_config->log_level;
-    ctx->log_cfg.self_comp = decoder_config->self_comp;
-    ctx->log_cfg.self_comp_class = decoder_config->self_comp_class;
-
-    if (decoder_config->self_comp) {
-        ctx->trace_class = bt_trace_class_create(decoder_config->self_comp);
-        if (!ctx->trace_class) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot create empty trace class.");
-            goto error;
-        }
-    }
-
-    ctx->ctf_tc = ctf_trace_class_create();
-    if (!ctx->ctf_tc) {
-        _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot create CTF trace class.");
-        goto error;
-    }
-
-    /* Root declaration scope */
-    ctx->current_scope = ctx_decl_scope_create(ctx, NULL);
-    if (!ctx->current_scope) {
-        _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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 ctf_visitor_generate_ir *ctx)
-{
-    int ret = 0;
-    struct ctx_decl_scope *new_scope;
-
-    BT_ASSERT(ctx);
-    new_scope = ctx_decl_scope_create(ctx, ctx->current_scope);
-    if (!new_scope) {
-        _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("Cannot create declaration scope.");
-        ret = -ENOMEM;
-        goto end;
-    }
-
-    ctx->current_scope = new_scope;
-
-end:
-    return ret;
-}
-
-static void ctx_pop_scope(struct ctf_visitor_generate_ir *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 ctf_visitor_generate_ir *ctx,
-                                            struct ctf_node *ts_list,
-                                            struct ctf_field_class **decl);
-
-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 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 ctf_visitor_generate_ir *ctx, 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_COMP_LOGE_APPEND_CAUSE_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 ctf_visitor_generate_ir *ctx, struct bt_list_head *head,
-                          bt_uuid_t uuid)
-{
-    return ctf_ast_get_unary_uuid(head, uuid, ctx->log_cfg.log_level, ctx->log_cfg.self_comp);
-}
-
-static int get_boolean(struct ctf_visitor_generate_ir *ctx, struct ctf_node *unary_expr)
-{
-    int ret = 0;
-
-    if (unary_expr->type != NODE_UNARY_EXPRESSION) {
-        _BT_COMP_LOGE_APPEND_CAUSE_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") == 0 || strcmp(str, "TRUE") == 0) {
-            ret = TRUE;
-        } else if (strcmp(str, "false") == 0 || strcmp(str, "FALSE") == 0) {
-            ret = FALSE;
-        } else {
-            _BT_COMP_LOGE_APPEND_CAUSE_NODE(unary_expr, "Unexpected boolean value: value=\"%s\"",
-                                            str);
-            ret = -EINVAL;
-            goto end;
-        }
-        break;
-    }
-    default:
-        _BT_COMP_LOGE_APPEND_CAUSE_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_visitor_generate_ir *ctx,
-                                                      struct ctf_node *unary_expr)
-{
-    const char *str;
-    enum ctf_byte_order bo = CTF_BYTE_ORDER_UNKNOWN;
-
-    if (unary_expr->u.unary_expression.type != UNARY_STRING) {
-        _BT_COMP_LOGE_APPEND_CAUSE_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") == 0 || strcmp(str, "network") == 0) {
-        bo = CTF_BYTE_ORDER_BIG;
-    } else if (strcmp(str, "le") == 0) {
-        bo = CTF_BYTE_ORDER_LITTLE;
-    } else if (strcmp(str, "native") == 0) {
-        bo = CTF_BYTE_ORDER_DEFAULT;
-    } else {
-        _BT_COMP_LOGE_APPEND_CAUSE_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 ctf_visitor_generate_ir *ctx,
-                                               struct ctf_node *uexpr)
-{
-    enum ctf_byte_order bo = byte_order_from_unary_expr(ctx, 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 ctf_visitor_generate_ir *ctx,
-                                    struct ctf_node *cls_specifier, GString *str)
-{
-    int ret = 0;
-
-    if (cls_specifier->type != NODE_TYPE_SPECIFIER) {
-        _BT_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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 ctf_visitor_generate_ir *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 ctf_visitor_generate_ir *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 ctf_visitor_generate_ir *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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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) {
-        if (node_field_class_declarator &&
-            !bt_list_empty(&node_field_class_declarator->u.field_class_declarator.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_COMP_LOGE_APPEND_CAUSE_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 = ctf_field_class_as_int(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;
-
-            *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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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 = &array_decl->base.base;
-            break;
-        }
-        case UNARY_STRING:
-        {
-            /* Lookup unsigned integer definition, create seq. */
-            struct ctf_field_class_sequence *seq_decl = NULL;
-            char *length_name = ctf_ast_concatenate_unary_strings(length);
-
-            if (!length_name) {
-                _BT_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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 = &array_decl->base.base;
-            } else {
-                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);
-                decl = &seq_decl->base.base;
-            }
-
-            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 ctf_visitor_generate_ir *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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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 ctf_visitor_generate_ir *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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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 ctf_visitor_generate_ir *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_COMP_LOGE_APPEND_CAUSE_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 = ctf_field_class_as_variant(class_decl);
-
-            if (var_fc->tag_path.path->len == 0) {
-                _BT_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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 ctf_visitor_generate_ir *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_COMP_LOGE_APPEND_CAUSE_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 = ctf_field_class_as_variant(class_decl);
-
-        if (var_fc->tag_path.path->len == 0) {
-            _BT_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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 ctf_visitor_generate_ir *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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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 ctf_visitor_generate_ir *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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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 ctf_visitor_generate_ir *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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                "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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                "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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                    "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(ctx, min_align, &min_align_value);
-            if (ret) {
-                _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                    "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_COMP_LOGE_APPEND_CAUSE_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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                    "Cannot register structure field class in declaration scope: "
-                    "name=\"struct %s\", ret=%d",
-                    name, ret);
-                goto error;
-            }
-        }
-    }
-
-    return 0;
-
-error:
-    ctf_field_class_destroy(&(*struct_decl)->base);
-    *struct_decl = NULL;
-    return ret;
-}
-
-static int visit_variant_decl(struct ctf_visitor_generate_ir *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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                "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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                    "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_COMP_LOGE_APPEND_CAUSE_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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                    "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.
-         */
-        g_string_assign(untagged_variant_decl->tag_ref, tag);
-        *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(&untagged_variant_decl->base);
-    untagged_variant_decl = NULL;
-    ctf_field_class_destroy(&(*variant_decl)->base);
-    *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 ctf_visitor_generate_ir *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;
-    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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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;
-    }
-
-    ctf_field_class_enum_map_range(enum_decl, label, start.value.u, end.value.u);
-    return 0;
-
-error:
-    return ret;
-}
-
-static int visit_enum_decl(struct ctf_visitor_generate_ir *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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                "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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                    "Enumeration field class already declared in local scope: "
-                    "name=\"enum %s\"",
-                    name);
-                ret = -EINVAL;
-                goto error;
-            }
-        }
-
-        if (!container_cls) {
-            integer_decl = ctf_field_class_as_int(
-                ctx_decl_scope_lookup_alias(ctx->current_scope, "int", -1, true));
-            if (!integer_decl) {
-                _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                    "Cannot find implicit `int` field class alias for enumeration field class.");
-                ret = -EINVAL;
-                goto error;
-            }
-        } else {
-            ctf_field_class *decl;
-
-            ret = visit_field_class_declarator(ctx, container_cls, &qdummy_id, NULL, &decl, NULL);
-            if (ret) {
-                BT_ASSERT(!decl);
-                ret = -EINVAL;
-                goto error;
-            }
-
-            integer_decl = ctf_field_class_as_int(decl);
-        }
-
-        BT_ASSERT(integer_decl);
-
-        if (integer_decl->base.base.type != CTF_FIELD_CLASS_TYPE_INT) {
-            _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                "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(&(*enum_decl)->base, 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_COMP_LOGE_APPEND_CAUSE_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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                    "Cannot register enumeration field class in declaration scope: "
-                    "ret=%d",
-                    ret);
-                goto error;
-            }
-        }
-    }
-
-    goto end;
-
-error:
-    ctf_field_class_destroy(&(*enum_decl)->base.base.base);
-    *enum_decl = NULL;
-
-end:
-    ctf_field_class_destroy(&integer_decl->base.base);
-    integer_decl = NULL;
-    return ret;
-}
-
-static int visit_field_class_specifier(struct ctf_visitor_generate_ir *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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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 ctf_visitor_generate_ir *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_COMP_LOGE_APPEND_CAUSE_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") == 0) {
-            if (_IS_SET(&set, _INTEGER_SIGNED_SET)) {
-                _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "signed", "integer field class");
-                ret = -EPERM;
-                goto error;
-            }
-
-            signedness = get_boolean(ctx, right);
-            if (signedness < 0) {
-                _BT_COMP_LOGE_APPEND_CAUSE_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") == 0) {
-            if (_IS_SET(&set, _INTEGER_BYTE_ORDER_SET)) {
-                _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "byte_order", "integer field class");
-                ret = -EPERM;
-                goto error;
-            }
-
-            byte_order = get_real_byte_order(ctx, right);
-            if (byte_order == CTF_BYTE_ORDER_UNKNOWN) {
-                _BT_COMP_LOGE_APPEND_CAUSE_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") == 0) {
-            if (_IS_SET(&set, _INTEGER_SIZE_SET)) {
-                _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "size", "integer field class");
-                ret = -EPERM;
-                goto error;
-            }
-
-            if (right->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) {
-                _BT_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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") == 0) {
-            if (_IS_SET(&set, _INTEGER_ALIGN_SET)) {
-                _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "align", "integer field class");
-                ret = -EPERM;
-                goto error;
-            }
-
-            if (right->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) {
-                _BT_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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") == 0) {
-            if (_IS_SET(&set, _INTEGER_BASE_SET)) {
-                _BT_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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 =
-                    ctf_ast_concatenate_unary_strings(&expression->u.ctf_expression.right);
-                if (!s_right) {
-                    _BT_COMP_LOGE_APPEND_CAUSE_NODE(
-                        right,
-                        "Unexpected unary expression for integer field class's `base` attribute.");
-                    ret = -EINVAL;
-                    goto error;
-                }
-
-                if (strcmp(s_right, "decimal") == 0 || strcmp(s_right, "dec") == 0 ||
-                    strcmp(s_right, "d") == 0 || strcmp(s_right, "i") == 0 ||
-                    strcmp(s_right, "u") == 0) {
-                    base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL;
-                } else if (strcmp(s_right, "hexadecimal") == 0 || strcmp(s_right, "hex") == 0 ||
-                           strcmp(s_right, "x") == 0 || strcmp(s_right, "X") == 0 ||
-                           strcmp(s_right, "p") == 0) {
-                    base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL;
-                } else if (strcmp(s_right, "octal") == 0 || strcmp(s_right, "oct") == 0 ||
-                           strcmp(s_right, "o") == 0) {
-                    base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL;
-                } else if (strcmp(s_right, "binary") == 0 || strcmp(s_right, "b") == 0) {
-                    base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY;
-                } else {
-                    _BT_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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") == 0) {
-            char *s_right;
-
-            if (_IS_SET(&set, _INTEGER_ENCODING_SET)) {
-                _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "encoding", "integer field class");
-                ret = -EPERM;
-                goto error;
-            }
-
-            if (right->u.unary_expression.type != UNARY_STRING) {
-                _BT_COMP_LOGE_APPEND_CAUSE_NODE(
-                    right, "Invalid `encoding` attribute in integer field class: "
-                           "expecting unary string.");
-                ret = -EINVAL;
-                goto error;
-            }
-
-            s_right = ctf_ast_concatenate_unary_strings(&expression->u.ctf_expression.right);
-            if (!s_right) {
-                _BT_COMP_LOGE_APPEND_CAUSE_NODE(
-                    right,
-                    "Unexpected unary expression for integer field class's `encoding` attribute.");
-                ret = -EINVAL;
-                goto error;
-            }
-
-            if (strcmp(s_right, "UTF8") == 0 || strcmp(s_right, "utf8") == 0 ||
-                strcmp(s_right, "utf-8") == 0 || strcmp(s_right, "UTF-8") == 0 ||
-                strcmp(s_right, "ASCII") == 0 || strcmp(s_right, "ascii") == 0) {
-                encoding = CTF_ENCODING_UTF8;
-            } else if (strcmp(s_right, "none") == 0) {
-                encoding = CTF_ENCODING_NONE;
-            } else {
-                _BT_COMP_LOGE_APPEND_CAUSE_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") == 0) {
-            const char *clock_name;
-
-            if (_IS_SET(&set, _INTEGER_MAP_SET)) {
-                _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "map", "integer field class");
-                ret = -EPERM;
-                goto error;
-            }
-
-            if (right->u.unary_expression.type != UNARY_STRING) {
-                _BT_COMP_LOGE_APPEND_CAUSE_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 =
-                    ctf_ast_concatenate_unary_strings(&expression->u.ctf_expression.right);
-
-                if (!s_right) {
-                    _BT_COMP_LOGE_APPEND_CAUSE_NODE(
-                        right,
-                        "Unexpected unary expression for integer field class's `map` attribute.");
-                    ret = -EINVAL;
-                    goto error;
-                }
-
-                _BT_COMP_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_COMP_LOGE_APPEND_CAUSE_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_COMP_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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-            "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(&(*integer_decl)->base.base);
-    *integer_decl = NULL;
-    return ret;
-}
-
-static int visit_floating_point_number_decl(struct ctf_visitor_generate_ir *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_COMP_LOGE_APPEND_CAUSE_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") == 0) {
-            if (_IS_SET(&set, _FLOAT_BYTE_ORDER_SET)) {
-                _BT_COMP_LOGE_APPEND_CAUSE_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 == CTF_BYTE_ORDER_UNKNOWN) {
-                _BT_COMP_LOGE_APPEND_CAUSE_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") == 0) {
-            if (_IS_SET(&set, _FLOAT_EXP_DIG_SET)) {
-                _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "exp_dig",
-                                                    "floating point number field class");
-                ret = -EPERM;
-                goto error;
-            }
-
-            if (right->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) {
-                _BT_COMP_LOGE_APPEND_CAUSE_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") == 0) {
-            if (_IS_SET(&set, _FLOAT_MANT_DIG_SET)) {
-                _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "mant_dig",
-                                                    "floating point number field class");
-                ret = -EPERM;
-                goto error;
-            }
-
-            if (right->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) {
-                _BT_COMP_LOGE_APPEND_CAUSE_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") == 0) {
-            if (_IS_SET(&set, _FLOAT_ALIGN_SET)) {
-                _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "align",
-                                                    "floating point number field class");
-                ret = -EPERM;
-                goto error;
-            }
-
-            if (right->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) {
-                _BT_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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_COMP_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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-            "Missing `mant_dig` attribute in floating point number field class.");
-        ret = -EPERM;
-        goto error;
-    }
-
-    if (!_IS_SET(&set, _FLOAT_EXP_DIG_SET)) {
-        _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-            "Missing `exp_dig` attribute in floating point number field class.");
-        ret = -EPERM;
-        goto error;
-    }
-
-    if (mant_dig != 24 && mant_dig != 53) {
-        _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE("`mant_dig` attribute: expecting 24 or 53.");
-        ret = -EPERM;
-        goto error;
-    }
-
-    if (mant_dig == 24 && exp_dig != 8) {
-        _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-            "`exp_dig` attribute: expecting 8 because `mant_dig` is 24.");
-        ret = -EPERM;
-        goto error;
-    }
-
-    if (mant_dig == 53 && exp_dig != 11) {
-        _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-            "`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(&(*float_decl)->base.base);
-    *float_decl = NULL;
-    return ret;
-}
-
-static int visit_string_decl(struct ctf_visitor_generate_ir *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_COMP_LOGE_APPEND_CAUSE_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") == 0) {
-            char *s_right;
-
-            if (_IS_SET(&set, _STRING_ENCODING_SET)) {
-                _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(left, "encoding", "string field class");
-                ret = -EPERM;
-                goto error;
-            }
-
-            if (right->u.unary_expression.type != UNARY_STRING) {
-                _BT_COMP_LOGE_APPEND_CAUSE_NODE(
-                    right, "Invalid `encoding` attribute in string field class: "
-                           "expecting unary string.");
-                ret = -EINVAL;
-                goto error;
-            }
-
-            s_right = ctf_ast_concatenate_unary_strings(&expression->u.ctf_expression.right);
-            if (!s_right) {
-                _BT_COMP_LOGE_APPEND_CAUSE_NODE(
-                    right,
-                    "Unexpected unary expression for string field class's `encoding` attribute.");
-                ret = -EINVAL;
-                goto error;
-            }
-
-            if (strcmp(s_right, "UTF8") == 0 || strcmp(s_right, "utf8") == 0 ||
-                strcmp(s_right, "utf-8") == 0 || strcmp(s_right, "UTF-8") == 0 ||
-                strcmp(s_right, "ASCII") == 0 || strcmp(s_right, "ascii") == 0) {
-                encoding = CTF_ENCODING_UTF8;
-            } else if (strcmp(s_right, "none") == 0) {
-                encoding = CTF_ENCODING_NONE;
-            } else {
-                _BT_COMP_LOGE_APPEND_CAUSE_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_COMP_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(&(*string_decl)->base);
-    *string_decl = NULL;
-    return ret;
-}
-
-static int visit_field_class_specifier_list(struct ctf_visitor_generate_ir *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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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:
-    {
-        ctf_field_class_int *int_decl;
-
-        ret = visit_integer_decl(ctx, &node->u.integer.expressions, &int_decl);
-        if (ret) {
-            BT_ASSERT(!int_decl);
-            goto error;
-        }
-
-        *decl = &int_decl->base.base;
-        break;
-    }
-    case TYPESPEC_FLOATING_POINT:
-    {
-        ctf_field_class_float *float_decl;
-
-        ret =
-            visit_floating_point_number_decl(ctx, &node->u.floating_point.expressions, &float_decl);
-        if (ret) {
-            BT_ASSERT(!float_decl);
-            goto error;
-        }
-
-        *decl = &float_decl->base.base;
-        break;
-    }
-    case TYPESPEC_STRING:
-    {
-        ctf_field_class_string *string_decl;
-
-        ret = visit_string_decl(ctx, &node->u.string.expressions, &string_decl);
-        if (ret) {
-            BT_ASSERT(!string_decl);
-            goto error;
-        }
-
-        *decl = &string_decl->base;
-        break;
-    }
-    case TYPESPEC_STRUCT:
-    {
-        ctf_field_class_struct *struct_decl;
-
-        ret = visit_struct_decl(ctx, node->u._struct.name, &node->u._struct.declaration_list,
-                                node->u._struct.has_body, &node->u._struct.min_align, &struct_decl);
-        if (ret) {
-            BT_ASSERT(!struct_decl);
-            goto error;
-        }
-
-        *decl = &struct_decl->base;
-        break;
-    }
-    case TYPESPEC_VARIANT:
-    {
-        ctf_field_class_variant *variant_decl;
-
-        ret = visit_variant_decl(ctx, node->u.variant.name, node->u.variant.choice,
-                                 &node->u.variant.declaration_list, node->u.variant.has_body,
-                                 &variant_decl);
-        if (ret) {
-            BT_ASSERT(!variant_decl);
-            goto error;
-        }
-
-        *decl = &variant_decl->base;
-        break;
-    }
-    case TYPESPEC_ENUM:
-    {
-        ctf_field_class_enum *enum_decl;
-
-        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, &enum_decl);
-        if (ret) {
-            BT_ASSERT(!enum_decl);
-            goto error;
-        }
-
-        *decl = &enum_decl->base.base.base;
-        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_COMP_LOGE_APPEND_CAUSE_NODE(first, "Cannot visit field class specifier: ret=%d",
-                                            ret);
-            BT_ASSERT(!*decl);
-            goto error;
-        }
-        break;
-    default:
-        _BT_COMP_LOGE_APPEND_CAUSE_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(*decl);
-    *decl = NULL;
-    return ret;
-}
-
-static int visit_event_decl_entry(struct ctf_visitor_generate_ir *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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_NODE(node,
-                                            "Cannot add field class alias found in event class.");
-            goto error;
-        }
-        break;
-    case NODE_CTF_EXPRESSION:
-    {
-        left = ctf_ast_concatenate_unary_strings(&node->u.ctf_expression.left);
-        if (!left) {
-            _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Cannot concatenate unary strings.");
-            ret = -EINVAL;
-            goto error;
-        }
-
-        if (strcmp(left, "name") == 0) {
-            /* This is already known at this stage */
-            if (_IS_SET(set, _EVENT_NAME_SET)) {
-                _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(node, "name", "event class");
-                ret = -EPERM;
-                goto error;
-            }
-
-            _SET(set, _EVENT_NAME_SET);
-        } else if (strcmp(left, "id") == 0) {
-            int64_t id = -1;
-
-            if (_IS_SET(set, _EVENT_ID_SET)) {
-                _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(node, "id", "event class");
-                ret = -EPERM;
-                goto error;
-            }
-
-            ret = get_unary_unsigned(ctx, &node->u.ctf_expression.right, (uint64_t *) &id);
-            /* Only read "id" if get_unary_unsigned() succeeded. */
-            if (ret || (!ret && id < 0)) {
-                _BT_COMP_LOGE_APPEND_CAUSE_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") == 0) {
-            if (_IS_SET(set, _EVENT_STREAM_ID_SET)) {
-                _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(node, "stream_id", "event class");
-                ret = -EPERM;
-                goto error;
-            }
-
-            ret = get_unary_unsigned(ctx, &node->u.ctf_expression.right, stream_id);
-
-            /*
-             * Only read "stream_id" if get_unary_unsigned()
-             * succeeded.
-             */
-            if (ret) {
-                _BT_COMP_LOGE_APPEND_CAUSE_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") == 0) {
-            if (_IS_SET(set, _EVENT_CONTEXT_SET)) {
-                _BT_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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") == 0) {
-            if (_IS_SET(set, _EVENT_FIELDS_SET)) {
-                _BT_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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") == 0) {
-            uint64_t loglevel_value;
-            bool is_log_level_known = true;
-            bt_event_class_log_level log_level;
-
-            if (_IS_SET(set, _EVENT_LOG_LEVEL_SET)) {
-                _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(node, "loglevel", "event class");
-                ret = -EPERM;
-                goto error;
-            }
-
-            ret = get_unary_unsigned(ctx, &node->u.ctf_expression.right, &loglevel_value);
-            if (ret) {
-                _BT_COMP_LOGE_APPEND_CAUSE_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:
-                is_log_level_known = false;
-                _BT_COMP_LOGW_NODE(
-                    node,
-                    "Not setting event class's log level because its value is unknown: "
-                    "log-level=%" PRIu64,
-                    loglevel_value);
-            }
-
-            if (is_log_level_known) {
-                ctf_event_class_set_log_level(event_class, log_level);
-            }
-
-            _SET(set, _EVENT_LOG_LEVEL_SET);
-        } else if (strcmp(left, "model.emf.uri") == 0) {
-            char *right;
-
-            if (_IS_SET(set, _EVENT_MODEL_EMF_URI_SET)) {
-                _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(node, "model.emf.uri", "event class");
-                ret = -EPERM;
-                goto error;
-            }
-
-            right = ctf_ast_concatenate_unary_strings(&node->u.ctf_expression.right);
-            if (!right) {
-                _BT_COMP_LOGE_APPEND_CAUSE_NODE(
-                    node,
-                    "Unexpected unary expression for event class's `model.emf.uri` attribute.");
-                ret = -EINVAL;
-                goto error;
-            }
-
-            if (strlen(right) == 0) {
-                _BT_COMP_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_COMP_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:
-    g_free(left);
-
-end:
-    return ret;
-}
-
-static char *get_event_decl_name(struct ctf_visitor_generate_ir *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 = ctf_ast_concatenate_unary_strings(&iter->u.ctf_expression.left);
-        if (!left) {
-            _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter, "Cannot concatenate unary strings.");
-            goto error;
-        }
-
-        if (strcmp(left, "name") == 0) {
-            name = ctf_ast_concatenate_unary_strings(&iter->u.ctf_expression.right);
-            if (!name) {
-                _BT_COMP_LOGE_APPEND_CAUSE_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 ctf_visitor_generate_ir *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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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 = (ctf_stream_class *) ctx->ctf_tc->stream_classes->pdata[0];
-            stream_id = stream_class->id;
-            break;
-        default:
-            _BT_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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);
-    }
-
-    g_free(event_name);
-
-    return ret;
-}
-
-static int auto_map_field_to_trace_clock_class(struct ctf_visitor_generate_ir *ctx,
-                                               struct ctf_field_class *fc)
-{
-    struct ctf_clock_class *clock_class_to_map_to = NULL;
-    uint64_t clock_class_count;
-
-    if (!fc) {
-        return 0;
-    }
-
-    if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
-        return 0;
-    }
-
-    ctf_field_class_int *int_fc = ctf_field_class_as_int(fc);
-
-    if (int_fc->mapped_clock_class) {
-        /* Already mapped */
-        return 0;
-    }
-
-    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");
-        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 = (ctf_clock_class *) 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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-            "Timestamp field found with no mapped clock class, "
-            "but there's more than one clock class in the trace at this point.");
-        return -1;
-    }
-
-    BT_ASSERT(clock_class_to_map_to);
-    int_fc->mapped_clock_class = clock_class_to_map_to;
-
-    return 0;
-}
-
-static int auto_map_fields_to_trace_clock_class(struct ctf_visitor_generate_ir *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 = (ctf_field_class_struct *) root_fc;
-    struct ctf_field_class_variant *var_fc = (ctf_field_class_variant *) 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);
-        } else {
-            bt_common_abort();
-        }
-
-        if (strcmp(named_fc->name->str, field_name) == 0) {
-            ret = auto_map_field_to_trace_clock_class(ctx, named_fc->fc);
-            if (ret) {
-                _BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                    "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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                "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 ctf_visitor_generate_ir *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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_NODE(node,
-                                            "Cannot add field class alias found in stream class.");
-            goto error;
-        }
-        break;
-    case NODE_CTF_EXPRESSION:
-    {
-        left = ctf_ast_concatenate_unary_strings(&node->u.ctf_expression.left);
-        if (!left) {
-            _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Cannot concatenate unary strings.");
-            ret = -EINVAL;
-            goto error;
-        }
-
-        if (strcmp(left, "id") == 0) {
-            int64_t id;
-
-            if (_IS_SET(set, _STREAM_ID_SET)) {
-                _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(node, "id", "stream declaration");
-                ret = -EPERM;
-                goto error;
-            }
-
-            ret = get_unary_unsigned(ctx, &node->u.ctf_expression.right, (uint64_t *) &id);
-
-            /* Only read "id" if get_unary_unsigned() succeeded. */
-            if (ret || (!ret && id < 0)) {
-                _BT_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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") == 0) {
-            if (_IS_SET(set, _STREAM_EVENT_HEADER_SET)) {
-                _BT_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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") == 0) {
-            if (_IS_SET(set, _STREAM_EVENT_CONTEXT_SET)) {
-                _BT_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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") == 0) {
-            if (_IS_SET(set, _STREAM_PACKET_CONTEXT_SET)) {
-                _BT_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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_COMP_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 ctf_visitor_generate_ir *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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_NODE(node, "Stream class has a `id` attribute, "
-                                                  "but trace has no packet header field class.");
-            ret = -EINVAL;
-            goto error;
-        }
-
-        named_fc = ctf_field_class_struct_borrow_member_by_name(
-            ctf_field_class_as_struct(ctx->ctf_tc->packet_header_fc), "stream_id");
-        if (!named_fc) {
-            _BT_COMP_LOGE_APPEND_CAUSE_NODE(
-                node, "Stream class has a `id` attribute, "
-                      "but trace's packet header field class has no `stream_id` field.");
-            ret = -EINVAL;
-            goto error;
-        }
-
-        if (named_fc->fc->type != CTF_FIELD_CLASS_TYPE_INT &&
-            named_fc->fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
-            _BT_COMP_LOGE_APPEND_CAUSE_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.");
-            ret = -EINVAL;
-            goto error;
-        }
-    } else {
-        /* Allow only _one_ ID-less stream */
-        if (ctx->ctf_tc->stream_classes->len != 0) {
-            _BT_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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 ctf_visitor_generate_ir *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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_NODE(
-                node, "Cannot add field class alias found in trace (`trace` block).");
-            goto error;
-        }
-        break;
-    case NODE_CTF_EXPRESSION:
-    {
-        left = ctf_ast_concatenate_unary_strings(&node->u.ctf_expression.left);
-        if (!left) {
-            _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Cannot concatenate unary strings.");
-            ret = -EINVAL;
-            goto error;
-        }
-
-        if (strcmp(left, "major") == 0) {
-            if (_IS_SET(set, _TRACE_MAJOR_SET)) {
-                _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(node, "major", "trace");
-                ret = -EPERM;
-                goto error;
-            }
-
-            ret = get_unary_unsigned(ctx, &node->u.ctf_expression.right, &val);
-            if (ret) {
-                _BT_COMP_LOGE_APPEND_CAUSE_NODE(
-                    node, "Unexpected unary expression for trace's `major` attribute.");
-                ret = -EINVAL;
-                goto error;
-            }
-
-            if (val != 1) {
-                _BT_COMP_LOGE_APPEND_CAUSE_NODE(node,
-                                                "Invalid trace's `minor` attribute: expecting 1.");
-                ret = -EINVAL;
-                goto error;
-            }
-
-            ctx->ctf_tc->major = val;
-            _SET(set, _TRACE_MAJOR_SET);
-        } else if (strcmp(left, "minor") == 0) {
-            if (_IS_SET(set, _TRACE_MINOR_SET)) {
-                _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(node, "minor", "trace");
-                ret = -EPERM;
-                goto error;
-            }
-
-            ret = get_unary_unsigned(ctx, &node->u.ctf_expression.right, &val);
-            if (ret) {
-                _BT_COMP_LOGE_APPEND_CAUSE_NODE(
-                    node, "Unexpected unary expression for trace's `minor` attribute.");
-                ret = -EINVAL;
-                goto error;
-            }
-
-            if (val != 8) {
-                _BT_COMP_LOGE_APPEND_CAUSE_NODE(node,
-                                                "Invalid trace's `minor` attribute: expecting 8.");
-                ret = -EINVAL;
-                goto error;
-            }
-
-            ctx->ctf_tc->minor = val;
-            _SET(set, _TRACE_MINOR_SET);
-        } else if (strcmp(left, "uuid") == 0) {
-            if (_IS_SET(set, _TRACE_UUID_SET)) {
-                _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(node, "uuid", "trace");
-                ret = -EPERM;
-                goto error;
-            }
-
-            ret = get_unary_uuid(ctx, &node->u.ctf_expression.right, ctx->ctf_tc->uuid);
-            if (ret) {
-                _BT_COMP_LOGE_APPEND_CAUSE_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") == 0) {
-            /* Default byte order is already known at this stage */
-            if (_IS_SET(set, _TRACE_BYTE_ORDER_SET)) {
-                _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(node, "byte_order", "trace");
-                ret = -EPERM;
-                goto error;
-            }
-
-            BT_ASSERT(ctx->ctf_tc->default_byte_order != CTF_BYTE_ORDER_UNKNOWN);
-            _SET(set, _TRACE_BYTE_ORDER_SET);
-        } else if (strcmp(left, "packet.header") == 0) {
-            if (_IS_SET(set, _TRACE_PACKET_HEADER_SET)) {
-                _BT_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGW_NODE(node,
-                               "Unknown attribute in stream class: "
-                               "attr-name=\"%s\"",
-                               left);
-        }
-
-        g_free(left);
-        left = NULL;
-        break;
-    }
-    default:
-        _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Unknown expression in trace.");
-        ret = -EINVAL;
-        goto error;
-    }
-
-    return 0;
-
-error:
-    g_free(left);
-    return ret;
-}
-
-static int visit_trace_decl(struct ctf_visitor_generate_ir *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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_NODE(node,
-                                        "Missing `major` attribute in trace (`trace` block).");
-        ret = -EPERM;
-        goto error;
-    }
-
-    if (!_IS_SET(&set, _TRACE_MINOR_SET)) {
-        _BT_COMP_LOGE_APPEND_CAUSE_NODE(node,
-                                        "Missing `minor` attribute in trace (`trace` block).");
-        ret = -EPERM;
-        goto error;
-    }
-
-    if (!_IS_SET(&set, _TRACE_BYTE_ORDER_SET)) {
-        _BT_COMP_LOGE_APPEND_CAUSE_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 ctf_visitor_generate_ir *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_COMP_LOGE_APPEND_CAUSE_NODE(entry_node,
-                                            "Wrong expression in environment entry: "
-                                            "node-type=%d",
-                                            entry_node->type);
-            ret = -EPERM;
-            goto error;
-        }
-
-        left = ctf_ast_concatenate_unary_strings(&entry_node->u.ctf_expression.left);
-        if (!left) {
-            _BT_COMP_LOGE_APPEND_CAUSE_NODE(entry_node, "Cannot get environment entry's name.");
-            ret = -EINVAL;
-            goto error;
-        }
-
-        if (is_unary_string(right_head)) {
-            char *right = ctf_ast_concatenate_unary_strings(right_head);
-
-            if (!right) {
-                _BT_COMP_LOGE_APPEND_CAUSE_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_COMP_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(ctx, right_head, (uint64_t *) &v);
-            } else {
-                ret = get_unary_signed(right_head, &v);
-            }
-            if (ret) {
-                _BT_COMP_LOGE_APPEND_CAUSE_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_COMP_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 ctf_visitor_generate_ir *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 = ctf_ast_concatenate_unary_strings(&node->u.ctf_expression.left);
-            if (!left) {
-                _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Cannot concatenate unary strings.");
-                ret = -EINVAL;
-                goto error;
-            }
-
-            if (strcmp(left, "byte_order") == 0) {
-                enum ctf_byte_order bo;
-
-                if (_IS_SET(&set, _TRACE_BYTE_ORDER_SET)) {
-                    _BT_COMP_LOGE_APPEND_CAUSE_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(ctx, right_node);
-                if (bo == CTF_BYTE_ORDER_UNKNOWN) {
-                    _BT_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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 ctf_visitor_generate_ir *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_COMP_LOGE_APPEND_CAUSE_NODE(entry_node, "Unexpected node type: node-type=%d",
-                                        entry_node->type);
-        ret = -EPERM;
-        goto error;
-    }
-
-    left = ctf_ast_concatenate_unary_strings(&entry_node->u.ctf_expression.left);
-    if (!left) {
-        _BT_COMP_LOGE_APPEND_CAUSE_NODE(entry_node, "Cannot concatenate unary strings.");
-        ret = -EINVAL;
-        goto error;
-    }
-
-    if (strcmp(left, "name") == 0) {
-        char *right;
-
-        if (_IS_SET(set, _CLOCK_NAME_SET)) {
-            _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "name", "clock class");
-            ret = -EPERM;
-            goto error;
-        }
-
-        right = ctf_ast_concatenate_unary_strings(&entry_node->u.ctf_expression.right);
-        if (!right) {
-            _BT_COMP_LOGE_APPEND_CAUSE_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") == 0) {
-        bt_uuid_t uuid;
-
-        if (_IS_SET(set, _CLOCK_UUID_SET)) {
-            _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "uuid", "clock class");
-            ret = -EPERM;
-            goto error;
-        }
-
-        ret = get_unary_uuid(ctx, &entry_node->u.ctf_expression.right, uuid);
-        if (ret) {
-            _BT_COMP_LOGE_APPEND_CAUSE_NODE(entry_node, "Invalid clock class's `uuid` attribute.");
-            goto error;
-        }
-
-        clock->has_uuid = true;
-        bt_uuid_copy(clock->uuid, uuid);
-        _SET(set, _CLOCK_UUID_SET);
-    } else if (strcmp(left, "description") == 0) {
-        char *right;
-
-        if (_IS_SET(set, _CLOCK_DESCRIPTION_SET)) {
-            _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "description", "clock class");
-            ret = -EPERM;
-            goto error;
-        }
-
-        right = ctf_ast_concatenate_unary_strings(&entry_node->u.ctf_expression.right);
-        if (!right) {
-            _BT_COMP_LOGE_APPEND_CAUSE_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") == 0) {
-        uint64_t freq = UINT64_C(-1);
-
-        if (_IS_SET(set, _CLOCK_FREQ_SET)) {
-            _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "freq", "clock class");
-            ret = -EPERM;
-            goto error;
-        }
-
-        ret = get_unary_unsigned(ctx, &entry_node->u.ctf_expression.right, &freq);
-        if (ret) {
-            _BT_COMP_LOGE_APPEND_CAUSE_NODE(
-                entry_node, "Unexpected unary expression for clock class's `freq` attribute.");
-            ret = -EINVAL;
-            goto error;
-        }
-
-        if (freq == UINT64_C(-1) || freq == 0) {
-            _BT_COMP_LOGE_APPEND_CAUSE_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") == 0) {
-        uint64_t precision;
-
-        if (_IS_SET(set, _CLOCK_PRECISION_SET)) {
-            _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "precision", "clock class");
-            ret = -EPERM;
-            goto error;
-        }
-
-        ret = get_unary_unsigned(ctx, &entry_node->u.ctf_expression.right, &precision);
-        if (ret) {
-            _BT_COMP_LOGE_APPEND_CAUSE_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") == 0) {
-        if (_IS_SET(set, _CLOCK_OFFSET_S_SET)) {
-            _BT_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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") == 0) {
-        if (_IS_SET(set, _CLOCK_OFFSET_SET)) {
-            _BT_COMP_LOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "offset", "clock class");
-            ret = -EPERM;
-            goto error;
-        }
-
-        ret = get_unary_unsigned(ctx, &entry_node->u.ctf_expression.right, offset_cycles);
-        if (ret) {
-            _BT_COMP_LOGE_APPEND_CAUSE_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") == 0) {
-        struct ctf_node *right;
-
-        if (_IS_SET(set, _CLOCK_ABSOLUTE_SET)) {
-            _BT_COMP_LOGE_APPEND_CAUSE_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(ctx, right);
-        if (ret < 0) {
-            _BT_COMP_LOGE_APPEND_CAUSE_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_COMP_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_is_absolute(struct ctf_visitor_generate_ir *ctx,
-                                          struct ctf_clock_class *clock)
-{
-    if (ctx->decoder_config.force_clock_class_origin_unix_epoch) {
-        clock->is_absolute = true;
-    }
-
-    return;
-}
-
-static void apply_clock_class_offset(struct ctf_visitor_generate_ir *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 ctf_visitor_generate_ir *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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_NODE(entry_node, "Cannot visit clock class's entry: ret=%d",
-                                            ret);
-            goto end;
-        }
-    }
-
-    if (!_IS_SET(&set, _CLOCK_NAME_SET)) {
-        _BT_COMP_LOGE_APPEND_CAUSE_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);
-    apply_clock_class_is_absolute(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 ctf_visitor_generate_ir *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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_NODE(root_decl_node, "Unexpected node type: node-type=%d",
-                                        root_decl_node->type);
-        ret = -EPERM;
-        goto end;
-    }
-
-end:
-    return ret;
-}
-
-struct ctf_visitor_generate_ir *
-ctf_visitor_generate_ir_create(const struct ctf_metadata_decoder_config *decoder_config)
-{
-    struct ctf_visitor_generate_ir *ctx = NULL;
-
-    /* Create visitor's context */
-    ctx = ctx_create(decoder_config);
-    if (!ctx) {
-        BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, decoder_config->log_level, decoder_config->self_comp,
-                            "Cannot create visitor's context.");
-        goto error;
-    }
-
-    goto end;
-
-error:
-    ctx_destroy(ctx);
-    ctx = NULL;
-
-end:
-    return ctx;
-}
-
-void ctf_visitor_generate_ir_destroy(struct ctf_visitor_generate_ir *visitor)
-{
-    ctx_destroy(visitor);
-}
-
-bt_trace_class *ctf_visitor_generate_ir_get_ir_trace_class(struct ctf_visitor_generate_ir *ctx)
-{
-    BT_ASSERT_DBG(ctx);
-
-    if (ctx->trace_class) {
-        bt_trace_class_get_ref(ctx->trace_class);
-    }
-
-    return ctx->trace_class;
-}
-
-struct ctf_trace_class *
-ctf_visitor_generate_ir_borrow_ctf_trace_class(struct ctf_visitor_generate_ir *ctx)
-{
-    BT_ASSERT_DBG(ctx);
-    BT_ASSERT_DBG(ctx->ctf_tc);
-    return ctx->ctf_tc;
-}
-
-int ctf_visitor_generate_ir_visit_node(struct ctf_visitor_generate_ir *ctx, struct ctf_node *node)
-{
-    int ret = 0;
-
-    BT_COMP_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 == CTF_BYTE_ORDER_UNKNOWN) {
-            bt_list_for_each_entry (iter, &node->u.root.trace, siblings) {
-                if (got_trace_decl) {
-                    _BT_COMP_LOGE_APPEND_CAUSE_NODE(node, "Duplicate trace (`trace` block).");
-                    ret = -1;
-                    goto end;
-                }
-
-                ret = set_trace_byte_order(ctx, iter);
-                if (ret) {
-                    _BT_COMP_LOGE_APPEND_CAUSE_NODE(node,
-                                                    "Cannot set trace's native byte order: "
-                                                    "ret=%d",
-                                                    ret);
-                    goto end;
-                }
-
-                got_trace_decl = true;
-            }
-
-            if (!got_trace_decl) {
-                BT_COMP_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);
-
-        /* Environment */
-        bt_list_for_each_entry (iter, &node->u.root.env, siblings) {
-            ret = visit_env(ctx, iter);
-            if (ret) {
-                _BT_COMP_LOGE_APPEND_CAUSE_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);
-
-        /*
-         * Visit clock blocks.
-         */
-        bt_list_for_each_entry (iter, &node->u.root.clock, siblings) {
-            ret = visit_clock_decl(ctx, iter);
-            if (ret) {
-                _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter, "Cannot visit clock class: ret=%d", ret);
-                goto end;
-            }
-        }
-
-        BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope);
-
-        /*
-         * 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_COMP_LOGE_APPEND_CAUSE_NODE(iter, "Cannot visit root entry: ret=%d", ret);
-                goto end;
-            }
-        }
-
-        BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope);
-
-        /* Callsite blocks are not supported */
-        bt_list_for_each_entry (iter, &node->u.root.callsite, siblings) {
-            _BT_COMP_LOGW_NODE(iter, "\"callsite\" blocks are not supported as of this version.");
-        }
-
-        BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope);
-
-        /* Trace */
-        bt_list_for_each_entry (iter, &node->u.root.trace, siblings) {
-            ret = visit_trace_decl(ctx, iter);
-            if (ret) {
-                _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter,
-                                                "Cannot visit trace (`trace` block): "
-                                                "ret=%d",
-                                                ret);
-                goto end;
-            }
-        }
-
-        BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope);
-
-        /* Streams */
-        bt_list_for_each_entry (iter, &node->u.root.stream, siblings) {
-            ret = visit_stream_decl(ctx, iter);
-            if (ret) {
-                _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter, "Cannot visit stream class: ret=%d", ret);
-                goto end;
-            }
-        }
-
-        BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope);
-
-        /* Events */
-        bt_list_for_each_entry (iter, &node->u.root.event, siblings) {
-            ret = visit_event_decl(ctx, iter);
-            if (ret) {
-                _BT_COMP_LOGE_APPEND_CAUSE_NODE(iter, "Cannot visit event class: ret=%d", ret);
-                goto end;
-            }
-        }
-
-        BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope);
-        break;
-    }
-    default:
-        _BT_COMP_LOGE_APPEND_CAUSE_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, &ctx->log_cfg);
-    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;
-    }
-
-    /* Update structure/array/sequence alignments */
-    ret = ctf_trace_class_update_alignments(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, &ctx->log_cfg);
-    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, &ctx->log_cfg);
-    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, &ctx->log_cfg);
-
-    if (ctx->trace_class) {
-        /* Copy new CTF metadata -> new IR metadata */
-        ret = ctf_trace_class_translate(ctx->log_cfg.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.cpp b/src/plugins/ctf/common/metadata/visitor-parent-links.cpp
deleted file mode 100644 (file)
index 84c504f..0000000
+++ /dev/null
@@ -1,441 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright 2010 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Common Trace Format Metadata Parent Link Creator.
- */
-
-#include <errno.h>
-
-#define BT_COMP_LOG_SELF_COMP (log_cfg->self_comp)
-#define BT_LOG_OUTPUT_LEVEL   (log_cfg->log_level)
-#define BT_LOG_TAG            "PLUGIN/CTF/META/PARENT-LINKS-VISITOR"
-#include "logging.hpp"
-
-#include "common/list.h"
-
-#include "ast.hpp"
-
-static int ctf_visitor_unary_expression(int depth, struct ctf_node *node,
-                                        struct meta_log_config *log_cfg)
-{
-    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_COMP_LOGE_APPEND_CAUSE_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, log_cfg);
-        if (ret)
-            return ret;
-        break;
-
-    case UNARY_UNKNOWN:
-    default:
-        _BT_COMP_LOGE_APPEND_CAUSE_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,
-                                      struct meta_log_config *log_cfg)
-{
-    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, log_cfg);
-        if (ret)
-            return ret;
-        break;
-
-    case TYPESPEC_UNKNOWN:
-    default:
-        _BT_COMP_LOGE_APPEND_CAUSE_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,
-                                              struct meta_log_config *log_cfg)
-{
-    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, log_cfg);
-        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, log_cfg);
-            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, log_cfg);
-                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,
-                                           log_cfg);
-            if (ret)
-                return ret;
-        }
-        break;
-    case TYPEDEC_UNKNOWN:
-    default:
-        _BT_COMP_LOGE_APPEND_CAUSE_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, struct meta_log_config *log_cfg)
-{
-    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, log_cfg);
-            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, log_cfg);
-            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, log_cfg);
-            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, log_cfg);
-            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, log_cfg);
-            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, log_cfg);
-            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, log_cfg);
-            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, log_cfg);
-            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, log_cfg);
-            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, log_cfg);
-            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, log_cfg);
-            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, log_cfg);
-            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, log_cfg);
-            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, log_cfg);
-            if (ret)
-                return ret;
-        }
-        depth--;
-        break;
-    case NODE_UNARY_EXPRESSION:
-        return ctf_visitor_unary_expression(depth, node, log_cfg);
-
-    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, log_cfg);
-        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, log_cfg);
-            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, log_cfg);
-        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, log_cfg);
-            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, log_cfg);
-        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, log_cfg);
-            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, log_cfg);
-        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, log_cfg);
-        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, log_cfg);
-            if (ret)
-                return ret;
-        }
-        break;
-
-    case NODE_TYPE_SPECIFIER:
-        ret = ctf_visitor_type_specifier(depth, node, log_cfg);
-        if (ret)
-            return ret;
-        break;
-    case NODE_POINTER:
-        break;
-    case NODE_TYPE_DECLARATOR:
-        ret = ctf_visitor_field_class_declarator(depth, node, log_cfg);
-        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, log_cfg);
-            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, log_cfg);
-            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, log_cfg);
-            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, log_cfg);
-            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, log_cfg);
-            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, log_cfg);
-            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, log_cfg);
-        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, log_cfg);
-            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, log_cfg);
-            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, log_cfg);
-            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, log_cfg);
-            if (ret)
-                return ret;
-        }
-        break;
-
-    case NODE_UNKNOWN:
-    default:
-        _BT_COMP_LOGE_APPEND_CAUSE_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.cpp b/src/plugins/ctf/common/metadata/visitor-semantic-validator.cpp
deleted file mode 100644 (file)
index 4fad136..0000000
+++ /dev/null
@@ -1,996 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright 2010 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Common Trace Format Metadata Semantic Validator.
- */
-
-#include <errno.h>
-
-#define BT_COMP_LOG_SELF_COMP (log_cfg->self_comp)
-#define BT_LOG_OUTPUT_LEVEL   (log_cfg->log_level)
-#define BT_LOG_TAG            "PLUGIN/CTF/META/SEMANTIC-VALIDATOR-VISITOR"
-#include "logging.hpp"
-
-#include "common/list.h"
-
-#include "ast.hpp"
-
-#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,
-                                       struct meta_log_config *log_cfg);
-
-static int ctf_visitor_unary_expression(int, struct ctf_node *node, struct meta_log_config *log_cfg)
-{
-    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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_LINENO(
-                node->lineno,
-                "Link `...` is not allowed on the first node of the unary expression list.");
-            goto errperm;
-        }
-        break;
-    default:
-        _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, "Unknown expression link type: type=%d",
-                                          node->u.unary_expression.link);
-        return -EINVAL;
-    }
-    return 0;
-
-errinval:
-    _BT_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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, struct ctf_node *node,
-                                                  struct meta_log_config *log_cfg)
-{
-    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_COMP_LOGE_APPEND_CAUSE_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, struct ctf_node *node,
-                                             struct meta_log_config *log_cfg)
-{
-    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_COMP_LOGE_APPEND_CAUSE_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,
-                                              struct meta_log_config *log_cfg)
-{
-    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)
-            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, log_cfg);
-        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, log_cfg);
-            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_COMP_LOGE_APPEND_CAUSE_LINENO(
-                        node->lineno, "Expecting unary expression as length: node-type=%s",
-                        node_type(iter));
-                    return -EINVAL;
-                }
-                ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg);
-                if (ret)
-                    return ret;
-            }
-        } else {
-            if (node->parent->type == NODE_TYPEALIAS_TARGET) {
-                _BT_COMP_LOGE_APPEND_CAUSE_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, log_cfg);
-            if (ret)
-                return ret;
-        }
-        break;
-    }
-    case TYPEDEC_UNKNOWN:
-    default:
-        _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, "Unknown field class declarator: type=%d",
-                                          node->u.field_class_declarator.type);
-        return -EINVAL;
-    }
-    depth--;
-    return 0;
-
-errinval:
-    _BT_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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,
-                                       struct meta_log_config *log_cfg)
-{
-    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, log_cfg);
-            if (ret)
-                return ret;
-        }
-        bt_list_for_each_entry (iter, &node->u.root.trace, siblings) {
-            ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg);
-            if (ret)
-                return ret;
-        }
-        bt_list_for_each_entry (iter, &node->u.root.stream, siblings) {
-            ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg);
-            if (ret)
-                return ret;
-        }
-        bt_list_for_each_entry (iter, &node->u.root.event, siblings) {
-            ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg);
-            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, log_cfg);
-            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, log_cfg);
-            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, log_cfg);
-            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, log_cfg);
-            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, log_cfg);
-            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, log_cfg);
-            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, log_cfg);
-            if (ret)
-                return ret;
-        }
-        bt_list_for_each_entry (iter, &node->u.ctf_expression.right, siblings) {
-            ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg);
-            if (ret)
-                return ret;
-        }
-        depth--;
-        break;
-    case NODE_UNARY_EXPRESSION:
-        return ctf_visitor_unary_expression(depth, node, log_cfg);
-
-    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, log_cfg);
-        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, log_cfg);
-            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, log_cfg);
-        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, log_cfg);
-            if (ret)
-                return ret;
-            nr_declarators++;
-        }
-        if (nr_declarators > 1) {
-            _BT_COMP_LOGE_APPEND_CAUSE_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, log_cfg);
-        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, log_cfg);
-            if (ret)
-                return ret;
-            nr_declarators++;
-        }
-        if (nr_declarators > 1) {
-            _BT_COMP_LOGE_APPEND_CAUSE_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, log_cfg);
-        if (ret)
-            return ret;
-        ret = _ctf_visitor_semantic_check(depth + 1, node->u.field_class_alias.alias, log_cfg);
-        if (ret)
-            return ret;
-        break;
-
-    case NODE_TYPE_SPECIFIER_LIST:
-        ret = ctf_visitor_field_class_specifier_list(depth, node, log_cfg);
-        if (ret)
-            return ret;
-        break;
-    case NODE_TYPE_SPECIFIER:
-        ret = ctf_visitor_field_class_specifier(depth, node, log_cfg);
-        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, log_cfg);
-        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, log_cfg);
-            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, log_cfg);
-            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, log_cfg);
-            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_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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, log_cfg);
-            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, log_cfg);
-        if (ret)
-            return ret;
-
-        bt_list_for_each_entry (iter, &node->u._enum.enumerator_list, siblings) {
-            ret = _ctf_visitor_semantic_check(depth + 1, iter, log_cfg);
-            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, log_cfg);
-        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, log_cfg);
-            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, log_cfg);
-            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, log_cfg);
-            if (ret)
-                return ret;
-        }
-        break;
-
-    case NODE_UNKNOWN:
-    default:
-        _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno, "Unknown node type: type=%d", node->type);
-        return -EINVAL;
-    }
-    return ret;
-
-errinval:
-    _BT_COMP_LOGE_APPEND_CAUSE_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_COMP_LOGE_APPEND_CAUSE_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, struct meta_log_config *log_cfg)
-{
-    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, log_cfg);
-    if (ret) {
-        _BT_COMP_LOGE_APPEND_CAUSE_LINENO(node->lineno,
-                                          "Cannot create parent links in metadata's AST: "
-                                          "ret=%d",
-                                          ret);
-        goto end;
-    }
-
-    ret = _ctf_visitor_semantic_check(depth, node, log_cfg);
-    if (ret) {
-        _BT_COMP_LOGE_APPEND_CAUSE_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/msg-iter.cpp b/src/plugins/ctf/common/msg-iter/msg-iter.cpp
deleted file mode 100644 (file)
index 33ad4a2..0000000
+++ /dev/null
@@ -1,3008 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright (c) 2015-2018 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2015-2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Babeltrace - CTF message iterator
- */
-
-#include <glib.h>
-#include <inttypes.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-
-#include <babeltrace2/babeltrace.h>
-
-#define BT_COMP_LOG_SELF_COMP (msg_it->self_comp)
-#define BT_LOG_OUTPUT_LEVEL   (msg_it->log_level)
-#define BT_LOG_TAG            "PLUGIN/CTF/MSG-ITER"
-#include "logging/comp-logging.h"
-
-#include "common/assert.h"
-#include "common/common.h"
-
-#include "../bfcr/bfcr.hpp"
-#include "msg-iter.hpp"
-#include "plugins/ctf/common/metadata/ctf-meta.hpp"
-
-/* 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
-{
-    struct ctf_msg_iter *msg_it;
-
-    /* Entries (struct stack_entry) */
-    GArray *entries;
-
-    /* Number of active entries */
-    size_t size;
-};
-
-/* State */
-enum state
-{
-    STATE_INIT,
-    STATE_SWITCH_PACKET,
-    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_EMIT_MSG_STREAM_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_EMIT_QUEUED_MSG_EVENT,
-    STATE_SKIP_PACKET_PADDING,
-    STATE_EMIT_MSG_PACKET_END_MULTI,
-    STATE_EMIT_MSG_PACKET_END_SINGLE,
-    STATE_EMIT_QUEUED_MSG_PACKET_END,
-    STATE_CHECK_EMIT_MSG_STREAM_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 ctf_msg_iter
-{
-    /* Visit stack */
-    struct stack *stack;
-
-    /* Current message iterator to create messages (weak) */
-    bt_self_message_iterator *self_msg_iter;
-
-    /*
-     * True if library objects are unavailable during the decoding and
-     * should not be created/used.
-     */
-    bool dry_run;
-
-    /*
-     * 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 (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;
-
-    /*
-     * True if we need to emit a packet beginning message before we emit
-     * the next event message or the packet end message.
-     */
-    bool emit_delayed_packet_beginning_msg;
-
-    /*
-     * True if this is the first packet we are reading, and therefore if we
-     * should emit a stream beginning message.
-     */
-    bool emit_stream_beginning_message;
-
-    /*
-     * True if we need to emit a stream end message at the end of the
-     * current stream. A live stream may never receive any data and thus
-     * never send a stream beginning message which removes the need to emit
-     * a stream end message.
-     */
-    bool emit_stream_end_message;
-
-    /* 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 ctf_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;
-
-    /* Iterator's current log level */
-    bt_logging_level log_level;
-
-    /* Iterator's owning self component, or `NULL` if none (query) */
-    bt_self_component *self_comp;
-};
-
-static inline const char *state_string(enum state state)
-{
-    switch (state) {
-    case STATE_INIT:
-        return "INIT";
-    case STATE_SWITCH_PACKET:
-        return "SWITCH_PACKET";
-    case STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN:
-        return "DSCOPE_TRACE_PACKET_HEADER_BEGIN";
-    case STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE:
-        return "DSCOPE_TRACE_PACKET_HEADER_CONTINUE";
-    case STATE_AFTER_TRACE_PACKET_HEADER:
-        return "AFTER_TRACE_PACKET_HEADER";
-    case STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN:
-        return "DSCOPE_STREAM_PACKET_CONTEXT_BEGIN";
-    case STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE:
-        return "DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE";
-    case STATE_AFTER_STREAM_PACKET_CONTEXT:
-        return "AFTER_STREAM_PACKET_CONTEXT";
-    case STATE_EMIT_MSG_STREAM_BEGINNING:
-        return "EMIT_MSG_STREAM_BEGINNING";
-    case STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS:
-        return "CHECK_EMIT_MSG_DISCARDED_EVENTS";
-    case STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS:
-        return "CHECK_EMIT_MSG_DISCARDED_PACKETS";
-    case STATE_EMIT_MSG_PACKET_BEGINNING:
-        return "EMIT_MSG_PACKET_BEGINNING";
-    case STATE_EMIT_MSG_DISCARDED_EVENTS:
-        return "EMIT_MSG_DISCARDED_EVENTS";
-    case STATE_EMIT_MSG_DISCARDED_PACKETS:
-        return "EMIT_MSG_DISCARDED_PACKETS";
-    case STATE_DSCOPE_EVENT_HEADER_BEGIN:
-        return "DSCOPE_EVENT_HEADER_BEGIN";
-    case STATE_DSCOPE_EVENT_HEADER_CONTINUE:
-        return "DSCOPE_EVENT_HEADER_CONTINUE";
-    case STATE_AFTER_EVENT_HEADER:
-        return "AFTER_EVENT_HEADER";
-    case STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN:
-        return "DSCOPE_EVENT_COMMON_CONTEXT_BEGIN";
-    case STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE:
-        return "DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE";
-    case STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN:
-        return "DSCOPE_EVENT_SPEC_CONTEXT_BEGIN";
-    case STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE:
-        return "DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE";
-    case STATE_DSCOPE_EVENT_PAYLOAD_BEGIN:
-        return "DSCOPE_EVENT_PAYLOAD_BEGIN";
-    case STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE:
-        return "DSCOPE_EVENT_PAYLOAD_CONTINUE";
-    case STATE_EMIT_MSG_EVENT:
-        return "EMIT_MSG_EVENT";
-    case STATE_EMIT_QUEUED_MSG_EVENT:
-        return "EMIT_QUEUED_MSG_EVENT";
-    case STATE_SKIP_PACKET_PADDING:
-        return "SKIP_PACKET_PADDING";
-    case STATE_EMIT_MSG_PACKET_END_MULTI:
-        return "EMIT_MSG_PACKET_END_MULTI";
-    case STATE_EMIT_MSG_PACKET_END_SINGLE:
-        return "EMIT_MSG_PACKET_END_SINGLE";
-    case STATE_EMIT_QUEUED_MSG_PACKET_END:
-        return "EMIT_QUEUED_MSG_PACKET_END";
-    case STATE_CHECK_EMIT_MSG_STREAM_END:
-        return "CHECK_EMIT_MSG_STREAM_END";
-    case STATE_EMIT_MSG_STREAM_END:
-        return "EMIT_MSG_STREAM_END";
-    case STATE_DONE:
-        return "DONE";
-    }
-
-    bt_common_abort();
-}
-
-static struct stack *stack_new(struct ctf_msg_iter *msg_it)
-{
-    bt_self_component *self_comp = msg_it->self_comp;
-    struct stack *stack = NULL;
-
-    stack = g_new0(struct stack, 1);
-    if (!stack) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to allocate one stack.");
-        goto error;
-    }
-
-    stack->msg_it = msg_it;
-    stack->entries = g_array_new(FALSE, TRUE, sizeof(struct stack_entry));
-    if (!stack->entries) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to allocate a GArray.");
-        goto error;
-    }
-
-    BT_COMP_LOGD("Created stack: msg-it-addr=%p, stack-addr=%p", msg_it, stack);
-    goto end;
-
-error:
-    g_free(stack);
-    stack = NULL;
-
-end:
-    return stack;
-}
-
-static void stack_destroy(struct stack *stack)
-{
-    struct ctf_msg_iter *msg_it;
-
-    BT_ASSERT_DBG(stack);
-    msg_it = stack->msg_it;
-    BT_COMP_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;
-    struct ctf_msg_iter *msg_it;
-
-    BT_ASSERT_DBG(stack);
-    msg_it = stack->msg_it;
-    BT_ASSERT_DBG(base);
-    BT_COMP_LOGT("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 = &bt_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_DBG(stack);
-    return stack->size;
-}
-
-static void stack_pop(struct stack *stack)
-{
-    struct ctf_msg_iter *msg_it;
-
-    BT_ASSERT_DBG(stack);
-    BT_ASSERT_DBG(stack_size(stack));
-    msg_it = stack->msg_it;
-    BT_COMP_LOGT("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_DBG(stack);
-    BT_ASSERT_DBG(stack_size(stack));
-    return &bt_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_DBG(stack);
-    stack->size = 0;
-}
-
-static inline enum ctf_msg_iter_status
-msg_iter_status_from_m_status(enum ctf_msg_iter_medium_status m_status)
-{
-    /* They are the same */
-    return (ctf_msg_iter_status) m_status;
-}
-
-static inline size_t buf_size_bits(struct ctf_msg_iter *msg_it)
-{
-    return msg_it->buf.sz * 8;
-}
-
-static inline size_t buf_available_bits(struct ctf_msg_iter *msg_it)
-{
-    return buf_size_bits(msg_it) - msg_it->buf.at;
-}
-
-static inline size_t packet_at(struct ctf_msg_iter *msg_it)
-{
-    return msg_it->buf.packet_offset + msg_it->buf.at;
-}
-
-static inline void buf_consume_bits(struct ctf_msg_iter *msg_it, size_t incr)
-{
-    BT_COMP_LOGT("Advancing cursor: msg-it-addr=%p, cur-before=%zu, cur-after=%zu", msg_it,
-                 msg_it->buf.at, msg_it->buf.at + incr);
-    msg_it->buf.at += incr;
-}
-
-static enum ctf_msg_iter_status request_medium_bytes(struct ctf_msg_iter *msg_it)
-{
-    bt_self_component *self_comp = msg_it->self_comp;
-    uint8_t *buffer_addr = NULL;
-    size_t buffer_sz = 0;
-    enum ctf_msg_iter_medium_status m_status;
-
-    BT_COMP_LOGD("Calling user function (request bytes): msg-it-addr=%p, "
-                 "request-size=%zu",
-                 msg_it, msg_it->medium.max_request_sz);
-    m_status = msg_it->medium.medops.request_bytes(msg_it->medium.max_request_sz, &buffer_addr,
-                                                   &buffer_sz, msg_it->medium.data);
-    BT_COMP_LOGD("User function returned: status=%s, buf-addr=%p, buf-size=%zu",
-                 ctf_msg_iter_medium_status_string(m_status), buffer_addr, buffer_sz);
-    if (m_status == CTF_MSG_ITER_MEDIUM_STATUS_OK) {
-        BT_ASSERT(buffer_sz != 0);
-
-        /* New packet offset is old one + old size (in bits) */
-        msg_it->buf.packet_offset += buf_size_bits(msg_it);
-
-        /* Restart at the beginning of the new medium buffer */
-        msg_it->buf.at = 0;
-        msg_it->buf.last_eh_at = SIZE_MAX;
-
-        /* New medium buffer size */
-        msg_it->buf.sz = buffer_sz;
-
-        /* New medium buffer address */
-        msg_it->buf.addr = buffer_addr;
-
-        BT_COMP_LOGD("User function returned new bytes: "
-                     "packet-offset=%zu, cur=%zu, size=%zu, addr=%p",
-                     msg_it->buf.packet_offset, msg_it->buf.at, msg_it->buf.sz, msg_it->buf.addr);
-        BT_COMP_LOGT_MEM(buffer_addr, buffer_sz, "Returned bytes at %p:", buffer_addr);
-    } else if (m_status == CTF_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 (msg_it->cur_exp_packet_total_size >= 0) {
-            if (packet_at(msg_it) == msg_it->cur_exp_packet_total_size) {
-                goto end;
-            }
-        } else {
-            if (packet_at(msg_it) == 0) {
-                goto end;
-            }
-
-            if (msg_it->buf.last_eh_at != SIZE_MAX && msg_it->buf.at == msg_it->buf.last_eh_at) {
-                goto end;
-            }
-        }
-
-        /* All other states are invalid */
-        BT_COMP_LOGE_APPEND_CAUSE(
-            self_comp,
-            "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",
-            ctf_msg_iter_medium_status_string(m_status), state_string(msg_it->state),
-            msg_it->cur_exp_packet_total_size, msg_it->buf.at, packet_at(msg_it),
-            msg_it->buf.last_eh_at);
-        m_status = CTF_MSG_ITER_MEDIUM_STATUS_ERROR;
-    } else if (m_status < 0) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "User function failed: "
-                                  "status=%s",
-                                  ctf_msg_iter_medium_status_string(m_status));
-    }
-
-end:
-    return msg_iter_status_from_m_status(m_status);
-}
-
-static inline enum ctf_msg_iter_status buf_ensure_available_bits(struct ctf_msg_iter *msg_it)
-{
-    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
-
-    if (G_UNLIKELY(buf_available_bits(msg_it) == 0)) {
-        /*
-         * This _cannot_ return CTF_MSG_ITER_STATUS_OK
-         * _and_ no bits.
-         */
-        status = request_medium_bytes(msg_it);
-    }
-
-    return status;
-}
-
-static enum ctf_msg_iter_status
-read_dscope_begin_state(struct ctf_msg_iter *msg_it, struct ctf_field_class *dscope_fc,
-                        enum state done_state, enum state continue_state, bt_field *dscope_field)
-{
-    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
-    bt_self_component *self_comp = msg_it->self_comp;
-    enum bt_bfcr_status bfcr_status;
-    size_t consumed_bits;
-
-    msg_it->cur_dscope_field = dscope_field;
-    BT_COMP_LOGT("Starting BFCR: msg-it-addr=%p, bfcr-addr=%p, fc-addr=%p", msg_it, msg_it->bfcr,
-                 dscope_fc);
-    consumed_bits = bt_bfcr_start(msg_it->bfcr, dscope_fc, msg_it->buf.addr, msg_it->buf.at,
-                                  packet_at(msg_it), msg_it->buf.sz, &bfcr_status);
-    BT_COMP_LOGT("BFCR consumed bits: size=%zu", consumed_bits);
-
-    switch (bfcr_status) {
-    case BT_BFCR_STATUS_OK:
-        /* Field class was read completely */
-        BT_COMP_LOGT_STR("Field was completely decoded.");
-        msg_it->state = done_state;
-        break;
-    case BT_BFCR_STATUS_EOF:
-        BT_COMP_LOGT_STR("BFCR needs more data to decode field completely.");
-        msg_it->state = continue_state;
-        break;
-    default:
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "BFCR failed to start: msg-it-addr=%p, bfcr-addr=%p, "
-                                  "status=%s",
-                                  msg_it, msg_it->bfcr, bt_bfcr_status_string(bfcr_status));
-        status = CTF_MSG_ITER_STATUS_ERROR;
-        goto end;
-    }
-
-    /* Consume bits now since we know we're not in an error state */
-    buf_consume_bits(msg_it, consumed_bits);
-
-end:
-    return status;
-}
-
-static enum ctf_msg_iter_status read_dscope_continue_state(struct ctf_msg_iter *msg_it,
-                                                           enum state done_state)
-{
-    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
-    bt_self_component *self_comp = msg_it->self_comp;
-    enum bt_bfcr_status bfcr_status;
-    size_t consumed_bits;
-
-    BT_COMP_LOGT("Continuing BFCR: msg-it-addr=%p, bfcr-addr=%p", msg_it, msg_it->bfcr);
-
-    status = buf_ensure_available_bits(msg_it);
-    if (status != CTF_MSG_ITER_STATUS_OK) {
-        if (status < 0) {
-            BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                      "Cannot ensure that buffer has at least one byte: "
-                                      "msg-addr=%p, status=%s",
-                                      msg_it, ctf_msg_iter_status_string(status));
-        } else {
-            BT_COMP_LOGT("Cannot ensure that buffer has at least one byte: "
-                         "msg-addr=%p, status=%s",
-                         msg_it, ctf_msg_iter_status_string(status));
-        }
-
-        goto end;
-    }
-
-    consumed_bits = bt_bfcr_continue(msg_it->bfcr, msg_it->buf.addr, msg_it->buf.sz, &bfcr_status);
-    BT_COMP_LOGT("BFCR consumed bits: size=%zu", consumed_bits);
-
-    switch (bfcr_status) {
-    case BT_BFCR_STATUS_OK:
-        /* Type was read completely. */
-        BT_COMP_LOGT_STR("Field was completely decoded.");
-        msg_it->state = done_state;
-        break;
-    case BT_BFCR_STATUS_EOF:
-        /* Stay in this continue state. */
-        BT_COMP_LOGT_STR("BFCR needs more data to decode field completely.");
-        break;
-    default:
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "BFCR failed to continue: msg-it-addr=%p, bfcr-addr=%p, "
-                                  "status=%s",
-                                  msg_it, msg_it->bfcr, bt_bfcr_status_string(bfcr_status));
-        status = CTF_MSG_ITER_STATUS_ERROR;
-        goto end;
-    }
-
-    /* Consume bits now since we know we're not in an error state. */
-    buf_consume_bits(msg_it, consumed_bits);
-end:
-    return status;
-}
-
-static void release_event_dscopes(struct ctf_msg_iter *msg_it)
-{
-    msg_it->dscopes.event_common_context = NULL;
-    msg_it->dscopes.event_spec_context = NULL;
-    msg_it->dscopes.event_payload = NULL;
-}
-
-static void release_all_dscopes(struct ctf_msg_iter *msg_it)
-{
-    msg_it->dscopes.stream_packet_context = NULL;
-
-    release_event_dscopes(msg_it);
-}
-
-static enum ctf_msg_iter_status switch_packet_state(struct ctf_msg_iter *msg_it)
-{
-    enum ctf_msg_iter_status status;
-    bt_self_component *self_comp = msg_it->self_comp;
-
-    /*
-     * 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(msg_it);
-
-    if (msg_it->cur_exp_packet_total_size != -1) {
-        msg_it->cur_packet_offset += msg_it->cur_exp_packet_total_size;
-    }
-
-    BT_COMP_LOGD("Switching packet: msg-it-addr=%p, cur=%zu, "
-                 "packet-offset=%" PRId64,
-                 msg_it, msg_it->buf.at, msg_it->cur_packet_offset);
-    stack_clear(msg_it->stack);
-    msg_it->meta.ec = NULL;
-    BT_PACKET_PUT_REF_AND_RESET(msg_it->packet);
-    BT_MESSAGE_PUT_REF_AND_RESET(msg_it->event_msg);
-    release_all_dscopes(msg_it);
-    msg_it->cur_dscope_field = NULL;
-
-    if (msg_it->medium.medops.switch_packet) {
-        enum ctf_msg_iter_medium_status medium_status;
-
-        medium_status = msg_it->medium.medops.switch_packet(msg_it->medium.data);
-        if (medium_status == CTF_MSG_ITER_MEDIUM_STATUS_EOF) {
-            /* No more packets. */
-            msg_it->state = STATE_CHECK_EMIT_MSG_STREAM_END;
-            status = CTF_MSG_ITER_STATUS_OK;
-            goto end;
-        } else if (medium_status != CTF_MSG_ITER_MEDIUM_STATUS_OK) {
-            status = msg_iter_status_from_m_status(medium_status);
-            goto end;
-        }
-
-        /*
-         * After the packet switch, the medium might want to give us a
-         * different buffer for the new packet.
-         */
-        status = request_medium_bytes(msg_it);
-        if (status != CTF_MSG_ITER_STATUS_OK) {
-            goto end;
-        }
-    }
-
-    /*
-     * Adjust current buffer so that addr points to the beginning of the new
-     * packet.
-     */
-    if (msg_it->buf.addr) {
-        size_t consumed_bytes = (size_t) (msg_it->buf.at / CHAR_BIT);
-
-        /* Packets are assumed to start on a byte frontier. */
-        if (msg_it->buf.at % CHAR_BIT) {
-            BT_COMP_LOGE_APPEND_CAUSE(
-                self_comp,
-                "Cannot switch packet: current position is not a multiple of 8: "
-                "msg-it-addr=%p, cur=%zu",
-                msg_it, msg_it->buf.at);
-            status = CTF_MSG_ITER_STATUS_ERROR;
-            goto end;
-        }
-
-        msg_it->buf.addr += consumed_bytes;
-        msg_it->buf.sz -= consumed_bytes;
-        msg_it->buf.at = 0;
-        msg_it->buf.packet_offset = 0;
-        BT_COMP_LOGD("Adjusted buffer: addr=%p, size=%zu", msg_it->buf.addr, msg_it->buf.sz);
-    }
-
-    msg_it->cur_exp_packet_content_size = -1;
-    msg_it->cur_exp_packet_total_size = -1;
-    msg_it->cur_stream_class_id = -1;
-    msg_it->cur_event_class_id = -1;
-    msg_it->cur_data_stream_id = -1;
-    msg_it->prev_packet_snapshots = msg_it->snapshots;
-    msg_it->snapshots.discarded_events = UINT64_C(-1);
-    msg_it->snapshots.packets = UINT64_C(-1);
-    msg_it->snapshots.beginning_clock = UINT64_C(-1);
-    msg_it->snapshots.end_clock = UINT64_C(-1);
-    msg_it->state = STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN;
-
-    status = CTF_MSG_ITER_STATUS_OK;
-end:
-    return status;
-}
-
-static enum ctf_msg_iter_status read_packet_header_begin_state(struct ctf_msg_iter *msg_it)
-{
-    struct ctf_field_class *packet_header_fc = NULL;
-    bt_self_component *self_comp = msg_it->self_comp;
-    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
-
-    /*
-     * 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.
-     */
-    status = buf_ensure_available_bits(msg_it);
-    switch (status) {
-    case CTF_MSG_ITER_STATUS_OK:
-        break;
-    case CTF_MSG_ITER_STATUS_EOF:
-        status = CTF_MSG_ITER_STATUS_OK;
-        msg_it->state = STATE_CHECK_EMIT_MSG_STREAM_END;
-        goto end;
-    default:
-        goto end;
-    }
-
-    /* Packet header class is common to the whole trace class. */
-    packet_header_fc = msg_it->meta.tc->packet_header_fc;
-    if (!packet_header_fc) {
-        msg_it->state = STATE_AFTER_TRACE_PACKET_HEADER;
-        goto end;
-    }
-
-    msg_it->cur_stream_class_id = -1;
-    msg_it->cur_event_class_id = -1;
-    msg_it->cur_data_stream_id = -1;
-    BT_COMP_LOGD("Decoding packet header field: "
-                 "msg-it-addr=%p, trace-class-addr=%p, fc-addr=%p",
-                 msg_it, msg_it->meta.tc, packet_header_fc);
-    status = read_dscope_begin_state(msg_it, packet_header_fc, STATE_AFTER_TRACE_PACKET_HEADER,
-                                     STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE, NULL);
-    if (status < 0) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "Cannot decode packet header field: "
-                                  "msg-it-addr=%p, trace-class-addr=%p, "
-                                  "fc-addr=%p",
-                                  msg_it, msg_it->meta.tc, packet_header_fc);
-    }
-
-end:
-    return status;
-}
-
-static enum ctf_msg_iter_status read_packet_header_continue_state(struct ctf_msg_iter *msg_it)
-{
-    return read_dscope_continue_state(msg_it, STATE_AFTER_TRACE_PACKET_HEADER);
-}
-
-static inline enum ctf_msg_iter_status set_current_stream_class(struct ctf_msg_iter *msg_it)
-{
-    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
-    bt_self_component *self_comp = msg_it->self_comp;
-    struct ctf_stream_class *new_stream_class = NULL;
-
-    if (msg_it->cur_stream_class_id == -1) {
-        /*
-         * No current stream class ID field, therefore only one
-         * stream class.
-         */
-        if (msg_it->meta.tc->stream_classes->len != 1) {
-            BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                      "Need exactly one stream class since there's "
-                                      "no stream class ID field: "
-                                      "msg-it-addr=%p",
-                                      msg_it);
-            status = CTF_MSG_ITER_STATUS_ERROR;
-            goto end;
-        }
-
-        new_stream_class = (ctf_stream_class *) msg_it->meta.tc->stream_classes->pdata[0];
-        msg_it->cur_stream_class_id = new_stream_class->id;
-    }
-
-    new_stream_class =
-        ctf_trace_class_borrow_stream_class_by_id(msg_it->meta.tc, msg_it->cur_stream_class_id);
-    if (!new_stream_class) {
-        BT_COMP_LOGE_APPEND_CAUSE(
-            self_comp,
-            "No stream class with ID of stream class ID to use in trace class: "
-            "msg-it-addr=%p, stream-class-id=%" PRIu64 ", "
-            "trace-class-addr=%p",
-            msg_it, msg_it->cur_stream_class_id, msg_it->meta.tc);
-        status = CTF_MSG_ITER_STATUS_ERROR;
-        goto end;
-    }
-
-    if (msg_it->meta.sc) {
-        if (new_stream_class != msg_it->meta.sc) {
-            BT_COMP_LOGE_APPEND_CAUSE(
-                self_comp,
-                "Two packets refer to two different stream classes within the same packet sequence: "
-                "msg-it-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",
-                msg_it, msg_it->meta.sc, msg_it->meta.sc->id, new_stream_class,
-                new_stream_class->id, msg_it->meta.tc);
-            status = CTF_MSG_ITER_STATUS_ERROR;
-            goto end;
-        }
-    } else {
-        msg_it->meta.sc = new_stream_class;
-    }
-
-    BT_COMP_LOGD("Set current stream class: "
-                 "msg-it-addr=%p, stream-class-addr=%p, "
-                 "stream-class-id=%" PRId64,
-                 msg_it, msg_it->meta.sc, msg_it->meta.sc->id);
-
-end:
-    return status;
-}
-
-static inline enum ctf_msg_iter_status set_current_stream(struct ctf_msg_iter *msg_it)
-{
-    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
-    bt_self_component *self_comp = msg_it->self_comp;
-    bt_stream *stream = NULL;
-
-    BT_COMP_LOGD("Calling user function (get stream): msg-it-addr=%p, "
-                 "stream-class-addr=%p, stream-class-id=%" PRId64,
-                 msg_it, msg_it->meta.sc, msg_it->meta.sc->id);
-    stream = msg_it->medium.medops.borrow_stream(msg_it->meta.sc->ir_sc, msg_it->cur_data_stream_id,
-                                                 msg_it->medium.data);
-    bt_stream_get_ref(stream);
-    BT_COMP_LOGD("User function returned: stream-addr=%p", stream);
-    if (!stream) {
-        BT_COMP_LOGE_APPEND_CAUSE(
-            self_comp,
-            "User function failed to return a stream object for the given stream class.");
-        status = CTF_MSG_ITER_STATUS_ERROR;
-        goto end;
-    }
-
-    if (msg_it->stream && stream != msg_it->stream) {
-        BT_COMP_LOGE_APPEND_CAUSE(
-            self_comp,
-            "User function returned a different stream than the previous one for the same sequence of packets.");
-        status = CTF_MSG_ITER_STATUS_ERROR;
-        goto end;
-    }
-
-    BT_STREAM_MOVE_REF(msg_it->stream, stream);
-
-end:
-    bt_stream_put_ref(stream);
-    return status;
-}
-
-static inline enum ctf_msg_iter_status set_current_packet(struct ctf_msg_iter *msg_it)
-{
-    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
-    bt_self_component *self_comp = msg_it->self_comp;
-    bt_packet *packet = NULL;
-
-    BT_COMP_LOGD("Creating packet from stream: "
-                 "msg-it-addr=%p, stream-addr=%p, "
-                 "stream-class-addr=%p, "
-                 "stream-class-id=%" PRId64,
-                 msg_it, msg_it->stream, msg_it->meta.sc, msg_it->meta.sc->id);
-
-    /* Create packet */
-    BT_ASSERT(msg_it->stream);
-    packet = bt_packet_create(msg_it->stream);
-    if (!packet) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "Cannot create packet from stream: "
-                                  "msg-it-addr=%p, stream-addr=%p, "
-                                  "stream-class-addr=%p, "
-                                  "stream-class-id=%" PRId64,
-                                  msg_it, msg_it->stream, msg_it->meta.sc, msg_it->meta.sc->id);
-        goto error;
-    }
-
-    goto end;
-
-error:
-    BT_PACKET_PUT_REF_AND_RESET(packet);
-    status = CTF_MSG_ITER_STATUS_ERROR;
-
-end:
-    BT_PACKET_MOVE_REF(msg_it->packet, packet);
-    return status;
-}
-
-static enum ctf_msg_iter_status after_packet_header_state(struct ctf_msg_iter *msg_it)
-{
-    enum ctf_msg_iter_status status;
-
-    status = set_current_stream_class(msg_it);
-    if (status != CTF_MSG_ITER_STATUS_OK) {
-        goto end;
-    }
-
-    if (!msg_it->dry_run) {
-        status = set_current_stream(msg_it);
-        if (status != CTF_MSG_ITER_STATUS_OK) {
-            goto end;
-        }
-
-        status = set_current_packet(msg_it);
-        if (status != CTF_MSG_ITER_STATUS_OK) {
-            goto end;
-        }
-    }
-
-    msg_it->state = STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN;
-
-    status = CTF_MSG_ITER_STATUS_OK;
-
-end:
-    return status;
-}
-
-static enum ctf_msg_iter_status read_packet_context_begin_state(struct ctf_msg_iter *msg_it)
-{
-    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
-    bt_self_component *self_comp = msg_it->self_comp;
-    struct ctf_field_class *packet_context_fc;
-
-    BT_ASSERT(msg_it->meta.sc);
-    packet_context_fc = msg_it->meta.sc->packet_context_fc;
-    if (!packet_context_fc) {
-        BT_COMP_LOGD("No packet packet context field class in stream class: continuing: "
-                     "msg-it-addr=%p, stream-class-addr=%p, "
-                     "stream-class-id=%" PRId64,
-                     msg_it, msg_it->meta.sc, msg_it->meta.sc->id);
-        msg_it->state = STATE_AFTER_STREAM_PACKET_CONTEXT;
-        goto end;
-    }
-
-    if (packet_context_fc->in_ir && !msg_it->dry_run) {
-        BT_ASSERT(!msg_it->dscopes.stream_packet_context);
-        BT_ASSERT(msg_it->packet);
-        msg_it->dscopes.stream_packet_context = bt_packet_borrow_context_field(msg_it->packet);
-        BT_ASSERT(msg_it->dscopes.stream_packet_context);
-    }
-
-    BT_COMP_LOGD("Decoding packet context field: "
-                 "msg-it-addr=%p, stream-class-addr=%p, "
-                 "stream-class-id=%" PRId64 ", fc-addr=%p",
-                 msg_it, msg_it->meta.sc, msg_it->meta.sc->id, packet_context_fc);
-    status = read_dscope_begin_state(msg_it, packet_context_fc, STATE_AFTER_STREAM_PACKET_CONTEXT,
-                                     STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE,
-                                     msg_it->dscopes.stream_packet_context);
-    if (status < 0) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "Cannot decode packet context field: "
-                                  "msg-it-addr=%p, stream-class-addr=%p, "
-                                  "stream-class-id=%" PRId64 ", fc-addr=%p",
-                                  msg_it, msg_it->meta.sc, msg_it->meta.sc->id, packet_context_fc);
-    }
-
-end:
-    return status;
-}
-
-static enum ctf_msg_iter_status read_packet_context_continue_state(struct ctf_msg_iter *msg_it)
-{
-    return read_dscope_continue_state(msg_it, STATE_AFTER_STREAM_PACKET_CONTEXT);
-}
-
-static enum ctf_msg_iter_status set_current_packet_content_sizes(struct ctf_msg_iter *msg_it)
-{
-    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
-    bt_self_component *self_comp = msg_it->self_comp;
-
-    if (msg_it->cur_exp_packet_total_size == -1) {
-        if (msg_it->cur_exp_packet_content_size != -1) {
-            msg_it->cur_exp_packet_total_size = msg_it->cur_exp_packet_content_size;
-        }
-    } else {
-        if (msg_it->cur_exp_packet_content_size == -1) {
-            msg_it->cur_exp_packet_content_size = msg_it->cur_exp_packet_total_size;
-        }
-    }
-
-    BT_ASSERT(
-        (msg_it->cur_exp_packet_total_size >= 0 && msg_it->cur_exp_packet_content_size >= 0) ||
-        (msg_it->cur_exp_packet_total_size < 0 && msg_it->cur_exp_packet_content_size < 0));
-
-    if (msg_it->cur_exp_packet_content_size > msg_it->cur_exp_packet_total_size) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "Invalid packet or content size: "
-                                  "content size is greater than packet size: "
-                                  "msg-it-addr=%p, packet-context-field-addr=%p, "
-                                  "packet-size=%" PRId64 ", content-size=%" PRId64,
-                                  msg_it, msg_it->dscopes.stream_packet_context,
-                                  msg_it->cur_exp_packet_total_size,
-                                  msg_it->cur_exp_packet_content_size);
-        status = CTF_MSG_ITER_STATUS_ERROR;
-        goto end;
-    }
-
-    BT_COMP_LOGD("Set current packet and content sizes: "
-                 "msg-it-addr=%p, packet-size=%" PRIu64 ", content-size=%" PRIu64,
-                 msg_it, msg_it->cur_exp_packet_total_size, msg_it->cur_exp_packet_content_size);
-
-end:
-    return status;
-}
-
-static enum ctf_msg_iter_status after_packet_context_state(struct ctf_msg_iter *msg_it)
-{
-    enum ctf_msg_iter_status status;
-
-    status = set_current_packet_content_sizes(msg_it);
-    if (status != CTF_MSG_ITER_STATUS_OK) {
-        goto end;
-    }
-
-    if (msg_it->emit_stream_beginning_message) {
-        msg_it->state = STATE_EMIT_MSG_STREAM_BEGINNING;
-    } else {
-        msg_it->state = STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS;
-    }
-
-end:
-    return status;
-}
-
-static enum ctf_msg_iter_status read_event_header_begin_state(struct ctf_msg_iter *msg_it)
-{
-    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
-    bt_self_component *self_comp = msg_it->self_comp;
-    struct ctf_field_class *event_header_fc = NULL;
-
-    /* Reset the position of the last event header */
-    msg_it->buf.last_eh_at = msg_it->buf.at;
-    msg_it->cur_event_class_id = -1;
-
-    /* Check if we have some content left */
-    if (msg_it->cur_exp_packet_content_size >= 0) {
-        if (G_UNLIKELY(packet_at(msg_it) == msg_it->cur_exp_packet_content_size)) {
-            /* No more events! */
-            BT_COMP_LOGD("Reached end of packet: msg-it-addr=%p, "
-                         "cur=%zu",
-                         msg_it, packet_at(msg_it));
-            msg_it->state = STATE_EMIT_MSG_PACKET_END_MULTI;
-            goto end;
-        } else if (G_UNLIKELY(packet_at(msg_it) > msg_it->cur_exp_packet_content_size)) {
-            /* That's not supposed to happen */
-            BT_COMP_LOGD(
-                "Before decoding event header field: cursor is passed the packet's content: "
-                "msg-it-addr=%p, content-size=%" PRId64 ", "
-                "cur=%zu",
-                msg_it, msg_it->cur_exp_packet_content_size, packet_at(msg_it));
-            status = CTF_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(msg_it);
-        switch (status) {
-        case CTF_MSG_ITER_STATUS_OK:
-            break;
-        case CTF_MSG_ITER_STATUS_EOF:
-            status = CTF_MSG_ITER_STATUS_OK;
-            msg_it->state = STATE_EMIT_MSG_PACKET_END_SINGLE;
-            goto end;
-        default:
-            goto end;
-        }
-    }
-
-    release_event_dscopes(msg_it);
-    BT_ASSERT(msg_it->meta.sc);
-    event_header_fc = msg_it->meta.sc->event_header_fc;
-    if (!event_header_fc) {
-        msg_it->state = STATE_AFTER_EVENT_HEADER;
-        goto end;
-    }
-
-    BT_COMP_LOGD("Decoding event header field: "
-                 "msg-it-addr=%p, stream-class-addr=%p, "
-                 "stream-class-id=%" PRId64 ", "
-                 "fc-addr=%p",
-                 msg_it, msg_it->meta.sc, msg_it->meta.sc->id, event_header_fc);
-    status = read_dscope_begin_state(msg_it, event_header_fc, STATE_AFTER_EVENT_HEADER,
-                                     STATE_DSCOPE_EVENT_HEADER_CONTINUE, NULL);
-    if (status < 0) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "Cannot decode event header field: "
-                                  "msg-it-addr=%p, stream-class-addr=%p, "
-                                  "stream-class-id=%" PRId64 ", fc-addr=%p",
-                                  msg_it, msg_it->meta.sc, msg_it->meta.sc->id, event_header_fc);
-    }
-
-end:
-    return status;
-}
-
-static enum ctf_msg_iter_status read_event_header_continue_state(struct ctf_msg_iter *msg_it)
-{
-    return read_dscope_continue_state(msg_it, STATE_AFTER_EVENT_HEADER);
-}
-
-static inline enum ctf_msg_iter_status set_current_event_class(struct ctf_msg_iter *msg_it)
-{
-    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
-    bt_self_component *self_comp = msg_it->self_comp;
-
-    struct ctf_event_class *new_event_class = NULL;
-
-    if (msg_it->cur_event_class_id == -1) {
-        /*
-         * No current event class ID field, therefore only one
-         * event class.
-         */
-        if (msg_it->meta.sc->event_classes->len != 1) {
-            BT_COMP_LOGE_APPEND_CAUSE(
-                self_comp,
-                "Need exactly one event class since there's no event class ID field: "
-                "msg-it-addr=%p",
-                msg_it);
-            status = CTF_MSG_ITER_STATUS_ERROR;
-            goto end;
-        }
-
-        new_event_class = (ctf_event_class *) msg_it->meta.sc->event_classes->pdata[0];
-        msg_it->cur_event_class_id = new_event_class->id;
-    }
-
-    new_event_class =
-        ctf_stream_class_borrow_event_class_by_id(msg_it->meta.sc, msg_it->cur_event_class_id);
-    if (!new_event_class) {
-        BT_COMP_LOGE_APPEND_CAUSE(
-            self_comp,
-            "No event class with ID of event class ID to use in stream class: "
-            "msg-it-addr=%p, stream-class-id=%" PRIu64 ", "
-            "event-class-id=%" PRIu64 ", "
-            "trace-class-addr=%p",
-            msg_it, msg_it->meta.sc->id, msg_it->cur_event_class_id, msg_it->meta.tc);
-        status = CTF_MSG_ITER_STATUS_ERROR;
-        goto end;
-    }
-
-    msg_it->meta.ec = new_event_class;
-    BT_COMP_LOGD("Set current event class: "
-                 "msg-it-addr=%p, event-class-addr=%p, "
-                 "event-class-id=%" PRId64 ", "
-                 "event-class-name=\"%s\"",
-                 msg_it, msg_it->meta.ec, msg_it->meta.ec->id, msg_it->meta.ec->name->str);
-
-end:
-    return status;
-}
-
-static inline enum ctf_msg_iter_status set_current_event_message(struct ctf_msg_iter *msg_it)
-{
-    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
-    bt_self_component *self_comp = msg_it->self_comp;
-    bt_message *msg = NULL;
-
-    BT_ASSERT_DBG(msg_it->meta.ec);
-    BT_ASSERT_DBG(msg_it->packet);
-    BT_COMP_LOGD("Creating event message from event class and packet: "
-                 "msg-it-addr=%p, ec-addr=%p, ec-name=\"%s\", packet-addr=%p",
-                 msg_it, msg_it->meta.ec, msg_it->meta.ec->name->str, msg_it->packet);
-    BT_ASSERT_DBG(msg_it->self_msg_iter);
-    BT_ASSERT_DBG(msg_it->meta.sc);
-
-    if (bt_stream_class_borrow_default_clock_class(msg_it->meta.sc->ir_sc)) {
-        msg = bt_message_event_create_with_packet_and_default_clock_snapshot(
-            msg_it->self_msg_iter, msg_it->meta.ec->ir_ec, msg_it->packet,
-            msg_it->default_clock_snapshot);
-    } else {
-        msg = bt_message_event_create_with_packet(msg_it->self_msg_iter, msg_it->meta.ec->ir_ec,
-                                                  msg_it->packet);
-    }
-
-    if (!msg) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "Cannot create event message: "
-                                  "msg-it-addr=%p, ec-addr=%p, ec-name=\"%s\", "
-                                  "packet-addr=%p",
-                                  msg_it, msg_it->meta.ec, msg_it->meta.ec->name->str,
-                                  msg_it->packet);
-        goto error;
-    }
-
-    goto end;
-
-error:
-    BT_MESSAGE_PUT_REF_AND_RESET(msg);
-    status = CTF_MSG_ITER_STATUS_ERROR;
-
-end:
-    BT_MESSAGE_MOVE_REF(msg_it->event_msg, msg);
-    return status;
-}
-
-static enum ctf_msg_iter_status after_event_header_state(struct ctf_msg_iter *msg_it)
-{
-    enum ctf_msg_iter_status status;
-
-    status = set_current_event_class(msg_it);
-    if (status != CTF_MSG_ITER_STATUS_OK) {
-        goto end;
-    }
-
-    if (G_UNLIKELY(msg_it->dry_run)) {
-        goto next_state;
-    }
-
-    status = set_current_event_message(msg_it);
-    if (status != CTF_MSG_ITER_STATUS_OK) {
-        goto end;
-    }
-
-    msg_it->event = bt_message_event_borrow_event(msg_it->event_msg);
-    BT_ASSERT_DBG(msg_it->event);
-
-next_state:
-    msg_it->state = STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN;
-
-end:
-    return status;
-}
-
-static enum ctf_msg_iter_status read_event_common_context_begin_state(struct ctf_msg_iter *msg_it)
-{
-    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
-    bt_self_component *self_comp = msg_it->self_comp;
-    struct ctf_field_class *event_common_context_fc;
-
-    event_common_context_fc = msg_it->meta.sc->event_common_context_fc;
-    if (!event_common_context_fc) {
-        msg_it->state = STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN;
-        goto end;
-    }
-
-    if (event_common_context_fc->in_ir && !msg_it->dry_run) {
-        BT_ASSERT_DBG(!msg_it->dscopes.event_common_context);
-        msg_it->dscopes.event_common_context = bt_event_borrow_common_context_field(msg_it->event);
-        BT_ASSERT_DBG(msg_it->dscopes.event_common_context);
-    }
-
-    BT_COMP_LOGT("Decoding event common context field: "
-                 "msg-it-addr=%p, stream-class-addr=%p, "
-                 "stream-class-id=%" PRId64 ", "
-                 "fc-addr=%p",
-                 msg_it, msg_it->meta.sc, msg_it->meta.sc->id, event_common_context_fc);
-    status = read_dscope_begin_state(
-        msg_it, event_common_context_fc, STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN,
-        STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE, msg_it->dscopes.event_common_context);
-    if (status < 0) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "Cannot decode event common context field: "
-                                  "msg-it-addr=%p, stream-class-addr=%p, "
-                                  "stream-class-id=%" PRId64 ", fc-addr=%p",
-                                  msg_it, msg_it->meta.sc, msg_it->meta.sc->id,
-                                  event_common_context_fc);
-    }
-
-end:
-    return status;
-}
-
-static enum ctf_msg_iter_status
-read_event_common_context_continue_state(struct ctf_msg_iter *msg_it)
-{
-    return read_dscope_continue_state(msg_it, STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN);
-}
-
-static enum ctf_msg_iter_status read_event_spec_context_begin_state(struct ctf_msg_iter *msg_it)
-{
-    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
-    bt_self_component *self_comp = msg_it->self_comp;
-    struct ctf_field_class *event_spec_context_fc;
-
-    event_spec_context_fc = msg_it->meta.ec->spec_context_fc;
-    if (!event_spec_context_fc) {
-        msg_it->state = STATE_DSCOPE_EVENT_PAYLOAD_BEGIN;
-        goto end;
-    }
-
-    if (event_spec_context_fc->in_ir && !msg_it->dry_run) {
-        BT_ASSERT_DBG(!msg_it->dscopes.event_spec_context);
-        msg_it->dscopes.event_spec_context = bt_event_borrow_specific_context_field(msg_it->event);
-        BT_ASSERT_DBG(msg_it->dscopes.event_spec_context);
-    }
-
-    BT_COMP_LOGT("Decoding event specific context field: "
-                 "msg-it-addr=%p, event-class-addr=%p, "
-                 "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
-                 "fc-addr=%p",
-                 msg_it, msg_it->meta.ec, msg_it->meta.ec->name->str, msg_it->meta.ec->id,
-                 event_spec_context_fc);
-    status = read_dscope_begin_state(
-        msg_it, event_spec_context_fc, STATE_DSCOPE_EVENT_PAYLOAD_BEGIN,
-        STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE, msg_it->dscopes.event_spec_context);
-    if (status < 0) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "Cannot decode event specific context field: "
-                                  "msg-it-addr=%p, event-class-addr=%p, "
-                                  "event-class-name=\"%s\", "
-                                  "event-class-id=%" PRId64 ", fc-addr=%p",
-                                  msg_it, msg_it->meta.ec, msg_it->meta.ec->name->str,
-                                  msg_it->meta.ec->id, event_spec_context_fc);
-    }
-
-end:
-    return status;
-}
-
-static enum ctf_msg_iter_status read_event_spec_context_continue_state(struct ctf_msg_iter *msg_it)
-{
-    return read_dscope_continue_state(msg_it, STATE_DSCOPE_EVENT_PAYLOAD_BEGIN);
-}
-
-static enum ctf_msg_iter_status read_event_payload_begin_state(struct ctf_msg_iter *msg_it)
-{
-    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
-    bt_self_component *self_comp = msg_it->self_comp;
-    struct ctf_field_class *event_payload_fc;
-
-    event_payload_fc = msg_it->meta.ec->payload_fc;
-    if (!event_payload_fc) {
-        msg_it->state = STATE_EMIT_MSG_EVENT;
-        goto end;
-    }
-
-    if (event_payload_fc->in_ir && !msg_it->dry_run) {
-        BT_ASSERT_DBG(!msg_it->dscopes.event_payload);
-        msg_it->dscopes.event_payload = bt_event_borrow_payload_field(msg_it->event);
-        BT_ASSERT_DBG(msg_it->dscopes.event_payload);
-    }
-
-    BT_COMP_LOGT("Decoding event payload field: "
-                 "msg-it-addr=%p, event-class-addr=%p, "
-                 "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
-                 "fc-addr=%p",
-                 msg_it, msg_it->meta.ec, msg_it->meta.ec->name->str, msg_it->meta.ec->id,
-                 event_payload_fc);
-    status =
-        read_dscope_begin_state(msg_it, event_payload_fc, STATE_EMIT_MSG_EVENT,
-                                STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE, msg_it->dscopes.event_payload);
-    if (status < 0) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "Cannot decode event payload field: "
-                                  "msg-it-addr=%p, event-class-addr=%p, "
-                                  "event-class-name=\"%s\", "
-                                  "event-class-id=%" PRId64 ", fc-addr=%p",
-                                  msg_it, msg_it->meta.ec, msg_it->meta.ec->name->str,
-                                  msg_it->meta.ec->id, event_payload_fc);
-    }
-
-end:
-    return status;
-}
-
-static enum ctf_msg_iter_status read_event_payload_continue_state(struct ctf_msg_iter *msg_it)
-{
-    return read_dscope_continue_state(msg_it, STATE_EMIT_MSG_EVENT);
-}
-
-static enum ctf_msg_iter_status skip_packet_padding_state(struct ctf_msg_iter *msg_it)
-{
-    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
-    size_t bits_to_skip;
-    const enum state next_state = STATE_SWITCH_PACKET;
-
-    BT_ASSERT(msg_it->cur_exp_packet_total_size > 0);
-    bits_to_skip = msg_it->cur_exp_packet_total_size - packet_at(msg_it);
-    if (bits_to_skip == 0) {
-        msg_it->state = next_state;
-        goto end;
-    } else {
-        size_t bits_to_consume;
-
-        BT_COMP_LOGD("Trying to skip %zu bits of padding: msg-it-addr=%p, size=%zu", bits_to_skip,
-                     msg_it, bits_to_skip);
-        status = buf_ensure_available_bits(msg_it);
-        if (status != CTF_MSG_ITER_STATUS_OK) {
-            goto end;
-        }
-
-        bits_to_consume = MIN(buf_available_bits(msg_it), bits_to_skip);
-        BT_COMP_LOGD("Skipping %zu bits of padding: msg-it-addr=%p, size=%zu", bits_to_consume,
-                     msg_it, bits_to_consume);
-        buf_consume_bits(msg_it, bits_to_consume);
-        bits_to_skip = msg_it->cur_exp_packet_total_size - packet_at(msg_it);
-        if (bits_to_skip == 0) {
-            msg_it->state = next_state;
-            goto end;
-        }
-    }
-
-end:
-    return status;
-}
-
-static enum ctf_msg_iter_status check_emit_msg_discarded_events(struct ctf_msg_iter *msg_it)
-{
-    msg_it->state = STATE_EMIT_MSG_DISCARDED_EVENTS;
-
-    if (!msg_it->meta.sc->has_discarded_events) {
-        msg_it->state = STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS;
-        goto end;
-    }
-
-    if (msg_it->prev_packet_snapshots.discarded_events == UINT64_C(-1)) {
-        if (msg_it->snapshots.discarded_events == 0 ||
-            msg_it->snapshots.discarded_events == UINT64_C(-1)) {
-            /*
-             * Stream's first packet with no discarded
-             * events or no information about discarded
-             * events: do not emit.
-             */
-            msg_it->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(msg_it->snapshots.discarded_events != UINT64_C(-1));
-
-        if (msg_it->snapshots.discarded_events - msg_it->prev_packet_snapshots.discarded_events ==
-            0) {
-            /*
-             * No discarded events since previous packet: do
-             * not emit.
-             */
-            msg_it->state = STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS;
-        }
-    }
-
-end:
-    return CTF_MSG_ITER_STATUS_OK;
-}
-
-static enum ctf_msg_iter_status check_emit_msg_discarded_packets(struct ctf_msg_iter *msg_it)
-{
-    msg_it->state = STATE_EMIT_MSG_DISCARDED_PACKETS;
-
-    if (!msg_it->meta.sc->has_discarded_packets) {
-        msg_it->state = STATE_EMIT_MSG_PACKET_BEGINNING;
-        goto end;
-    }
-
-    if (msg_it->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).
-         */
-        msg_it->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(msg_it->snapshots.packets != UINT64_C(-1));
-
-        if (msg_it->snapshots.packets - msg_it->prev_packet_snapshots.packets <= 1) {
-            /*
-             * No discarded packets since previous packet:
-             * do not emit.
-             */
-            msg_it->state = STATE_EMIT_MSG_PACKET_BEGINNING;
-        }
-    }
-
-end:
-    return CTF_MSG_ITER_STATUS_OK;
-}
-
-static inline enum state check_emit_msg_stream_end(struct ctf_msg_iter *msg_it)
-{
-    enum state next_state;
-
-    if (msg_it->emit_stream_end_message) {
-        next_state = STATE_EMIT_MSG_STREAM_END;
-    } else {
-        next_state = STATE_DONE;
-    }
-
-    return next_state;
-}
-
-static inline enum ctf_msg_iter_status handle_state(struct ctf_msg_iter *msg_it)
-{
-    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
-    const enum state state = msg_it->state;
-
-    BT_COMP_LOGT("Handling state: msg-it-addr=%p, state=%s", msg_it, state_string(state));
-
-    // TODO: optimalize!
-    switch (state) {
-    case STATE_INIT:
-        msg_it->state = STATE_SWITCH_PACKET;
-        break;
-    case STATE_SWITCH_PACKET:
-        status = switch_packet_state(msg_it);
-        break;
-    case STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN:
-        status = read_packet_header_begin_state(msg_it);
-        break;
-    case STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE:
-        status = read_packet_header_continue_state(msg_it);
-        break;
-    case STATE_AFTER_TRACE_PACKET_HEADER:
-        status = after_packet_header_state(msg_it);
-        break;
-    case STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN:
-        status = read_packet_context_begin_state(msg_it);
-        break;
-    case STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE:
-        status = read_packet_context_continue_state(msg_it);
-        break;
-    case STATE_AFTER_STREAM_PACKET_CONTEXT:
-        status = after_packet_context_state(msg_it);
-        break;
-    case STATE_EMIT_MSG_STREAM_BEGINNING:
-        msg_it->state = STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS;
-        break;
-    case STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS:
-        status = check_emit_msg_discarded_events(msg_it);
-        break;
-    case STATE_EMIT_MSG_DISCARDED_EVENTS:
-        msg_it->state = STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS;
-        break;
-    case STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS:
-        status = check_emit_msg_discarded_packets(msg_it);
-        break;
-    case STATE_EMIT_MSG_DISCARDED_PACKETS:
-        msg_it->state = STATE_EMIT_MSG_PACKET_BEGINNING;
-        break;
-    case STATE_EMIT_MSG_PACKET_BEGINNING:
-        msg_it->state = STATE_DSCOPE_EVENT_HEADER_BEGIN;
-        break;
-    case STATE_DSCOPE_EVENT_HEADER_BEGIN:
-        status = read_event_header_begin_state(msg_it);
-        break;
-    case STATE_DSCOPE_EVENT_HEADER_CONTINUE:
-        status = read_event_header_continue_state(msg_it);
-        break;
-    case STATE_AFTER_EVENT_HEADER:
-        status = after_event_header_state(msg_it);
-        break;
-    case STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN:
-        status = read_event_common_context_begin_state(msg_it);
-        break;
-    case STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE:
-        status = read_event_common_context_continue_state(msg_it);
-        break;
-    case STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN:
-        status = read_event_spec_context_begin_state(msg_it);
-        break;
-    case STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE:
-        status = read_event_spec_context_continue_state(msg_it);
-        break;
-    case STATE_DSCOPE_EVENT_PAYLOAD_BEGIN:
-        status = read_event_payload_begin_state(msg_it);
-        break;
-    case STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE:
-        status = read_event_payload_continue_state(msg_it);
-        break;
-    case STATE_EMIT_MSG_EVENT:
-        msg_it->state = STATE_DSCOPE_EVENT_HEADER_BEGIN;
-        break;
-    case STATE_EMIT_QUEUED_MSG_EVENT:
-        msg_it->state = STATE_EMIT_MSG_EVENT;
-        break;
-    case STATE_SKIP_PACKET_PADDING:
-        status = skip_packet_padding_state(msg_it);
-        break;
-    case STATE_EMIT_MSG_PACKET_END_MULTI:
-        msg_it->state = STATE_SKIP_PACKET_PADDING;
-        break;
-    case STATE_EMIT_MSG_PACKET_END_SINGLE:
-        msg_it->state = STATE_EMIT_MSG_STREAM_END;
-        break;
-    case STATE_EMIT_QUEUED_MSG_PACKET_END:
-        msg_it->state = STATE_EMIT_MSG_PACKET_END_SINGLE;
-        break;
-    case STATE_CHECK_EMIT_MSG_STREAM_END:
-        msg_it->state = check_emit_msg_stream_end(msg_it);
-        break;
-    case STATE_EMIT_MSG_STREAM_END:
-        msg_it->state = STATE_DONE;
-        break;
-    case STATE_DONE:
-        break;
-    default:
-        BT_COMP_LOGF("Unknown CTF plugin message iterator state: "
-                     "msg-it-addr=%p, state=%d",
-                     msg_it, msg_it->state);
-        bt_common_abort();
-    }
-
-    BT_COMP_LOGT("Handled state: msg-it-addr=%p, status=%s, "
-                 "prev-state=%s, cur-state=%s",
-                 msg_it, ctf_msg_iter_status_string(status), state_string(state),
-                 state_string(msg_it->state));
-    return status;
-}
-
-void ctf_msg_iter_reset_for_next_stream_file(struct ctf_msg_iter *msg_it)
-{
-    BT_ASSERT(msg_it);
-    BT_COMP_LOGD("Resetting message iterator: addr=%p", msg_it);
-    stack_clear(msg_it->stack);
-    msg_it->meta.sc = NULL;
-    msg_it->meta.ec = NULL;
-    BT_PACKET_PUT_REF_AND_RESET(msg_it->packet);
-    BT_STREAM_PUT_REF_AND_RESET(msg_it->stream);
-    BT_MESSAGE_PUT_REF_AND_RESET(msg_it->event_msg);
-    release_all_dscopes(msg_it);
-    msg_it->cur_dscope_field = NULL;
-
-    msg_it->buf.addr = NULL;
-    msg_it->buf.sz = 0;
-    msg_it->buf.at = 0;
-    msg_it->buf.last_eh_at = SIZE_MAX;
-    msg_it->buf.packet_offset = 0;
-    msg_it->state = STATE_INIT;
-    msg_it->cur_exp_packet_content_size = -1;
-    msg_it->cur_exp_packet_total_size = -1;
-    msg_it->cur_packet_offset = -1;
-    msg_it->cur_event_class_id = -1;
-    msg_it->snapshots.beginning_clock = UINT64_C(-1);
-    msg_it->snapshots.end_clock = UINT64_C(-1);
-}
-
-/**
- * Resets the internal state of a CTF message iterator.
- */
-void ctf_msg_iter_reset(struct ctf_msg_iter *msg_it)
-{
-    ctf_msg_iter_reset_for_next_stream_file(msg_it);
-    msg_it->cur_stream_class_id = -1;
-    msg_it->cur_data_stream_id = -1;
-    msg_it->snapshots.discarded_events = UINT64_C(-1);
-    msg_it->snapshots.packets = UINT64_C(-1);
-    msg_it->prev_packet_snapshots.discarded_events = UINT64_C(-1);
-    msg_it->prev_packet_snapshots.packets = UINT64_C(-1);
-    msg_it->prev_packet_snapshots.beginning_clock = UINT64_C(-1);
-    msg_it->prev_packet_snapshots.end_clock = UINT64_C(-1);
-    msg_it->emit_stream_beginning_message = true;
-    msg_it->emit_stream_end_message = false;
-}
-
-static bt_field *borrow_next_field(struct ctf_msg_iter *msg_it)
-{
-    bt_field *next_field = NULL;
-    bt_field *base_field;
-    const bt_field_class *base_fc;
-    bt_field_class_type base_fc_type;
-    size_t index;
-
-    BT_ASSERT_DBG(!stack_empty(msg_it->stack));
-    index = stack_top(msg_it->stack)->index;
-    base_field = stack_top(msg_it->stack)->base;
-    BT_ASSERT_DBG(base_field);
-    base_fc = bt_field_borrow_class_const(base_field);
-    BT_ASSERT_DBG(base_fc);
-    base_fc_type = bt_field_class_get_type(base_fc);
-
-    if (base_fc_type == BT_FIELD_CLASS_TYPE_STRUCTURE) {
-        BT_ASSERT_DBG(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);
-    } else if (bt_field_class_type_is(base_fc_type, BT_FIELD_CLASS_TYPE_ARRAY)) {
-        BT_ASSERT_DBG(index < bt_field_array_get_length(base_field));
-        next_field = bt_field_array_borrow_element_field_by_index(base_field, index);
-    } else if (bt_field_class_type_is(base_fc_type, BT_FIELD_CLASS_TYPE_VARIANT)) {
-        BT_ASSERT_DBG(index == 0);
-        next_field = bt_field_variant_borrow_selected_option_field(base_field);
-    } else {
-        bt_common_abort();
-    }
-
-    BT_ASSERT_DBG(next_field);
-    return next_field;
-}
-
-static void update_default_clock(struct ctf_msg_iter *msg_it, uint64_t new_val,
-                                 uint64_t new_val_size)
-{
-    uint64_t new_val_mask;
-    uint64_t cur_value_masked;
-
-    BT_ASSERT_DBG(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) {
-        msg_it->default_clock_snapshot = new_val;
-        goto end;
-    }
-
-    new_val_mask = (1ULL << new_val_size) - 1;
-    cur_value_masked = msg_it->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.
-         */
-        msg_it->default_clock_snapshot += new_val_mask + 1;
-    }
-
-    /* Clear the low bits of the current clock value. */
-    msg_it->default_clock_snapshot &= ~new_val_mask;
-
-    /* Set the low bits of the current clock value. */
-    msg_it->default_clock_snapshot |= new_val;
-
-end:
-    BT_COMP_LOGT("Updated default clock's value from integer field's value: "
-                 "value=%" PRIu64,
-                 msg_it->default_clock_snapshot);
-}
-
-/*
- * Ensure the message iterator's `stored_values` array is large enough to
- * accommodate `storing_index`.
- *
- * We may need more slots in the array than initially allocated if more
- * metadata arrives along the way.
- */
-static void ensure_stored_values_size(ctf_msg_iter *msg_it, uint64_t storing_index)
-{
-    if (G_UNLIKELY(storing_index >= msg_it->stored_values->len)) {
-        g_array_set_size(msg_it->stored_values, msg_it->meta.tc->stored_value_count);
-    }
-}
-
-static enum bt_bfcr_status bfcr_unsigned_int_cb(uint64_t value, struct ctf_field_class *fc,
-                                                void *data)
-{
-    ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
-    bt_self_component *self_comp = msg_it->self_comp;
-    enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
-
-    bt_field *field = NULL;
-
-    BT_COMP_LOGT("Unsigned integer function called from BFCR: "
-                 "msg-it-addr=%p, bfcr-addr=%p, fc-addr=%p, "
-                 "fc-type=%d, fc-in-ir=%d, value=%" PRIu64,
-                 msg_it, msg_it->bfcr, fc, fc->type, fc->in_ir, value);
-
-    ctf_field_class_int *int_fc = ctf_field_class_as_int(fc);
-
-    if (G_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:
-        msg_it->cur_event_class_id = value;
-        break;
-    case CTF_FIELD_CLASS_MEANING_DATA_STREAM_ID:
-        msg_it->cur_data_stream_id = value;
-        break;
-    case CTF_FIELD_CLASS_MEANING_PACKET_BEGINNING_TIME:
-        msg_it->snapshots.beginning_clock = value;
-        break;
-    case CTF_FIELD_CLASS_MEANING_PACKET_END_TIME:
-        msg_it->snapshots.end_clock = value;
-        break;
-    case CTF_FIELD_CLASS_MEANING_STREAM_CLASS_ID:
-        msg_it->cur_stream_class_id = value;
-        break;
-    case CTF_FIELD_CLASS_MEANING_MAGIC:
-        if (value != 0xc1fc1fc1) {
-            BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                      "Invalid CTF magic number: msg-it-addr=%p, "
-                                      "magic=%" PRIx64,
-                                      msg_it, value);
-            status = BT_BFCR_STATUS_ERROR;
-            goto end;
-        }
-
-        break;
-    case CTF_FIELD_CLASS_MEANING_PACKET_COUNTER_SNAPSHOT:
-        msg_it->snapshots.packets = value;
-        break;
-    case CTF_FIELD_CLASS_MEANING_DISC_EV_REC_COUNTER_SNAPSHOT:
-        msg_it->snapshots.discarded_events = value;
-        break;
-    case CTF_FIELD_CLASS_MEANING_EXP_PACKET_TOTAL_SIZE:
-        msg_it->cur_exp_packet_total_size = value;
-        break;
-    case CTF_FIELD_CLASS_MEANING_EXP_PACKET_CONTENT_SIZE:
-        msg_it->cur_exp_packet_content_size = value;
-        break;
-    default:
-        bt_common_abort();
-    }
-
-update_def_clock:
-    if (G_UNLIKELY(int_fc->mapped_clock_class)) {
-        update_default_clock(msg_it, value, int_fc->base.size);
-    }
-
-    if (G_UNLIKELY(int_fc->storing_index >= 0)) {
-        ensure_stored_values_size(msg_it, int_fc->storing_index);
-        bt_g_array_index(msg_it->stored_values, uint64_t, (uint64_t) int_fc->storing_index) = value;
-    }
-
-    if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) {
-        goto end;
-    }
-
-    field = borrow_next_field(msg_it);
-    BT_ASSERT_DBG(field);
-    BT_ASSERT_DBG(bt_field_borrow_class_const(field) == fc->ir_fc);
-    BT_ASSERT_DBG(bt_field_class_type_is(bt_field_get_class_type(field),
-                                         BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER));
-    bt_field_integer_unsigned_set_value(field, value);
-    stack_top(msg_it->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;
-    ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
-    bt_self_component *self_comp = msg_it->self_comp;
-    enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
-    bt_field *string_field = NULL;
-    char str[2] = {'\0', '\0'};
-
-    BT_COMP_LOGT("Unsigned integer character function called from BFCR: "
-                 "msg-it-addr=%p, bfcr-addr=%p, fc-addr=%p, "
-                 "fc-type=%d, fc-in-ir=%d, value=%" PRIu64,
-                 msg_it, msg_it->bfcr, fc, fc->type, fc->in_ir, value);
-
-    ctf_field_class_int *int_fc = ctf_field_class_as_int(fc);
-    BT_ASSERT_DBG(int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE);
-    BT_ASSERT_DBG(!int_fc->mapped_clock_class);
-    BT_ASSERT_DBG(int_fc->storing_index < 0);
-
-    if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) {
-        goto end;
-    }
-
-    if (msg_it->done_filling_string) {
-        goto end;
-    }
-
-    if (value == 0) {
-        msg_it->done_filling_string = true;
-        goto end;
-    }
-
-    string_field = stack_top(msg_it->stack)->base;
-    BT_ASSERT_DBG(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_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "Cannot append character to string field's value: "
-                                  "msg-it-addr=%p, field-addr=%p, ret=%d",
-                                  msg_it, 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;
-    ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
-
-    BT_COMP_LOGT("Signed integer function called from BFCR: "
-                 "msg-it-addr=%p, bfcr-addr=%p, fc-addr=%p, "
-                 "fc-type=%d, fc-in-ir=%d, value=%" PRId64,
-                 msg_it, msg_it->bfcr, fc, fc->type, fc->in_ir, value);
-
-    ctf_field_class_int *int_fc = ctf_field_class_as_int(fc);
-    BT_ASSERT_DBG(int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE);
-
-    if (G_UNLIKELY(int_fc->storing_index >= 0)) {
-        ensure_stored_values_size(msg_it, int_fc->storing_index);
-        bt_g_array_index(msg_it->stored_values, uint64_t, (uint64_t) int_fc->storing_index) =
-            (uint64_t) value;
-    }
-
-    if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) {
-        goto end;
-    }
-
-    field = borrow_next_field(msg_it);
-    BT_ASSERT_DBG(field);
-    BT_ASSERT_DBG(bt_field_borrow_class_const(field) == fc->ir_fc);
-    BT_ASSERT_DBG(
-        bt_field_class_type_is(bt_field_get_class_type(field), BT_FIELD_CLASS_TYPE_SIGNED_INTEGER));
-    bt_field_integer_signed_set_value(field, value);
-    stack_top(msg_it->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;
-    ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
-    bt_field_class_type type;
-
-    BT_COMP_LOGT("Floating point number function called from BFCR: "
-                 "msg-it-addr=%p, bfcr-addr=%p, fc-addr=%p, "
-                 "fc-type=%d, fc-in-ir=%d, value=%f",
-                 msg_it, msg_it->bfcr, fc, fc->type, fc->in_ir, value);
-
-    if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) {
-        goto end;
-    }
-
-    field = borrow_next_field(msg_it);
-    type = bt_field_get_class_type(field);
-    BT_ASSERT_DBG(field);
-    BT_ASSERT_DBG(bt_field_borrow_class_const(field) == fc->ir_fc);
-    BT_ASSERT_DBG(bt_field_class_type_is(type, BT_FIELD_CLASS_TYPE_REAL));
-
-    if (type == BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL) {
-        bt_field_real_single_precision_set_value(field, (float) value);
-    } else {
-        bt_field_real_double_precision_set_value(field, value);
-    }
-    stack_top(msg_it->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;
-    ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
-
-    BT_COMP_LOGT("String (beginning) function called from BFCR: "
-                 "msg-it-addr=%p, bfcr-addr=%p, fc-addr=%p, "
-                 "fc-type=%d, fc-in-ir=%d",
-                 msg_it, msg_it->bfcr, fc, fc->type, fc->in_ir);
-
-    if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) {
-        goto end;
-    }
-
-    field = borrow_next_field(msg_it);
-    BT_ASSERT_DBG(field);
-    BT_ASSERT_DBG(bt_field_borrow_class_const(field) == fc->ir_fc);
-    BT_ASSERT_DBG(bt_field_get_class_type(field) == BT_FIELD_CLASS_TYPE_STRING);
-    bt_field_string_clear(field);
-
-    /*
-     * 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(msg_it->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;
-    ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
-    bt_self_component *self_comp = msg_it->self_comp;
-    int ret;
-
-    BT_COMP_LOGT("String (substring) function called from BFCR: "
-                 "msg-it-addr=%p, bfcr-addr=%p, fc-addr=%p, "
-                 "fc-type=%d, fc-in-ir=%d, string-length=%zu",
-                 msg_it, msg_it->bfcr, fc, fc->type, fc->in_ir, len);
-
-    if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) {
-        goto end;
-    }
-
-    field = stack_top(msg_it->stack)->base;
-    BT_ASSERT_DBG(field);
-
-    /* Append current substring */
-    ret = bt_field_string_append_with_length(field, value, len);
-    if (ret) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "Cannot append substring to string field's value: "
-                                  "msg-it-addr=%p, field-addr=%p, string-length=%zu, "
-                                  "ret=%d",
-                                  msg_it, 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)
-{
-    ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
-
-    BT_COMP_LOGT("String (end) function called from BFCR: "
-                 "msg-it-addr=%p, bfcr-addr=%p, fc-addr=%p, "
-                 "fc-type=%d, fc-in-ir=%d",
-                 msg_it, msg_it->bfcr, fc, fc->type, fc->in_ir);
-
-    if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) {
-        goto end;
-    }
-
-    /* Pop string field */
-    stack_pop(msg_it->stack);
-
-    /* Go to next field */
-    stack_top(msg_it->stack)->index++;
-
-end:
-    return BT_BFCR_STATUS_OK;
-}
-
-static enum bt_bfcr_status bfcr_compound_begin_cb(struct ctf_field_class *fc, void *data)
-{
-    ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
-    bt_field *field;
-
-    BT_COMP_LOGT("Compound (beginning) function called from BFCR: "
-                 "msg-it-addr=%p, bfcr-addr=%p, fc-addr=%p, "
-                 "fc-type=%d, fc-in-ir=%d",
-                 msg_it, msg_it->bfcr, fc, fc->type, fc->in_ir);
-
-    if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) {
-        goto end;
-    }
-
-    /* Borrow field */
-    if (stack_empty(msg_it->stack)) {
-        /* Root: already set by read_dscope_begin_state() */
-        field = msg_it->cur_dscope_field;
-    } else {
-        field = borrow_next_field(msg_it);
-        BT_ASSERT_DBG(field);
-    }
-
-    /* Push field */
-    BT_ASSERT_DBG(field);
-    BT_ASSERT_DBG(bt_field_borrow_class_const(field) == fc->ir_fc);
-    stack_push(msg_it->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) {
-        ctf_field_class_array_base *array_fc = ctf_field_class_as_array_base(fc);
-
-        if (array_fc->is_text) {
-            BT_ASSERT_DBG(bt_field_get_class_type(field) == BT_FIELD_CLASS_TYPE_STRING);
-            msg_it->done_filling_string = false;
-            bt_field_string_clear(field);
-            bt_bfcr_set_unsigned_int_cb(msg_it->bfcr, bfcr_unsigned_int_char_cb);
-        }
-    }
-
-end:
-    return BT_BFCR_STATUS_OK;
-}
-
-static enum bt_bfcr_status bfcr_compound_end_cb(struct ctf_field_class *fc, void *data)
-{
-    ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
-
-    BT_COMP_LOGT("Compound (end) function called from BFCR: "
-                 "msg-it-addr=%p, bfcr-addr=%p, fc-addr=%p, "
-                 "fc-type=%d, fc-in-ir=%d",
-                 msg_it, msg_it->bfcr, fc, fc->type, fc->in_ir);
-
-    if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) {
-        goto end;
-    }
-
-    BT_ASSERT_DBG(!stack_empty(msg_it->stack));
-    BT_ASSERT_DBG(bt_field_borrow_class_const(stack_top(msg_it->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) {
-        ctf_field_class_array_base *array_fc = ctf_field_class_as_array_base(fc);
-
-        if (array_fc->is_text) {
-            BT_ASSERT_DBG(bt_field_get_class_type(stack_top(msg_it->stack)->base) ==
-                          BT_FIELD_CLASS_TYPE_STRING);
-            bt_bfcr_set_unsigned_int_cb(msg_it->bfcr, bfcr_unsigned_int_cb);
-        }
-    }
-
-    /* Pop stack */
-    stack_pop(msg_it->stack);
-
-    /* If the stack is not empty, increment the base's index */
-    if (!stack_empty(msg_it->stack)) {
-        stack_top(msg_it->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;
-    ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
-    bt_self_component *self_comp = msg_it->self_comp;
-    struct ctf_field_class_sequence *seq_fc = ctf_field_class_as_sequence(fc);
-    int64_t length;
-    int ret;
-
-    length =
-        (uint64_t) bt_g_array_index(msg_it->stored_values, uint64_t, seq_fc->stored_length_index);
-
-    if (G_UNLIKELY(msg_it->dry_run)) {
-        goto end;
-    }
-
-    seq_field = stack_top(msg_it->stack)->base;
-    BT_ASSERT_DBG(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_DBG(bt_field_class_type_is(bt_field_get_class_type(seq_field),
-                                             BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY));
-        ret = bt_field_array_dynamic_set_length(seq_field, (uint64_t) length);
-        if (ret) {
-            BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                      "Cannot set dynamic array field's length field: "
-                                      "msg-it-addr=%p, field-addr=%p, "
-                                      "length=%" PRIu64,
-                                      msg_it, seq_field, length);
-            length = -1;
-        }
-    }
-
-end:
-    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;
-    ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
-    ctf_field_class_variant *var_fc = ctf_field_class_as_variant(fc);
-    struct ctf_named_field_class *selected_option = NULL;
-    bt_self_component *self_comp = msg_it->self_comp;
-    struct ctf_field_class *ret_fc = NULL;
-    union
-    {
-        uint64_t u;
-        int64_t i;
-    } tag;
-
-    /* Get variant's tag */
-    tag.u = bt_g_array_index(msg_it->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_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "Cannot find variant field class's option: "
-                                  "msg-it-addr=%p, var-fc-addr=%p, u-tag=%" PRIu64 ", "
-                                  "i-tag=%" PRId64,
-                                  msg_it, var_fc, tag.u, tag.i);
-        ret_fc = NULL;
-        goto end;
-    }
-
-    selected_option =
-        ctf_field_class_variant_borrow_option_by_index(var_fc, (uint64_t) option_index);
-
-    if (selected_option->fc->in_ir && !msg_it->dry_run) {
-        bt_field *var_field = stack_top(msg_it->stack)->base;
-
-        ret = bt_field_variant_select_option_by_index(var_field, option_index);
-        if (ret) {
-            BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                      "Cannot select variant field's option field: "
-                                      "msg-it-addr=%p, var-field-addr=%p, "
-                                      "opt-index=%" PRId64,
-                                      msg_it, var_field, option_index);
-            ret_fc = NULL;
-            goto end;
-        }
-    }
-
-    ret_fc = selected_option->fc;
-
-end:
-    return ret_fc;
-}
-
-static bt_message *create_msg_stream_beginning(struct ctf_msg_iter *msg_it)
-{
-    bt_self_component *self_comp = msg_it->self_comp;
-    bt_message *msg;
-
-    BT_ASSERT(msg_it->stream);
-    BT_ASSERT(msg_it->self_msg_iter);
-    msg = bt_message_stream_beginning_create(msg_it->self_msg_iter, msg_it->stream);
-    if (!msg) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "Cannot create stream beginning message: "
-                                  "msg-it-addr=%p, stream-addr=%p",
-                                  msg_it, msg_it->stream);
-    }
-
-    return msg;
-}
-
-static bt_message *create_msg_stream_end(struct ctf_msg_iter *msg_it)
-{
-    bt_self_component *self_comp = msg_it->self_comp;
-    bt_message *msg;
-
-    if (!msg_it->stream) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "Cannot create stream end message because stream is NULL: "
-                                  "msg-it-addr=%p",
-                                  msg_it);
-        msg = NULL;
-        goto end;
-    }
-
-    BT_ASSERT(msg_it->self_msg_iter);
-    msg = bt_message_stream_end_create(msg_it->self_msg_iter, msg_it->stream);
-    if (!msg) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "Cannot create stream end message: "
-                                  "msg-it-addr=%p, stream-addr=%p",
-                                  msg_it, msg_it->stream);
-    }
-
-end:
-    return msg;
-}
-
-static bt_message *create_msg_packet_beginning(struct ctf_msg_iter *msg_it, bool use_default_cs)
-{
-    bt_self_component *self_comp = msg_it->self_comp;
-    bt_message *msg;
-    const bt_stream_class *sc = msg_it->meta.sc->ir_sc;
-
-    BT_ASSERT(msg_it->packet);
-    BT_ASSERT(sc);
-    BT_ASSERT(msg_it->self_msg_iter);
-
-    if (msg_it->meta.sc->packets_have_ts_begin) {
-        BT_ASSERT(msg_it->snapshots.beginning_clock != UINT64_C(-1));
-        uint64_t raw_cs_value;
-
-        /*
-         * Either use the decoded packet `timestamp_begin` field or the
-         * current stream's default clock_snapshot.
-         */
-        if (use_default_cs) {
-            raw_cs_value = msg_it->default_clock_snapshot;
-        } else {
-            raw_cs_value = msg_it->snapshots.beginning_clock;
-        }
-
-        msg = bt_message_packet_beginning_create_with_default_clock_snapshot(
-            msg_it->self_msg_iter, msg_it->packet, raw_cs_value);
-    } else {
-        msg = bt_message_packet_beginning_create(msg_it->self_msg_iter, msg_it->packet);
-    }
-
-    if (!msg) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "Cannot create packet beginning message: "
-                                  "msg-it-addr=%p, packet-addr=%p",
-                                  msg_it, msg_it->packet);
-        goto end;
-    }
-
-end:
-    return msg;
-}
-
-static bt_message *emit_delayed_packet_beg_msg(struct ctf_msg_iter *msg_it)
-{
-    bool packet_beg_ts_need_fix_up;
-
-    msg_it->emit_delayed_packet_beginning_msg = false;
-
-    /*
-     * Only fix the packet's timestamp_begin if it's larger than the first
-     * event of the packet. If there was no event in the packet, the
-     * `default_clock_snapshot` field will be either equal or greater than
-     * `snapshots.beginning_clock` so there is not fix needed.
-     */
-    packet_beg_ts_need_fix_up = msg_it->default_clock_snapshot < msg_it->snapshots.beginning_clock;
-
-    /* create_msg_packet_beginning() logs errors */
-    return create_msg_packet_beginning(msg_it, packet_beg_ts_need_fix_up);
-}
-
-static bt_message *create_msg_packet_end(struct ctf_msg_iter *msg_it)
-{
-    bt_message *msg;
-    bool update_default_cs = true;
-    bt_self_component *self_comp = msg_it->self_comp;
-
-    if (!msg_it->packet) {
-        msg = NULL;
-        goto end;
-    }
-
-    /*
-     * Check if we need to emit the delayed packet
-     * beginning message instead of the packet end message.
-     */
-    if (G_UNLIKELY(msg_it->emit_delayed_packet_beginning_msg)) {
-        msg = emit_delayed_packet_beg_msg(msg_it);
-        /* Don't forget to emit the packet end message. */
-        msg_it->state = STATE_EMIT_QUEUED_MSG_PACKET_END;
-        goto end;
-    }
-
-    /* Check if may be affected by lttng-crash timestamp_end quirk. */
-    if (G_UNLIKELY(msg_it->meta.tc->quirks.lttng_crash)) {
-        /*
-         * Check if the `timestamp_begin` field is non-zero but
-         * `timestamp_end` is zero. It means the trace is affected by
-         * the lttng-crash packet `timestamp_end` quirk and must be
-         * fixed up by omitting to update the default clock snapshot to
-         * the `timestamp_end` as is typically done.
-         */
-        if (msg_it->snapshots.beginning_clock != 0 && msg_it->snapshots.end_clock == 0) {
-            update_default_cs = false;
-        }
-    }
-
-    /*
-     * Check if may be affected by lttng event-after-packet `timestamp_end`
-     * quirk.
-     */
-    if (msg_it->meta.tc->quirks.lttng_event_after_packet) {
-        /*
-         * Check if `timestamp_end` is smaller then the current
-         * default_clock_snapshot (which is set to the last event
-         * decoded). It means the trace is affected by the lttng
-         * `event-after-packet` packet `timestamp_end` quirk and must
-         * be fixed up by omitting to update the default clock snapshot
-         * to the `timestamp_end` as is typically done.
-         */
-        if (msg_it->snapshots.end_clock < msg_it->default_clock_snapshot) {
-            update_default_cs = false;
-        }
-    }
-
-    /* Update default clock from packet's end time. */
-    if (msg_it->snapshots.end_clock != UINT64_C(-1) && update_default_cs) {
-        msg_it->default_clock_snapshot = msg_it->snapshots.end_clock;
-    }
-
-    BT_ASSERT(msg_it->self_msg_iter);
-
-    if (msg_it->meta.sc->packets_have_ts_end) {
-        BT_ASSERT(msg_it->snapshots.end_clock != UINT64_C(-1));
-        msg = bt_message_packet_end_create_with_default_clock_snapshot(
-            msg_it->self_msg_iter, msg_it->packet, msg_it->default_clock_snapshot);
-    } else {
-        msg = bt_message_packet_end_create(msg_it->self_msg_iter, msg_it->packet);
-    }
-
-    if (!msg) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "Cannot create packet end message: "
-                                  "msg-it-addr=%p, packet-addr=%p",
-                                  msg_it, msg_it->packet);
-        goto end;
-    }
-
-    BT_PACKET_PUT_REF_AND_RESET(msg_it->packet);
-
-end:
-    return msg;
-}
-
-static bt_message *create_msg_discarded_events(struct ctf_msg_iter *msg_it)
-{
-    bt_message *msg;
-    bt_self_component *self_comp = msg_it->self_comp;
-    uint64_t beginning_raw_value = UINT64_C(-1);
-    uint64_t end_raw_value = UINT64_C(-1);
-
-    BT_ASSERT(msg_it->self_msg_iter);
-    BT_ASSERT(msg_it->stream);
-    BT_ASSERT(msg_it->meta.sc->has_discarded_events);
-
-    if (msg_it->meta.sc->discarded_events_have_default_cs) {
-        if (msg_it->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 = msg_it->snapshots.beginning_clock;
-            end_raw_value = msg_it->snapshots.end_clock;
-        } else {
-            beginning_raw_value = msg_it->prev_packet_snapshots.end_clock;
-            end_raw_value = msg_it->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(
-            msg_it->self_msg_iter, msg_it->stream, beginning_raw_value, end_raw_value);
-    } else {
-        msg = bt_message_discarded_events_create(msg_it->self_msg_iter, msg_it->stream);
-    }
-
-    if (!msg) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "Cannot create discarded events message: "
-                                  "msg-it-addr=%p, stream-addr=%p",
-                                  msg_it, msg_it->stream);
-        goto end;
-    }
-
-    if (msg_it->prev_packet_snapshots.discarded_events != UINT64_C(-1)) {
-        bt_message_discarded_events_set_count(msg,
-                                              msg_it->snapshots.discarded_events -
-                                                  msg_it->prev_packet_snapshots.discarded_events);
-    }
-
-end:
-    return msg;
-}
-
-static bt_message *create_msg_discarded_packets(struct ctf_msg_iter *msg_it)
-{
-    bt_message *msg;
-    bt_self_component *self_comp = msg_it->self_comp;
-
-    BT_ASSERT(msg_it->self_msg_iter);
-    BT_ASSERT(msg_it->stream);
-    BT_ASSERT(msg_it->meta.sc->has_discarded_packets);
-    BT_ASSERT(msg_it->prev_packet_snapshots.packets != UINT64_C(-1));
-
-    if (msg_it->meta.sc->discarded_packets_have_default_cs) {
-        BT_ASSERT(msg_it->prev_packet_snapshots.end_clock != UINT64_C(-1));
-        BT_ASSERT(msg_it->snapshots.beginning_clock != UINT64_C(-1));
-        msg = bt_message_discarded_packets_create_with_default_clock_snapshots(
-            msg_it->self_msg_iter, msg_it->stream, msg_it->prev_packet_snapshots.end_clock,
-            msg_it->snapshots.beginning_clock);
-    } else {
-        msg = bt_message_discarded_packets_create(msg_it->self_msg_iter, msg_it->stream);
-    }
-
-    if (!msg) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "Cannot create discarded packets message: "
-                                  "msg-it-addr=%p, stream-addr=%p",
-                                  msg_it, msg_it->stream);
-        goto end;
-    }
-
-    bt_message_discarded_packets_set_count(msg, msg_it->snapshots.packets -
-                                                    msg_it->prev_packet_snapshots.packets - 1);
-
-end:
-    return msg;
-}
-
-struct ctf_msg_iter *ctf_msg_iter_create(struct ctf_trace_class *tc, size_t max_request_sz,
-                                         struct ctf_msg_iter_medium_ops medops, void *data,
-                                         bt_logging_level log_level, bt_self_component *self_comp,
-                                         bt_self_message_iterator *self_msg_iter)
-{
-    struct ctf_msg_iter *msg_it = 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_ASSERT(max_request_sz > 0);
-
-    BT_COMP_LOG_CUR_LVL(BT_LOG_DEBUG, log_level, self_comp,
-                        "Creating CTF plugin message iterator: "
-                        "trace-addr=%p, max-request-size=%zu, "
-                        "data=%p, log-level=%s",
-                        tc, max_request_sz, data, bt_common_logging_level_string(log_level));
-    msg_it = g_new0(struct ctf_msg_iter, 1);
-    if (!msg_it) {
-        BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_comp,
-                            "Failed to allocate one CTF plugin message iterator.");
-        goto end;
-    }
-    msg_it->self_comp = self_comp;
-    msg_it->self_msg_iter = self_msg_iter;
-    msg_it->log_level = log_level;
-    msg_it->meta.tc = tc;
-    msg_it->medium.medops = medops;
-    msg_it->medium.max_request_sz = max_request_sz;
-    msg_it->medium.data = data;
-    msg_it->stack = stack_new(msg_it);
-    msg_it->stored_values = g_array_new(FALSE, TRUE, sizeof(uint64_t));
-    g_array_set_size(msg_it->stored_values, tc->stored_value_count);
-
-    if (!msg_it->stack) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to create field stack.");
-        goto error;
-    }
-
-    msg_it->bfcr = bt_bfcr_create(cbs, msg_it, log_level, NULL);
-    if (!msg_it->bfcr) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to create binary class reader (BFCR).");
-        goto error;
-    }
-
-    ctf_msg_iter_reset(msg_it);
-    BT_COMP_LOGD("Created CTF plugin message iterator: "
-                 "trace-addr=%p, max-request-size=%zu, "
-                 "data=%p, msg-it-addr=%p, log-level=%s",
-                 tc, max_request_sz, data, msg_it, bt_common_logging_level_string(log_level));
-    msg_it->cur_packet_offset = 0;
-
-end:
-    return msg_it;
-
-error:
-    ctf_msg_iter_destroy(msg_it);
-    msg_it = NULL;
-    goto end;
-}
-
-void ctf_msg_iter_destroy(struct ctf_msg_iter *msg_it)
-{
-    BT_PACKET_PUT_REF_AND_RESET(msg_it->packet);
-    BT_STREAM_PUT_REF_AND_RESET(msg_it->stream);
-    release_all_dscopes(msg_it);
-
-    BT_COMP_LOGD("Destroying CTF plugin message iterator: addr=%p", msg_it);
-
-    if (msg_it->stack) {
-        BT_COMP_LOGD_STR("Destroying field stack.");
-        stack_destroy(msg_it->stack);
-    }
-
-    if (msg_it->bfcr) {
-        BT_COMP_LOGD("Destroying BFCR: bfcr-addr=%p", msg_it->bfcr);
-        bt_bfcr_destroy(msg_it->bfcr);
-    }
-
-    if (msg_it->stored_values) {
-        g_array_free(msg_it->stored_values, TRUE);
-    }
-
-    g_free(msg_it);
-}
-
-enum ctf_msg_iter_status ctf_msg_iter_get_next_message(struct ctf_msg_iter *msg_it,
-                                                       const bt_message **message)
-{
-    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
-    bt_self_component *self_comp = msg_it->self_comp;
-
-    BT_ASSERT_DBG(msg_it);
-    BT_ASSERT_DBG(message);
-    BT_COMP_LOGD("Getting next message: msg-it-addr=%p", msg_it);
-
-    while (true) {
-        status = handle_state(msg_it);
-        if (G_UNLIKELY(status == CTF_MSG_ITER_STATUS_AGAIN)) {
-            BT_COMP_LOGD_STR("Medium returned CTF_MSG_ITER_STATUS_AGAIN.");
-            goto end;
-        } else if (G_UNLIKELY(status != CTF_MSG_ITER_STATUS_OK)) {
-            BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot handle state: msg-it-addr=%p, state=%s",
-                                      msg_it, state_string(msg_it->state));
-            goto end;
-        }
-
-        switch (msg_it->state) {
-        case STATE_EMIT_MSG_EVENT:
-            BT_ASSERT_DBG(msg_it->event_msg);
-
-            /*
-             * Check if we need to emit the delayed packet
-             * beginning message instead of the event message.
-             */
-            if (G_UNLIKELY(msg_it->emit_delayed_packet_beginning_msg)) {
-                *message = emit_delayed_packet_beg_msg(msg_it);
-                if (!*message) {
-                    status = CTF_MSG_ITER_STATUS_ERROR;
-                }
-
-                /*
-                 * Don't forget to emit the event message of
-                 * the event record that was just decoded.
-                 */
-                msg_it->state = STATE_EMIT_QUEUED_MSG_EVENT;
-
-            } else {
-                *message = msg_it->event_msg;
-                msg_it->event_msg = NULL;
-            }
-            goto end;
-        case STATE_EMIT_MSG_DISCARDED_EVENTS:
-            /* create_msg_discarded_events() logs errors */
-            *message = create_msg_discarded_events(msg_it);
-
-            if (!*message) {
-                status = CTF_MSG_ITER_STATUS_ERROR;
-            }
-
-            goto end;
-        case STATE_EMIT_MSG_DISCARDED_PACKETS:
-            /* create_msg_discarded_packets() logs errors */
-            *message = create_msg_discarded_packets(msg_it);
-
-            if (!*message) {
-                status = CTF_MSG_ITER_STATUS_ERROR;
-            }
-
-            goto end;
-        case STATE_EMIT_MSG_PACKET_BEGINNING:
-            if (G_UNLIKELY(msg_it->meta.tc->quirks.barectf_event_before_packet)) {
-                msg_it->emit_delayed_packet_beginning_msg = true;
-                /*
-                 * There is no message to return yet as this
-                 * packet beginning message is delayed until we
-                 * decode the first event message of the
-                 * packet.
-                 */
-                break;
-            } else {
-                /* create_msg_packet_beginning() logs errors */
-                *message = create_msg_packet_beginning(msg_it, false);
-                if (!*message) {
-                    status = CTF_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 */
-            *message = create_msg_packet_end(msg_it);
-
-            if (!*message) {
-                status = CTF_MSG_ITER_STATUS_ERROR;
-            }
-
-            goto end;
-        case STATE_EMIT_MSG_STREAM_BEGINNING:
-            /* create_msg_stream_beginning() logs errors */
-            *message = create_msg_stream_beginning(msg_it);
-            msg_it->emit_stream_beginning_message = false;
-            msg_it->emit_stream_end_message = true;
-
-            if (!*message) {
-                status = CTF_MSG_ITER_STATUS_ERROR;
-            }
-
-            goto end;
-        case STATE_EMIT_MSG_STREAM_END:
-            /* create_msg_stream_end() logs errors */
-            *message = create_msg_stream_end(msg_it);
-            msg_it->emit_stream_end_message = false;
-
-            if (!*message) {
-                status = CTF_MSG_ITER_STATUS_ERROR;
-            }
-
-            goto end;
-        case STATE_DONE:
-            status = CTF_MSG_ITER_STATUS_EOF;
-            goto end;
-        default:
-            /* Non-emitting state: continue */
-            break;
-        }
-    }
-
-end:
-    return status;
-}
-
-static enum ctf_msg_iter_status decode_until_state(struct ctf_msg_iter *msg_it,
-                                                   enum state target_state_1,
-                                                   enum state target_state_2)
-{
-    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
-    bt_self_component *self_comp = msg_it->self_comp;
-
-    BT_ASSERT_DBG(msg_it);
-
-    do {
-        /*
-         * Check if we reached the state at which we want to stop
-         * decoding.
-         */
-        if (msg_it->state == target_state_1 || msg_it->state == target_state_2) {
-            goto end;
-        }
-
-        status = handle_state(msg_it);
-        if (G_UNLIKELY(status == CTF_MSG_ITER_STATUS_AGAIN)) {
-            BT_COMP_LOGD_STR("Medium returned CTF_MSG_ITER_STATUS_AGAIN.");
-            goto end;
-        } else if (G_UNLIKELY(status != CTF_MSG_ITER_STATUS_OK)) {
-            BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot handle state: msg-it-addr=%p, state=%s",
-                                      msg_it, state_string(msg_it->state));
-            goto end;
-        }
-
-        switch (msg_it->state) {
-        case STATE_INIT:
-        case STATE_SWITCH_PACKET:
-        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_EMIT_MSG_STREAM_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:
-        case STATE_EMIT_MSG_PACKET_BEGINNING:
-        case STATE_DSCOPE_EVENT_HEADER_BEGIN:
-        case STATE_DSCOPE_EVENT_HEADER_CONTINUE:
-        case STATE_AFTER_EVENT_HEADER:
-        case STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN:
-        case STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE:
-        case STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN:
-        case STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE:
-        case STATE_DSCOPE_EVENT_PAYLOAD_BEGIN:
-        case STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE:
-        case STATE_EMIT_MSG_EVENT:
-        case STATE_EMIT_QUEUED_MSG_EVENT:
-        case STATE_SKIP_PACKET_PADDING:
-        case STATE_EMIT_MSG_PACKET_END_MULTI:
-        case STATE_EMIT_MSG_PACKET_END_SINGLE:
-        case STATE_EMIT_QUEUED_MSG_PACKET_END:
-        case STATE_EMIT_MSG_STREAM_END:
-            break;
-        case STATE_DONE:
-            /* fall-through */
-        default:
-            /* We should never get to the STATE_DONE state. */
-            BT_COMP_LOGF("Unexpected state: msg-it-addr=%p, state=%s", msg_it,
-                         state_string(msg_it->state));
-            bt_common_abort();
-        }
-    } while (true);
-
-end:
-    return status;
-}
-
-static enum ctf_msg_iter_status read_packet_header_context_fields(struct ctf_msg_iter *msg_it)
-{
-    int ret;
-    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
-
-    status = decode_until_state(msg_it, STATE_EMIT_MSG_PACKET_BEGINNING, (state) -1);
-    if (status != CTF_MSG_ITER_STATUS_OK) {
-        goto end;
-    }
-
-    ret = set_current_packet_content_sizes(msg_it);
-    if (ret) {
-        status = CTF_MSG_ITER_STATUS_ERROR;
-        goto end;
-    }
-
-end:
-    return status;
-}
-
-enum ctf_msg_iter_status ctf_msg_iter_seek(struct ctf_msg_iter *msg_it, off_t offset)
-{
-    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
-    enum ctf_msg_iter_medium_status medium_status;
-
-    BT_ASSERT(msg_it);
-    BT_ASSERT(offset >= 0);
-    BT_ASSERT(msg_it->medium.medops.seek);
-
-    medium_status = msg_it->medium.medops.seek(offset, msg_it->medium.data);
-    if (medium_status != CTF_MSG_ITER_MEDIUM_STATUS_OK) {
-        if (medium_status == CTF_MSG_ITER_MEDIUM_STATUS_EOF) {
-            status = CTF_MSG_ITER_STATUS_EOF;
-        } else {
-            status = CTF_MSG_ITER_STATUS_ERROR;
-            goto end;
-        }
-    }
-
-    ctf_msg_iter_reset(msg_it);
-    msg_it->cur_packet_offset = offset;
-
-end:
-    return status;
-}
-
-static enum ctf_msg_iter_status clock_snapshot_at_msg_iter_state(struct ctf_msg_iter *msg_it,
-                                                                 enum state target_state_1,
-                                                                 enum state target_state_2,
-                                                                 uint64_t *clock_snapshot)
-{
-    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
-
-    BT_ASSERT_DBG(msg_it);
-    BT_ASSERT_DBG(clock_snapshot);
-    status = decode_until_state(msg_it, target_state_1, target_state_2);
-    if (status != CTF_MSG_ITER_STATUS_OK) {
-        goto end;
-    }
-
-    *clock_snapshot = msg_it->default_clock_snapshot;
-end:
-    return status;
-}
-
-enum ctf_msg_iter_status
-ctf_msg_iter_curr_packet_first_event_clock_snapshot(struct ctf_msg_iter *msg_it,
-                                                    uint64_t *first_clock_snapshot)
-{
-    return clock_snapshot_at_msg_iter_state(msg_it, STATE_AFTER_EVENT_HEADER, (state) -1,
-                                            first_clock_snapshot);
-}
-
-enum ctf_msg_iter_status
-ctf_msg_iter_curr_packet_last_event_clock_snapshot(struct ctf_msg_iter *msg_it,
-                                                   uint64_t *last_clock_snapshot)
-{
-    return clock_snapshot_at_msg_iter_state(msg_it, STATE_EMIT_MSG_PACKET_END_SINGLE,
-                                            STATE_EMIT_MSG_PACKET_END_MULTI, last_clock_snapshot);
-}
-
-enum ctf_msg_iter_status
-ctf_msg_iter_get_packet_properties(struct ctf_msg_iter *msg_it,
-                                   struct ctf_msg_iter_packet_properties *props)
-{
-    enum ctf_msg_iter_status status;
-
-    BT_ASSERT_DBG(msg_it);
-    BT_ASSERT_DBG(props);
-    status = read_packet_header_context_fields(msg_it);
-    if (status != CTF_MSG_ITER_STATUS_OK) {
-        goto end;
-    }
-
-    props->exp_packet_total_size = msg_it->cur_exp_packet_total_size;
-    props->exp_packet_content_size = msg_it->cur_exp_packet_content_size;
-    props->stream_class_id = (uint64_t) msg_it->cur_stream_class_id;
-    props->data_stream_id = msg_it->cur_data_stream_id;
-    props->snapshots.discarded_events = msg_it->snapshots.discarded_events;
-    props->snapshots.packets = msg_it->snapshots.packets;
-    props->snapshots.beginning_clock = msg_it->snapshots.beginning_clock;
-    props->snapshots.end_clock = msg_it->snapshots.end_clock;
-
-end:
-    return status;
-}
-
-void ctf_msg_iter_set_dry_run(struct ctf_msg_iter *msg_it, bool val)
-{
-    msg_it->dry_run = val;
-}
diff --git a/src/plugins/ctf/common/msg-iter/msg-iter.hpp b/src/plugins/ctf/common/msg-iter/msg-iter.hpp
deleted file mode 100644 (file)
index 0b49c1c..0000000
+++ /dev/null
@@ -1,341 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2015-2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Babeltrace - CTF message iterator
- */
-
-#ifndef CTF_MSG_ITER_H
-#define CTF_MSG_ITER_H
-
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-
-#include <babeltrace2/babeltrace.h>
-
-#include "common/common.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.  These use the same values as
- * libbabeltrace2.
- */
-enum ctf_msg_iter_medium_status
-{
-    /**
-     * End of file.
-     *
-     * The medium function called by the message iterator
-     * function reached the end of the file.
-     */
-    CTF_MSG_ITER_MEDIUM_STATUS_EOF = 1,
-
-    /**
-     * There is no data available right now, try again later.
-     */
-    CTF_MSG_ITER_MEDIUM_STATUS_AGAIN = 11,
-
-    /** General error. */
-    CTF_MSG_ITER_MEDIUM_STATUS_ERROR = -1,
-
-    /** Memory error. */
-    CTF_MSG_ITER_MEDIUM_STATUS_MEMORY_ERROR = -12,
-
-    /** Everything okay. */
-    CTF_MSG_ITER_MEDIUM_STATUS_OK = 0,
-};
-
-/**
- * CTF message iterator API status code.
- */
-enum ctf_msg_iter_status
-{
-    /**
-     * End of file.
-     *
-     * The medium function called by the message iterator
-     * function reached the end of the file.
-     */
-    CTF_MSG_ITER_STATUS_EOF = CTF_MSG_ITER_MEDIUM_STATUS_EOF,
-
-    /**
-     * There is no data available right now, try again later.
-     *
-     * Some condition resulted in the
-     * ctf_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.
-     */
-    CTF_MSG_ITER_STATUS_AGAIN = CTF_MSG_ITER_MEDIUM_STATUS_AGAIN,
-
-    /** General error. */
-    CTF_MSG_ITER_STATUS_ERROR = CTF_MSG_ITER_MEDIUM_STATUS_ERROR,
-
-    /** Memory error. */
-    CTF_MSG_ITER_STATUS_MEMORY_ERROR = CTF_MSG_ITER_MEDIUM_STATUS_MEMORY_ERROR,
-
-    /** Everything okay. */
-    CTF_MSG_ITER_STATUS_OK = CTF_MSG_ITER_MEDIUM_STATUS_OK,
-};
-
-/**
- * Medium operations.
- *
- * Those user functions are called by the message iterator
- * functions to request medium actions.
- */
-struct ctf_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>#CTF_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>#CTF_MSG_ITER_MEDIUM_STATUS_AGAIN</b>: No data is
-     *     available right now. In this case, the message
-     *     iterator function called by the user returns
-     *     #CTF_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>#CTF_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
-     *     #CTF_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
-     *     #CTF_MSG_ITER_MEDIUM_STATUS_EOF on the \em following
-     *     call.
-     *   - <b>#CTF_MSG_ITER_MEDIUM_STATUS_ERROR</b>: A fatal
-     *     error occurred during this operation. In this case, the
-     *     message iterator function called by the user returns
-     *     #CTF_MSG_ITER_STATUS_ERROR.
-     *
-     * If #CTF_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 ctf_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 position in the medium.
-     *
-     * @param offset   Offset to use for the given directive
-     * @param data             User data
-     * @returns                One of #ctf_msg_iter_medium_status values
-     */
-    enum ctf_msg_iter_medium_status (*seek)(off_t offset, void *data);
-
-    /**
-     * Called when the message iterator wishes to inform the medium that it
-     * is about to start a new packet.
-     *
-     * After the iterator has called switch_packet, the following call to
-     * request_bytes must return the content at the start of the next
-     * packet.  */
-    enum ctf_msg_iter_medium_status (*switch_packet)(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);
-};
-
-/**
- * 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
- *                             ctf_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
- */
-struct ctf_msg_iter *ctf_msg_iter_create(struct ctf_trace_class *tc, size_t max_request_sz,
-                                         struct ctf_msg_iter_medium_ops medops, void *medops_data,
-                                         bt_logging_level log_level, bt_self_component *self_comp,
-                                         bt_self_message_iterator *self_msg_iter);
-
-/**
- * Destroys a CTF message iterator, freeing all internal resources.
- *
- * The registered trace's reference count is decremented.
- *
- * @param msg_iter             CTF message iterator
- */
-void ctf_msg_iter_destroy(struct ctf_msg_iter *msg_iter);
-
-/**
- * Returns the next message from a CTF message iterator.
- *
- * Upon successful completion, #CTF_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 #CTF_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 #CTF_MSG_ITER_STATUS_OK
- * @returns                    One of #ctf_msg_iter_status values
- */
-enum ctf_msg_iter_status ctf_msg_iter_get_next_message(struct ctf_msg_iter *msg_it,
-                                                       const bt_message **message);
-
-struct ctf_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;
-};
-
-enum ctf_msg_iter_status
-ctf_msg_iter_get_packet_properties(struct ctf_msg_iter *msg_it,
-                                   struct ctf_msg_iter_packet_properties *props);
-
-enum ctf_msg_iter_status
-ctf_msg_iter_curr_packet_first_event_clock_snapshot(struct ctf_msg_iter *msg_it,
-                                                    uint64_t *first_event_cs);
-
-enum ctf_msg_iter_status
-ctf_msg_iter_curr_packet_last_event_clock_snapshot(struct ctf_msg_iter *msg_it,
-                                                   uint64_t *last_event_cs);
-
-enum ctf_msg_iter_status ctf_msg_iter_seek(struct ctf_msg_iter *msg_it, 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
- * ctf_msg_iter_set_emit_stream_beginning_message(), the first message
- * which this iterator emits after calling ctf_msg_iter_reset() is of
- * type `CTF_MESSAGE_TYPE_STREAM_BEGINNING`.
- */
-void ctf_msg_iter_reset(struct ctf_msg_iter *msg_it);
-
-/*
- * Like ctf_msg_iter_reset(), but preserves stream-dependent state.
- */
-void ctf_msg_iter_reset_for_next_stream_file(struct ctf_msg_iter *msg_it);
-
-void ctf_msg_iter_set_dry_run(struct ctf_msg_iter *msg_it, bool val);
-
-static inline const char *ctf_msg_iter_medium_status_string(enum ctf_msg_iter_medium_status status)
-{
-    switch (status) {
-    case CTF_MSG_ITER_MEDIUM_STATUS_EOF:
-        return "EOF";
-    case CTF_MSG_ITER_MEDIUM_STATUS_AGAIN:
-        return "AGAIN";
-    case CTF_MSG_ITER_MEDIUM_STATUS_ERROR:
-        return "ERROR";
-    case CTF_MSG_ITER_MEDIUM_STATUS_MEMORY_ERROR:
-        return "MEMORY_ERROR";
-    case CTF_MSG_ITER_MEDIUM_STATUS_OK:
-        return "OK";
-    }
-
-    bt_common_abort();
-}
-
-static inline const char *ctf_msg_iter_status_string(enum ctf_msg_iter_status status)
-{
-    switch (status) {
-    case CTF_MSG_ITER_STATUS_EOF:
-        return "EOF";
-    case CTF_MSG_ITER_STATUS_AGAIN:
-        return "AGAIN";
-    case CTF_MSG_ITER_STATUS_ERROR:
-        return "ERROR";
-    case CTF_MSG_ITER_STATUS_MEMORY_ERROR:
-        return "MEMORY_ERROR";
-    case CTF_MSG_ITER_STATUS_OK:
-        return "OK";
-    }
-
-    bt_common_abort();
-}
-
-#endif /* CTF_MSG_ITER_H */
diff --git a/src/plugins/ctf/common/print.hpp b/src/plugins/ctf/common/print.hpp
deleted file mode 100644 (file)
index 7db4dde..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Define PRINT_PREFIX and PRINT_ERR_STREAM, then include this file.
- */
-
-#ifndef CTF_BTR_PRINT_H
-#define CTF_BTR_PRINT_H
-
-#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 (babeltrace_debug) {                                                                    \
-            fprintf(stderr, "Debug: " PRINT_PREFIX ": " fmt, ##__VA_ARGS__);                       \
-        }                                                                                          \
-    } while (0)
-
-#endif /* CTF_BTR_PRINT_H */
diff --git a/src/plugins/ctf/common/src/bfcr/bfcr.cpp b/src/plugins/ctf/common/src/bfcr/bfcr.cpp
new file mode 100644 (file)
index 0000000..4ee3548
--- /dev/null
@@ -0,0 +1,1271 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2015-2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Babeltrace - CTF binary field class reader (BFCR)
+ */
+
+#include "common/align.h"
+#include "common/assert.h"
+#include "common/common.h"
+#include "compat/bitfield.h"
+#include "cpp-common/bt2c/logging.hpp"
+#include "cpp-common/vendor/fmt/format.h"
+
+#include "../metadata/tsdl/ctf-meta.hpp"
+#include "bfcr.hpp"
+
+#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
+{
+    struct bt_bfcr *bfcr;
+
+    /* 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,
+};
+
+static const char *format_as(bfcr_state state) noexcept
+{
+    switch (state) {
+    case BFCR_STATE_NEXT_FIELD:
+        return "NEXT_FIELD";
+
+    case BFCR_STATE_ALIGN_BASIC:
+        return "ALIGN_BASIC";
+
+    case BFCR_STATE_ALIGN_COMPOUND:
+        return "ALIGN_COMPOUND";
+
+    case BFCR_STATE_READ_BASIC_BEGIN:
+        return "READ_BASIC_BEGIN";
+
+    case BFCR_STATE_READ_BASIC_CONTINUE:
+        return "READ_BASIC_CONTINUE";
+
+    case BFCR_STATE_DONE:
+        return "DONE";
+    }
+
+    bt_common_abort();
+}
+
+/* Binary class reader */
+struct bt_bfcr
+{
+    explicit bt_bfcr(const bt2c::Logger& parentLogger) : logger {parentLogger, "PLUGIN/CTF/BFCR"}
+    {
+    }
+
+    bt2c::Logger logger;
+
+    /* BFCR stack */
+    struct stack *stack = nullptr;
+
+    /* Current basic field class */
+    struct ctf_field_class *cur_basic_field_class = nullptr;
+
+    /* Current state */
+    enum bfcr_state state = static_cast<bfcr_state>(0);
+
+    /*
+     * 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 CTF_BYTE_ORDER_UNKNOWN on reset and when the last
+     * basic field class was a string class.
+     */
+    enum ctf_byte_order last_bo = CTF_BYTE_ORDER_UNKNOWN;
+
+    /* Current byte order (copied to last_bo after a successful read) */
+    enum ctf_byte_order cur_bo = CTF_BYTE_ORDER_UNKNOWN;
+
+    /* Stitch buffer infos */
+    struct
+    {
+        /* Stitch buffer */
+        uint8_t buf[16] {};
+
+        /* Offset, within stitch buffer, of first bit */
+        size_t offset = 0;
+
+        /* Length (bits) of data in stitch buffer from offset */
+        size_t at = 0;
+    } stitch;
+
+    /* User buffer infos */
+    struct
+    {
+        /* Address */
+        const uint8_t *addr = nullptr;
+
+        /* Offset of data from address (bits) */
+        size_t offset = 0;
+
+        /* Current position from offset (bits) */
+        size_t at = 0;
+
+        /* Offset of offset within whole packet (bits) */
+        size_t packet_offset = 0;
+
+        /* Data size in buffer (bits) */
+        size_t sz = 0;
+
+        /* Buffer size (bytes) */
+        size_t buf_sz = 0;
+    } buf;
+
+    /* User stuff */
+    struct
+    {
+        /* Callback functions */
+        bt_bfcr_cbs cbs {};
+
+        /* Private data */
+        void *data = nullptr;
+    } user;
+};
+
+static struct stack *stack_new(struct bt_bfcr *bfcr)
+{
+    struct stack *stack = NULL;
+
+    stack = g_new0(struct stack, 1);
+    if (!stack) {
+        BT_CPPLOGE_SPEC(bfcr->logger, "Failed to allocate one stack.");
+        goto error;
+    }
+
+    stack->bfcr = bfcr;
+    stack->entries = g_array_new(FALSE, TRUE, sizeof(struct stack_entry));
+    if (!stack->entries) {
+        BT_CPPLOGE_SPEC(bfcr->logger, "Failed to allocate a GArray.");
+        goto error;
+    }
+
+    BT_CPPLOGD_SPEC(bfcr->logger, "Created stack: addr={}", fmt::ptr(stack));
+    return stack;
+
+error:
+    g_free(stack);
+    return NULL;
+}
+
+static void stack_destroy(struct stack *stack)
+{
+    struct bt_bfcr *bfcr;
+
+    if (!stack) {
+        return;
+    }
+
+    bfcr = stack->bfcr;
+    BT_CPPLOGD_SPEC(bfcr->logger, "Destroying stack: addr={}", fmt::ptr(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;
+    struct bt_bfcr *bfcr;
+
+    BT_ASSERT_DBG(stack);
+    BT_ASSERT_DBG(base_class);
+    bfcr = stack->bfcr;
+    BT_CPPLOGT_SPEC(bfcr->logger,
+                    "Pushing field class on stack: stack-addr={}, "
+                    "fc-addr={}, fc-type={}, base-length={}, "
+                    "stack-size-before={}, stack-size-after={}",
+                    fmt::ptr(stack), fmt::ptr(base_class), (int) 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 = &bt_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:
+    {
+        ctf_field_class_struct *struct_fc = ctf_field_class_as_struct(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 = ctf_field_class_as_array(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:
+        bt_common_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_CPPLOGW_SPEC(bfcr->logger,
+                        "Cannot get compound field class's field count: "
+                        "bfcr-addr={}, fc-addr={}, fc-type={}",
+                        fmt::ptr(bfcr), fmt::ptr(base_class), (int) 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_DBG(stack);
+    return stack->size;
+}
+
+static void stack_pop(struct stack *stack)
+{
+    struct bt_bfcr *bfcr;
+
+    BT_ASSERT_DBG(stack);
+    BT_ASSERT_DBG(stack_size(stack));
+    bfcr = stack->bfcr;
+    BT_CPPLOGT_SPEC(bfcr->logger,
+                    "Popping from stack: "
+                    "stack-addr={}, stack-size-before={}, stack-size-after={}",
+                    fmt::ptr(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_DBG(stack);
+    stack->size = 0;
+}
+
+static inline struct stack_entry *stack_top(struct stack *stack)
+{
+    BT_ASSERT_DBG(stack);
+    BT_ASSERT_DBG(stack_size(stack));
+    return &bt_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_CPPLOGT_SPEC(bfcr->logger, "Advancing cursor: bfcr-addr={}, cur-before={}, cur-after={}",
+                    fmt::ptr(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(struct bt_bfcr *bfcr, 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:
+        bt_common_abort();
+    }
+
+    BT_CPPLOGT_SPEC(bfcr->logger, "Read unsigned bit array: cur={}, size={}, bo={}, val={}", at,
+                    field_size, (int) bo, *v);
+}
+
+static inline void read_signed_bitfield(struct bt_bfcr *bfcr, 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:
+        bt_common_abort();
+    }
+
+    BT_CPPLOGT_SPEC(bfcr->logger, "Read signed bit array: cur={}, size={}, bo={}, val={}", at,
+                    field_size, (int) 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 == CTF_BYTE_ORDER_UNKNOWN) {
+        goto end;
+    }
+
+    /* Always valid if next byte order is unknown */
+    if (next_bo == CTF_BYTE_ORDER_UNKNOWN) {
+        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_CPPLOGW_SPEC(bfcr->logger,
+                        "Cannot read bit array: two different byte orders not at a byte boundary: "
+                        "bfcr-addr={}, last-bo={}, next-bo={}",
+                        fmt::ptr(bfcr), (int) bfcr->last_bo, (int) 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;
+    ctf_field_class_float *fc = ctf_field_class_as_float(bfcr->cur_basic_field_class);
+
+    BT_ASSERT_DBG(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(bfcr, 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(bfcr, buf, at, field_size, bo, &f64.u);
+        dblval = f64.d;
+        break;
+    }
+    default:
+        /* Only 32-bit and 64-bit fields are supported currently */
+        bt_common_abort();
+    }
+
+    BT_CPPLOGT_SPEC(bfcr->logger, "Read floating point number value: bfcr={}, cur={}, val={}",
+                    fmt::ptr(bfcr), at, dblval);
+
+    if (bfcr->user.cbs.classes.floating_point) {
+        BT_CPPLOGT_SPEC(bfcr->logger, "Calling user function (floating point number).");
+        status = bfcr->user.cbs.classes.floating_point(dblval, bfcr->cur_basic_field_class,
+                                                       bfcr->user.data);
+        BT_CPPLOGT_SPEC(bfcr->logger, "User function returned: status={}", status);
+        if (status != BT_BFCR_STATUS_OK) {
+            BT_CPPLOGW_SPEC(bfcr->logger, "User function failed: bfcr-addr={}, status={}",
+                            fmt::ptr(bfcr), 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;
+    ctf_field_class_int *fc = ctf_field_class_as_int(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(bfcr, buf, at, field_size, bo, &v);
+
+        if (bfcr->user.cbs.classes.signed_int) {
+            BT_CPPLOGT_SPEC(bfcr->logger, "Calling user function (signed integer).");
+            status =
+                bfcr->user.cbs.classes.signed_int(v, bfcr->cur_basic_field_class, bfcr->user.data);
+            BT_CPPLOGT_SPEC(bfcr->logger, "User function returned: status={}", status);
+            if (status != BT_BFCR_STATUS_OK) {
+                BT_CPPLOGW_SPEC(bfcr->logger,
+                                "User function failed: "
+                                "bfcr-addr={}, status={}",
+                                fmt::ptr(bfcr), status);
+            }
+        }
+    } else {
+        uint64_t v;
+
+        read_unsigned_bitfield(bfcr, buf, at, field_size, bo, &v);
+
+        if (bfcr->user.cbs.classes.unsigned_int) {
+            BT_CPPLOGT_SPEC(bfcr->logger, "Calling user function (unsigned integer).");
+            status = bfcr->user.cbs.classes.unsigned_int(v, bfcr->cur_basic_field_class,
+                                                         bfcr->user.data);
+            BT_CPPLOGT_SPEC(bfcr->logger, "User function returned: status={}", status);
+            if (status != BT_BFCR_STATUS_OK) {
+                BT_CPPLOGW_SPEC(bfcr->logger,
+                                "User function failed: "
+                                "bfcr-addr={}, status={}",
+                                fmt::ptr(bfcr), 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;
+    ctf_field_class_bit_array *fc = ctf_field_class_as_bit_array(bfcr->cur_basic_field_class);
+
+    if (!at_least_one_bit_left(bfcr)) {
+        BT_CPPLOGT_SPEC(bfcr->logger, "Reached end of data: bfcr-addr={}", fmt::ptr(bfcr));
+        status = BT_BFCR_STATUS_EOF;
+        goto end;
+    }
+
+    available = available_bits(bfcr);
+    needed_bits = fc->size - bfcr->stitch.at;
+    BT_CPPLOGT_SPEC(bfcr->logger,
+                    "Continuing basic field decoding: "
+                    "bfcr-addr={}, field-size={}, needed-size={}, "
+                    "available-size={}",
+                    fmt::ptr(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_CPPLOGW_SPEC(bfcr->logger,
+                            "Cannot read basic field: "
+                            "bfcr-addr={}, fc-addr={}, status={}",
+                            fmt::ptr(bfcr), fmt::ptr(bfcr->cur_basic_field_class), 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_CPPLOGT_SPEC(bfcr->logger,
+                    "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;
+    ctf_field_class_bit_array *fc = ctf_field_class_as_bit_array(bfcr->cur_basic_field_class);
+
+    if (!at_least_one_bit_left(bfcr)) {
+        BT_CPPLOGT_SPEC(bfcr->logger, "Reached end of data: bfcr-addr={}", fmt::ptr(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_DBG(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_CPPLOGW_SPEC(bfcr->logger,
+                            "Cannot read basic field: "
+                            "bfcr-addr={}, fc-addr={}, status={}",
+                            fmt::ptr(bfcr), fmt::ptr(bfcr->cur_basic_field_class), 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_CPPLOGT_SPEC(bfcr->logger,
+                    "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_CPPLOGT_SPEC(bfcr->logger, "Reached end of data: bfcr-addr={}", fmt::ptr(bfcr));
+        status = BT_BFCR_STATUS_EOF;
+        goto end;
+    }
+
+    BT_ASSERT_DBG(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_DBG(bfcr->buf.addr);
+    first_chr = &bfcr->buf.addr[buf_at_bytes];
+    result = (const uint8_t *) memchr(first_chr, '\0', available_bytes);
+
+    if (begin && bfcr->user.cbs.classes.string_begin) {
+        BT_CPPLOGT_SPEC(bfcr->logger, "Calling user function (string, beginning).");
+        status = bfcr->user.cbs.classes.string_begin(bfcr->cur_basic_field_class, bfcr->user.data);
+        BT_CPPLOGT_SPEC(bfcr->logger, "User function returned: status={}", status);
+        if (status != BT_BFCR_STATUS_OK) {
+            BT_CPPLOGW_SPEC(bfcr->logger, "User function failed: bfcr-addr={}, status={}",
+                            fmt::ptr(bfcr), status);
+            goto end;
+        }
+    }
+
+    if (!result) {
+        /* No null character yet */
+        if (bfcr->user.cbs.classes.string) {
+            BT_CPPLOGT_SPEC(bfcr->logger, "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_CPPLOGT_SPEC(bfcr->logger, "User function returned: status={}", status);
+            if (status != BT_BFCR_STATUS_OK) {
+                BT_CPPLOGW_SPEC(bfcr->logger,
+                                "User function failed: "
+                                "bfcr-addr={}, status={}",
+                                fmt::ptr(bfcr), 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_CPPLOGT_SPEC(bfcr->logger, "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_CPPLOGT_SPEC(bfcr->logger, "User function returned: status={}", status);
+            if (status != BT_BFCR_STATUS_OK) {
+                BT_CPPLOGW_SPEC(bfcr->logger,
+                                "User function failed: "
+                                "bfcr-addr={}, status={}",
+                                fmt::ptr(bfcr), status);
+                goto end;
+            }
+        }
+
+        if (bfcr->user.cbs.classes.string_end) {
+            BT_CPPLOGT_SPEC(bfcr->logger, "Calling user function (string, end).");
+            status =
+                bfcr->user.cbs.classes.string_end(bfcr->cur_basic_field_class, bfcr->user.data);
+            BT_CPPLOGT_SPEC(bfcr->logger, "User function returned: status={}", status);
+            if (status != BT_BFCR_STATUS_OK) {
+                BT_CPPLOGW_SPEC(bfcr->logger,
+                                "User function failed: "
+                                "bfcr-addr={}, status={}",
+                                fmt::ptr(bfcr), 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_DBG(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:
+        bt_common_abort();
+    }
+
+    return status;
+}
+
+static inline enum bt_bfcr_status read_basic_continue_state(struct bt_bfcr *bfcr)
+{
+    enum bt_bfcr_status status;
+
+    BT_ASSERT_DBG(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:
+        bt_common_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 = BT_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_DBG(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_CPPLOGT_SPEC(bfcr->logger, "Reached end of data when aligning: bfcr-addr={}",
+                        fmt::ptr(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_CPPLOGT_SPEC(bfcr->logger, "Calling user function (compound, end).");
+            status = bfcr->user.cbs.classes.compound_end(top->base_class, bfcr->user.data);
+            BT_CPPLOGT_SPEC(bfcr->logger, "User function returned: status={}", status);
+            if (status != BT_BFCR_STATUS_OK) {
+                BT_CPPLOGW_SPEC(bfcr->logger, "User function failed: bfcr-addr={}, status={}",
+                                fmt::ptr(bfcr), 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(
+                               ctf_field_class_as_struct(top->base_class), (uint64_t) top->index)
+                               ->fc;
+        break;
+    case CTF_FIELD_CLASS_TYPE_ARRAY:
+    case CTF_FIELD_CLASS_TYPE_SEQUENCE:
+    {
+        ctf_field_class_array_base *array_fc = ctf_field_class_as_array_base(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_CPPLOGW_SPEC(bfcr->logger,
+                        "Cannot get the field class of the next field: "
+                        "bfcr-addr={}, base-fc-addr={}, base-fc-type={}, index={}",
+                        fmt::ptr(bfcr), fmt::ptr(top->base_class), (int) 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_CPPLOGT_SPEC(bfcr->logger, "Calling user function (compound, begin).");
+            status = bfcr->user.cbs.classes.compound_begin(next_field_class, bfcr->user.data);
+            BT_CPPLOGT_SPEC(bfcr->logger, "User function returned: status={}", status);
+            if (status != BT_BFCR_STATUS_OK) {
+                BT_CPPLOGW_SPEC(bfcr->logger, "User function failed: bfcr-addr={}, status={}",
+                                fmt::ptr(bfcr), 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_CPPLOGT_SPEC(bfcr->logger,
+                        "Replacing current basic field class: "
+                        "bfcr-addr={}, cur-basic-fc-addr={}, "
+                        "next-basic-fc-addr={}",
+                        fmt::ptr(bfcr), fmt::ptr(bfcr->cur_basic_field_class),
+                        fmt::ptr(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_CPPLOGT_SPEC(bfcr->logger, "Handling state: bfcr-addr={}, state={}", fmt::ptr(bfcr),
+                    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_CPPLOGT_SPEC(bfcr->logger, "Handled state: bfcr-addr={}, status={}", fmt::ptr(bfcr), status);
+    return status;
+}
+
+struct bt_bfcr *bt_bfcr_create(struct bt_bfcr_cbs cbs, void *data, const bt2c::Logger& logger)
+{
+    BT_CPPLOGD_SPEC(logger, "Creating binary field class reader (BFCR).");
+
+    bt_bfcr *bfcr = new bt_bfcr {logger};
+    bfcr->stack = stack_new(bfcr);
+    if (!bfcr->stack) {
+        BT_CPPLOGE_SPEC(bfcr->logger, "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_CPPLOGD_SPEC(bfcr->logger, "Created BFCR: addr={}", fmt::ptr(bfcr));
+
+end:
+    return bfcr;
+}
+
+void bt_bfcr_destroy(struct bt_bfcr *bfcr)
+{
+    if (bfcr->stack) {
+        stack_destroy(bfcr->stack);
+    }
+
+    BT_CPPLOGD_SPEC(bfcr->logger, "Destroying BFCR: addr={}", fmt::ptr(bfcr));
+    delete bfcr;
+}
+
+static void reset(struct bt_bfcr *bfcr)
+{
+    BT_CPPLOGD_SPEC(bfcr->logger, "Resetting BFCR: addr={}", fmt::ptr(bfcr));
+    stack_clear(bfcr->stack);
+    stitch_reset(bfcr);
+    bfcr->buf.addr = NULL;
+    bfcr->last_bo = CTF_BYTE_ORDER_UNKNOWN;
+}
+
+static void update_packet_offset(struct bt_bfcr *bfcr)
+{
+    BT_CPPLOGT_SPEC(bfcr->logger,
+                    "Updating packet offset for next call: "
+                    "bfcr-addr={}, cur-packet-offset={}, next-packet-offset={}",
+                    fmt::ptr(bfcr), bfcr->buf.packet_offset,
+                    bfcr->buf.packet_offset + bfcr->buf.at);
+    bfcr->buf.packet_offset += bfcr->buf.at;
+}
+
+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_DBG(bfcr);
+    BT_ASSERT_DBG(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_CPPLOGT_SPEC(bfcr->logger,
+                    "Starting decoding: bfcr-addr={}, fc-addr={}, "
+                    "buf-addr={}, buf-size={}, offset={}, "
+                    "packet-offset={}",
+                    fmt::ptr(bfcr), fmt::ptr(cls), fmt::ptr(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_CPPLOGT_SPEC(bfcr->logger, "Calling user function (compound, begin).");
+            *status = bfcr->user.cbs.classes.compound_begin(cls, bfcr->user.data);
+            BT_CPPLOGT_SPEC(bfcr->logger, "User function returned: status={}", *status);
+            if (*status != BT_BFCR_STATUS_OK) {
+                BT_CPPLOGW_SPEC(bfcr->logger, "User function failed: bfcr-addr={}, status={}",
+                                fmt::ptr(bfcr), *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_CPPLOGT_SPEC(bfcr->logger, "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;
+}
+
+size_t bt_bfcr_continue(struct bt_bfcr *bfcr, const uint8_t *buf, size_t sz,
+                        enum bt_bfcr_status *status)
+{
+    BT_ASSERT_DBG(bfcr);
+    BT_ASSERT_DBG(buf);
+    BT_ASSERT_DBG(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_CPPLOGT_SPEC(bfcr->logger, "Continuing decoding: bfcr-addr={}, buf-addr={}, buf-size={}",
+                    fmt::ptr(bfcr), fmt::ptr(buf), sz);
+
+    /* Continue running the machine */
+    BT_CPPLOGT_SPEC(bfcr->logger, "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;
+}
+
+void bt_bfcr_set_unsigned_int_cb(struct bt_bfcr *bfcr, bt_bfcr_unsigned_int_cb_func cb)
+{
+    BT_ASSERT_DBG(bfcr);
+    BT_ASSERT_DBG(cb);
+    bfcr->user.cbs.classes.unsigned_int = cb;
+}
diff --git a/src/plugins/ctf/common/src/bfcr/bfcr.hpp b/src/plugins/ctf/common/src/bfcr/bfcr.hpp
new file mode 100644 (file)
index 0000000..984b695
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2015-2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Babeltrace - CTF binary field class reader (BFCR)
+ */
+
+#ifndef CTF_BFCR_H
+#define CTF_BFCR_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <babeltrace2/babeltrace.h>
+
+#include "cpp-common/vendor/fmt/format.h" /* IWYU pragma: keep */
+
+#include "../metadata/tsdl/ctf-meta.hpp"
+
+namespace bt2c {
+
+class Logger;
+
+} /* namespace bt2c */
+
+/**
+ * @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,
+};
+
+inline const char *format_as(bt_bfcr_status status) noexcept
+{
+    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";
+        break;
+    }
+
+    bt_common_abort();
+}
+
+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
+ */
+struct bt_bfcr *bt_bfcr_create(struct bt_bfcr_cbs cbs, void *data, const bt2c::Logger& logger);
+
+/**
+ * Destroys a CTF binary class reader, freeing all internal resources.
+ *
+ * @param bfcr Binary class reader
+ */
+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
+ */
+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
+ */
+size_t bt_bfcr_continue(struct bt_bfcr *bfcr, const uint8_t *buf, size_t sz,
+                        enum bt_bfcr_status *status);
+
+void bt_bfcr_set_unsigned_int_cb(struct bt_bfcr *bfcr, bt_bfcr_unsigned_int_cb_func cb);
+
+#endif /* CTF_BFCR_H */
diff --git a/src/plugins/ctf/common/src/clk-cls-cfg.hpp b/src/plugins/ctf/common/src/clk-cls-cfg.hpp
new file mode 100644 (file)
index 0000000..0c3b52d
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright (c) 2022 EfficiOS Inc. and Linux Foundation
+ */
+
+#ifndef CTF_COMMON_SRC_CLK_CLS_CFG_HPP
+#define CTF_COMMON_SRC_CLK_CLS_CFG_HPP
+
+#include <cstdint>
+
+namespace ctf {
+namespace src {
+
+struct ClkClsCfg
+{
+    std::int64_t offsetSec = 0;
+    std::int64_t offsetNanoSec = 0;
+    bool forceOriginIsUnixEpoch = false;
+};
+
+} /* namespace src */
+} /* namespace ctf */
+
+#endif /* CTF_COMMON_SRC_CLK_CLS_CFG_HPP */
diff --git a/src/plugins/ctf/common/src/metadata/tsdl/ast.hpp b/src/plugins/ctf/common/src/metadata/tsdl/ast.hpp
new file mode 100644 (file)
index 0000000..597cb3a
--- /dev/null
@@ -0,0 +1,611 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2011-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ */
+
+#ifndef _CTF_AST_H
+#define _CTF_AST_H
+
+#include <memory>
+
+#include <glib.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <babeltrace2/babeltrace.h>
+
+#include "common/assert.h"
+#include "common/list.h"
+#include "cpp-common/bt2/trace-ir.hpp"
+#include "cpp-common/vendor/fmt/format.h" /* IWYU pragma: keep */
+
+#include "ctf-meta.hpp"
+#include "decoder.hpp"
+
+// 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
+};
+
+inline const char *format_as(enum node_type type) noexcept
+{
+    switch (type) {
+#define ENTRY(S)                                                                                   \
+case S:                                                                                            \
+    return G_STRINGIFY(S);
+
+        FOREACH_CTF_NODES(ENTRY)
+#undef ENTRY
+    }
+
+    bt_common_abort();
+}
+
+enum ctf_unary
+{
+    UNARY_UNKNOWN = 0,
+    UNARY_STRING,
+    UNARY_SIGNED_CONSTANT,
+    UNARY_UNSIGNED_CONSTANT,
+    UNARY_SBRAC,
+};
+
+inline const char *format_as(ctf_unary value) noexcept
+{
+    switch (value) {
+    case UNARY_UNKNOWN:
+        return "UNARY_UNKNOWN";
+
+    case UNARY_STRING:
+        return "UNARY_STRING";
+
+    case UNARY_SIGNED_CONSTANT:
+        return "UNARY_SIGNED_CONSTANT";
+
+    case UNARY_UNSIGNED_CONSTANT:
+        return "UNARY_UNSIGNED_CONSTANT";
+
+    case UNARY_SBRAC:
+        return "UNARY_SBRAC";
+    }
+
+    bt_common_abort();
+}
+
+enum ctf_unary_link
+{
+    UNARY_LINK_UNKNOWN = 0,
+    UNARY_DOTLINK,
+    UNARY_ARROWLINK,
+    UNARY_DOTDOTDOT,
+};
+
+enum ctf_typedec
+{
+    TYPEDEC_UNKNOWN = 0,
+    TYPEDEC_ID,     /* identifier */
+    TYPEDEC_NESTED, /* (), array or sequence */
+};
+
+inline const char *format_as(ctf_typedec value) noexcept
+{
+    switch (value) {
+    case TYPEDEC_UNKNOWN:
+        return "TYPEDEC_UNKNOWN";
+
+    case TYPEDEC_ID:
+        return "TYPEDEC_ID";
+
+    case TYPEDEC_NESTED:
+        return "TYPEDEC_NESTED";
+    }
+
+    bt_common_abort();
+}
+
+enum ctf_typespec
+{
+    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,
+};
+
+inline const char *format_as(ctf_typespec value) noexcept
+{
+    switch (value) {
+    case TYPESPEC_UNKNOWN:
+        return "TYPESPEC_UNKNOWN";
+
+    case TYPESPEC_VOID:
+        return "TYPESPEC_VOID";
+
+    case TYPESPEC_CHAR:
+        return "TYPESPEC_CHAR";
+
+    case TYPESPEC_SHORT:
+        return "TYPESPEC_SHORT";
+
+    case TYPESPEC_INT:
+        return "TYPESPEC_INT";
+
+    case TYPESPEC_LONG:
+        return "TYPESPEC_LONG";
+
+    case TYPESPEC_FLOAT:
+        return "TYPESPEC_FLOAT";
+
+    case TYPESPEC_DOUBLE:
+        return "TYPESPEC_DOUBLE";
+
+    case TYPESPEC_SIGNED:
+        return "TYPESPEC_SIGNED";
+
+    case TYPESPEC_UNSIGNED:
+        return "TYPESPEC_UNSIGNED";
+
+    case TYPESPEC_BOOL:
+        return "TYPESPEC_BOOL";
+
+    case TYPESPEC_COMPLEX:
+        return "TYPESPEC_COMPLEX";
+
+    case TYPESPEC_IMAGINARY:
+        return "TYPESPEC_IMAGINARY";
+
+    case TYPESPEC_CONST:
+        return "TYPESPEC_CONST";
+
+    case TYPESPEC_ID_TYPE:
+        return "TYPESPEC_ID_TYPE";
+
+    case TYPESPEC_FLOATING_POINT:
+        return "TYPESPEC_FLOATING_POINT";
+
+    case TYPESPEC_INTEGER:
+        return "TYPESPEC_INTEGER";
+
+    case TYPESPEC_STRING:
+        return "TYPESPEC_STRING";
+
+    case TYPESPEC_STRUCT:
+        return "TYPESPEC_STRUCT";
+
+    case TYPESPEC_VARIANT:
+        return "TYPESPEC_VARIANT";
+
+    case TYPESPEC_ENUM:
+        return "TYPESPEC_ENUM";
+    }
+
+    bt_common_abort();
+}
+
+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
+        {
+            ctf_unary 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;
+            ctf_unary_link 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
+        {
+            ctf_typespec 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;
+            ctf_typedec 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);
+
+struct ctf_visitor_generate_ir
+{
+    using UP = std::unique_ptr<ctf_visitor_generate_ir>;
+
+    explicit ctf_visitor_generate_ir(ctf_metadata_decoder_config decoderConfig,
+                                     bt2c::Logger loggerParam) :
+        decoder_config {std::move(decoderConfig)},
+        logger {std::move(loggerParam)}
+    {
+    }
+
+    ~ctf_visitor_generate_ir();
+
+    /* Trace IR trace class being filled (owned by this) */
+    bt2::TraceClass::Shared trace_class;
+
+    /* CTF meta trace being filled (owned by this) */
+    struct ctf_trace_class *ctf_tc = nullptr;
+
+    /* Current declaration scope (top of the stack) (owned by this) */
+    struct ctx_decl_scope *current_scope = nullptr;
+
+    /* True if trace declaration is visited */
+    bool is_trace_visited = false;
+
+    /* True if this is an LTTng trace */
+    bool is_lttng = false;
+
+    /* Config passed by the user */
+    struct ctf_metadata_decoder_config decoder_config;
+
+    bt2c::Logger logger;
+};
+
+ctf_visitor_generate_ir::UP
+ctf_visitor_generate_ir_create(const struct ctf_metadata_decoder_config *config);
+
+bt2::TraceClass::Shared
+ctf_visitor_generate_ir_get_ir_trace_class(struct ctf_visitor_generate_ir *visitor);
+
+struct ctf_trace_class *
+ctf_visitor_generate_ir_borrow_ctf_trace_class(struct ctf_visitor_generate_ir *visitor);
+
+int ctf_visitor_generate_ir_visit_node(struct ctf_visitor_generate_ir *visitor,
+                                       struct ctf_node *node);
+
+int ctf_visitor_semantic_check(int depth, struct ctf_node *node, const bt2c::Logger& logger);
+
+int ctf_visitor_parent_links(int depth, struct ctf_node *node, const bt2c::Logger& logger);
+
+static inline char *ctf_ast_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);
+}
+
+#ifndef BT_COMP_LOG_CUR_LVL
+#    define BT_AST_LOG_LEVEL_UNUSED_ATTR __attribute__((unused))
+#else
+#    define BT_AST_LOG_LEVEL_UNUSED_ATTR
+#endif
+
+static inline int ctf_ast_get_unary_uuid(struct bt_list_head *head, bt_uuid_t uuid,
+                                         const bt2c::Logger& logger)
+{
+    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_from_str(src_string, uuid);
+        if (ret) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "Cannot parse UUID: uuid=\"{}\"", src_string);
+            goto end;
+        }
+    }
+
+end:
+    return ret;
+}
+
+#endif /* _CTF_AST_H */
diff --git a/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-configure-ir-trace.cpp b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-configure-ir-trace.cpp
new file mode 100644 (file)
index 0000000..dbcbbbd
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
+ */
+
+#include <babeltrace2/babeltrace.h>
+
+#include "cpp-common/bt2c/uuid.hpp"
+
+#include "ctf-meta-configure-ir-trace.hpp"
+#include "plugins/ctf/common/src/metadata/tsdl/ctf-meta.hpp"
+
+void ctf_trace_class_configure_ir_trace(struct ctf_trace_class *tc, const bt2::Trace ir_trace)
+{
+    uint64_t i;
+
+    BT_ASSERT(tc);
+
+    if (tc->is_uuid_set) {
+        ir_trace.uuid(bt2c::Uuid {tc->uuid});
+    }
+
+    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);
+
+        switch (env_entry->type) {
+        case CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT:
+            ir_trace.environmentEntry(env_entry->name->str, env_entry->value.i);
+            break;
+        case CTF_TRACE_CLASS_ENV_ENTRY_TYPE_STR:
+            ir_trace.environmentEntry(env_entry->name->str, env_entry->value.str->str);
+            break;
+        default:
+            bt_common_abort();
+        }
+    }
+}
diff --git a/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-configure-ir-trace.hpp b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-configure-ir-trace.hpp
new file mode 100644 (file)
index 0000000..2adffb5
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
+ */
+
+#ifndef _CTF_META_CONFIGURE_IR_TRACE_H
+#define _CTF_META_CONFIGURE_IR_TRACE_H
+
+#include "cpp-common/bt2/trace-ir.hpp"
+
+void ctf_trace_class_configure_ir_trace(struct ctf_trace_class *tc, bt2::Trace ir_trace);
+
+#endif /* _CTF_META_CONFIGURE_IR_TRACE_H */
diff --git a/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-resolve.cpp b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-resolve.cpp
new file mode 100644 (file)
index 0000000..4420746
--- /dev/null
@@ -0,0 +1,1250 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2016-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ */
+
+#include <babeltrace2/babeltrace.h>
+
+#include "common/assert.h"
+#include "common/common.h"
+#include "cpp-common/bt2c/logging.hpp"
+#include "cpp-common/vendor/fmt/format.h"
+
+#include "ctf-meta-visitors.hpp"
+
+using field_class_stack_t = GPtrArray;
+
+/*
+ * 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
+{
+    explicit resolve_context(const bt2c::Logger& parentLogger) :
+        logger {parentLogger, "PLUGIN/CTF/META/RESOLVE"}
+    {
+    }
+
+    bt2c::Logger logger;
+
+    struct ctf_trace_class *tc = nullptr;
+    struct ctf_stream_class *sc = nullptr;
+    struct ctf_event_class *ec = nullptr;
+
+    struct
+    {
+        struct ctf_field_class *packet_header = nullptr;
+        struct ctf_field_class *packet_context = nullptr;
+        struct ctf_field_class *event_header = nullptr;
+        struct ctf_field_class *event_common_context = nullptr;
+        struct ctf_field_class *event_spec_context = nullptr;
+        struct ctf_field_class *event_payload = nullptr;
+    } scopes;
+
+    /* Root scope being visited */
+    enum ctf_scope root_scope = CTF_SCOPE_PACKET_HEADER;
+    field_class_stack_t *field_class_stack = nullptr;
+    struct ctf_field_class *cur_fc = nullptr;
+};
+
+/* 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_t *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_t *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_t *stack, struct ctf_field_class *fc,
+                                  struct resolve_context *ctx)
+{
+    int ret = 0;
+    struct field_class_stack_frame *frame = NULL;
+
+    if (!stack || !fc) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                     "Invalid parameter: stack or field class is `NULL`.");
+        ret = -1;
+        goto end;
+    }
+
+    frame = g_new0(struct field_class_stack_frame, 1);
+    if (!frame) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                     "Failed to allocate one field class stack frame.");
+        ret = -1;
+        goto end;
+    }
+
+    BT_CPPLOGD_SPEC(ctx->logger,
+                    "Pushing field class on context's stack: "
+                    "fc-addr={}, stack-size-before={}",
+                    fmt::ptr(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_t *stack)
+{
+    return stack->len == 0;
+}
+
+/*
+ * Returns the number of frames in `stack`.
+ */
+static size_t field_class_stack_size(field_class_stack_t *stack)
+{
+    return stack->len;
+}
+
+/*
+ * Returns the top frame of `stack`.
+ */
+static struct field_class_stack_frame *field_class_stack_peek(field_class_stack_t *stack)
+{
+    BT_ASSERT(stack);
+    BT_ASSERT(!field_class_stack_empty(stack));
+
+    return (field_class_stack_frame *) g_ptr_array_index(stack, stack->len - 1);
+}
+
+/*
+ * Returns the frame at index `index` in `stack`.
+ */
+static struct field_class_stack_frame *field_class_stack_at(field_class_stack_t *stack,
+                                                            size_t index)
+{
+    BT_ASSERT(stack);
+    BT_ASSERT(index < stack->len);
+
+    return (field_class_stack_frame *) g_ptr_array_index(stack, index);
+}
+
+/*
+ * Removes the top frame of `stack`.
+ */
+static void field_class_stack_pop(field_class_stack_t *stack, struct resolve_context *ctx)
+{
+    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_CPPLOGD_SPEC(ctx->logger, "Popping context's stack: stack-size-before={}", 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:
+        bt_common_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,
+                                                           struct resolve_context *ctx)
+{
+    enum ctf_scope scope;
+    enum ctf_scope ret = CTF_SCOPE_PACKET_UNKNOWN;
+    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 = (ctf_scope) (scope + 1)) {
+        /*
+         * Check 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_CPPLOGD_SPEC(ctx->logger,
+                            "Prefix does not match: trying the next one: "
+                            "path=\"{}\", path-prefix=\"{}\", scope={}",
+                            pathstr, absolute_path_prefixes[scope], scope);
+            continue;
+        }
+
+        /* Found it! */
+        ret = scope;
+        BT_CPPLOGD_SPEC(ctx->logger,
+                        "Found root scope from absolute path: "
+                        "path=\"{}\", scope={}",
+                        pathstr, scope);
+        goto end;
+    }
+
+end:
+    return ret;
+}
+
+/*
+ * Destroys a path token.
+ */
+static void ptokens_destroy_func(gpointer ptoken, gpointer)
+{
+    g_string_free((GString *) 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, struct resolve_context *ctx)
+{
+    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_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger, "Empty path token: path=\"{}\", pos={}",
+                                             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,
+                                 struct resolve_context *ctx)
+{
+    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_CPPLOGD_SPEC(ctx->logger, "Current path token: token=\"{}\"", 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_orig_name(fc, ft_name);
+            if (child_index < 0) {
+                /*
+                 * Error: field name does not exist or
+                 * wrong current class.
+                 */
+                BT_CPPLOGD_SPEC(ctx->logger,
+                                "Cannot get index of field class: "
+                                "field-name=\"{}\", "
+                                "src-index={}, "
+                                "child-index={}, "
+                                "first-level-done={}",
+                                ft_name, src_index, child_index, first_level_done);
+                ret = -1;
+                goto end;
+            } else if (child_index > src_index && !first_level_done) {
+                BT_CPPLOGD_SPEC(ctx->logger,
+                                "Child field class is located after source field class: "
+                                "field-name=\"{}\", "
+                                "src-index={}, "
+                                "child-index={}, "
+                                "first-level-done={}",
+                                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_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                         "Trace class is already translated: "
+                                         "root-scope={}",
+                                         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_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                         "No current stream class: "
+                                         "root-scope={}",
+                                         field_path->root);
+            ret = -1;
+            goto end;
+        }
+
+        if (ctx->sc->is_translated) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                         "Stream class is already translated: "
+                                         "root-scope={}",
+                                         field_path->root);
+            ret = -1;
+            goto end;
+        }
+
+        break;
+    case CTF_SCOPE_EVENT_SPECIFIC_CONTEXT:
+    case CTF_SCOPE_EVENT_PAYLOAD:
+        if (!ctx->ec) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                         "No current event class: "
+                                         "root-scope={}",
+                                         field_path->root);
+            ret = -1;
+            goto end;
+        }
+
+        if (ctx->ec->is_translated) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                         "Event class is already translated: "
+                                         "root-scope={}",
+                                         field_path->root);
+            ret = -1;
+            goto end;
+        }
+
+        break;
+
+    default:
+        bt_common_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_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                     "Root field class is not available: "
+                                     "root-scope={}",
+                                     field_path->root);
+        ret = -1;
+        goto end;
+    }
+
+    /* Locate target */
+    ret = ptokens_to_field_path(cur_ptoken, field_path, fc, INT64_MAX, ctx);
+
+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_CPPLOGD_SPEC(ctx->logger,
+                        "Locating target field class from current parent field class: "
+                        "parent-pos={}, parent-fc-addr={}, "
+                        "cur-index={}",
+                        parent_pos_in_stack, fmt::ptr(parent_class), cur_index);
+
+        /* Locate target from current parent class */
+        ret = ptokens_to_field_path(ptokens, &tail_field_path, parent_class, cur_index, ctx);
+        if (ret) {
+            /* Not found... yet */
+            BT_CPPLOGD_SPEC(ctx->logger, "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, ctx);
+    if (!ptokens) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                     "Cannot convert path string to path tokens: "
+                                     "path=\"{}\"",
+                                     pathstr);
+        ret = -1;
+        goto end;
+    }
+
+    /* Absolute or relative path? */
+    root_scope = get_root_scope_from_absolute_pathstr(pathstr, ctx);
+
+    if (root_scope == CTF_SCOPE_PACKET_UNKNOWN) {
+        /* Relative path: start with current root scope */
+        field_path->root = ctx->root_scope;
+        BT_CPPLOGD_SPEC(ctx->logger,
+                        "Detected relative path: starting with current root scope: "
+                        "scope={}",
+                        field_path->root);
+        ret = relative_ptokens_to_field_path(ptokens, field_path, ctx);
+        if (ret) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                         "Cannot get relative field path of path string: "
+                                         "path=\"{}\", start-scope={}, end-scope={}",
+                                         pathstr, ctx->root_scope, field_path->root);
+            goto end;
+        }
+    } else {
+        /* Absolute path: use found root scope */
+        field_path->root = root_scope;
+        BT_CPPLOGD_SPEC(ctx->logger,
+                        "Detected absolute path: using root scope: "
+                        "scope={}",
+                        field_path->root);
+        ret = absolute_ptokens_to_field_path(ptokens, field_path, ctx);
+        if (ret) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                         "Cannot get absolute field path of path string: "
+                                         "path=\"{}\", root-scope={}",
+                                         pathstr, root_scope);
+            goto end;
+        }
+    }
+
+    if (ret == 0) {
+        BT_CPPLOGD_SPEC(ctx->logger, "Found field path: path=\"{}\", field-path=\"{}\"", pathstr,
+                        *field_path);
+    }
+
+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_CPPLOGE_APPEND_CAUSE_SPEC(
+            ctx->logger, "Root field class is not available: root-scope={}", 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.
+ */
+static int64_t get_field_paths_lca_index(struct ctf_field_path *field_path1,
+                                         struct ctf_field_path *field_path2,
+                                         struct resolve_context *ctx)
+{
+    int64_t lca_index = 0;
+    uint64_t field_path1_len, field_path2_len;
+
+    BT_CPPLOGD_SPEC(ctx->logger,
+                    "Finding lowest common ancestor (LCA) between two field paths: "
+                    "field-path-1=\"{}\", field-path-2=\"{}\"",
+                    *field_path1, *field_path2);
+
+    /*
+     * 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_CPPLOGE_APPEND_CAUSE_SPEC(
+                ctx->logger,
+                "Source field class is an ancestor of target field class or vice versa: "
+                "lca-index={}, "
+                "field-path-1-len={}, "
+                "field-path-2-len={}",
+                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_CPPLOGD_SPEC(ctx->logger, "Found LCA: lca-index={}", 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_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                     "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_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                     "Target field class is located after source field class: "
+                                     "target-root={}, source-root={}",
+                                     target_field_path->root, 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, ctx);
+        if (lca_index < 0) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger, "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_CPPLOGE_APPEND_CAUSE_SPEC(
+                ctx->logger,
+                "Target field class's index is greater than or equal to source field class's index in LCA: "
+                "lca-index={}, "
+                "target-index={}, "
+                "source-index={}",
+                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_CPPLOGE_APPEND_CAUSE_SPEC(
+                ctx->logger,
+                "Variant field class's tag field class is not an enumeration field class: "
+                "tag-fc-addr={}, tag-fc-id={}",
+                fmt::ptr(target_fc), (int) target_fc->type);
+            ret = -1;
+            goto end;
+        }
+        break;
+    case CTF_FIELD_CLASS_TYPE_SEQUENCE:
+    {
+        if (target_fc->type != CTF_FIELD_CLASS_TYPE_INT &&
+            target_fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(
+                ctx->logger,
+                "Sequence field class's length field class is not an unsigned integer field class: "
+                "length-fc-addr={}, length-fc-id={}",
+                fmt::ptr(target_fc), (int) target_fc->type);
+            ret = -1;
+            goto end;
+        }
+
+        ctf_field_class_int *int_fc = ctf_field_class_as_int(target_fc);
+
+        if (int_fc->is_signed) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(
+                ctx->logger,
+                "Sequence field class's length field class is not an unsigned integer field class: "
+                "length-fc-addr={}, length-fc-id={}",
+                fmt::ptr(target_fc), (int) target_fc->type);
+            ret = -1;
+            goto end;
+        }
+        break;
+    }
+    default:
+        bt_common_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;
+
+    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 = ctf_field_class_as_sequence(fc);
+        pathstr = seq_fc->length_ref->str;
+        break;
+    }
+    case CTF_FIELD_CLASS_TYPE_VARIANT:
+    {
+        struct ctf_field_class_variant *var_fc = ctf_field_class_as_variant(fc);
+        pathstr = var_fc->tag_ref->str;
+        break;
+    }
+    default:
+        bt_common_abort();
+    }
+
+    if (!pathstr) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger, "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_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                     "Cannot get target field path for path string: "
+                                     "path=\"{}\"",
+                                     pathstr);
+        goto end;
+    }
+
+    /* Get target field class */
+    target_fc = field_path_to_field_class(&target_field_path, ctx);
+    if (!target_fc) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                     "Cannot get target field class for path string: "
+                                     "path=\"{}\", target-field-path=\"{}\"",
+                                     pathstr, target_field_path);
+        ret = -1;
+        goto end;
+    }
+
+    ret = validate_target_field_path(&target_field_path, target_fc, ctx);
+    if (ret) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                     "Invalid target field path for path string: "
+                                     "path=\"{}\", target-field-path=\"{}\"",
+                                     pathstr, target_field_path);
+        goto end;
+    }
+
+    /* Set target field path and target field class */
+    switch (fc->type) {
+    case CTF_FIELD_CLASS_TYPE_SEQUENCE:
+    {
+        ctf_field_class_sequence *seq_fc = ctf_field_class_as_sequence(fc);
+
+        ctf_field_path_copy_content(&seq_fc->length_path, &target_field_path);
+        seq_fc->length_fc = ctf_field_class_as_int(target_fc);
+        break;
+    }
+    case CTF_FIELD_CLASS_TYPE_VARIANT:
+    {
+        ctf_field_class_variant *var_fc = ctf_field_class_as_variant(fc);
+
+        ctf_field_path_copy_content(&var_fc->tag_path, &target_field_path);
+        ctf_field_class_variant_set_tag_field_class(var_fc, ctf_field_class_as_enum(target_fc));
+        break;
+    }
+    default:
+        bt_common_abort();
+    }
+
+end:
+    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_CPPLOGE_APPEND_CAUSE_SPEC(
+                ctx->logger,
+                "Cannot resolve sequence field class's length or variant field class's tag: "
+                "ret={}, fc-addr={}",
+                ret, fmt::ptr(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, ctx);
+        if (ret) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                         "Cannot push field class on context's stack: "
+                                         "fc-addr={}",
+                                         fmt::ptr(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_CPPLOGD_SPEC(ctx->logger,
+                            "Resolving field class's child field class: "
+                            "parent-fc-addr={}, child-fc-addr={}, "
+                            "index={}, count={}",
+                            fmt::ptr(fc), fmt::ptr(child_fc), i, field_count);
+            ret = resolve_field_class(child_fc, ctx);
+            if (ret) {
+                goto end;
+            }
+        }
+
+        field_class_stack_pop(ctx->field_class_stack, ctx);
+        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 = CTF_SCOPE_PACKET_UNKNOWN;
+    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_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                     "Cannot resolve event specific context field class: "
+                                     "ret={}",
+                                     ret);
+        goto end;
+    }
+
+    ctx->scopes.event_payload = ec->payload_fc;
+    ret = resolve_root_class(CTF_SCOPE_EVENT_PAYLOAD, ctx);
+    if (ret) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                     "Cannot resolve event payload field class: "
+                                     "ret={}",
+                                     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_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                         "Cannot resolve packet context field class: "
+                                         "ret={}",
+                                         ret);
+            goto end;
+        }
+
+        ctx->scopes.event_header = sc->event_header_fc;
+        ret = resolve_root_class(CTF_SCOPE_EVENT_HEADER, ctx);
+        if (ret) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                         "Cannot resolve event header field class: "
+                                         "ret={}",
+                                         ret);
+            goto end;
+        }
+
+        ctx->scopes.event_common_context = sc->event_common_context_fc;
+        ret = resolve_root_class(CTF_SCOPE_EVENT_COMMON_CONTEXT, ctx);
+        if (ret) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                         "Cannot resolve event common context field class: "
+                                         "ret={}",
+                                         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++) {
+        ctf_event_class *ec = (ctf_event_class *) sc->event_classes->pdata[i];
+
+        ret = resolve_event_class_field_classes(ctx, ec);
+        if (ret) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                         "Cannot resolve event class's field classes: "
+                                         "ec-id={}, ec-name=\"{}\"",
+                                         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;
+}
+
+int ctf_trace_class_resolve_field_classes(struct ctf_trace_class *tc,
+                                          const bt2c::Logger& parentLogger)
+{
+    int ret = 0;
+    uint64_t i;
+
+    resolve_context local_ctx(parentLogger);
+    local_ctx.tc = tc;
+    local_ctx.scopes.packet_header = tc->packet_header_fc;
+    local_ctx.root_scope = CTF_SCOPE_PACKET_HEADER;
+
+    struct resolve_context *ctx = &local_ctx;
+
+    /* Initialize class stack */
+    ctx->field_class_stack = field_class_stack_create();
+    if (!ctx->field_class_stack) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger, "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_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                         "Cannot resolve packet header field class: "
+                                         "ret={}",
+                                         ret);
+            goto end;
+        }
+    }
+
+    ctx->scopes.packet_header = tc->packet_header_fc;
+
+    for (i = 0; i < tc->stream_classes->len; i++) {
+        ctf_stream_class *sc = (ctf_stream_class *) tc->stream_classes->pdata[i];
+
+        ret = resolve_stream_class_field_classes(ctx, sc);
+        if (ret) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                         "Cannot resolve stream class's field classes: "
+                                         "sc-id={}",
+                                         sc->id);
+            goto end;
+        }
+    }
+
+end:
+    field_class_stack_destroy(ctx->field_class_stack);
+    return ret;
+}
diff --git a/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-translate.cpp b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-translate.cpp
new file mode 100644 (file)
index 0000000..b62dabf
--- /dev/null
@@ -0,0 +1,656 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include <babeltrace2/babeltrace.h>
+
+#include "common/assert.h"
+
+#include "ctf-meta-visitors.hpp"
+
+namespace ctf {
+
+struct MetaTranslateCtx
+{
+    bt_self_component *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;
+};
+
+} /* namespace ctf */
+
+static inline bt_field_class *ctf_field_class_to_ir(ctf::MetaTranslateCtx *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(ctf::MetaTranslateCtx *ctx,
+                                                        struct ctf_field_class_int *fc)
+{
+    bt_field_class *ir_fc;
+
+    if (fc->is_signed) {
+        ir_fc = bt_field_class_integer_signed_create(ctx->ir_tc);
+    } else {
+        ir_fc = bt_field_class_integer_unsigned_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(ctf::MetaTranslateCtx *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_enumeration_signed_create(ctx->ir_tc);
+    } else {
+        ir_fc = bt_field_class_enumeration_unsigned_create(ctx->ir_tc);
+    }
+
+    BT_ASSERT(ir_fc);
+    ctf_field_class_int_set_props(&fc->base, 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);
+        bt_integer_range_set_signed *range_set_signed = NULL;
+        bt_integer_range_set_unsigned *range_set_unsigned = NULL;
+        uint64_t range_i;
+
+        if (fc->base.is_signed) {
+            range_set_signed = bt_integer_range_set_signed_create();
+            BT_ASSERT(range_set_signed);
+        } else {
+            range_set_unsigned = bt_integer_range_set_unsigned_create();
+            BT_ASSERT(range_set_unsigned);
+        }
+
+        for (range_i = 0; range_i < mapping->ranges->len; range_i++) {
+            struct ctf_range *range =
+                ctf_field_class_enum_mapping_borrow_range_by_index(mapping, range_i);
+
+            if (fc->base.is_signed) {
+                ret = bt_integer_range_set_signed_add_range(range_set_signed, range->lower.i,
+                                                            range->upper.i);
+            } else {
+                ret = bt_integer_range_set_unsigned_add_range(range_set_unsigned, range->lower.u,
+                                                              range->upper.u);
+            }
+
+            BT_ASSERT(ret == 0);
+        }
+
+        if (fc->base.is_signed) {
+            ret = bt_field_class_enumeration_signed_add_mapping(ir_fc, mapping->label->str,
+                                                                range_set_signed);
+            BT_INTEGER_RANGE_SET_SIGNED_PUT_REF_AND_RESET(range_set_signed);
+        } else {
+            ret = bt_field_class_enumeration_unsigned_add_mapping(ir_fc, mapping->label->str,
+                                                                  range_set_unsigned);
+            BT_INTEGER_RANGE_SET_UNSIGNED_PUT_REF_AND_RESET(range_set_unsigned);
+        }
+
+        BT_ASSERT(ret == 0);
+    }
+
+    return ir_fc;
+}
+
+static inline bt_field_class *ctf_field_class_float_to_ir(ctf::MetaTranslateCtx *ctx,
+                                                          struct ctf_field_class_float *fc)
+{
+    bt_field_class *ir_fc;
+
+    if (fc->base.size == 32) {
+        ir_fc = bt_field_class_real_single_precision_create(ctx->ir_tc);
+    } else {
+        ir_fc = bt_field_class_real_double_precision_create(ctx->ir_tc);
+    }
+    BT_ASSERT(ir_fc);
+
+    return ir_fc;
+}
+
+static inline bt_field_class *ctf_field_class_string_to_ir(ctf::MetaTranslateCtx *ctx)
+{
+    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(ctf::MetaTranslateCtx *ctx,
+                                                        struct ctf_field_class_struct *fc,
+                                                        bt_field_class *ir_fc, bool,
+                                                        struct ctf_field_class_struct *)
+{
+    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(ctf::MetaTranslateCtx *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(ctf::MetaTranslateCtx *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 const bt_field_class_enumeration_mapping *
+find_ir_enum_field_class_mapping_by_label(const bt_field_class *fc, const char *label,
+                                          bool is_signed)
+{
+    const bt_field_class_enumeration_mapping *mapping = NULL;
+    uint64_t i;
+
+    for (i = 0; i < bt_field_class_enumeration_get_mapping_count(fc); i++) {
+        const bt_field_class_enumeration_mapping *this_mapping;
+        const bt_field_class_enumeration_signed_mapping *signed_this_mapping = NULL;
+        const bt_field_class_enumeration_unsigned_mapping *unsigned_this_mapping = NULL;
+
+        if (is_signed) {
+            signed_this_mapping =
+                bt_field_class_enumeration_signed_borrow_mapping_by_index_const(fc, i);
+            BT_ASSERT(signed_this_mapping);
+            this_mapping =
+                bt_field_class_enumeration_signed_mapping_as_mapping_const(signed_this_mapping);
+        } else {
+            unsigned_this_mapping =
+                bt_field_class_enumeration_unsigned_borrow_mapping_by_index_const(fc, i);
+            BT_ASSERT(unsigned_this_mapping);
+            this_mapping =
+                bt_field_class_enumeration_unsigned_mapping_as_mapping_const(unsigned_this_mapping);
+        }
+
+        BT_ASSERT(this_mapping);
+
+        if (strcmp(bt_field_class_enumeration_mapping_get_label(this_mapping), label) == 0) {
+            mapping = this_mapping;
+            goto end;
+        }
+    }
+
+end:
+    return mapping;
+}
+
+static inline bt_field_class *ctf_field_class_variant_to_ir(ctf::MetaTranslateCtx *ctx,
+                                                            struct ctf_field_class_variant *fc)
+{
+    int ret;
+    bt_field_class *ir_fc;
+    uint64_t i;
+    bt_field_class *ir_tag_fc = NULL;
+
+    if (fc->tag_path.root != CTF_SCOPE_PACKET_HEADER &&
+        fc->tag_path.root != CTF_SCOPE_EVENT_HEADER) {
+        ir_tag_fc = borrow_ir_fc_from_field_path(ctx, &fc->tag_path);
+        BT_ASSERT(ir_tag_fc);
+    }
+
+    ir_fc = bt_field_class_variant_create(ctx->ir_tc, ir_tag_fc);
+    BT_ASSERT(ir_fc);
+
+    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);
+
+        if (ir_tag_fc) {
+            /*
+             * At this point the trace IR selector
+             * (enumeration) field class already exists if
+             * the variant is tagged (`ir_tag_fc`). This one
+             * already contains range sets for its mappings,
+             * so we just reuse the same, finding them by
+             * matching a variant field class's option's
+             * _original_ name (with a leading underscore,
+             * possibly) with a selector field class's
+             * mapping name.
+             */
+            if (fc->tag_fc->base.is_signed) {
+                const bt_field_class_enumeration_signed_mapping *mapping =
+                    (bt_field_class_enumeration_signed_mapping *)
+                        find_ir_enum_field_class_mapping_by_label(ir_tag_fc,
+                                                                  named_fc->orig_name->str, true);
+                const bt_integer_range_set_signed *range_set;
+
+                BT_ASSERT(mapping);
+                range_set = bt_field_class_enumeration_signed_mapping_borrow_ranges_const(mapping);
+                BT_ASSERT(range_set);
+                ret = bt_field_class_variant_with_selector_field_integer_signed_append_option(
+                    ir_fc, named_fc->name->str, option_ir_fc, range_set);
+            } else {
+                const bt_field_class_enumeration_unsigned_mapping *mapping =
+                    (bt_field_class_enumeration_unsigned_mapping *)
+                        find_ir_enum_field_class_mapping_by_label(ir_tag_fc,
+                                                                  named_fc->orig_name->str, false);
+                const bt_integer_range_set_unsigned *range_set;
+
+                BT_ASSERT(mapping);
+                range_set =
+                    bt_field_class_enumeration_unsigned_mapping_borrow_ranges_const(mapping);
+                BT_ASSERT(range_set);
+                ret = bt_field_class_variant_with_selector_field_integer_unsigned_append_option(
+                    ir_fc, named_fc->name->str, option_ir_fc, range_set);
+            }
+        } else {
+            ret = bt_field_class_variant_without_selector_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(ctf::MetaTranslateCtx *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_array_static_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(ctf::MetaTranslateCtx *ctx,
+                                                             struct ctf_field_class_sequence *fc)
+{
+    bt_field_class *ir_fc;
+    bt_field_class *elem_ir_fc;
+    bt_field_class *length_fc = NULL;
+
+    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);
+
+    if (fc->length_path.root != CTF_SCOPE_PACKET_HEADER &&
+        fc->length_path.root != CTF_SCOPE_EVENT_HEADER) {
+        length_fc = borrow_ir_fc_from_field_path(ctx, &fc->length_path);
+        BT_ASSERT(length_fc);
+    }
+
+    ir_fc = bt_field_class_array_dynamic_create(ctx->ir_tc, elem_ir_fc, length_fc);
+    BT_ASSERT(ir_fc);
+    bt_field_class_put_ref(elem_ir_fc);
+    BT_ASSERT(ir_fc);
+
+end:
+    return ir_fc;
+}
+
+static inline bt_field_class *ctf_field_class_to_ir(ctf::MetaTranslateCtx *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, ctf_field_class_as_int(fc));
+        break;
+    case CTF_FIELD_CLASS_TYPE_ENUM:
+        ir_fc = ctf_field_class_enum_to_ir(ctx, ctf_field_class_as_enum(fc));
+        break;
+    case CTF_FIELD_CLASS_TYPE_FLOAT:
+        ir_fc = ctf_field_class_float_to_ir(ctx, ctf_field_class_as_float(fc));
+        break;
+    case CTF_FIELD_CLASS_TYPE_STRING:
+        ir_fc = ctf_field_class_string_to_ir(ctx);
+        break;
+    case CTF_FIELD_CLASS_TYPE_STRUCT:
+        ir_fc = ctf_field_class_struct_to_ir(ctx, ctf_field_class_as_struct(fc));
+        break;
+    case CTF_FIELD_CLASS_TYPE_ARRAY:
+        ir_fc = ctf_field_class_array_to_ir(ctx, ctf_field_class_as_array(fc));
+        break;
+    case CTF_FIELD_CLASS_TYPE_SEQUENCE:
+        ir_fc = ctf_field_class_sequence_to_ir(ctx, ctf_field_class_as_sequence(fc));
+        break;
+    case CTF_FIELD_CLASS_TYPE_VARIANT:
+        ir_fc = ctf_field_class_variant_to_ir(ctx, ctf_field_class_as_variant(fc));
+        break;
+    default:
+        bt_common_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(ctf::MetaTranslateCtx *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:
+        bt_common_abort();
+    }
+
+    if (fc && ctf_field_class_struct_has_immediate_member_in_ir(ctf_field_class_as_struct(fc))) {
+        ir_fc = ctf_field_class_to_ir(ctx, fc);
+    }
+
+    return ir_fc;
+}
+
+static inline void ctf_event_class_to_ir(ctf::MetaTranslateCtx *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->is_log_level_set) {
+        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(ctf::MetaTranslateCtx *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);
+
+    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_supports_packets(ctx->ir_sc, BT_TRUE, ctx->sc->packets_have_ts_begin,
+                                         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->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);
+
+    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(ctf::MetaTranslateCtx *ctx)
+{
+    int ret = 0;
+    uint64_t i;
+
+    BT_ASSERT(ctx->tc);
+    BT_ASSERT(ctx->ir_tc);
+
+    if (ctx->tc->is_translated) {
+        goto end;
+    }
+
+    for (i = 0; i < ctx->tc->clock_classes->len; i++) {
+        ctf_clock_class *cc = (ctf_clock_class *) ctx->tc->clock_classes->pdata[i];
+
+        cc->ir_cc = bt_clock_class_create(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;
+}
+
+int ctf_trace_class_translate(bt_self_component *self_comp, bt_trace_class *ir_tc,
+                              struct ctf_trace_class *tc)
+{
+    int ret = 0;
+    uint64_t i;
+    ctf::MetaTranslateCtx ctx = {};
+
+    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 = (ctf_stream_class *) tc->stream_classes->pdata[i];
+
+        ctf_stream_class_to_ir(&ctx);
+
+        for (j = 0; j < ctx.sc->event_classes->len; j++) {
+            ctx.ec = (ctf_event_class *) 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/src/metadata/tsdl/ctf-meta-update-alignments.cpp b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-alignments.cpp
new file mode 100644 (file)
index 0000000..bea62bf
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2020 Philippe Proulx <pproulx@efficios.com>
+ */
+
+#include <stdint.h>
+
+#include "ctf-meta-visitors.hpp"
+
+static inline int set_alignments(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 = ctf_field_class_as_struct(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_alignments(named_fc->fc);
+            if (ret) {
+                goto end;
+            }
+
+            if (named_fc->fc->alignment > fc->alignment) {
+                fc->alignment = named_fc->fc->alignment;
+            }
+        }
+
+        break;
+    }
+    case CTF_FIELD_CLASS_TYPE_VARIANT:
+    {
+        struct ctf_field_class_variant *var_fc = ctf_field_class_as_variant(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_alignments(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 = ctf_field_class_as_array_base(fc);
+
+        ret = set_alignments(array_fc->elem_fc);
+        if (ret) {
+            goto end;
+        }
+
+        /*
+         * Use the alignment of the array/sequence field class's
+         * element FC as its own alignment.
+         *
+         * This is especially important when the array/sequence
+         * field's effective length is zero: as per CTF 1.8, the
+         * stream data decoding process still needs to align the
+         * cursor using the element's alignment [1]:
+         *
+         * > Arrays are always aligned on their element
+         * > alignment requirement.
+         *
+         * For example:
+         *
+         *     struct {
+         *         integer { size = 8; } a;
+         *         integer { size = 8; align = 16; } b[0];
+         *         integer { size = 8; } c;
+         *     };
+         *
+         * When using this to decode the bytes 1, 2, and 3, then
+         * the decoded values are:
+         *
+         * `a`: 1
+         * `b`: []
+         * `c`: 3
+         *
+         * [1]: https://diamon.org/ctf/#spec4.2.3
+         */
+        array_fc->base.alignment = array_fc->elem_fc->alignment;
+        break;
+    }
+    default:
+        break;
+    }
+
+end:
+    return ret;
+}
+
+int ctf_trace_class_update_alignments(struct ctf_trace_class *ctf_tc)
+{
+    int ret = 0;
+    uint64_t i;
+
+    if (!ctf_tc->is_translated) {
+        ret = set_alignments(ctf_tc->packet_header_fc);
+        if (ret) {
+            goto end;
+        }
+    }
+
+    for (i = 0; i < ctf_tc->stream_classes->len; i++) {
+        ctf_stream_class *sc = (ctf_stream_class *) ctf_tc->stream_classes->pdata[i];
+        uint64_t j;
+
+        if (!sc->is_translated) {
+            ret = set_alignments(sc->packet_context_fc);
+            if (ret) {
+                goto end;
+            }
+
+            ret = set_alignments(sc->event_header_fc);
+            if (ret) {
+                goto end;
+            }
+
+            ret = set_alignments(sc->event_common_context_fc);
+            if (ret) {
+                goto end;
+            }
+        }
+
+        for (j = 0; j < sc->event_classes->len; j++) {
+            struct ctf_event_class *ec = (ctf_event_class *) sc->event_classes->pdata[j];
+
+            if (ec->is_translated) {
+                continue;
+            }
+
+            ret = set_alignments(ec->spec_context_fc);
+            if (ret) {
+                goto end;
+            }
+
+            ret = set_alignments(ec->payload_fc);
+            if (ret) {
+                goto end;
+            }
+        }
+    }
+
+end:
+    return ret;
+}
diff --git a/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-default-clock-classes.cpp b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-default-clock-classes.cpp
new file mode 100644 (file)
index 0000000..cd9acdf
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
+ */
+
+#include <babeltrace2/babeltrace.h>
+
+#include "cpp-common/bt2c/logging.hpp"
+
+#include "ctf-meta-visitors.hpp"
+
+static inline int find_mapped_clock_class(struct ctf_field_class *fc,
+                                          struct ctf_clock_class **clock_class,
+                                          const bt2c::Logger& logger)
+{
+    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 = ctf_field_class_as_int(fc);
+
+        if (int_fc->mapped_clock_class) {
+            if (*clock_class && *clock_class != int_fc->mapped_clock_class) {
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(logger,
+                                             "Stream class contains more than one "
+                                             "clock class: expected-cc-name=\"{}\", "
+                                             "other-cc-name=\"{}\"",
+                                             (*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 = ctf_field_class_as_struct(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, logger);
+            if (ret) {
+                goto end;
+            }
+        }
+
+        break;
+    }
+    case CTF_FIELD_CLASS_TYPE_VARIANT:
+    {
+        struct ctf_field_class_variant *var_fc = ctf_field_class_as_variant(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, logger);
+            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 = ctf_field_class_as_array_base(fc);
+
+        ret = find_mapped_clock_class(array_fc->elem_fc, clock_class, logger);
+        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,
+                                                          const bt2c::Logger& logger)
+{
+    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, logger);
+    if (ret) {
+        goto end;
+    }
+
+    ret = find_mapped_clock_class(stream_class->event_header_fc, &clock_class, logger);
+    if (ret) {
+        goto end;
+    }
+
+    ret = find_mapped_clock_class(stream_class->event_common_context_fc, &clock_class, logger);
+    if (ret) {
+        goto end;
+    }
+
+    for (i = 0; i < stream_class->event_classes->len; i++) {
+        struct ctf_event_class *event_class =
+            (ctf_event_class *) stream_class->event_classes->pdata[i];
+
+        ret = find_mapped_clock_class(event_class->spec_context_fc, &clock_class, logger);
+        if (ret) {
+            goto end;
+        }
+
+        ret = find_mapped_clock_class(event_class->payload_fc, &clock_class, logger);
+        if (ret) {
+            goto end;
+        }
+    }
+
+    if (!stream_class->default_clock_class) {
+        stream_class->default_clock_class = clock_class;
+    }
+
+end:
+    return ret;
+}
+
+int ctf_trace_class_update_default_clock_classes(struct ctf_trace_class *ctf_tc,
+                                                 const bt2c::Logger& parentLogger)
+{
+    uint64_t i;
+    int ret = 0;
+    struct ctf_clock_class *clock_class = NULL;
+    bt2c::Logger logger {parentLogger, "PLUGIN/CTF/META/UPDATE-DEF-CC"};
+
+    ret = find_mapped_clock_class(ctf_tc->packet_header_fc, &clock_class, logger);
+    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_stream_class *) ctf_tc->stream_classes->pdata[i];
+
+        ret = update_stream_class_default_clock_class(
+            (ctf_stream_class *) ctf_tc->stream_classes->pdata[i], logger);
+        if (ret) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(logger,
+                                         "Stream class contains more than one "
+                                         "clock class: stream-class-id={}",
+                                         sc->id);
+            goto end;
+        }
+    }
+
+end:
+    return ret;
+}
diff --git a/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-in-ir.cpp b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-in-ir.cpp
new file mode 100644 (file)
index 0000000..c790238
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
+ */
+
+#include <assert.h>
+#include <glib.h>
+#include <stdint.h>
+
+#include "common/assert.h"
+#include "compat/glib.h"
+
+#include "ctf-meta-visitors.hpp"
+
+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 = ctf_field_class_as_struct(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 = ctf_field_class_as_variant(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 = ctf_field_class_as_array_base(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 = ctf_field_class_as_int(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 = ctf_field_class_as_struct(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 = ctf_field_class_as_variant(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 = ctf_field_class_as_array_base(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 = ctf_field_class_as_array(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 = ctf_field_class_as_sequence(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.
+ */
+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++) {
+        ctf_stream_class *sc = (ctf_stream_class *) ctf_tc->stream_classes->pdata[i];
+        uint64_t j;
+
+        for (j = 0; j < sc->event_classes->len; j++) {
+            ctf_event_class *ec = (ctf_event_class *) 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/src/metadata/tsdl/ctf-meta-update-meanings.cpp b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-meanings.cpp
new file mode 100644 (file)
index 0000000..23c6574
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include "ctf-meta-visitors.hpp"
+
+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 = ctf_field_class_as_int(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 = ctf_field_class_as_struct(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 = ctf_field_class_as_variant(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 = ctf_field_class_as_array_base(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(
+                ctf_field_class_as_struct(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(
+                ctf_field_class_as_struct(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(
+                ctf_field_class_as_struct(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(
+                ctf_field_class_as_struct(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(
+                ctf_field_class_as_struct(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(
+                ctf_field_class_as_struct(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 = (ctf_event_class *) sc->event_classes->pdata[i];
+
+        if (ec->is_translated) {
+            continue;
+        }
+    }
+
+end:
+    return ret;
+}
+
+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(
+            ctf_field_class_as_struct(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(
+            ctf_field_class_as_struct(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(
+            ctf_field_class_as_struct(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(
+            ctf_field_class_as_struct(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 = ctf_field_class_as_array(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_stream_class *) ctf_tc->stream_classes->pdata[i]);
+        if (ret) {
+            goto end;
+        }
+    }
+
+end:
+    return ret;
+}
diff --git a/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-stream-class-config.cpp b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-stream-class-config.cpp
new file mode 100644 (file)
index 0000000..a8f5add
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
+ */
+
+#include <stdint.h>
+
+#include "ctf-meta-visitors.hpp"
+
+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_stream_class *) 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(
+            ctf_field_class_as_struct(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(
+            ctf_field_class_as_struct(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(
+            ctf_field_class_as_struct(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(
+            ctf_field_class_as_struct(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/src/metadata/tsdl/ctf-meta-update-text-array-sequence.cpp b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-text-array-sequence.cpp
new file mode 100644 (file)
index 0000000..6c3bfc9
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
+ */
+
+#include <stdint.h>
+
+#include "ctf-meta-visitors.hpp"
+
+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 = ctf_field_class_as_struct(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 = ctf_field_class_as_variant(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 = ctf_field_class_as_array_base(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 = ctf_field_class_as_int(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;
+}
+
+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++) {
+        ctf_stream_class *sc = (ctf_stream_class *) 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 = (ctf_event_class *) 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/src/metadata/tsdl/ctf-meta-update-value-storing-indexes.cpp b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-value-storing-indexes.cpp
new file mode 100644 (file)
index 0000000..65e4c9f
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include "common/assert.h"
+
+#include "ctf-meta-visitors.hpp"
+
+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:
+    {
+        ctf_field_class_variant *var_fc = ctf_field_class_as_variant(fc);
+
+        field_path = &var_fc->tag_path;
+        stored_value_index = &var_fc->stored_tag_index;
+        tgt_fc = &var_fc->tag_fc->base;
+        break;
+    }
+    case CTF_FIELD_CLASS_TYPE_SEQUENCE:
+    {
+        struct ctf_field_class_sequence *seq_fc = ctf_field_class_as_sequence(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 = ctf_field_class_as_struct(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 = ctf_field_class_as_variant(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 = ctf_field_class_as_array_base(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;
+}
+
+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;
+        ctf_stream_class *sc = (ctf_stream_class *) 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 = (ctf_event_class *) 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/src/metadata/tsdl/ctf-meta-validate.cpp b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-validate.cpp
new file mode 100644 (file)
index 0000000..cb4e2b8
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
+ */
+
+#include <babeltrace2/babeltrace.h>
+
+#include "cpp-common/bt2c/logging.hpp"
+
+#include "ctf-meta-visitors.hpp"
+
+static int validate_stream_class(struct ctf_stream_class *sc, const bt2c::Logger& logger)
+{
+    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(
+        ctf_field_class_as_struct(sc->packet_context_fc), "timestamp_begin");
+    if (fc) {
+        if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(logger,
+                                         "Invalid packet context field class: "
+                                         "`timestamp_begin` member is not an integer field class.");
+            goto invalid;
+        }
+
+        int_fc = ctf_field_class_as_int(fc);
+
+        if (int_fc->is_signed) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "Invalid packet context field class: "
+                                                 "`timestamp_begin` member is signed.");
+            goto invalid;
+        }
+    }
+
+    fc = ctf_field_class_struct_borrow_member_field_class_by_name(
+        ctf_field_class_as_struct(sc->packet_context_fc), "timestamp_end");
+    if (fc) {
+        if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(logger,
+                                         "Invalid packet context field class: "
+                                         "`timestamp_end` member is not an integer field class.");
+            goto invalid;
+        }
+
+        int_fc = ctf_field_class_as_int(fc);
+
+        if (int_fc->is_signed) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "Invalid packet context field class: "
+                                                 "`timestamp_end` member is signed.");
+            goto invalid;
+        }
+    }
+
+    fc = ctf_field_class_struct_borrow_member_field_class_by_name(
+        ctf_field_class_as_struct(sc->packet_context_fc), "events_discarded");
+    if (fc) {
+        if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(
+                logger, "Invalid packet context field class: "
+                        "`events_discarded` member is not an integer field class.");
+            goto invalid;
+        }
+
+        int_fc = ctf_field_class_as_int(fc);
+
+        if (int_fc->is_signed) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "Invalid packet context field class: "
+                                                 "`events_discarded` member is signed.");
+            goto invalid;
+        }
+    }
+
+    fc = ctf_field_class_struct_borrow_member_field_class_by_name(
+        ctf_field_class_as_struct(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_CPPLOGE_APPEND_CAUSE_SPEC(logger,
+                                         "Invalid packet context field class: "
+                                         "`packet_seq_num` member is not an integer field class.");
+            goto invalid;
+        }
+
+        int_fc = ctf_field_class_as_int(fc);
+
+        if (int_fc->is_signed) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "Invalid packet context field class: "
+                                                 "`packet_seq_num` member is signed.");
+            goto invalid;
+        }
+    }
+
+    fc = ctf_field_class_struct_borrow_member_field_class_by_name(
+        ctf_field_class_as_struct(sc->packet_context_fc), "packet_size");
+    if (fc) {
+        if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(logger,
+                                         "Invalid packet context field class: "
+                                         "`packet_size` member is not an integer field class.");
+            goto invalid;
+        }
+
+        int_fc = ctf_field_class_as_int(fc);
+
+        if (int_fc->is_signed) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "Invalid packet context field class: "
+                                                 "`packet_size` member is signed.");
+            goto invalid;
+        }
+    }
+
+    fc = ctf_field_class_struct_borrow_member_field_class_by_name(
+        ctf_field_class_as_struct(sc->packet_context_fc), "content_size");
+    if (fc) {
+        if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(logger,
+                                         "Invalid packet context field class: "
+                                         "`content_size` member is not an integer field class.");
+            goto invalid;
+        }
+
+        int_fc = ctf_field_class_as_int(fc);
+
+        if (int_fc->is_signed) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "Invalid packet context field class: "
+                                                 "`content_size` member is signed.");
+            goto invalid;
+        }
+    }
+
+    fc = ctf_field_class_struct_borrow_member_field_class_by_name(
+        ctf_field_class_as_struct(sc->event_header_fc), "id");
+    if (fc) {
+        if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "Invalid event header field class: "
+                                                 "`id` member is not an integer field class.");
+            goto invalid;
+        }
+
+        int_fc = ctf_field_class_as_int(fc);
+
+        if (int_fc->is_signed) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "Invalid event header field class: "
+                                                 "`id` member is signed.");
+            goto invalid;
+        }
+    } else {
+        if (sc->event_classes->len > 1) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "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;
+}
+
+int ctf_trace_class_validate(struct ctf_trace_class *ctf_tc, const bt2c::Logger& parentLogger)
+{
+    int ret = 0;
+    struct ctf_field_class_int *int_fc;
+    uint64_t i;
+
+    bt2c::Logger logger {parentLogger, "PLUGIN/CTF/META/VALIDATE"};
+
+    if (!ctf_tc->is_translated) {
+        struct ctf_field_class *fc;
+
+        fc = ctf_field_class_struct_borrow_member_field_class_by_name(
+            ctf_field_class_as_struct(ctf_tc->packet_header_fc), "magic");
+        if (fc) {
+            struct ctf_named_field_class *named_fc = ctf_field_class_struct_borrow_member_by_index(
+                ctf_field_class_as_struct(ctf_tc->packet_header_fc), 0);
+
+            if (named_fc->fc != fc) {
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "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_CPPLOGE_APPEND_CAUSE_SPEC(logger,
+                                             "Invalid packet header field class: "
+                                             "`magic` member is not an integer field class.");
+                goto invalid;
+            }
+
+            int_fc = ctf_field_class_as_int(fc);
+
+            if (int_fc->is_signed) {
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "Invalid packet header field class: "
+                                                     "`magic` member is signed.");
+                goto invalid;
+            }
+
+            if (int_fc->base.size != 32) {
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "Invalid packet header field class: "
+                                                     "`magic` member is not 32-bit.");
+                goto invalid;
+            }
+        }
+
+        fc = ctf_field_class_struct_borrow_member_field_class_by_name(
+            ctf_field_class_as_struct(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_CPPLOGE_APPEND_CAUSE_SPEC(logger,
+                                             "Invalid packet header field class: "
+                                             "`stream_id` member is not an integer field class.");
+                goto invalid;
+            }
+
+            int_fc = ctf_field_class_as_int(fc);
+
+            if (int_fc->is_signed) {
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "Invalid packet header field class: "
+                                                     "`stream_id` member is signed.");
+                goto invalid;
+            }
+        } else {
+            if (ctf_tc->stream_classes->len > 1) {
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "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(
+            ctf_field_class_as_struct(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_CPPLOGE_APPEND_CAUSE_SPEC(
+                    logger, "Invalid packet header field class: "
+                            "`stream_instance_id` member is not an integer field class.");
+                goto invalid;
+            }
+
+            int_fc = ctf_field_class_as_int(fc);
+
+            if (int_fc->is_signed) {
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "Invalid packet header field class: "
+                                                     "`stream_instance_id` member is signed.");
+                goto invalid;
+            }
+        }
+
+        fc = ctf_field_class_struct_borrow_member_field_class_by_name(
+            ctf_field_class_as_struct(ctf_tc->packet_header_fc), "uuid");
+        if (fc) {
+            if (fc->type != CTF_FIELD_CLASS_TYPE_ARRAY) {
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "Invalid packet header field class: "
+                                                     "`uuid` member is not an array field class.");
+                goto invalid;
+            }
+
+            ctf_field_class_array *array_fc = ctf_field_class_as_array(fc);
+
+            if (array_fc->length != 16) {
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(
+                    logger, "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_CPPLOGE_APPEND_CAUSE_SPEC(logger, "Invalid packet header field class: "
+                                                     "`uuid` member's element field class is not "
+                                                     "an integer field class.");
+                goto invalid;
+            }
+
+            int_fc = ctf_field_class_as_int(array_fc->base.elem_fc);
+
+            if (int_fc->is_signed) {
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "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_CPPLOGE_APPEND_CAUSE_SPEC(logger, "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_CPPLOGE_APPEND_CAUSE_SPEC(logger, "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_stream_class *) ctf_tc->stream_classes->pdata[i];
+
+        ret = validate_stream_class(sc, logger);
+        if (ret) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "Invalid stream class: sc-id={}", sc->id);
+            goto invalid;
+        }
+    }
+
+    goto end;
+
+invalid:
+    ret = -1;
+
+end:
+    return ret;
+}
diff --git a/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-visitors.hpp b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-visitors.hpp
new file mode 100644 (file)
index 0000000..1a6f708
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
+ */
+
+#ifndef _CTF_META_VISITORS_H
+#define _CTF_META_VISITORS_H
+
+#include <babeltrace2/babeltrace.h>
+
+#include "ctf-meta.hpp"
+
+namespace bt2c {
+
+class Logger;
+
+} /* namespace bt2c */
+
+int ctf_trace_class_resolve_field_classes(struct ctf_trace_class *tc,
+                                          const bt2c::Logger& parentLogger);
+
+int ctf_trace_class_translate(bt_self_component *self_comp, bt_trace_class *ir_tc,
+                              struct ctf_trace_class *tc);
+
+int ctf_trace_class_update_default_clock_classes(struct ctf_trace_class *ctf_tc,
+                                                 const bt2c::Logger& parentLogger);
+
+int ctf_trace_class_update_in_ir(struct ctf_trace_class *ctf_tc);
+
+int ctf_trace_class_update_meanings(struct ctf_trace_class *ctf_tc);
+
+int ctf_trace_class_update_text_array_sequence(struct ctf_trace_class *ctf_tc);
+
+int ctf_trace_class_update_alignments(struct ctf_trace_class *ctf_tc);
+
+int ctf_trace_class_update_value_storing_indexes(struct ctf_trace_class *ctf_tc);
+
+int ctf_trace_class_update_stream_class_config(struct ctf_trace_class *ctf_tc);
+
+int ctf_trace_class_validate(struct ctf_trace_class *ctf_tc, const bt2c::Logger& parentLogger);
+
+void ctf_trace_class_warn_meaningless_header_fields(struct ctf_trace_class *ctf_tc,
+                                                    const bt2c::Logger& parentLogger);
+
+#endif /* _CTF_META_VISITORS_H */
diff --git a/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-warn-meaningless-header-fields.cpp b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-warn-meaningless-header-fields.cpp
new file mode 100644 (file)
index 0000000..f09a6b3
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
+ */
+
+#include <babeltrace2/babeltrace.h>
+
+#include "common/assert.h"
+#include "cpp-common/bt2c/logging.hpp"
+
+#include "ctf-meta-visitors.hpp"
+
+static inline void warn_meaningless_field(const char *name, const char *scope_name,
+                                          const bt2c::Logger& logger)
+{
+    BT_ASSERT(name);
+    BT_CPPLOGW_SPEC(logger, "User field found in {}: ignoring: name=\"{}\"", scope_name, name);
+}
+
+static inline void warn_meaningless_fields(struct ctf_field_class *fc, const char *name,
+                                           const char *scope_name, const bt2c::Logger& logger)
+{
+    uint64_t i;
+
+    if (!fc) {
+        goto end;
+    }
+
+    /*
+     * 'name' is guaranteed to be non-NULL whenever the field class is not a
+     * structure. In the case of a structure field class, its members' names
+     * are used.
+     */
+    switch (fc->type) {
+    case CTF_FIELD_CLASS_TYPE_FLOAT:
+    case CTF_FIELD_CLASS_TYPE_STRING:
+        warn_meaningless_field(name, scope_name, logger);
+        break;
+    case CTF_FIELD_CLASS_TYPE_INT:
+    case CTF_FIELD_CLASS_TYPE_ENUM:
+    {
+        struct ctf_field_class_int *int_fc = ctf_field_class_as_int(fc);
+
+        if (int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE && !int_fc->mapped_clock_class) {
+            warn_meaningless_field(name, scope_name, logger);
+        }
+
+        break;
+    }
+    case CTF_FIELD_CLASS_TYPE_STRUCT:
+    {
+        struct ctf_field_class_struct *struct_fc = ctf_field_class_as_struct(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, logger);
+        }
+
+        break;
+    }
+    case CTF_FIELD_CLASS_TYPE_VARIANT:
+    {
+        struct ctf_field_class_variant *var_fc = ctf_field_class_as_variant(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, logger);
+        }
+
+        break;
+    }
+    case CTF_FIELD_CLASS_TYPE_ARRAY:
+    {
+        struct ctf_field_class_array *array_fc = ctf_field_class_as_array(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 = ctf_field_class_as_array_base(fc);
+
+        warn_meaningless_fields(array_fc->elem_fc, name, scope_name, logger);
+        break;
+    }
+    default:
+        bt_common_abort();
+    }
+
+end:
+    return;
+}
+
+void ctf_trace_class_warn_meaningless_header_fields(struct ctf_trace_class *ctf_tc,
+                                                    const bt2c::Logger& parentLogger)
+{
+    uint64_t i;
+    bt2c::Logger logger {parentLogger, "PLUGIN/CTF/META/WARN-MEANINGLESS-HEADER-FIELDS"};
+
+    if (!ctf_tc->is_translated) {
+        warn_meaningless_fields(ctf_tc->packet_header_fc, NULL, "packet header", logger);
+    }
+
+    for (i = 0; i < ctf_tc->stream_classes->len; i++) {
+        ctf_stream_class *sc = (ctf_stream_class *) ctf_tc->stream_classes->pdata[i];
+
+        if (!sc->is_translated) {
+            warn_meaningless_fields(sc->event_header_fc, NULL, "event header", logger);
+        }
+    }
+}
diff --git a/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta.hpp b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta.hpp
new file mode 100644 (file)
index 0000000..5efa710
--- /dev/null
@@ -0,0 +1,1776 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
+ */
+
+#ifndef _CTF_META_H
+#define _CTF_META_H
+
+#include <glib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <babeltrace2/babeltrace.h>
+
+#include "common/assert.h"
+#include "common/common.h"
+#include "common/uuid.h"
+#include "cpp-common/vendor/fmt/format.h" /* IWYU pragma: keep */
+
+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,
+};
+
+inline const char *format_as(ctf_field_class_type type) noexcept
+{
+    switch (type) {
+    case CTF_FIELD_CLASS_TYPE_INT:
+        return "CTF_FIELD_CLASS_TYPE_INT";
+
+    case CTF_FIELD_CLASS_TYPE_ENUM:
+        return "CTF_FIELD_CLASS_TYPE_ENUM";
+
+    case CTF_FIELD_CLASS_TYPE_FLOAT:
+        return "CTF_FIELD_CLASS_TYPE_FLOAT";
+
+    case CTF_FIELD_CLASS_TYPE_STRING:
+        return "CTF_FIELD_CLASS_TYPE_STRING";
+
+    case CTF_FIELD_CLASS_TYPE_STRUCT:
+        return "CTF_FIELD_CLASS_TYPE_STRUCT";
+
+    case CTF_FIELD_CLASS_TYPE_ARRAY:
+        return "CTF_FIELD_CLASS_TYPE_ARRAY";
+
+    case CTF_FIELD_CLASS_TYPE_SEQUENCE:
+        return "CTF_FIELD_CLASS_TYPE_SEQUENCE";
+
+    case CTF_FIELD_CLASS_TYPE_VARIANT:
+        return "CTF_FIELD_CLASS_TYPE_VARIANT";
+    }
+
+    bt_common_abort();
+}
+
+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_UNKNOWN,
+    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_UNKNOWN = -1,
+    CTF_SCOPE_PACKET_HEADER = 0,
+    CTF_SCOPE_PACKET_CONTEXT,
+    CTF_SCOPE_EVENT_HEADER,
+    CTF_SCOPE_EVENT_COMMON_CONTEXT,
+    CTF_SCOPE_EVENT_SPECIFIC_CONTEXT,
+    CTF_SCOPE_EVENT_PAYLOAD,
+};
+
+inline const char *format_as(const ctf_scope scope) noexcept
+{
+    switch (scope) {
+    case CTF_SCOPE_PACKET_UNKNOWN:
+        return "PACKET_UNKNOWN";
+
+    case CTF_SCOPE_PACKET_HEADER:
+        return "PACKET_HEADER";
+
+    case CTF_SCOPE_PACKET_CONTEXT:
+        return "PACKET_CONTEXT";
+
+    case CTF_SCOPE_EVENT_HEADER:
+        return "EVENT_HEADER";
+
+    case CTF_SCOPE_EVENT_COMMON_CONTEXT:
+        return "EVENT_COMMON_CONTEXT";
+
+    case CTF_SCOPE_EVENT_SPECIFIC_CONTEXT:
+        return "EVENT_SPECIFIC_CONTEXT";
+
+    case CTF_SCOPE_EVENT_PAYLOAD:
+        return "EVENT_PAYLOAD";
+    }
+
+    bt_common_abort();
+}
+
+struct ctf_clock_class
+{
+    GString *name;
+    GString *description;
+    uint64_t frequency;
+    uint64_t precision;
+    int64_t offset_seconds;
+    uint64_t offset_cycles;
+    bt_uuid_t uuid;
+    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;
+
+    /* Array of `struct ctf_range` */
+    GArray *ranges;
+};
+
+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
+{
+    /* Original name which can include a leading `_` */
+    GString *orig_name;
+
+    /* Name as translated to trace IR (leading `_` removed) */
+    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;
+    bool is_log_level_set;
+
+    /* 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;
+    bt_uuid_t uuid;
+    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;
+
+    struct
+    {
+        bool lttng_crash;
+        bool lttng_event_after_packet;
+        bool barectf_event_before_packet;
+    } quirks;
+};
+
+static inline ctf_field_class_bit_array *ctf_field_class_as_bit_array(ctf_field_class *fc)
+{
+    BT_ASSERT_DBG(!fc ||
+                  (fc->type == CTF_FIELD_CLASS_TYPE_INT || fc->type == CTF_FIELD_CLASS_TYPE_ENUM ||
+                   fc->type == CTF_FIELD_CLASS_TYPE_FLOAT));
+    return (ctf_field_class_bit_array *) fc;
+}
+
+static inline ctf_field_class_int *ctf_field_class_as_int(ctf_field_class *fc)
+{
+    BT_ASSERT_DBG(!fc ||
+                  (fc->type == CTF_FIELD_CLASS_TYPE_INT || fc->type == CTF_FIELD_CLASS_TYPE_ENUM));
+    return (ctf_field_class_int *) fc;
+}
+
+static inline ctf_field_class_enum *ctf_field_class_as_enum(ctf_field_class *fc)
+{
+    BT_ASSERT_DBG(!fc || fc->type == CTF_FIELD_CLASS_TYPE_ENUM);
+    return (ctf_field_class_enum *) fc;
+}
+
+static inline ctf_field_class_float *ctf_field_class_as_float(ctf_field_class *fc)
+{
+    BT_ASSERT_DBG(!fc || fc->type == CTF_FIELD_CLASS_TYPE_FLOAT);
+    return (ctf_field_class_float *) fc;
+}
+
+static inline ctf_field_class_string *ctf_field_class_as_string(ctf_field_class *fc)
+{
+    BT_ASSERT_DBG(!fc || fc->type == CTF_FIELD_CLASS_TYPE_STRING);
+    return (ctf_field_class_string *) fc;
+}
+
+static inline ctf_field_class_struct *ctf_field_class_as_struct(ctf_field_class *fc)
+{
+    BT_ASSERT_DBG(!fc || fc->type == CTF_FIELD_CLASS_TYPE_STRUCT);
+    return (ctf_field_class_struct *) fc;
+}
+
+static inline ctf_field_class_array_base *ctf_field_class_as_array_base(ctf_field_class *fc)
+{
+    BT_ASSERT_DBG(!fc || (fc->type == CTF_FIELD_CLASS_TYPE_ARRAY ||
+                          fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE));
+    return (ctf_field_class_array_base *) fc;
+}
+
+static inline ctf_field_class_array *ctf_field_class_as_array(ctf_field_class *fc)
+{
+    BT_ASSERT_DBG(!fc || fc->type == CTF_FIELD_CLASS_TYPE_ARRAY);
+    return (ctf_field_class_array *) fc;
+}
+
+static inline ctf_field_class_sequence *ctf_field_class_as_sequence(ctf_field_class *fc)
+{
+    BT_ASSERT_DBG(!fc || fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE);
+    return (ctf_field_class_sequence *) fc;
+}
+
+static inline ctf_field_class_variant *ctf_field_class_as_variant(ctf_field_class *fc)
+{
+    BT_ASSERT_DBG(!fc || fc->type == CTF_FIELD_CLASS_TYPE_VARIANT);
+    return (ctf_field_class_variant *) fc;
+}
+
+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(&fc->base, 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(&fc->base, 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);
+    named_fc->orig_name = g_string_new(NULL);
+    BT_ASSERT(named_fc->orig_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);
+    }
+
+    if (named_fc->orig_name) {
+        g_string_free(named_fc->orig_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);
+    mapping->ranges = g_array_new(FALSE, TRUE, sizeof(struct ctf_range));
+    BT_ASSERT(mapping->ranges);
+}
+
+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);
+    }
+
+    if (mapping->ranges) {
+        g_array_free(mapping->ranges, 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(&fc->base, 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(&fc->base, 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(&fc->base, 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(&fc->base, 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(&fc->base, 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(&fc->base.base, 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(&fc->base.base, 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 =
+                &bt_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 =
+                &bt_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(&fc->base);
+    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(&fc->base);
+
+    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 =
+                &bt_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(ctf_field_class_as_int(fc));
+        break;
+    case CTF_FIELD_CLASS_TYPE_ENUM:
+        _ctf_field_class_enum_destroy(ctf_field_class_as_enum(fc));
+        break;
+    case CTF_FIELD_CLASS_TYPE_FLOAT:
+        _ctf_field_class_float_destroy(ctf_field_class_as_float(fc));
+        break;
+    case CTF_FIELD_CLASS_TYPE_STRING:
+        _ctf_field_class_string_destroy(ctf_field_class_as_string(fc));
+        break;
+    case CTF_FIELD_CLASS_TYPE_STRUCT:
+        _ctf_field_class_struct_destroy(ctf_field_class_as_struct(fc));
+        break;
+    case CTF_FIELD_CLASS_TYPE_ARRAY:
+        _ctf_field_class_array_destroy(ctf_field_class_as_array(fc));
+        break;
+    case CTF_FIELD_CLASS_TYPE_SEQUENCE:
+        _ctf_field_class_sequence_destroy(ctf_field_class_as_sequence(fc));
+        break;
+    case CTF_FIELD_CLASS_TYPE_VARIANT:
+        _ctf_field_class_variant_destroy(ctf_field_class_as_variant(fc));
+        break;
+    default:
+        bt_common_abort();
+    }
+}
+
+static inline struct ctf_range *
+ctf_field_class_enum_mapping_borrow_range_by_index(struct ctf_field_class_enum_mapping *mapping,
+                                                   uint64_t index)
+{
+    BT_ASSERT_DBG(mapping);
+    BT_ASSERT_DBG(index < mapping->ranges->len);
+    return &bt_g_array_index(mapping->ranges, struct ctf_range, index);
+}
+
+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_DBG(fc);
+    BT_ASSERT_DBG(index < fc->mappings->len);
+    return &bt_g_array_index(fc->mappings, struct ctf_field_class_enum_mapping, index);
+}
+
+static inline struct ctf_field_class_enum_mapping *
+ctf_field_class_enum_borrow_mapping_by_label(struct ctf_field_class_enum *fc, const char *label)
+{
+    struct ctf_field_class_enum_mapping *ret_mapping = NULL;
+    uint64_t i;
+
+    BT_ASSERT_DBG(fc);
+    BT_ASSERT_DBG(label);
+
+    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 (strcmp(mapping->label->str, label) == 0) {
+            ret_mapping = mapping;
+            goto end;
+        }
+    }
+
+end:
+    return ret_mapping;
+}
+
+static inline void ctf_field_class_enum_map_range(struct ctf_field_class_enum *fc,
+                                                  const char *label, uint64_t u_lower,
+                                                  uint64_t u_upper)
+{
+    struct ctf_field_class_enum_mapping *mapping = NULL;
+    struct ctf_range range = {
+        .lower =
+            {
+                .u = u_lower,
+            },
+        .upper =
+            {
+                .u = u_upper,
+            },
+    };
+    uint64_t i;
+
+    BT_ASSERT(fc);
+    BT_ASSERT(label);
+
+    for (i = 0; i < fc->mappings->len; i++) {
+        mapping = ctf_field_class_enum_borrow_mapping_by_index(fc, i);
+
+        if (strcmp(mapping->label->str, label) == 0) {
+            break;
+        }
+    }
+
+    if (i == fc->mappings->len) {
+        mapping = NULL;
+    }
+
+    if (!mapping) {
+        g_array_set_size(fc->mappings, fc->mappings->len + 1);
+        mapping = ctf_field_class_enum_borrow_mapping_by_index(fc, fc->mappings->len - 1);
+        _ctf_field_class_enum_mapping_init(mapping);
+        g_string_assign(mapping->label, label);
+    }
+
+    g_array_append_val(mapping->ranges, range);
+}
+
+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_DBG(fc);
+    BT_ASSERT_DBG(index < fc->members->len);
+    return &bt_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_DBG(fc);
+    BT_ASSERT_DBG(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)
+{
+    ctf_field_class *member_fc =
+        ctf_field_class_struct_borrow_member_field_class_by_name(struct_fc, name);
+
+    if (!member_fc) {
+        return nullptr;
+    }
+
+    if (member_fc->type != CTF_FIELD_CLASS_TYPE_INT &&
+        member_fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
+        return nullptr;
+    }
+
+    return ctf_field_class_as_int(member_fc);
+}
+
+static inline void _ctf_named_field_class_unescape_orig_name(struct ctf_named_field_class *named_fc)
+{
+    const char *name = named_fc->orig_name->str;
+
+    if (name[0] == '_') {
+        name++;
+    }
+
+    g_string_assign(named_fc->name, name);
+}
+
+static inline void ctf_field_class_struct_append_member(struct ctf_field_class_struct *fc,
+                                                        const char *orig_name,
+                                                        struct ctf_field_class *member_fc)
+{
+    struct ctf_named_field_class *named_fc;
+
+    BT_ASSERT(fc);
+    BT_ASSERT(orig_name);
+    g_array_set_size(fc->members, fc->members->len + 1);
+
+    named_fc = &bt_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->orig_name, orig_name);
+    _ctf_named_field_class_unescape_orig_name(named_fc);
+    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_DBG(fc);
+    BT_ASSERT_DBG(index < fc->options->len);
+    return &bt_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_DBG(fc);
+    BT_ASSERT_DBG(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_DBG(fc);
+    BT_ASSERT_DBG(index < fc->ranges->len);
+    return &bt_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 *orig_name,
+                                                         struct ctf_field_class *option_fc)
+{
+    struct ctf_named_field_class *named_fc;
+
+    BT_ASSERT(fc);
+    BT_ASSERT(orig_name);
+    g_array_set_size(fc->options, fc->options->len + 1);
+
+    named_fc = &bt_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->orig_name, orig_name);
+    _ctf_named_field_class_unescape_orig_name(named_fc);
+    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 range_i;
+        struct ctf_named_field_class *named_fc =
+            ctf_field_class_variant_borrow_option_by_index(fc, option_i);
+        struct ctf_field_class_enum_mapping *mapping;
+
+        mapping = ctf_field_class_enum_borrow_mapping_by_label(tag_fc, named_fc->orig_name->str);
+        if (!mapping) {
+            continue;
+        }
+
+        for (range_i = 0; range_i < mapping->ranges->len; range_i++) {
+            struct ctf_range *range =
+                ctf_field_class_enum_mapping_borrow_range_by_index(mapping, range_i);
+            struct ctf_field_class_variant_range var_range;
+
+            var_range.range = *range;
+            var_range.option_index = option_i;
+            g_array_append_val(fc->ranges, var_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(
+            (struct ctf_field_class_struct *) comp_fc, index);
+
+        BT_ASSERT_DBG(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(
+            (struct ctf_field_class_variant *) comp_fc, index);
+
+        BT_ASSERT_DBG(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 = (struct ctf_field_class_array_base *) 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 = (struct ctf_field_class_struct *) fc;
+
+        field_count = struct_fc->members->len;
+        break;
+    }
+    case CTF_FIELD_CLASS_TYPE_VARIANT:
+    {
+        struct ctf_field_class_variant *var_fc = (struct ctf_field_class_variant *) 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:
+        bt_common_abort();
+    }
+
+    return field_count;
+}
+
+static inline int64_t
+ctf_field_class_compound_get_field_class_index_from_orig_name(struct ctf_field_class *fc,
+                                                              const char *orig_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 = (struct ctf_field_class_struct *) 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(orig_name, named_fc->orig_name->str) == 0) {
+                ret_index = (int64_t) i;
+                goto end;
+            }
+        }
+
+        break;
+    }
+    case CTF_FIELD_CLASS_TYPE_VARIANT:
+    {
+        struct ctf_field_class_variant *var_fc = (struct ctf_field_class_variant *) 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(orig_name, named_fc->orig_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(const ctf_field_path *fp, uint64_t index)
+{
+    BT_ASSERT_DBG(fp);
+    BT_ASSERT_DBG(index < fp->path->len);
+    return bt_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);
+}
+
+inline std::string format_as(const ctf_field_path& path)
+{
+    std::string str = fmt::format("[{}", path.root);
+
+    for (guint i = 0; i < path.path->len; i++) {
+        str += fmt::format(", {}", ctf_field_path_borrow_index_by_index(&path, i));
+    }
+
+    str += ']';
+    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:
+        bt_common_abort();
+    }
+
+    BT_ASSERT_DBG(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_DBG(child_fc);
+        fc = child_fc;
+    }
+
+    BT_ASSERT_DBG(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(&dst_fc->base, &src_fc->base);
+    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(&copy_fc->base, &fc->base);
+
+    for (i = 0; i < fc->mappings->len; i++) {
+        uint64_t range_i;
+
+        struct ctf_field_class_enum_mapping *mapping =
+            &bt_g_array_index(fc->mappings, struct ctf_field_class_enum_mapping, i);
+
+        for (range_i = 0; range_i < mapping->ranges->len; range_i++) {
+            struct ctf_range *range = &bt_g_array_index(mapping->ranges, struct ctf_range, range_i);
+
+            ctf_field_class_enum_map_range(copy_fc, mapping->label->str, range->lower.u,
+                                           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(&copy_fc->base, &fc->base);
+    return copy_fc;
+}
+
+static inline struct ctf_field_class_string *
+_ctf_field_class_string_copy(struct ctf_field_class_string *)
+{
+    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 =
+            &bt_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 =
+            &bt_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 =
+            &bt_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(&copy_fc->base, &fc->base);
+    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(&copy_fc->base, &fc->base);
+    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 = &_ctf_field_class_int_copy(ctf_field_class_as_int(fc))->base.base;
+        break;
+    case CTF_FIELD_CLASS_TYPE_ENUM:
+        copy_fc = &_ctf_field_class_enum_copy(ctf_field_class_as_enum(fc))->base.base.base;
+        break;
+    case CTF_FIELD_CLASS_TYPE_FLOAT:
+        copy_fc = &_ctf_field_class_float_copy(ctf_field_class_as_float(fc))->base.base;
+        break;
+    case CTF_FIELD_CLASS_TYPE_STRING:
+        copy_fc = &_ctf_field_class_string_copy(ctf_field_class_as_string(fc))->base;
+        break;
+    case CTF_FIELD_CLASS_TYPE_STRUCT:
+        copy_fc = &_ctf_field_class_struct_copy(ctf_field_class_as_struct(fc))->base;
+        break;
+    case CTF_FIELD_CLASS_TYPE_ARRAY:
+        copy_fc = &_ctf_field_class_array_copy(ctf_field_class_as_array(fc))->base.base;
+        break;
+    case CTF_FIELD_CLASS_TYPE_SEQUENCE:
+        copy_fc = &_ctf_field_class_sequence_copy(ctf_field_class_as_sequence(fc))->base.base;
+        break;
+    case CTF_FIELD_CLASS_TYPE_VARIANT:
+        copy_fc = &_ctf_field_class_variant_copy(ctf_field_class_as_variant(fc))->base;
+        break;
+    default:
+        bt_common_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->is_log_level_set = false;
+    return ec;
+}
+
+static inline void ctf_event_class_set_log_level(struct ctf_event_class *ec,
+                                                 enum bt_event_class_log_level log_level)
+{
+    BT_ASSERT(ec);
+    ec->log_level = log_level;
+    ec->is_log_level_set = true;
+}
+
+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_DBG(sc);
+    return (struct ctf_event_class *) 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 = CTF_BYTE_ORDER_UNKNOWN;
+    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 =
+                &bt_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 = &bt_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_DBG(tc);
+
+    for (i = 0; i < tc->stream_classes->len; i++) {
+        struct ctf_stream_class *sc = (struct ctf_stream_class *) 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_DBG(tc);
+    BT_ASSERT_DBG(name);
+
+    for (i = 0; i < tc->clock_classes->len; i++) {
+        struct ctf_clock_class *cc = (struct ctf_clock_class *) tc->clock_classes->pdata[i];
+
+        BT_ASSERT_DBG(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_DBG(tc);
+    BT_ASSERT_DBG(index < tc->env_entries->len);
+    return &bt_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_DBG(tc);
+    BT_ASSERT_DBG(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/src/metadata/tsdl/decoder-packetized-file-stream-to-buf.cpp b/src/plugins/ctf/common/src/metadata/tsdl/decoder-packetized-file-stream-to-buf.cpp
new file mode 100644 (file)
index 0000000..b6de4d6
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2016-2017 Philippe Proulx <pproulx@efficios.com>
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "common/uuid.h"
+#include "compat/memstream.h"
+
+#include "decoder-packetized-file-stream-to-buf.hpp"
+#include "decoder.hpp"
+
+#define TSDL_MAGIC 0x75d11d57
+
+struct packet_header
+{
+    uint32_t magic;
+    bt_uuid_t uuid;
+    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 int decode_packet(FILE *in_fp, FILE *out_fp, int byte_order, bool *is_uuid_set,
+                         uint8_t *uuid, const bt2c::Logger& logger)
+{
+    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_CPPLOGE_ERRNO_APPEND_CAUSE_SPEC(logger, "Failed to get current metadata file position",
+                                           ".");
+        goto error;
+    }
+    BT_CPPLOGD_SPEC(logger, "Decoding metadata packet: offset={}", offset);
+    readlen = fread(&header, sizeof(header), 1, in_fp);
+    if (feof(in_fp) != 0) {
+        BT_CPPLOGI_SPEC(logger, "Reached end of file: offset={}", ftell(in_fp));
+        goto end;
+    }
+    if (readlen < 1) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "Cannot decode metadata packet: offset={}", 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_CPPLOGE_APPEND_CAUSE_SPEC(
+            logger,
+            "Metadata packet compression is not supported as of this version: "
+            "compression-scheme={}, offset={}",
+            (unsigned int) header.compression_scheme, offset);
+        goto error;
+    }
+
+    if (header.encryption_scheme) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(
+            logger,
+            "Metadata packet encryption is not supported as of this version: "
+            "encryption-scheme={}, offset={}",
+            (unsigned int) header.encryption_scheme, offset);
+        goto error;
+    }
+
+    if (header.checksum || header.checksum_scheme) {
+        auto checksum = header.checksum;
+
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(
+            logger,
+            "Metadata packet checksum verification is not supported as of this version: "
+            "checksum-scheme={}, checksum={}, offset={}",
+            (unsigned int) header.checksum_scheme, checksum, offset);
+        goto error;
+    }
+
+    if (!ctf_metadata_decoder_is_packet_version_valid(header.major, header.minor)) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(logger,
+                                     "Invalid metadata packet version: "
+                                     "version={}.{}, offset={}",
+                                     header.major, header.minor, offset);
+        goto error;
+    }
+
+    /* Set expected trace UUID if not set; otherwise validate it */
+    if (is_uuid_set) {
+        if (!*is_uuid_set) {
+            bt_uuid_copy(uuid, header.uuid);
+            *is_uuid_set = true;
+        } else if (bt_uuid_compare(header.uuid, uuid)) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(
+                logger,
+                "Metadata UUID mismatch between packets of the same stream: "
+                "packet-uuid=\"" BT_UUID_FMT "\", "
+                "expected-uuid=\"" BT_UUID_FMT "\", "
+                "offset={}",
+                BT_UUID_FMT_VALUES(header.uuid), BT_UUID_FMT_VALUES(uuid), offset);
+            goto error;
+        }
+    }
+
+    if ((header.content_size / CHAR_BIT) < sizeof(header)) {
+        auto content_size = header.content_size;
+
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(logger,
+                                     "Bad metadata packet content size: content-size={}, "
+                                     "offset={}",
+                                     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_CPPLOGE_APPEND_CAUSE_SPEC(logger,
+                                         "Cannot read metadata packet buffer: "
+                                         "offset={}, read-size={}",
+                                         ftell(in_fp), loop_read);
+            goto error;
+        }
+        if (readlen > loop_read) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(logger,
+                                         "fread returned more byte than expected: "
+                                         "read-size-asked={}, read-size-returned={}",
+                                         loop_read, readlen);
+            goto error;
+        }
+
+        writelen = fwrite(buf, sizeof(uint8_t), readlen, out_fp);
+        if (writelen < readlen || ferror(out_fp)) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(logger,
+                                         "Cannot write decoded metadata text to buffer: "
+                                         "read-offset={}, write-size={}",
+                                         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_CPPLOGW_SPEC(logger, "Missing padding at the end of the metadata stream.");
+            }
+            break;
+        }
+    }
+
+    goto end;
+
+error:
+    ret = -1;
+
+end:
+    return ret;
+}
+
+int ctf_metadata_decoder_packetized_file_stream_to_buf(FILE *fp, char **buf, int byte_order,
+                                                       bool *is_uuid_set, uint8_t *uuid,
+                                                       const bt2c::Logger& parentLogger)
+{
+    FILE *out_fp;
+    size_t size;
+    int ret = 0;
+    int tret;
+    size_t packet_index = 0;
+    bt2c::Logger logger {parentLogger, "PLUGIN/CTF/META/DECODER-DECODE-PACKET"};
+
+    out_fp = bt_open_memstream(buf, &size);
+    if (!out_fp) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "Cannot open memory stream: {}.", strerror(errno));
+        goto error;
+    }
+
+    for (;;) {
+        if (feof(fp) != 0) {
+            break;
+        }
+
+        tret = decode_packet(fp, out_fp, byte_order, is_uuid_set, uuid, logger);
+        if (tret) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "Cannot decode packet: index={}", packet_index);
+            goto error;
+        }
+
+        packet_index++;
+    }
+
+    /* Make sure the whole string ends with a null character */
+    tret = fputc('\0', out_fp);
+    if (tret == EOF) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "Cannot append '\\0' to the decoded metadata buffer.");
+        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_CPPLOGE_ERRNO_APPEND_CAUSE_SPEC(logger, "Cannot close memory stream", ".");
+        goto error;
+    }
+
+    goto end;
+
+error:
+    ret = -1;
+
+    if (out_fp) {
+        if (bt_close_memstream(buf, &size, out_fp)) {
+            BT_CPPLOGE_ERRNO_SPEC(logger, "Cannot close memory stream", ".");
+        }
+    }
+
+    if (*buf) {
+        free(*buf);
+        *buf = NULL;
+    }
+
+end:
+    return ret;
+}
diff --git a/src/plugins/ctf/common/src/metadata/tsdl/decoder-packetized-file-stream-to-buf.hpp b/src/plugins/ctf/common/src/metadata/tsdl/decoder-packetized-file-stream-to-buf.hpp
new file mode 100644 (file)
index 0000000..6190b06
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2019 Efficios Inc.
+ */
+
+#ifndef SRC_PLUGINS_CTF_COMMON_METADATA_DECODER_PACKETIZED_FILE_STREAM_TO_BUF
+#define SRC_PLUGINS_CTF_COMMON_METADATA_DECODER_PACKETIZED_FILE_STREAM_TO_BUF
+
+#include <cstdio>
+
+#include <stdint.h>
+
+#include <babeltrace2/babeltrace.h>
+
+namespace bt2c {
+
+class Logger;
+
+} /* namespace bt2c */
+
+int ctf_metadata_decoder_packetized_file_stream_to_buf(FILE *fp, char **buf, int byte_order,
+                                                       bool *is_uuid_set, uint8_t *uuid,
+                                                       const bt2c::Logger& parentLogger);
+
+#endif /* SRC_PLUGINS_CTF_COMMON_METADATA_DECODER_PACKETIZED_FILE_STREAM_TO_BUF */
diff --git a/src/plugins/ctf/common/src/metadata/tsdl/decoder.cpp b/src/plugins/ctf/common/src/metadata/tsdl/decoder.cpp
new file mode 100644 (file)
index 0000000..7e5e8bb
--- /dev/null
@@ -0,0 +1,475 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2016-2017 Philippe Proulx <pproulx@efficios.com>
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "common/assert.h"
+#include "common/uuid.h"
+#include "compat/memstream.h"
+#include "cpp-common/vendor/fmt/format.h"
+
+#include "ast.hpp"
+#include "decoder-packetized-file-stream-to-buf.hpp"
+#include "decoder.hpp"
+#include "parser-wrap.hpp"
+#include "scanner.hpp"
+
+#define TSDL_MAGIC 0x75d11d57
+
+struct ctf_metadata_decoder
+{
+    explicit ctf_metadata_decoder(const bt2c::Logger& parentLogger) :
+        logger {parentLogger, "PLUGIN/CTF/META/DECODER"}, config {logger}
+    {
+    }
+
+    bt2c::Logger logger;
+    struct ctf_scanner *scanner = nullptr;
+    GString *text = nullptr;
+    ctf_visitor_generate_ir::UP visitor;
+    bt_uuid_t uuid {};
+    bool is_uuid_set = false;
+    int bo = 0;
+    struct ctf_metadata_decoder_config config;
+    bool has_checked_plaintext_signature = false;
+};
+
+struct packet_header
+{
+    uint32_t magic;
+    bt_uuid_t uuid;
+    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__));
+
+int ctf_metadata_decoder_is_packetized(FILE *fp, bool *is_packetized, int *byte_order,
+                                       const bt2c::Logger& logger)
+{
+    uint32_t magic;
+    size_t len;
+    int ret = 0;
+
+    *is_packetized = false;
+    len = fread(&magic, sizeof(magic), 1, fp);
+    if (len != 1) {
+        BT_CPPLOGI_SPEC(
+            logger,
+            "Cannot read first metadata packet header: assuming the stream is not packetized.");
+        ret = -1;
+        goto end;
+    }
+
+    if (byte_order) {
+        if (magic == TSDL_MAGIC) {
+            *is_packetized = true;
+            *byte_order = BYTE_ORDER;
+        } else if (magic == GUINT32_SWAP_LE_BE(TSDL_MAGIC)) {
+            *is_packetized = true;
+            *byte_order = BYTE_ORDER == BIG_ENDIAN ? LITTLE_ENDIAN : BIG_ENDIAN;
+        }
+    }
+
+end:
+    rewind(fp);
+
+    return ret;
+}
+
+ctf_metadata_decoder_up
+ctf_metadata_decoder_create(const struct ctf_metadata_decoder_config *config)
+{
+    BT_ASSERT(config);
+    BT_CPPLOGD_SPEC(config->logger,
+                    "Creating CTF metadata decoder: "
+                    "clock-class-offset-s={}, "
+                    "clock-class-offset-ns={}",
+                    config->clkClsCfg.offsetSec, config->clkClsCfg.offsetNanoSec);
+
+    ctf_metadata_decoder *mdec = new ctf_metadata_decoder {config->logger};
+    mdec->scanner = ctf_scanner_alloc(mdec->logger);
+    if (!mdec->scanner) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(mdec->logger,
+                                     "Cannot allocate a metadata lexical scanner: "
+                                     "mdec-addr={}",
+                                     fmt::ptr(mdec));
+        goto error;
+    }
+
+    mdec->text = g_string_new(NULL);
+    if (!mdec->text) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(mdec->logger,
+                                     "Failed to allocate one GString: "
+                                     "mdec-addr={}",
+                                     fmt::ptr(mdec));
+        goto error;
+    }
+
+    mdec->bo = -1;
+    mdec->config = *config;
+    mdec->visitor = ctf_visitor_generate_ir_create(config);
+    if (!mdec->visitor) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(mdec->logger,
+                                     "Failed to create a CTF IR metadata AST visitor: "
+                                     "mdec-addr={}",
+                                     fmt::ptr(mdec));
+        goto error;
+    }
+
+    BT_CPPLOGD_SPEC(mdec->logger,
+                    "Creating CTF metadata decoder: "
+                    "clock-class-offset-s={}, "
+                    "clock-class-offset-ns={}, addr={}",
+                    config->clkClsCfg.offsetSec, config->clkClsCfg.offsetNanoSec, fmt::ptr(mdec));
+    goto end;
+
+error:
+    ctf_metadata_decoder_destroy(mdec);
+    mdec = NULL;
+
+end:
+    return ctf_metadata_decoder_up {mdec};
+}
+
+void ctf_metadata_decoder_destroy(struct ctf_metadata_decoder *mdec)
+{
+    if (!mdec) {
+        return;
+    }
+
+    if (mdec->scanner) {
+        ctf_scanner_free(mdec->scanner);
+    }
+
+    if (mdec->text) {
+        g_string_free(mdec->text, TRUE);
+    }
+
+    BT_CPPLOGD_SPEC(mdec->logger, "Destroying CTF metadata decoder: addr={}", fmt::ptr(mdec));
+
+    delete mdec;
+}
+
+void ctf_metadata_decoder_deleter::operator()(ctf_metadata_decoder *decoder)
+{
+    ctf_metadata_decoder_destroy(decoder);
+}
+
+enum ctf_metadata_decoder_status
+ctf_metadata_decoder_append_content(struct ctf_metadata_decoder *mdec, FILE *fp)
+{
+    enum ctf_metadata_decoder_status status = CTF_METADATA_DECODER_STATUS_OK;
+    int ret;
+    char *buf = NULL;
+    bool close_fp = false;
+    long start_pos = -1;
+    bool is_packetized;
+
+    BT_ASSERT(mdec);
+    ret = ctf_metadata_decoder_is_packetized(fp, &is_packetized, &mdec->bo, mdec->logger);
+    if (ret) {
+        status = CTF_METADATA_DECODER_STATUS_ERROR;
+        goto end;
+    }
+
+    if (is_packetized) {
+        BT_CPPLOGI_SPEC(mdec->logger, "Metadata stream is packetized: mdec-addr={}",
+                        fmt::ptr(mdec));
+        ret = ctf_metadata_decoder_packetized_file_stream_to_buf(
+            fp, &buf, mdec->bo, &mdec->is_uuid_set, mdec->uuid, mdec->logger);
+        if (ret) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(
+                mdec->logger,
+                "Cannot decode packetized metadata packets to metadata text: "
+                "mdec-addr={}, ret={}",
+                fmt::ptr(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_CPPLOGE_APPEND_CAUSE_SPEC(mdec->logger,
+                                         "Cannot memory-open metadata buffer: {}: "
+                                         "mdec-addr={}",
+                                         strerror(errno), fmt::ptr(mdec));
+            status = CTF_METADATA_DECODER_STATUS_ERROR;
+            goto end;
+        }
+    } else if (!mdec->has_checked_plaintext_signature) {
+        unsigned int major, minor;
+        ssize_t nr_items;
+        const long init_pos = ftell(fp);
+
+        BT_CPPLOGI_SPEC(mdec->logger, "Metadata stream is plain text: mdec-addr={}",
+                        fmt::ptr(mdec));
+
+        if (init_pos < 0) {
+            BT_CPPLOGE_ERRNO_APPEND_CAUSE_SPEC(mdec->logger, "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_CPPLOGW_SPEC(
+                mdec->logger,
+                "Missing \"/* CTF major.minor\" signature in plain text metadata file stream: "
+                "mdec-addr={}",
+                fmt::ptr(mdec));
+        }
+
+        BT_CPPLOGI_SPEC(mdec->logger, "Found metadata stream version in signature: version={}.{}",
+                        major, minor);
+
+        if (!ctf_metadata_decoder_is_packet_version_valid(major, minor)) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(mdec->logger,
+                                         "Invalid metadata version found in plain text signature: "
+                                         "version={}.{}, mdec-addr={}",
+                                         major, minor, fmt::ptr(mdec));
+            status = CTF_METADATA_DECODER_STATUS_INVAL_VERSION;
+            goto end;
+        }
+
+        if (fseek(fp, init_pos, SEEK_SET)) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(
+                mdec->logger,
+                "Cannot seek metadata file stream to initial position: {}: "
+                "mdec-addr={}",
+                strerror(errno), fmt::ptr(mdec));
+            status = CTF_METADATA_DECODER_STATUS_ERROR;
+            goto end;
+        }
+
+        mdec->has_checked_plaintext_signature = true;
+    }
+
+#if YYDEBUG
+    if (mdec->logger.wouldLogT()) {
+        yydebug = 1;
+    }
+#endif
+
+    /* Save the file's position: we'll seek back to append the plain text */
+    BT_ASSERT(fp);
+
+    if (mdec->config.keep_plain_text) {
+        start_pos = ftell(fp);
+    }
+
+    /* Append the metadata text content */
+    ret = ctf_scanner_append_ast(mdec->scanner, fp);
+    if (ret) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(mdec->logger,
+                                     "Cannot create the metadata AST out of the metadata text: "
+                                     "mdec-addr={}",
+                                     fmt::ptr(mdec));
+        status = CTF_METADATA_DECODER_STATUS_INCOMPLETE;
+        goto end;
+    }
+
+    /* We know it's complete: append plain text */
+    if (mdec->config.keep_plain_text) {
+        BT_ASSERT(start_pos != -1);
+        ret = fseek(fp, start_pos, SEEK_SET);
+        if (ret) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(mdec->logger, "Failed to seek file: ret={}, mdec-addr={}",
+                                         ret, fmt::ptr(mdec));
+            status = CTF_METADATA_DECODER_STATUS_ERROR;
+            goto end;
+        }
+
+        ret = bt_common_append_file_content_to_g_string(mdec->text, fp);
+        if (ret) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(mdec->logger,
+                                         "Failed to append to current plain text: "
+                                         "ret={}, mdec-addr={}",
+                                         ret, fmt::ptr(mdec));
+            status = CTF_METADATA_DECODER_STATUS_ERROR;
+            goto end;
+        }
+    }
+
+    ret = ctf_visitor_semantic_check(0, &mdec->scanner->ast->root, mdec->logger);
+    if (ret) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(mdec->logger,
+                                     "Validation of the metadata semantics failed: "
+                                     "mdec-addr={}",
+                                     fmt::ptr(mdec));
+        status = CTF_METADATA_DECODER_STATUS_ERROR;
+        goto end;
+    }
+
+    if (mdec->config.create_trace_class) {
+        ret = ctf_visitor_generate_ir_visit_node(mdec->visitor.get(), &mdec->scanner->ast->root);
+        switch (ret) {
+        case 0:
+            /* Success */
+            break;
+        case -EINCOMPLETE:
+            BT_CPPLOGD_SPEC(mdec->logger,
+                            "While visiting metadata AST: incomplete data: "
+                            "mdec-addr={}",
+                            fmt::ptr(mdec));
+            status = CTF_METADATA_DECODER_STATUS_INCOMPLETE;
+            goto end;
+        default:
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(mdec->logger,
+                                         "Failed to visit AST node to create CTF IR objects: "
+                                         "mdec-addr={}, ret={}",
+                                         fmt::ptr(mdec), ret);
+            status = CTF_METADATA_DECODER_STATUS_IR_VISITOR_ERROR;
+            goto end;
+        }
+    }
+
+end:
+#if YYDEBUG
+    yydebug = 0;
+#endif
+
+    if (fp && close_fp) {
+        if (fclose(fp)) {
+            BT_CPPLOGE_SPEC(mdec->logger,
+                            "Cannot close metadata file stream: "
+                            "mdec-addr={}",
+                            fmt::ptr(mdec));
+        }
+    }
+
+    free(buf);
+
+    return status;
+}
+
+bt2::TraceClass::Shared ctf_metadata_decoder_get_ir_trace_class(struct ctf_metadata_decoder *mdec)
+{
+    BT_ASSERT_DBG(mdec);
+    BT_ASSERT_DBG(mdec->config.create_trace_class);
+    return ctf_visitor_generate_ir_get_ir_trace_class(mdec->visitor.get());
+}
+
+struct ctf_trace_class *
+ctf_metadata_decoder_borrow_ctf_trace_class(struct ctf_metadata_decoder *mdec)
+{
+    BT_ASSERT_DBG(mdec);
+    BT_ASSERT_DBG(mdec->config.create_trace_class);
+    return ctf_visitor_generate_ir_borrow_ctf_trace_class(mdec->visitor.get());
+}
+
+const char *ctf_metadata_decoder_get_text(struct ctf_metadata_decoder *mdec)
+{
+    BT_ASSERT_DBG(mdec);
+    BT_ASSERT_DBG(mdec->config.keep_plain_text);
+    return mdec->text->str;
+}
+
+int ctf_metadata_decoder_get_byte_order(struct ctf_metadata_decoder *mdec)
+{
+    BT_ASSERT_DBG(mdec);
+    return mdec->bo;
+}
+
+int ctf_metadata_decoder_get_uuid(struct ctf_metadata_decoder *mdec, bt_uuid_t uuid)
+{
+    int ret = 0;
+
+    BT_ASSERT_DBG(mdec);
+
+    if (!mdec->is_uuid_set) {
+        ret = -1;
+        goto end;
+    }
+
+    bt_uuid_copy(uuid, mdec->uuid);
+
+end:
+    return ret;
+}
+
+static enum ctf_metadata_decoder_status find_uuid_in_trace_decl(struct ctf_metadata_decoder *mdec,
+                                                                struct ctf_node *trace_node,
+                                                                bt_uuid_t uuid)
+{
+    enum ctf_metadata_decoder_status status = CTF_METADATA_DECODER_STATUS_OK;
+    struct ctf_node *entry_node;
+    struct bt_list_head *decl_list = &trace_node->u.trace.declaration_list;
+    char *left = NULL;
+
+    bt_list_for_each_entry (entry_node, decl_list, siblings) {
+        if (entry_node->type == NODE_CTF_EXPRESSION) {
+            int ret;
+
+            left = ctf_ast_concatenate_unary_strings(&entry_node->u.ctf_expression.left);
+            if (!left) {
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(mdec->logger, "Cannot concatenate unary strings.");
+                status = CTF_METADATA_DECODER_STATUS_ERROR;
+                goto end;
+            }
+
+            if (strcmp(left, "uuid") == 0) {
+                ret =
+                    ctf_ast_get_unary_uuid(&entry_node->u.ctf_expression.right, uuid, mdec->logger);
+                if (ret) {
+                    BT_CPPLOGE_APPEND_CAUSE_SPEC(mdec->logger, "Invalid trace's `uuid` attribute.");
+                    status = CTF_METADATA_DECODER_STATUS_ERROR;
+                    goto end;
+                }
+
+                goto end;
+            }
+
+            g_free(left);
+            left = NULL;
+        }
+    }
+
+    status = CTF_METADATA_DECODER_STATUS_NONE;
+
+end:
+    g_free(left);
+    return status;
+}
+
+enum ctf_metadata_decoder_status
+ctf_metadata_decoder_get_trace_class_uuid(struct ctf_metadata_decoder *mdec, bt_uuid_t uuid)
+{
+    enum ctf_metadata_decoder_status status = CTF_METADATA_DECODER_STATUS_INCOMPLETE;
+    struct ctf_node *root_node = &mdec->scanner->ast->root;
+    struct ctf_node *trace_node;
+
+    if (!root_node) {
+        status = CTF_METADATA_DECODER_STATUS_INCOMPLETE;
+        goto end;
+    }
+
+    trace_node = bt_list_entry(root_node->u.root.trace.next, struct ctf_node, siblings);
+    if (!trace_node) {
+        status = CTF_METADATA_DECODER_STATUS_INCOMPLETE;
+        goto end;
+    }
+
+    status = find_uuid_in_trace_decl(mdec, trace_node, uuid);
+
+end:
+    return status;
+}
diff --git a/src/plugins/ctf/common/src/metadata/tsdl/decoder.hpp b/src/plugins/ctf/common/src/metadata/tsdl/decoder.hpp
new file mode 100644 (file)
index 0000000..b4dbce8
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2016-2017 Philippe Proulx <pproulx@efficios.com>
+ */
+
+#ifndef _METADATA_DECODER_H
+#define _METADATA_DECODER_H
+
+#include <stdio.h>
+
+#include <babeltrace2/babeltrace.h>
+
+#include "common/uuid.h"
+#include "cpp-common/bt2/trace-ir.hpp"
+#include "cpp-common/bt2c/logging.hpp"
+#include "cpp-common/vendor/fmt/format.h" /* IWYU pragma: keep */
+
+#include "../../../src/clk-cls-cfg.hpp"
+
+/* 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_NONE = 1,
+    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,
+};
+
+inline const char *format_as(ctf_metadata_decoder_status status) noexcept
+{
+    switch (status) {
+    case CTF_METADATA_DECODER_STATUS_OK:
+        return "CTF_METADATA_DECODER_STATUS_OK";
+
+    case CTF_METADATA_DECODER_STATUS_NONE:
+        return "CTF_METADATA_DECODER_STATUS_NONE";
+
+    case CTF_METADATA_DECODER_STATUS_ERROR:
+        return "CTF_METADATA_DECODER_STATUS_ERROR";
+
+    case CTF_METADATA_DECODER_STATUS_INCOMPLETE:
+        return "CTF_METADATA_DECODER_STATUS_INCOMPLETE";
+
+    case CTF_METADATA_DECODER_STATUS_INVAL_VERSION:
+        return "CTF_METADATA_DECODER_STATUS_INVAL_VERSION";
+
+    case CTF_METADATA_DECODER_STATUS_IR_VISITOR_ERROR:
+        return "CTF_METADATA_DECODER_STATUS_IR_VISITOR_ERROR";
+    }
+
+    bt_common_abort();
+}
+
+/* Decoding configuration */
+struct ctf_metadata_decoder_config
+{
+    explicit ctf_metadata_decoder_config(const bt2c::Logger& parentLogger) :
+        logger {parentLogger, "PLUGIN/CTF/META/DECODER-CONFIG"}
+    {
+    }
+
+    bt2c::Logger logger;
+
+    /* Weak, used to create a bt_trace_class, if not nullptr. */
+    bt_self_component *self_comp = nullptr;
+
+    ctf::src::ClkClsCfg clkClsCfg;
+
+    /* True to create trace class objects */
+    bool create_trace_class = false;
+
+    /*
+     * True to keep the plain text when content is appended with
+     * ctf_metadata_decoder_append_content().
+     */
+    bool keep_plain_text = false;
+};
+
+struct ctf_metadata_decoder_deleter
+{
+    void operator()(struct ctf_metadata_decoder *decoder);
+};
+
+using ctf_metadata_decoder_up = std::unique_ptr<ctf_metadata_decoder, ctf_metadata_decoder_deleter>;
+
+/*
+ * Creates a CTF metadata decoder.
+ *
+ * Returns `NULL` on error.
+ */
+ctf_metadata_decoder_up
+ctf_metadata_decoder_create(const struct ctf_metadata_decoder_config *config);
+
+/*
+ * Destroys a CTF metadata decoder that you created with
+ * ctf_metadata_decoder_create().
+ */
+void ctf_metadata_decoder_destroy(struct ctf_metadata_decoder *metadata_decoder);
+
+/*
+ * Appends content to the metadata decoder.
+ *
+ * This function reads the metadata from the current position of `fp`
+ * until the end of this file stream.
+ *
+ * The metadata can be packetized or not.
+ *
+ * The metadata chunk needs to be complete and lexically 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 everything goes as expected, this function returns
+ * `CTF_METADATA_DECODER_STATUS_OK`.
+ */
+enum ctf_metadata_decoder_status
+ctf_metadata_decoder_append_content(struct ctf_metadata_decoder *metadata_decoder, FILE *fp);
+
+/*
+ * Returns the trace IR trace class of this metadata decoder (new
+ * reference).
+ *
+ * Returns `NULL` if there's none yet or if the metadata decoder is not
+ * configured to create trace classes.
+ */
+bt2::TraceClass::Shared ctf_metadata_decoder_get_ir_trace_class(struct ctf_metadata_decoder *mdec);
+
+/*
+ * Returns the CTF IR trace class of this metadata decoder.
+ *
+ * Returns `NULL` if there's none yet or if the metadata decoder is not
+ * configured to create trace classes.
+ */
+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 `fp` is
+ * packetized, setting `is_packetized` accordingly on success. On
+ * success, also sets `*byte_order` to the byte order of the first
+ * packet.
+ */
+int ctf_metadata_decoder_is_packetized(FILE *fp, bool *is_packetized, int *byte_order,
+                                       const bt2c::Logger& logger);
+
+/*
+ * Returns the byte order of the decoder's metadata stream as set by the
+ * last call to ctf_metadata_decoder_append_content().
+ *
+ * Returns -1 if unknown (plain text content).
+ */
+int ctf_metadata_decoder_get_byte_order(struct ctf_metadata_decoder *mdec);
+
+/*
+ * Returns the UUID of the decoder's metadata stream as set by the last
+ * call to ctf_metadata_decoder_append_content().
+ */
+int ctf_metadata_decoder_get_uuid(struct ctf_metadata_decoder *mdec, bt_uuid_t uuid);
+
+/*
+ * Returns the UUID of the decoder's trace class, if available.
+ *
+ * Returns:
+ *
+ * * `CTF_METADATA_DECODER_STATUS_OK`: success.
+ * * `CTF_METADATA_DECODER_STATUS_NONE`: no UUID.
+ * * `CTF_METADATA_DECODER_STATUS_INCOMPLETE`: missing metadata content.
+ */
+enum ctf_metadata_decoder_status
+ctf_metadata_decoder_get_trace_class_uuid(struct ctf_metadata_decoder *mdec, bt_uuid_t uuid);
+
+/*
+ * Returns the metadata decoder's current metadata text.
+ */
+const char *ctf_metadata_decoder_get_text(struct ctf_metadata_decoder *mdec);
+
+static inline bool ctf_metadata_decoder_is_packet_version_valid(unsigned int major,
+                                                                unsigned int minor)
+{
+    return major == 1 && minor == 8;
+}
+
+#endif /* _METADATA_DECODER_H */
diff --git a/src/plugins/ctf/common/src/metadata/tsdl/lexer.lpp b/src/plugins/ctf/common/src/metadata/tsdl/lexer.lpp
new file mode 100644 (file)
index 0000000..8bc0eed
--- /dev/null
@@ -0,0 +1,119 @@
+%{
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2010 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Common Trace Formal Lexer
+ */
+
+#include "plugins/ctf/common/src/metadata/tsdl/ast.hpp"
+#include "plugins/ctf/common/src/metadata/tsdl/logging.hpp"
+#include "plugins/ctf/common/src/metadata/tsdl/parser-wrap.hpp"
+#include "plugins/ctf/common/src/metadata/tsdl/scanner.hpp"
+
+#define YY_FATAL_ERROR(_msg)   BT_CPPLOGF_SPEC(currentCtfScanner->logger, "{}", _msg)
+
+#define PARSE_INTEGER_LITERAL(base)                                    \
+       do {                                                            \
+               errno = 0;                                              \
+               yylval->ull = strtoull(yytext, NULL, base);             \
+               if (errno) {                                            \
+                       _BT_CPPLOGE_APPEND_CAUSE_LINENO(                \
+                               currentCtfScanner->logger,              \
+                               yylineno,                               \
+                               "Cannot parser constant integer: "      \
+                               "base={}, text=\"{}\"", base, yytext);  \
+                       return CTF_ERROR;                               \
+               }                                                       \
+       } while (0)
+
+extern thread_local const ctf_scanner *const currentCtfScanner;
+%}
+
+%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_CPPLOGT_SPEC(currentCtfScanner->logger, "Got identifier: id=\"{}\"", yytext); setstring(yyextra, yylval, yytext); if (is_type(yyextra, yytext)) return ID_TYPE; else return IDENTIFIER;
+[ \t\r\n]                      ; /* ignore */
+.                              _BT_CPPLOGE_APPEND_CAUSE_LINENO(currentCtfScanner->logger, yylineno, "Invalid character: char=\"{}\", val={:#02x}", isprint((unsigned char) yytext[0]) ? yytext[0] : '\0', yytext[0]); return CTF_ERROR;
+%%
diff --git a/src/plugins/ctf/common/src/metadata/tsdl/logging.hpp b/src/plugins/ctf/common/src/metadata/tsdl/logging.hpp
new file mode 100644 (file)
index 0000000..ee019a3
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright (c) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ */
+
+#ifndef CTF_METADATA_LOGGING_H
+#define CTF_METADATA_LOGGING_H
+
+#include <babeltrace2/babeltrace.h>
+
+#include "cpp-common/bt2c/logging.hpp"
+
+#define _BT_CPPLOGT_LINENO(logger, _lineno, _msg, args...)                                         \
+    BT_CPPLOGT_SPEC((logger), "At line {} in metadata stream: " _msg, _lineno, ##args)
+
+#define _BT_CPPLOGW_LINENO(logger, _lineno, _msg, args...)                                         \
+    BT_CPPLOGW_SPEC((logger), "At line {} in metadata stream: " _msg, _lineno, ##args)
+
+#define _BT_CPPLOGE_LINENO(logger, _lineno, _msg, args...)                                         \
+    BT_CPPLOGE_SPEC((logger), "At line {} in metadata stream: " _msg, _lineno, ##args)
+
+#define _BT_CPPLOGE_APPEND_CAUSE_LINENO(logger, _lineno, _msg, args...)                            \
+    BT_CPPLOGE_APPEND_CAUSE_SPEC((logger), "At line {} in metadata stream: " _msg, _lineno, ##args)
+
+#endif /* CTF_METADATA_LOGGING_H */
diff --git a/src/plugins/ctf/common/src/metadata/tsdl/objstack.cpp b/src/plugins/ctf/common/src/metadata/tsdl/objstack.cpp
new file mode 100644 (file)
index 0000000..d124b3f
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Common Trace Format Object Stack.
+ */
+
+#include "common/align.h"
+#include "common/list.h"
+#include "cpp-common/bt2c/logging.hpp"
+
+#include "objstack.hpp"
+
+#define OBJSTACK_ALIGN    8 /* Object stack alignment */
+#define OBJSTACK_INIT_LEN 128
+#define OBJSTACK_POISON   0xcc
+
+struct objstack
+{
+    explicit objstack(const bt2c::Logger& parentLogger) :
+        logger {parentLogger, "PLUGIN/CTF/META/OBJSTACK"}
+    {
+    }
+
+    /* list of struct objstack_node */
+    bt_list_head head {};
+
+    bt2c::Logger logger;
+};
+
+struct objstack_node
+{
+    struct bt_list_head node;
+    size_t len;
+    size_t used_len;
+    char __attribute__((aligned(OBJSTACK_ALIGN))) data[];
+};
+
+objstack *objstack_create(const bt2c::Logger& parentLogger)
+{
+    struct objstack *objstack;
+    struct objstack_node *node;
+
+    objstack = new ::objstack {parentLogger};
+    node = (objstack_node *) calloc(sizeof(struct objstack_node) + OBJSTACK_INIT_LEN, sizeof(char));
+    if (!node) {
+        BT_CPPLOGE_SPEC(objstack->logger, "Failed to allocate one object stack node.");
+        delete 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);
+}
+
+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);
+    }
+
+    delete 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 = (objstack_node *) calloc(sizeof(struct objstack_node) + (last_node->len << 1),
+                                        sizeof(char));
+    if (!new_node) {
+        BT_CPPLOGE_SPEC(objstack->logger, "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;
+}
+
+void *objstack_alloc(struct objstack *objstack, size_t len)
+{
+    struct objstack_node *last_node;
+    void *p;
+
+    len = BT_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/src/metadata/tsdl/objstack.hpp b/src/plugins/ctf/common/src/metadata/tsdl/objstack.hpp
new file mode 100644 (file)
index 0000000..cc17d43
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Common Trace Format Object Stack.
+ */
+
+#ifndef _OBJSTACK_H
+#define _OBJSTACK_H
+
+#include <cstddef>
+
+namespace bt2c {
+
+class Logger;
+
+} /* namespace bt2c */
+
+struct objstack *objstack_create(const bt2c::Logger& parentLogger);
+void objstack_destroy(struct objstack *objstack);
+
+/*
+ * Allocate len bytes of zeroed memory.
+ * Return NULL on error.
+ */
+void *objstack_alloc(struct objstack *objstack, size_t len);
+
+#endif /* _OBJSTACK_H */
diff --git a/src/plugins/ctf/common/src/metadata/tsdl/parser-wrap.hpp b/src/plugins/ctf/common/src/metadata/tsdl/parser-wrap.hpp
new file mode 100644 (file)
index 0000000..bfc0e90
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2019 EfficiOS Inc.
+ */
+
+#ifndef BABELTRACE_PLUGINS_CTF_COMMON_METADATA_PARSER_WRAP_H
+#define BABELTRACE_PLUGINS_CTF_COMMON_METADATA_PARSER_WRAP_H
+
+/*
+ * Small wrapper around the bison-generated parser.h to conditionally define
+ * YYDEBUG (and therefore the yydebug declaration).
+ */
+
+#include "logging/log-api.h"
+
+#if BT_LOG_ENABLED_TRACE
+#    define YYDEBUG 1
+#else
+#    define YYDEBUG 0
+#endif
+
+#define ALLOW_INCLUDE_PARSER_H
+#include "plugins/ctf/common/src/metadata/tsdl/parser.hpp"
+#undef ALLOW_INCLUDE_PARSER_H
+
+#endif
diff --git a/src/plugins/ctf/common/src/metadata/tsdl/parser.ypp b/src/plugins/ctf/common/src/metadata/tsdl/parser.ypp
new file mode 100644 (file)
index 0000000..bf2d90c
--- /dev/null
@@ -0,0 +1,2616 @@
+%{
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Common Trace Format Metadata Grammar.
+ */
+
+#include "plugins/ctf/common/src/metadata/tsdl/logging.hpp"
+
+#include "common/list.h"
+#include "common/assert.h"
+
+#include "plugins/ctf/common/src/metadata/tsdl/scanner.hpp"
+#include "plugins/ctf/common/src/metadata/tsdl/ast.hpp"
+#include "plugins/ctf/common/src/metadata/tsdl/objstack.hpp"
+#include "plugins/ctf/common/src/metadata/tsdl/parser-wrap.hpp"
+
+/*
+ * Avoid warning about "yynerrs" being unused, seen with bison 3.5.1 + clang 15
+ * on Ubuntu 20.04.
+ */
+BT_DIAG_IGNORE_UNUSED_BUT_SET_VARIABLE
+
+thread_local const ctf_scanner *currentCtfScanner;
+
+#define YYFPRINTF(_stream, _fmt, args...)                                                          \
+    do {                                                                                           \
+        int size = snprintf(NULL, 0, (_fmt), ##args);                                              \
+        std::string str(size, '\0');                                                               \
+        int written = snprintf(&str[0], size + 1, (_fmt), ##args);                                 \
+        BT_ASSERT(size == written);                                                                \
+        BT_CPPLOGT_SPEC(currentCtfScanner->logger, "{}", str.c_str());                             \
+    } while (0)
+
+/* 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;
+       }
+}
+
+int yylex(union YYSTYPE *yyval, yyscan_t yyscanner);
+int yylex_init_extra(struct ctf_scanner *scanner, yyscan_t * ptr_yy_globals);
+int yylex_destroy(yyscan_t yyscanner);
+void yyrestart(FILE * in_str, yyscan_t yyscanner);
+int yyget_lineno(yyscan_t yyscanner);
+char *yyget_text(yyscan_t yyscanner);
+
+/*
+ * 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 = {
+       .parent = nullptr,
+       .siblings = {},
+       .tmp_head = {},
+       .lineno = 0,
+       .visited = 0,
+       .type = NODE_ERROR,
+};
+
+const char *node_type(struct ctf_node *node)
+{
+       switch (node->type) {
+#define ENTRY(S) case S: return #S;
+       FOREACH_CTF_NODES(ENTRY)
+#undef ENTRY
+       };
+
+       bt_common_abort();
+}
+
+void setstring(struct ctf_scanner *scanner, YYSTYPE *lvalp, const char *src)
+{
+       lvalp->s = (char *) 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_DBG(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 = (char *) objstack_alloc(scanner->objstack, len);
+       if (src[0] == 'L') {
+               // TODO: import wide string
+               _BT_CPPLOGE_APPEND_CAUSE_LINENO(currentCtfScanner->logger,
+                       yyget_lineno(scanner),
+                       "wide characters are not supported as of this version: "
+                       "scanner-addr={}", fmt::ptr(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_CPPLOGT_SPEC(currentCtfScanner->logger,
+               "Pushing scope: scanner-addr={}", fmt::ptr(scanner));
+       ns = (ctf_scanner_scope *) 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_CPPLOGT_SPEC(currentCtfScanner->logger,
+               "Popping scope: scanner-addr={}", fmt::ptr(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_CPPLOGT_SPEC(currentCtfScanner->logger,
+               "Looked up type: scanner-addr={}, id=\"{}\", ret={}",
+               fmt::ptr(s), id, ret);
+       return ret;
+}
+
+int is_type(struct ctf_scanner *scanner, const char *id)
+{
+       struct ctf_scanner_scope *it;
+       int ret = 0;
+
+       for (it = scanner->cs; it; it = it->parent) {
+               if (lookup_type(it, id)) {
+                       ret = 1;
+                       break;
+               }
+       }
+       BT_CPPLOGT_SPEC(currentCtfScanner->logger,
+               "Found if ID is type: scanner-addr={}, id=\"{}\", ret={}",
+               fmt::ptr(scanner), id, ret);
+       return ret;
+}
+
+static void add_type(struct ctf_scanner *scanner, char *id)
+{
+       BT_CPPLOGT_SPEC(currentCtfScanner->logger,
+               "Adding type: scanner-addr={}, id=\"{}\"", fmt::ptr(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 = (ctf_node *) objstack_alloc(scanner->objstack, sizeof(*node));
+       if (!node) {
+               _BT_CPPLOGE_APPEND_CAUSE_LINENO(currentCtfScanner->logger,
+                       yyget_lineno(scanner->scanner),
+                       "failed to allocate one stack entry: "
+                       "scanner-addr={}", fmt::ptr(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_CPPLOGE_SPEC(currentCtfScanner->logger, "Trying to create root node: scanner-addr={}",
+                       fmt::ptr(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_CPPLOGE_SPEC(currentCtfScanner->logger, "Unknown node type: scanner-addr={}, node-type={}",
+                       fmt::ptr(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_CPPLOGE_SPEC(currentCtfScanner->logger, "Unknown node type: node-type={}", 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_CPPLOGE_SPEC(currentCtfScanner->logger, "Unknown node type: node-type={}", 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_CPPLOGE_SPEC(currentCtfScanner->logger, "Unknown node type: node-type={}", 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_CPPLOGE_SPEC(currentCtfScanner->logger, "Unknown node type: node-type={}", 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_CPPLOGE_SPEC(currentCtfScanner->logger, "Unknown node type: node-type={}", 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_CPPLOGE_SPEC(currentCtfScanner->logger, "Unknown node type: node-type={}", 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_CPPLOGE_SPEC(currentCtfScanner->logger, "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_CPPLOGE_SPEC(currentCtfScanner->logger, "Unknown node type: node-type={}", parent->type);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static
+void yyerror(struct ctf_scanner *scanner, yyscan_t yyscanner, const char *str)
+{
+       _BT_CPPLOGE_APPEND_CAUSE_LINENO(currentCtfScanner->logger,
+               yyget_lineno(scanner->scanner),
+               "{}: token=\"{}\"", str, yyget_text(scanner->scanner));
+}
+
+#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 = (ctf_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 */
+       struct ClearCurrentCtfScanner {
+               ~ClearCurrentCtfScanner() {
+                       currentCtfScanner = nullptr;
+               }
+       } clearMoiLa;
+
+       currentCtfScanner = scanner;
+       yyrestart(input, scanner->scanner);
+       return yyparse(scanner, scanner->scanner);
+}
+
+struct ctf_scanner *ctf_scanner_alloc(const bt2c::Logger &parentLogger)
+{
+       ctf_scanner *scanner = new ctf_scanner {parentLogger};
+       int ret = yylex_init_extra(scanner, &scanner->scanner);
+       if (ret) {
+               BT_CPPLOGE_SPEC(scanner->logger, "yylex_init_extra() failed: ret={}", ret);
+               goto cleanup_scanner;
+       }
+       scanner->objstack = objstack_create(scanner->logger);
+       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_CPPLOGE_SPEC(scanner->logger, "yylex_destroy() failed: scanner-addr={}, ret={}",
+                       fmt::ptr(scanner), ret);
+cleanup_scanner:
+       delete scanner;
+       return NULL;
+}
+
+void ctf_scanner_free(struct ctf_scanner *scanner)
+{
+       int ret;
+
+       if (!scanner)
+               return;
+
+       struct ctf_scanner_scope *scope = scanner->cs;
+
+       do {
+               struct ctf_scanner_scope *parent = scope->parent;
+               finalize_scope(scope);
+
+               /*
+                * The root scope is allocated within the ctf_scanner structure,
+                * do doesn't need freeing.  All others are allocated on their
+                * own.
+                */
+               if (scope != &scanner->root_scope)
+                       free(scope);
+
+               scope = parent;
+       } while (scope);
+
+       objstack_destroy(scanner->objstack);
+       ret = yylex_destroy(scanner->scanner);
+       if (ret)
+               BT_CPPLOGE_SPEC(currentCtfScanner->logger, "yylex_destroy() failed: scanner-addr={}, ret={}",
+                       fmt::ptr(scanner), ret);
+       delete scanner;
+}
+
+/*
+ * The bison-provided version of strlen (yystrlen) generates a benign
+ * -Wnull-dereference warning.  That version is used when building on cygwin,
+ * for example, but you can also enable it by hand (to test) by removing the
+ * preprocessor conditional around it.
+ *
+ * Define yystrlen such that it will always use strlen.  As far as we know,
+ * strlen provided by all the platforms we use is reliable.
+ */
+#define yystrlen strlen
+
+%}
+
+/*
+ * This ends up in parser.h and makes sure those who want to include it pass
+ * through parser-wrap.h.
+ */
+%code requires {
+#ifndef ALLOW_INCLUDE_PARSER_H
+# error "Don't include parser.h directly, include parser-wrap.h instead."
+#endif
+
+#include "plugins/ctf/common/src/metadata/tsdl/scanner.hpp"
+}
+
+%code provides {
+       void setstring(struct ctf_scanner *scanner, YYSTYPE *lvalp, const char *src);
+
+       int import_string(struct ctf_scanner *scanner, YYSTYPE *lvalp, const char *src, char delim);
+}
+
+%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_SIGNED_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/src/metadata/tsdl/scanner-symbols.hpp b/src/plugins/ctf/common/src/metadata/tsdl/scanner-symbols.hpp
new file mode 100644 (file)
index 0000000..1f6f144
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2011-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ */
+
+#ifndef _CTF_SCANNER_SYMBOLS
+#define _CTF_SCANNER_SYMBOLS
+
+#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/src/metadata/tsdl/scanner.hpp b/src/plugins/ctf/common/src/metadata/tsdl/scanner.hpp
new file mode 100644 (file)
index 0000000..4f2a1f8
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2011-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ */
+
+#ifndef _CTF_SCANNER_H
+#define _CTF_SCANNER_H
+
+#include <stdio.h>
+
+#include "ast.hpp"
+
+#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
+{
+    explicit ctf_scanner(const bt2c::Logger& parentLogger) :
+        logger {parentLogger, "PLUGIN/CTF/META/PARSER"}
+    {
+    }
+
+    bt2c::Logger logger;
+    yyscan_t scanner {};
+    ctf_ast *ast = nullptr;
+    ctf_scanner_scope root_scope {};
+    ctf_scanner_scope *cs = nullptr;
+    struct objstack *objstack = nullptr;
+};
+
+struct ctf_scanner *ctf_scanner_alloc(const bt2c::Logger& parentLogger);
+
+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;
+}
+
+int is_type(struct ctf_scanner *scanner, const char *id);
+
+#endif /* _CTF_SCANNER_H */
diff --git a/src/plugins/ctf/common/src/metadata/tsdl/visitor-generate-ir.cpp b/src/plugins/ctf/common/src/metadata/tsdl/visitor-generate-ir.cpp
new file mode 100644 (file)
index 0000000..48034a3
--- /dev/null
@@ -0,0 +1,4667 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2010 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright 2015-2018 Philippe Proulx <philippe.proulx@efficios.com>
+ *
+ * Common Trace Format metadata visitor (generates CTF IR objects).
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "logging.hpp"
+
+#include "common/assert.h"
+#include "common/common.h"
+#include "common/uuid.h"
+#include "compat/endian.h" /* IWYU pragma: keep  */
+#include "cpp-common/bt2c/logging.hpp"
+
+#include "ast.hpp"
+#include "ctf-meta-visitors.hpp"
+
+/* 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_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger, "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_CPPLOGE_APPEND_CAUSE_DUP_ATTR(_node, _attr, _entity)                                   \
+    _BT_CPPLOGE_APPEND_CAUSE_LINENO(ctx->logger, (_node)->lineno,                                  \
+                                    "Duplicate attribute in {}: attr-name=\"{}\"", _entity, _attr)
+
+#define _BT_CPPLOGE_NODE(_node, _msg, args...)                                                     \
+    _BT_CPPLOGE_LINENO(ctx->logger, (_node)->lineno, _msg, ##args)
+
+#define _BT_CPPLOGE_APPEND_CAUSE_NODE(_node, _msg, args...)                                        \
+    _BT_CPPLOGE_APPEND_CAUSE_LINENO(ctx->logger, (_node)->lineno, _msg, ##args)
+
+#define _BT_CPPLOGW_NODE(_node, _msg, args...)                                                     \
+    _BT_CPPLOGW_LINENO(ctx->logger, (_node)->lineno, _msg, ##args)
+
+#define _BT_CPPLOGT_NODE(_node, _msg, args...)                                                     \
+    _BT_CPPLOGT_LINENO(ctx->logger, (_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;
+};
+
+/**
+ * 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 ctf_visitor_generate_ir *ctx,
+                                                    struct ctx_decl_scope *par_scope)
+{
+    struct ctx_decl_scope *scope;
+
+    scope = g_new(struct ctx_decl_scope, 1);
+    if (!scope) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger, "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)
+{
+    BT_ASSERT(name);
+    std::string prname = std::string {prefix} + name;
+    return g_quark_from_string(prname.c_str());
+}
+
+/**
+ * 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 = (ctf_field_class *) 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 ctf_field_class_as_enum(
+        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 ctf_field_class_as_struct(
+        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 ctf_field_class_as_variant(
+        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, 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, &decl->base.base.base);
+}
+
+/**
+ * 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, &decl->base);
+}
+
+/**
+ * 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, &decl->base);
+}
+
+ctf_visitor_generate_ir::~ctf_visitor_generate_ir()
+{
+    struct ctx_decl_scope *scope = this->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;
+    }
+
+    if (this->ctf_tc) {
+        ctf_trace_class_destroy(this->ctf_tc);
+    }
+}
+
+/**
+ * Creates a new visitor context.
+ *
+ * @param trace        Associated trace
+ * @returns    New visitor context, or NULL on error
+ */
+static ctf_visitor_generate_ir::UP
+ctx_create(const struct ctf_metadata_decoder_config *decoder_config, const bt2c::Logger& logger)
+{
+    BT_ASSERT(decoder_config);
+
+    ctf_visitor_generate_ir::UP ctx {new ctf_visitor_generate_ir {*decoder_config, logger}};
+
+    if (decoder_config->self_comp) {
+        bt_trace_class *trace_class = bt_trace_class_create(decoder_config->self_comp);
+        if (!trace_class) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger, "Cannot create empty trace class.");
+            goto error;
+        }
+
+        ctx->trace_class = bt2::TraceClass::Shared::createWithoutRef(trace_class);
+    }
+
+    ctx->ctf_tc = ctf_trace_class_create();
+    if (!ctx->ctf_tc) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger, "Cannot create CTF trace class.");
+        goto error;
+    }
+
+    /* Root declaration scope */
+    ctx->current_scope = ctx_decl_scope_create(ctx.get(), NULL);
+    if (!ctx->current_scope) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger, "Cannot create declaration scope.");
+        goto error;
+    }
+
+    goto end;
+
+error:
+    ctx.reset();
+
+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 ctf_visitor_generate_ir *ctx)
+{
+    int ret = 0;
+    struct ctx_decl_scope *new_scope;
+
+    BT_ASSERT(ctx);
+    new_scope = ctx_decl_scope_create(ctx, ctx->current_scope);
+    if (!new_scope) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger, "Cannot create declaration scope.");
+        ret = -ENOMEM;
+        goto end;
+    }
+
+    ctx->current_scope = new_scope;
+
+end:
+    return ret;
+}
+
+static void ctx_pop_scope(struct ctf_visitor_generate_ir *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 ctf_visitor_generate_ir *ctx,
+                                            struct ctf_node *ts_list,
+                                            struct ctf_field_class **decl);
+
+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 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 ctf_visitor_generate_ir *ctx, 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_CPPLOGE_APPEND_CAUSE_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 ctf_visitor_generate_ir *ctx, struct bt_list_head *head,
+                          bt_uuid_t uuid)
+{
+    return ctf_ast_get_unary_uuid(head, uuid, ctx->logger);
+}
+
+static int get_boolean(struct ctf_visitor_generate_ir *ctx, struct ctf_node *unary_expr)
+{
+    int ret = 0;
+
+    if (unary_expr->type != NODE_UNARY_EXPRESSION) {
+        _BT_CPPLOGE_APPEND_CAUSE_NODE(unary_expr, "Expecting unary expression: node-type={}",
+                                      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") == 0 || strcmp(str, "TRUE") == 0) {
+            ret = TRUE;
+        } else if (strcmp(str, "false") == 0 || strcmp(str, "FALSE") == 0) {
+            ret = FALSE;
+        } else {
+            _BT_CPPLOGE_APPEND_CAUSE_NODE(unary_expr, "Unexpected boolean value: value=\"{}\"",
+                                          str);
+            ret = -EINVAL;
+            goto end;
+        }
+        break;
+    }
+    default:
+        _BT_CPPLOGE_APPEND_CAUSE_NODE(unary_expr, "Unexpected unary expression type: node-type={}",
+                                      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_visitor_generate_ir *ctx,
+                                                      struct ctf_node *unary_expr)
+{
+    const char *str;
+    enum ctf_byte_order bo = CTF_BYTE_ORDER_UNKNOWN;
+
+    if (unary_expr->u.unary_expression.type != UNARY_STRING) {
+        _BT_CPPLOGE_APPEND_CAUSE_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") == 0 || strcmp(str, "network") == 0) {
+        bo = CTF_BYTE_ORDER_BIG;
+    } else if (strcmp(str, "le") == 0) {
+        bo = CTF_BYTE_ORDER_LITTLE;
+    } else if (strcmp(str, "native") == 0) {
+        bo = CTF_BYTE_ORDER_DEFAULT;
+    } else {
+        _BT_CPPLOGE_APPEND_CAUSE_NODE(unary_expr,
+                                      "Unexpected \"byte_order\" attribute value: "
+                                      "expecting `be`, `le`, `network`, or `native`: value=\"{}\"",
+                                      str);
+        goto end;
+    }
+
+end:
+    return bo;
+}
+
+static enum ctf_byte_order get_real_byte_order(struct ctf_visitor_generate_ir *ctx,
+                                               struct ctf_node *uexpr)
+{
+    enum ctf_byte_order bo = byte_order_from_unary_expr(ctx, 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 ctf_visitor_generate_ir *ctx,
+                                    struct ctf_node *cls_specifier, GString *str)
+{
+    int ret = 0;
+
+    if (cls_specifier->type != NODE_TYPE_SPECIFIER) {
+        _BT_CPPLOGE_APPEND_CAUSE_NODE(cls_specifier, "Unexpected node type: node-type={}",
+                                      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_CPPLOGE_APPEND_CAUSE_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_CPPLOGE_APPEND_CAUSE_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_CPPLOGE_APPEND_CAUSE_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_CPPLOGE_APPEND_CAUSE_NODE(cls_specifier->u.field_class_specifier.node,
+                                      "Unexpected field class specifier type: {}",
+                                      cls_specifier->u.field_class_specifier.type);
+        ret = -EINVAL;
+        goto end;
+    }
+
+end:
+    return ret;
+}
+
+static int get_class_specifier_list_name(struct ctf_visitor_generate_ir *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 ctf_visitor_generate_ir *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 ctf_visitor_generate_ir *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_CPPLOGE_APPEND_CAUSE_NODE(
+                node_field_class_declarator, "Unexpected field class declarator type: type={}",
+                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_CPPLOGE_APPEND_CAUSE_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) {
+        if (node_field_class_declarator &&
+            !bt_list_empty(&node_field_class_declarator->u.field_class_declarator.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_CPPLOGE_APPEND_CAUSE_NODE(node_field_class_declarator,
+                                              "Cannot find class alias: name=\"{}\"",
+                                              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 = ctf_field_class_as_int(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;
+
+            *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_CPPLOGE_APPEND_CAUSE_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_CPPLOGE_APPEND_CAUSE_NODE(first, "Unexpected node type: node-type={}", 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 = &array_decl->base.base;
+            break;
+        }
+        case UNARY_STRING:
+        {
+            /* Lookup unsigned integer definition, create seq. */
+            struct ctf_field_class_sequence *seq_decl = NULL;
+            char *length_name = ctf_ast_concatenate_unary_strings(length);
+
+            if (!length_name) {
+                _BT_CPPLOGE_APPEND_CAUSE_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_CPPLOGE_APPEND_CAUSE_NODE(node_field_class_declarator,
+                                                  "Cannot find environment entry: "
+                                                  "name=\"{}\"",
+                                                  env_entry_name);
+                    ret = -EINVAL;
+                    goto error;
+                }
+
+                if (env_entry->type != CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT) {
+                    _BT_CPPLOGE_APPEND_CAUSE_NODE(node_field_class_declarator,
+                                                  "Wrong environment entry type "
+                                                  "(expecting integer): "
+                                                  "name=\"{}\"",
+                                                  env_entry_name);
+                    ret = -EINVAL;
+                    goto error;
+                }
+
+                if (env_entry->value.i < 0) {
+                    _BT_CPPLOGE_APPEND_CAUSE_NODE(node_field_class_declarator,
+                                                  "Invalid, negative array length: "
+                                                  "env-entry-name=\"{}\", "
+                                                  "value={}",
+                                                  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 = &array_decl->base.base;
+            } else {
+                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);
+                decl = &seq_decl->base.base;
+            }
+
+            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 ctf_visitor_generate_ir *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_CPPLOGE_APPEND_CAUSE_NODE(cls_specifier_list,
+                                          "Cannot visit field class declarator: ret={}", 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_CPPLOGE_APPEND_CAUSE_NODE(cls_specifier_list,
+                                          "Duplicate field in structure field class: "
+                                          "field-name=\"{}\"",
+                                          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 ctf_visitor_generate_ir *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_CPPLOGE_APPEND_CAUSE_NODE(cls_specifier_list,
+                                          "Cannot visit field class declarator: ret={}", 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_CPPLOGE_APPEND_CAUSE_NODE(cls_specifier_list,
+                                          "Duplicate field in variant field class: "
+                                          "field-name=\"{}\"",
+                                          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 ctf_visitor_generate_ir *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_CPPLOGE_APPEND_CAUSE_NODE(iter, "Cannot visit field class declarator: ret={}", 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 = ctf_field_class_as_variant(class_decl);
+
+            if (var_fc->tag_path.path->len == 0) {
+                _BT_CPPLOGE_APPEND_CAUSE_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_CPPLOGE_APPEND_CAUSE_NODE(iter, "Cannot register field class alias: name=\"{}\"",
+                                          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 ctf_visitor_generate_ir *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_CPPLOGE_APPEND_CAUSE_NODE(node, "Cannot visit field class declarator: ret={}", 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 = ctf_field_class_as_variant(class_decl);
+
+        if (var_fc->tag_path.path->len == 0) {
+            _BT_CPPLOGE_APPEND_CAUSE_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_CPPLOGE_APPEND_CAUSE_NODE(target, "Expecting empty identifier: id=\"{}\"",
+                                      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_CPPLOGE_APPEND_CAUSE_NODE(node, "Cannot register class alias: name=\"{}\"",
+                                      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 ctf_visitor_generate_ir *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_CPPLOGE_APPEND_CAUSE_NODE(
+                entry_node, "Cannot add field class found in structure field class: ret={}", 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_CPPLOGE_APPEND_CAUSE_NODE(
+                entry_node, "Cannot add field class alias found in structure field class: ret={}",
+                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_CPPLOGE_APPEND_CAUSE_NODE(entry_node, "Unexpected node type: node-type={}",
+                                      entry_node->type);
+        ret = -EINVAL;
+        goto end;
+    }
+
+end:
+    return ret;
+}
+
+static int visit_variant_decl_entry(struct ctf_visitor_generate_ir *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_CPPLOGE_APPEND_CAUSE_NODE(
+                entry_node, "Cannot add field class found in variant field class: ret={}", 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_CPPLOGE_APPEND_CAUSE_NODE(
+                entry_node, "Cannot add field class alias found in variant field class: ret={}",
+                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_CPPLOGE_APPEND_CAUSE_NODE(entry_node, "Unexpected node type: node-type={}",
+                                      entry_node->type);
+        ret = -EINVAL;
+        goto end;
+    }
+
+end:
+    return ret;
+}
+
+static int visit_struct_decl(struct ctf_visitor_generate_ir *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_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                         "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_CPPLOGE_APPEND_CAUSE_SPEC(
+                ctx->logger, "Cannot find structure field class: name=\"struct {}\"", 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_CPPLOGE_APPEND_CAUSE_SPEC(
+                    ctx->logger,
+                    "Structure field class already declared in local scope: "
+                    "name=\"struct {}\"",
+                    name);
+                ret = -EINVAL;
+                goto error;
+            }
+        }
+
+        if (!bt_list_empty(min_align)) {
+            ret = get_unary_unsigned(ctx, min_align, &min_align_value);
+            if (ret) {
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(
+                    ctx->logger,
+                    "Unexpected unary expression for structure field class's `align` attribute: "
+                    "ret={}",
+                    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_CPPLOGE_APPEND_CAUSE_NODE(entry_node,
+                                              "Cannot visit structure field class entry: "
+                                              "ret={}",
+                                              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_CPPLOGE_APPEND_CAUSE_SPEC(
+                    ctx->logger,
+                    "Cannot register structure field class in declaration scope: "
+                    "name=\"struct {}\", ret={}",
+                    name, ret);
+                goto error;
+            }
+        }
+    }
+
+    return 0;
+
+error:
+    ctf_field_class_destroy(&(*struct_decl)->base);
+    *struct_decl = NULL;
+    return ret;
+}
+
+static int visit_variant_decl(struct ctf_visitor_generate_ir *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_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                         "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_CPPLOGE_APPEND_CAUSE_SPEC(
+                ctx->logger, "Cannot find variant field class: name=\"variant {}\"", 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_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                             "Variant field class already declared in local scope: "
+                                             "name=\"variant {}\"",
+                                             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_CPPLOGE_APPEND_CAUSE_NODE(entry_node,
+                                              "Cannot visit variant field class entry: "
+                                              "ret={}",
+                                              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_CPPLOGE_APPEND_CAUSE_SPEC(
+                    ctx->logger,
+                    "Cannot register variant field class in declaration scope: "
+                    "name=\"variant {}\", ret={}",
+                    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.
+         */
+        g_string_assign(untagged_variant_decl->tag_ref, tag);
+        *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(&untagged_variant_decl->base);
+    untagged_variant_decl = NULL;
+    ctf_field_class_destroy(&(*variant_decl)->base);
+    *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 ctf_visitor_generate_ir *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;
+    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_CPPLOGE_APPEND_CAUSE_NODE(iter,
+                                          "Wrong expression for enumeration field class label: "
+                                          "node-type={}, label=\"{}\"",
+                                          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_CPPLOGE_APPEND_CAUSE_NODE(iter,
+                                          "Invalid enumeration field class entry: "
+                                          "expecting constant signed or unsigned integer: "
+                                          "node-type={}, label=\"{}\"",
+                                          iter->u.unary_expression.type, label);
+            ret = -EINVAL;
+            goto error;
+        }
+
+        if (nr_vals > 1) {
+            _BT_CPPLOGE_APPEND_CAUSE_NODE(
+                iter, "Invalid enumeration field class entry: label=\"{}\"", 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;
+    }
+
+    ctf_field_class_enum_map_range(enum_decl, label, start.value.u, end.value.u);
+    return 0;
+
+error:
+    return ret;
+}
+
+static int visit_enum_decl(struct ctf_visitor_generate_ir *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_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                         "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_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                         "Cannot find enumeration field class: "
+                                         "name=\"enum {}\"",
+                                         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_CPPLOGE_APPEND_CAUSE_SPEC(
+                    ctx->logger,
+                    "Enumeration field class already declared in local scope: "
+                    "name=\"enum {}\"",
+                    name);
+                ret = -EINVAL;
+                goto error;
+            }
+        }
+
+        if (!container_cls) {
+            integer_decl = ctf_field_class_as_int(
+                ctx_decl_scope_lookup_alias(ctx->current_scope, "int", -1, true));
+            if (!integer_decl) {
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(
+                    ctx->logger,
+                    "Cannot find implicit `int` field class alias for enumeration field class.");
+                ret = -EINVAL;
+                goto error;
+            }
+        } else {
+            ctf_field_class *decl;
+
+            ret = visit_field_class_declarator(ctx, container_cls, &qdummy_id, NULL, &decl, NULL);
+            if (ret) {
+                BT_ASSERT(!decl);
+                ret = -EINVAL;
+                goto error;
+            }
+
+            integer_decl = ctf_field_class_as_int(decl);
+        }
+
+        BT_ASSERT(integer_decl);
+
+        if (integer_decl->base.base.type != CTF_FIELD_CLASS_TYPE_INT) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(
+                ctx->logger,
+                "Container field class for enumeration field class is not an integer field class: "
+                "fc-type={}",
+                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(&(*enum_decl)->base, 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_CPPLOGE_APPEND_CAUSE_NODE(iter,
+                                              "Cannot visit enumeration field class entry: "
+                                              "ret={}",
+                                              ret);
+                goto error;
+            }
+        }
+
+        if (name) {
+            ret = ctx_decl_scope_register_enum(ctx->current_scope, name, *enum_decl);
+            if (ret) {
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(
+                    ctx->logger,
+                    "Cannot register enumeration field class in declaration scope: "
+                    "ret={}",
+                    ret);
+                goto error;
+            }
+        }
+    }
+
+    goto end;
+
+error:
+    ctf_field_class_destroy(&(*enum_decl)->base.base.base);
+    *enum_decl = NULL;
+
+end:
+    ctf_field_class_destroy(&integer_decl->base.base);
+    integer_decl = NULL;
+    return ret;
+}
+
+static int visit_field_class_specifier(struct ctf_visitor_generate_ir *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_CPPLOGE_APPEND_CAUSE_NODE(cls_specifier_list,
+                                      "Cannot get field class specifier list's name: ret={}", ret);
+        goto error;
+    }
+
+    *decl = ctx_decl_scope_lookup_alias(ctx->current_scope, str->str, -1, true);
+    if (!*decl) {
+        _BT_CPPLOGE_APPEND_CAUSE_NODE(cls_specifier_list,
+                                      "Cannot find field class alias: name=\"{}\"", 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 ctf_visitor_generate_ir *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_CPPLOGE_APPEND_CAUSE_NODE(left, "Unexpected unary expression type: type={}",
+                                          left->u.unary_expression.type);
+            ret = -EINVAL;
+            goto error;
+        }
+
+        if (strcmp(left->u.unary_expression.u.string, "signed") == 0) {
+            if (_IS_SET(&set, _INTEGER_SIGNED_SET)) {
+                _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(left, "signed", "integer field class");
+                ret = -EPERM;
+                goto error;
+            }
+
+            signedness = get_boolean(ctx, right);
+            if (signedness < 0) {
+                _BT_CPPLOGE_APPEND_CAUSE_NODE(
+                    right,
+                    "Invalid boolean value for integer field class's `signed` attribute: "
+                    "ret={}",
+                    ret);
+                ret = -EINVAL;
+                goto error;
+            }
+
+            _SET(&set, _INTEGER_SIGNED_SET);
+        } else if (strcmp(left->u.unary_expression.u.string, "byte_order") == 0) {
+            if (_IS_SET(&set, _INTEGER_BYTE_ORDER_SET)) {
+                _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(left, "byte_order", "integer field class");
+                ret = -EPERM;
+                goto error;
+            }
+
+            byte_order = get_real_byte_order(ctx, right);
+            if (byte_order == CTF_BYTE_ORDER_UNKNOWN) {
+                _BT_CPPLOGE_APPEND_CAUSE_NODE(
+                    right,
+                    "Invalid `byte_order` attribute in integer field class: "
+                    "ret={}",
+                    ret);
+                ret = -EINVAL;
+                goto error;
+            }
+
+            _SET(&set, _INTEGER_BYTE_ORDER_SET);
+        } else if (strcmp(left->u.unary_expression.u.string, "size") == 0) {
+            if (_IS_SET(&set, _INTEGER_SIZE_SET)) {
+                _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(left, "size", "integer field class");
+                ret = -EPERM;
+                goto error;
+            }
+
+            if (right->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) {
+                _BT_CPPLOGE_APPEND_CAUSE_NODE(right,
+                                              "Invalid `size` attribute in integer field class: "
+                                              "expecting unsigned constant integer: "
+                                              "node-type={}",
+                                              right->u.unary_expression.type);
+                ret = -EINVAL;
+                goto error;
+            }
+
+            size = right->u.unary_expression.u.unsigned_constant;
+            if (size == 0) {
+                _BT_CPPLOGE_APPEND_CAUSE_NODE(right,
+                                              "Invalid `size` attribute in integer field class: "
+                                              "expecting positive constant integer: "
+                                              "size={}",
+                                              size);
+                ret = -EINVAL;
+                goto error;
+            } else if (size > 64) {
+                _BT_CPPLOGE_APPEND_CAUSE_NODE(
+                    right,
+                    "Invalid `size` attribute in integer field class: "
+                    "integer fields over 64 bits are not supported as of this version: "
+                    "size={}",
+                    size);
+                ret = -EINVAL;
+                goto error;
+            }
+
+            _SET(&set, _INTEGER_SIZE_SET);
+        } else if (strcmp(left->u.unary_expression.u.string, "align") == 0) {
+            if (_IS_SET(&set, _INTEGER_ALIGN_SET)) {
+                _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(left, "align", "integer field class");
+                ret = -EPERM;
+                goto error;
+            }
+
+            if (right->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) {
+                _BT_CPPLOGE_APPEND_CAUSE_NODE(right,
+                                              "Invalid `align` attribute in integer field class: "
+                                              "expecting unsigned constant integer: "
+                                              "node-type={}",
+                                              right->u.unary_expression.type);
+                ret = -EINVAL;
+                goto error;
+            }
+
+            alignment = right->u.unary_expression.u.unsigned_constant;
+            if (!is_align_valid(alignment)) {
+                _BT_CPPLOGE_APPEND_CAUSE_NODE(right,
+                                              "Invalid `align` attribute in integer field class: "
+                                              "expecting power of two: "
+                                              "align={}",
+                                              alignment);
+                ret = -EINVAL;
+                goto error;
+            }
+
+            _SET(&set, _INTEGER_ALIGN_SET);
+        } else if (strcmp(left->u.unary_expression.u.string, "base") == 0) {
+            if (_IS_SET(&set, _INTEGER_BASE_SET)) {
+                _BT_CPPLOGE_APPEND_CAUSE_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_CPPLOGE_APPEND_CAUSE_NODE(
+                        right,
+                        "Invalid `base` attribute in integer field class: "
+                        "base={}",
+                        right->u.unary_expression.u.unsigned_constant);
+                    ret = -EINVAL;
+                    goto error;
+                }
+                break;
+            }
+            case UNARY_STRING:
+            {
+                char *s_right =
+                    ctf_ast_concatenate_unary_strings(&expression->u.ctf_expression.right);
+                if (!s_right) {
+                    _BT_CPPLOGE_APPEND_CAUSE_NODE(
+                        right,
+                        "Unexpected unary expression for integer field class's `base` attribute.");
+                    ret = -EINVAL;
+                    goto error;
+                }
+
+                if (strcmp(s_right, "decimal") == 0 || strcmp(s_right, "dec") == 0 ||
+                    strcmp(s_right, "d") == 0 || strcmp(s_right, "i") == 0 ||
+                    strcmp(s_right, "u") == 0) {
+                    base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL;
+                } else if (strcmp(s_right, "hexadecimal") == 0 || strcmp(s_right, "hex") == 0 ||
+                           strcmp(s_right, "x") == 0 || strcmp(s_right, "X") == 0 ||
+                           strcmp(s_right, "p") == 0) {
+                    base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL;
+                } else if (strcmp(s_right, "octal") == 0 || strcmp(s_right, "oct") == 0 ||
+                           strcmp(s_right, "o") == 0) {
+                    base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL;
+                } else if (strcmp(s_right, "binary") == 0 || strcmp(s_right, "b") == 0) {
+                    base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY;
+                } else {
+                    _BT_CPPLOGE_APPEND_CAUSE_NODE(
+                        right,
+                        "Unexpected unary expression for integer field class's `base` attribute: "
+                        "base=\"{}\"",
+                        s_right);
+                    g_free(s_right);
+                    ret = -EINVAL;
+                    goto error;
+                }
+
+                g_free(s_right);
+                break;
+            }
+            default:
+                _BT_CPPLOGE_APPEND_CAUSE_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") == 0) {
+            char *s_right;
+
+            if (_IS_SET(&set, _INTEGER_ENCODING_SET)) {
+                _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(left, "encoding", "integer field class");
+                ret = -EPERM;
+                goto error;
+            }
+
+            if (right->u.unary_expression.type != UNARY_STRING) {
+                _BT_CPPLOGE_APPEND_CAUSE_NODE(
+                    right, "Invalid `encoding` attribute in integer field class: "
+                           "expecting unary string.");
+                ret = -EINVAL;
+                goto error;
+            }
+
+            s_right = ctf_ast_concatenate_unary_strings(&expression->u.ctf_expression.right);
+            if (!s_right) {
+                _BT_CPPLOGE_APPEND_CAUSE_NODE(
+                    right,
+                    "Unexpected unary expression for integer field class's `encoding` attribute.");
+                ret = -EINVAL;
+                goto error;
+            }
+
+            if (strcmp(s_right, "UTF8") == 0 || strcmp(s_right, "utf8") == 0 ||
+                strcmp(s_right, "utf-8") == 0 || strcmp(s_right, "UTF-8") == 0 ||
+                strcmp(s_right, "ASCII") == 0 || strcmp(s_right, "ascii") == 0) {
+                encoding = CTF_ENCODING_UTF8;
+            } else if (strcmp(s_right, "none") == 0) {
+                encoding = CTF_ENCODING_NONE;
+            } else {
+                _BT_CPPLOGE_APPEND_CAUSE_NODE(
+                    right,
+                    "Invalid `encoding` attribute in integer field class: "
+                    "unknown encoding: encoding=\"{}\"",
+                    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") == 0) {
+            const char *clock_name;
+
+            if (_IS_SET(&set, _INTEGER_MAP_SET)) {
+                _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(left, "map", "integer field class");
+                ret = -EPERM;
+                goto error;
+            }
+
+            if (right->u.unary_expression.type != UNARY_STRING) {
+                _BT_CPPLOGE_APPEND_CAUSE_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 =
+                    ctf_ast_concatenate_unary_strings(&expression->u.ctf_expression.right);
+
+                if (!s_right) {
+                    _BT_CPPLOGE_APPEND_CAUSE_NODE(
+                        right,
+                        "Unexpected unary expression for integer field class's `map` attribute.");
+                    ret = -EINVAL;
+                    goto error;
+                }
+
+                _BT_CPPLOGE_NODE(right,
+                                 "Invalid `map` attribute in integer field class: "
+                                 "cannot find clock class at this point: name=\"{}\"",
+                                 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_CPPLOGE_APPEND_CAUSE_NODE(right,
+                                              "Invalid `map` attribute in integer field class: "
+                                              "cannot find clock class at this point: name=\"{}\"",
+                                              clock_name);
+                ret = -EINVAL;
+                goto error;
+            }
+
+            _SET(&set, _INTEGER_MAP_SET);
+        } else {
+            _BT_CPPLOGW_NODE(left,
+                             "Unknown attribute in integer field class: "
+                             "attr-name=\"{}\"",
+                             left->u.unary_expression.u.string);
+        }
+    }
+
+    if (!_IS_SET(&set, _INTEGER_SIZE_SET)) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                     "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(&(*integer_decl)->base.base);
+    *integer_decl = NULL;
+    return ret;
+}
+
+static int visit_floating_point_number_decl(struct ctf_visitor_generate_ir *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_CPPLOGE_APPEND_CAUSE_NODE(left, "Unexpected unary expression type: type={}",
+                                          left->u.unary_expression.type);
+            ret = -EINVAL;
+            goto error;
+        }
+
+        if (strcmp(left->u.unary_expression.u.string, "byte_order") == 0) {
+            if (_IS_SET(&set, _FLOAT_BYTE_ORDER_SET)) {
+                _BT_CPPLOGE_APPEND_CAUSE_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 == CTF_BYTE_ORDER_UNKNOWN) {
+                _BT_CPPLOGE_APPEND_CAUSE_NODE(
+                    right,
+                    "Invalid `byte_order` attribute in floating point number field class: "
+                    "ret={}",
+                    ret);
+                ret = -EINVAL;
+                goto error;
+            }
+
+            _SET(&set, _FLOAT_BYTE_ORDER_SET);
+        } else if (strcmp(left->u.unary_expression.u.string, "exp_dig") == 0) {
+            if (_IS_SET(&set, _FLOAT_EXP_DIG_SET)) {
+                _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(left, "exp_dig",
+                                                  "floating point number field class");
+                ret = -EPERM;
+                goto error;
+            }
+
+            if (right->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) {
+                _BT_CPPLOGE_APPEND_CAUSE_NODE(
+                    right,
+                    "Invalid `exp_dig` attribute in floating point number field class: "
+                    "expecting unsigned constant integer: "
+                    "node-type={}",
+                    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") == 0) {
+            if (_IS_SET(&set, _FLOAT_MANT_DIG_SET)) {
+                _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(left, "mant_dig",
+                                                  "floating point number field class");
+                ret = -EPERM;
+                goto error;
+            }
+
+            if (right->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) {
+                _BT_CPPLOGE_APPEND_CAUSE_NODE(
+                    right,
+                    "Invalid `mant_dig` attribute in floating point number field class: "
+                    "expecting unsigned constant integer: "
+                    "node-type={}",
+                    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") == 0) {
+            if (_IS_SET(&set, _FLOAT_ALIGN_SET)) {
+                _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(left, "align",
+                                                  "floating point number field class");
+                ret = -EPERM;
+                goto error;
+            }
+
+            if (right->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) {
+                _BT_CPPLOGE_APPEND_CAUSE_NODE(
+                    right,
+                    "Invalid `align` attribute in floating point number field class: "
+                    "expecting unsigned constant integer: "
+                    "node-type={}",
+                    right->u.unary_expression.type);
+                ret = -EINVAL;
+                goto error;
+            }
+
+            alignment = right->u.unary_expression.u.unsigned_constant;
+
+            if (!is_align_valid(alignment)) {
+                _BT_CPPLOGE_APPEND_CAUSE_NODE(
+                    right,
+                    "Invalid `align` attribute in floating point number field class: "
+                    "expecting power of two: "
+                    "align={}",
+                    alignment);
+                ret = -EINVAL;
+                goto error;
+            }
+
+            _SET(&set, _FLOAT_ALIGN_SET);
+        } else {
+            _BT_CPPLOGW_NODE(left,
+                             "Unknown attribute in floating point number field class: "
+                             "attr-name=\"{}\"",
+                             left->u.unary_expression.u.string);
+        }
+    }
+
+    if (!_IS_SET(&set, _FLOAT_MANT_DIG_SET)) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(
+            ctx->logger, "Missing `mant_dig` attribute in floating point number field class.");
+        ret = -EPERM;
+        goto error;
+    }
+
+    if (!_IS_SET(&set, _FLOAT_EXP_DIG_SET)) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(
+            ctx->logger, "Missing `exp_dig` attribute in floating point number field class.");
+        ret = -EPERM;
+        goto error;
+    }
+
+    if (mant_dig != 24 && mant_dig != 53) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger, "`mant_dig` attribute: expecting 24 or 53.");
+        ret = -EPERM;
+        goto error;
+    }
+
+    if (mant_dig == 24 && exp_dig != 8) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                     "`exp_dig` attribute: expecting 8 because `mant_dig` is 24.");
+        ret = -EPERM;
+        goto error;
+    }
+
+    if (mant_dig == 53 && exp_dig != 11) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(ctx->logger,
+                                     "`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(&(*float_decl)->base.base);
+    *float_decl = NULL;
+    return ret;
+}
+
+static int visit_string_decl(struct ctf_visitor_generate_ir *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_CPPLOGE_APPEND_CAUSE_NODE(left, "Unexpected unary expression type: type={}",
+                                          left->u.unary_expression.type);
+            ret = -EINVAL;
+            goto error;
+        }
+
+        if (strcmp(left->u.unary_expression.u.string, "encoding") == 0) {
+            char *s_right;
+
+            if (_IS_SET(&set, _STRING_ENCODING_SET)) {
+                _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(left, "encoding", "string field class");
+                ret = -EPERM;
+                goto error;
+            }
+
+            if (right->u.unary_expression.type != UNARY_STRING) {
+                _BT_CPPLOGE_APPEND_CAUSE_NODE(right,
+                                              "Invalid `encoding` attribute in string field class: "
+                                              "expecting unary string.");
+                ret = -EINVAL;
+                goto error;
+            }
+
+            s_right = ctf_ast_concatenate_unary_strings(&expression->u.ctf_expression.right);
+            if (!s_right) {
+                _BT_CPPLOGE_APPEND_CAUSE_NODE(
+                    right,
+                    "Unexpected unary expression for string field class's `encoding` attribute.");
+                ret = -EINVAL;
+                goto error;
+            }
+
+            if (strcmp(s_right, "UTF8") == 0 || strcmp(s_right, "utf8") == 0 ||
+                strcmp(s_right, "utf-8") == 0 || strcmp(s_right, "UTF-8") == 0 ||
+                strcmp(s_right, "ASCII") == 0 || strcmp(s_right, "ascii") == 0) {
+                encoding = CTF_ENCODING_UTF8;
+            } else if (strcmp(s_right, "none") == 0) {
+                encoding = CTF_ENCODING_NONE;
+            } else {
+                _BT_CPPLOGE_APPEND_CAUSE_NODE(right,
+                                              "Invalid `encoding` attribute in string field class: "
+                                              "unknown encoding: encoding=\"{}\"",
+                                              s_right);
+                g_free(s_right);
+                ret = -EINVAL;
+                goto error;
+            }
+
+            g_free(s_right);
+            _SET(&set, _STRING_ENCODING_SET);
+        } else {
+            _BT_CPPLOGW_NODE(left,
+                             "Unknown attribute in string field class: "
+                             "attr-name=\"{}\"",
+                             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(&(*string_decl)->base);
+    *string_decl = NULL;
+    return ret;
+}
+
+static int visit_field_class_specifier_list(struct ctf_visitor_generate_ir *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_CPPLOGE_APPEND_CAUSE_NODE(ts_list, "Unexpected node type: node-type={}", 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_CPPLOGE_APPEND_CAUSE_NODE(first, "Unexpected node type: node-type={}", first->type);
+        ret = -EINVAL;
+        goto error;
+    }
+
+    node = first->u.field_class_specifier.node;
+
+    switch (first->u.field_class_specifier.type) {
+    case TYPESPEC_INTEGER:
+    {
+        ctf_field_class_int *int_decl;
+
+        ret = visit_integer_decl(ctx, &node->u.integer.expressions, &int_decl);
+        if (ret) {
+            BT_ASSERT(!int_decl);
+            goto error;
+        }
+
+        *decl = &int_decl->base.base;
+        break;
+    }
+    case TYPESPEC_FLOATING_POINT:
+    {
+        ctf_field_class_float *float_decl;
+
+        ret =
+            visit_floating_point_number_decl(ctx, &node->u.floating_point.expressions, &float_decl);
+        if (ret) {
+            BT_ASSERT(!float_decl);
+            goto error;
+        }
+
+        *decl = &float_decl->base.base;
+        break;
+    }
+    case TYPESPEC_STRING:
+    {
+        ctf_field_class_string *string_decl;
+
+        ret = visit_string_decl(ctx, &node->u.string.expressions, &string_decl);
+        if (ret) {
+            BT_ASSERT(!string_decl);
+            goto error;
+        }
+
+        *decl = &string_decl->base;
+        break;
+    }
+    case TYPESPEC_STRUCT:
+    {
+        ctf_field_class_struct *struct_decl;
+
+        ret = visit_struct_decl(ctx, node->u._struct.name, &node->u._struct.declaration_list,
+                                node->u._struct.has_body, &node->u._struct.min_align, &struct_decl);
+        if (ret) {
+            BT_ASSERT(!struct_decl);
+            goto error;
+        }
+
+        *decl = &struct_decl->base;
+        break;
+    }
+    case TYPESPEC_VARIANT:
+    {
+        ctf_field_class_variant *variant_decl;
+
+        ret = visit_variant_decl(ctx, node->u.variant.name, node->u.variant.choice,
+                                 &node->u.variant.declaration_list, node->u.variant.has_body,
+                                 &variant_decl);
+        if (ret) {
+            BT_ASSERT(!variant_decl);
+            goto error;
+        }
+
+        *decl = &variant_decl->base;
+        break;
+    }
+    case TYPESPEC_ENUM:
+    {
+        ctf_field_class_enum *enum_decl;
+
+        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, &enum_decl);
+        if (ret) {
+            BT_ASSERT(!enum_decl);
+            goto error;
+        }
+
+        *decl = &enum_decl->base.base.base;
+        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_CPPLOGE_APPEND_CAUSE_NODE(first, "Cannot visit field class specifier: ret={}", ret);
+            BT_ASSERT(!*decl);
+            goto error;
+        }
+        break;
+    default:
+        _BT_CPPLOGE_APPEND_CAUSE_NODE(first, "Unexpected field class specifier type: node-type={}",
+                                      first->u.field_class_specifier.type);
+        ret = -EINVAL;
+        goto error;
+    }
+
+    BT_ASSERT(*decl);
+    return 0;
+
+error:
+    ctf_field_class_destroy(*decl);
+    *decl = NULL;
+    return ret;
+}
+
+static int visit_event_decl_entry(struct ctf_visitor_generate_ir *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_CPPLOGE_APPEND_CAUSE_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_CPPLOGE_APPEND_CAUSE_NODE(node,
+                                          "Cannot add field class alias found in event class.");
+            goto error;
+        }
+        break;
+    case NODE_CTF_EXPRESSION:
+    {
+        left = ctf_ast_concatenate_unary_strings(&node->u.ctf_expression.left);
+        if (!left) {
+            _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Cannot concatenate unary strings.");
+            ret = -EINVAL;
+            goto error;
+        }
+
+        if (strcmp(left, "name") == 0) {
+            /* This is already known at this stage */
+            if (_IS_SET(set, _EVENT_NAME_SET)) {
+                _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(node, "name", "event class");
+                ret = -EPERM;
+                goto error;
+            }
+
+            _SET(set, _EVENT_NAME_SET);
+        } else if (strcmp(left, "id") == 0) {
+            int64_t id = -1;
+
+            if (_IS_SET(set, _EVENT_ID_SET)) {
+                _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(node, "id", "event class");
+                ret = -EPERM;
+                goto error;
+            }
+
+            ret = get_unary_unsigned(ctx, &node->u.ctf_expression.right, (uint64_t *) &id);
+            /* Only read "id" if get_unary_unsigned() succeeded. */
+            if (ret || (!ret && id < 0)) {
+                _BT_CPPLOGE_APPEND_CAUSE_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") == 0) {
+            if (_IS_SET(set, _EVENT_STREAM_ID_SET)) {
+                _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(node, "stream_id", "event class");
+                ret = -EPERM;
+                goto error;
+            }
+
+            ret = get_unary_unsigned(ctx, &node->u.ctf_expression.right, stream_id);
+
+            /*
+             * Only read "stream_id" if get_unary_unsigned()
+             * succeeded.
+             */
+            if (ret) {
+                _BT_CPPLOGE_APPEND_CAUSE_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") == 0) {
+            if (_IS_SET(set, _EVENT_CONTEXT_SET)) {
+                _BT_CPPLOGE_APPEND_CAUSE_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_CPPLOGE_APPEND_CAUSE_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") == 0) {
+            if (_IS_SET(set, _EVENT_FIELDS_SET)) {
+                _BT_CPPLOGE_APPEND_CAUSE_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_CPPLOGE_APPEND_CAUSE_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") == 0) {
+            uint64_t loglevel_value;
+            bool is_log_level_known = true;
+            bt_event_class_log_level log_level;
+
+            if (_IS_SET(set, _EVENT_LOG_LEVEL_SET)) {
+                _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(node, "loglevel", "event class");
+                ret = -EPERM;
+                goto error;
+            }
+
+            ret = get_unary_unsigned(ctx, &node->u.ctf_expression.right, &loglevel_value);
+            if (ret) {
+                _BT_CPPLOGE_APPEND_CAUSE_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:
+                is_log_level_known = false;
+                _BT_CPPLOGW_NODE(
+                    node,
+                    "Not setting event class's log level because its value is unknown: "
+                    "log-level={}",
+                    loglevel_value);
+            }
+
+            if (is_log_level_known) {
+                ctf_event_class_set_log_level(event_class, log_level);
+            }
+
+            _SET(set, _EVENT_LOG_LEVEL_SET);
+        } else if (strcmp(left, "model.emf.uri") == 0) {
+            char *right;
+
+            if (_IS_SET(set, _EVENT_MODEL_EMF_URI_SET)) {
+                _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(node, "model.emf.uri", "event class");
+                ret = -EPERM;
+                goto error;
+            }
+
+            right = ctf_ast_concatenate_unary_strings(&node->u.ctf_expression.right);
+            if (!right) {
+                _BT_CPPLOGE_APPEND_CAUSE_NODE(
+                    node,
+                    "Unexpected unary expression for event class's `model.emf.uri` attribute.");
+                ret = -EINVAL;
+                goto error;
+            }
+
+            if (strlen(right) == 0) {
+                _BT_CPPLOGW_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_CPPLOGW_NODE(node,
+                             "Unknown attribute in event class: "
+                             "attr-name=\"{}\"",
+                             left);
+        }
+
+        g_free(left);
+        left = NULL;
+        break;
+    }
+    default:
+        ret = -EPERM;
+        goto error;
+    }
+
+    goto end;
+
+error:
+    g_free(left);
+
+end:
+    return ret;
+}
+
+static char *get_event_decl_name(struct ctf_visitor_generate_ir *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 = ctf_ast_concatenate_unary_strings(&iter->u.ctf_expression.left);
+        if (!left) {
+            _BT_CPPLOGE_APPEND_CAUSE_NODE(iter, "Cannot concatenate unary strings.");
+            goto error;
+        }
+
+        if (strcmp(left, "name") == 0) {
+            name = ctf_ast_concatenate_unary_strings(&iter->u.ctf_expression.right);
+            if (!name) {
+                _BT_CPPLOGE_APPEND_CAUSE_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 ctf_visitor_generate_ir *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_CPPLOGE_APPEND_CAUSE_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_CPPLOGE_APPEND_CAUSE_NODE(iter,
+                                          "Cannot visit event class's entry: "
+                                          "ret={}",
+                                          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 = (ctf_stream_class *) ctx->ctf_tc->stream_classes->pdata[0];
+            stream_id = stream_class->id;
+            break;
+        default:
+            _BT_CPPLOGE_APPEND_CAUSE_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_CPPLOGE_APPEND_CAUSE_NODE(node,
+                                          "Cannot find stream class at this point: "
+                                          "id={}",
+                                          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_CPPLOGE_APPEND_CAUSE_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_CPPLOGE_APPEND_CAUSE_NODE(node,
+                                      "Duplicate event class (same ID) in the same stream class: "
+                                      "id={}",
+                                      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);
+    }
+
+    g_free(event_name);
+
+    return ret;
+}
+
+static int auto_map_field_to_trace_clock_class(struct ctf_visitor_generate_ir *ctx,
+                                               struct ctf_field_class *fc)
+{
+    struct ctf_clock_class *clock_class_to_map_to = NULL;
+    uint64_t clock_class_count;
+
+    if (!fc) {
+        return 0;
+    }
+
+    if (fc->type != CTF_FIELD_CLASS_TYPE_INT && fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
+        return 0;
+    }
+
+    ctf_field_class_int *int_fc = ctf_field_class_as_int(fc);
+
+    if (int_fc->mapped_clock_class) {
+        /* Already mapped */
+        return 0;
+    }
+
+    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");
+        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 = (ctf_clock_class *) 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_CPPLOGE_APPEND_CAUSE_SPEC(
+            ctx->logger, "Timestamp field found with no mapped clock class, "
+                         "but there's more than one clock class in the trace at this point.");
+        return -1;
+    }
+
+    BT_ASSERT(clock_class_to_map_to);
+    int_fc->mapped_clock_class = clock_class_to_map_to;
+
+    return 0;
+}
+
+static int auto_map_fields_to_trace_clock_class(struct ctf_visitor_generate_ir *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 = (ctf_field_class_struct *) root_fc;
+    struct ctf_field_class_variant *var_fc = (ctf_field_class_variant *) 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);
+        } else {
+            bt_common_abort();
+        }
+
+        if (strcmp(named_fc->name->str, field_name) == 0) {
+            ret = auto_map_field_to_trace_clock_class(ctx, named_fc->fc);
+            if (ret) {
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(
+                    ctx->logger,
+                    "Cannot automatically map field to trace's clock class: "
+                    "field-name=\"{}\"",
+                    field_name);
+                goto end;
+            }
+        }
+
+        ret = auto_map_fields_to_trace_clock_class(ctx, named_fc->fc, field_name);
+        if (ret) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(
+                ctx->logger,
+                "Cannot automatically map structure or variant field class's fields to trace's clock class: "
+                "field-name=\"{}\", root-field-name=\"{}\"",
+                field_name, named_fc->name->str);
+            goto end;
+        }
+    }
+
+end:
+    return ret;
+}
+
+static int visit_stream_decl_entry(struct ctf_visitor_generate_ir *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_CPPLOGE_APPEND_CAUSE_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_CPPLOGE_APPEND_CAUSE_NODE(node,
+                                          "Cannot add field class alias found in stream class.");
+            goto error;
+        }
+        break;
+    case NODE_CTF_EXPRESSION:
+    {
+        left = ctf_ast_concatenate_unary_strings(&node->u.ctf_expression.left);
+        if (!left) {
+            _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Cannot concatenate unary strings.");
+            ret = -EINVAL;
+            goto error;
+        }
+
+        if (strcmp(left, "id") == 0) {
+            int64_t id;
+
+            if (_IS_SET(set, _STREAM_ID_SET)) {
+                _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(node, "id", "stream declaration");
+                ret = -EPERM;
+                goto error;
+            }
+
+            ret = get_unary_unsigned(ctx, &node->u.ctf_expression.right, (uint64_t *) &id);
+
+            /* Only read "id" if get_unary_unsigned() succeeded. */
+            if (ret || (!ret && id < 0)) {
+                _BT_CPPLOGE_APPEND_CAUSE_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_CPPLOGE_APPEND_CAUSE_NODE(node, "Duplicate stream class (same ID): id={}", id);
+                ret = -EEXIST;
+                goto error;
+            }
+
+            stream_class->id = id;
+            _SET(set, _STREAM_ID_SET);
+        } else if (strcmp(left, "event.header") == 0) {
+            if (_IS_SET(set, _STREAM_EVENT_HEADER_SET)) {
+                _BT_CPPLOGE_APPEND_CAUSE_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_CPPLOGE_APPEND_CAUSE_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_CPPLOGE_APPEND_CAUSE_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") == 0) {
+            if (_IS_SET(set, _STREAM_EVENT_CONTEXT_SET)) {
+                _BT_CPPLOGE_APPEND_CAUSE_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_CPPLOGE_APPEND_CAUSE_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") == 0) {
+            if (_IS_SET(set, _STREAM_PACKET_CONTEXT_SET)) {
+                _BT_CPPLOGE_APPEND_CAUSE_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_CPPLOGE_APPEND_CAUSE_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_CPPLOGE_APPEND_CAUSE_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_CPPLOGE_APPEND_CAUSE_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_CPPLOGW_NODE(node,
+                             "Unknown attribute in stream class: "
+                             "attr-name=\"{}\"",
+                             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 ctf_visitor_generate_ir *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_CPPLOGE_APPEND_CAUSE_NODE(iter,
+                                          "Cannot visit stream class's entry: "
+                                          "ret={}",
+                                          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_CPPLOGE_APPEND_CAUSE_NODE(node, "Stream class has a `id` attribute, "
+                                                "but trace has no packet header field class.");
+            ret = -EINVAL;
+            goto error;
+        }
+
+        named_fc = ctf_field_class_struct_borrow_member_by_name(
+            ctf_field_class_as_struct(ctx->ctf_tc->packet_header_fc), "stream_id");
+        if (!named_fc) {
+            _BT_CPPLOGE_APPEND_CAUSE_NODE(
+                node, "Stream class has a `id` attribute, "
+                      "but trace's packet header field class has no `stream_id` field.");
+            ret = -EINVAL;
+            goto error;
+        }
+
+        if (named_fc->fc->type != CTF_FIELD_CLASS_TYPE_INT &&
+            named_fc->fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
+            _BT_CPPLOGE_APPEND_CAUSE_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.");
+            ret = -EINVAL;
+            goto error;
+        }
+    } else {
+        /* Allow only _one_ ID-less stream */
+        if (ctx->ctf_tc->stream_classes->len != 0) {
+            _BT_CPPLOGE_APPEND_CAUSE_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_CPPLOGE_APPEND_CAUSE_NODE(node, "Duplicate stream class (same ID): id={}",
+                                      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 ctf_visitor_generate_ir *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_CPPLOGE_APPEND_CAUSE_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_CPPLOGE_APPEND_CAUSE_NODE(
+                node, "Cannot add field class alias found in trace (`trace` block).");
+            goto error;
+        }
+        break;
+    case NODE_CTF_EXPRESSION:
+    {
+        left = ctf_ast_concatenate_unary_strings(&node->u.ctf_expression.left);
+        if (!left) {
+            _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Cannot concatenate unary strings.");
+            ret = -EINVAL;
+            goto error;
+        }
+
+        if (strcmp(left, "major") == 0) {
+            if (_IS_SET(set, _TRACE_MAJOR_SET)) {
+                _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(node, "major", "trace");
+                ret = -EPERM;
+                goto error;
+            }
+
+            ret = get_unary_unsigned(ctx, &node->u.ctf_expression.right, &val);
+            if (ret) {
+                _BT_CPPLOGE_APPEND_CAUSE_NODE(
+                    node, "Unexpected unary expression for trace's `major` attribute.");
+                ret = -EINVAL;
+                goto error;
+            }
+
+            if (val != 1) {
+                _BT_CPPLOGE_APPEND_CAUSE_NODE(node,
+                                              "Invalid trace's `minor` attribute: expecting 1.");
+                ret = -EINVAL;
+                goto error;
+            }
+
+            ctx->ctf_tc->major = val;
+            _SET(set, _TRACE_MAJOR_SET);
+        } else if (strcmp(left, "minor") == 0) {
+            if (_IS_SET(set, _TRACE_MINOR_SET)) {
+                _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(node, "minor", "trace");
+                ret = -EPERM;
+                goto error;
+            }
+
+            ret = get_unary_unsigned(ctx, &node->u.ctf_expression.right, &val);
+            if (ret) {
+                _BT_CPPLOGE_APPEND_CAUSE_NODE(
+                    node, "Unexpected unary expression for trace's `minor` attribute.");
+                ret = -EINVAL;
+                goto error;
+            }
+
+            if (val != 8) {
+                _BT_CPPLOGE_APPEND_CAUSE_NODE(node,
+                                              "Invalid trace's `minor` attribute: expecting 8.");
+                ret = -EINVAL;
+                goto error;
+            }
+
+            ctx->ctf_tc->minor = val;
+            _SET(set, _TRACE_MINOR_SET);
+        } else if (strcmp(left, "uuid") == 0) {
+            if (_IS_SET(set, _TRACE_UUID_SET)) {
+                _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(node, "uuid", "trace");
+                ret = -EPERM;
+                goto error;
+            }
+
+            ret = get_unary_uuid(ctx, &node->u.ctf_expression.right, ctx->ctf_tc->uuid);
+            if (ret) {
+                _BT_CPPLOGE_APPEND_CAUSE_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") == 0) {
+            /* Default byte order is already known at this stage */
+            if (_IS_SET(set, _TRACE_BYTE_ORDER_SET)) {
+                _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(node, "byte_order", "trace");
+                ret = -EPERM;
+                goto error;
+            }
+
+            BT_ASSERT(ctx->ctf_tc->default_byte_order != CTF_BYTE_ORDER_UNKNOWN);
+            _SET(set, _TRACE_BYTE_ORDER_SET);
+        } else if (strcmp(left, "packet.header") == 0) {
+            if (_IS_SET(set, _TRACE_PACKET_HEADER_SET)) {
+                _BT_CPPLOGE_APPEND_CAUSE_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_CPPLOGE_APPEND_CAUSE_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_CPPLOGW_NODE(node,
+                             "Unknown attribute in stream class: "
+                             "attr-name=\"{}\"",
+                             left);
+        }
+
+        g_free(left);
+        left = NULL;
+        break;
+    }
+    default:
+        _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Unknown expression in trace.");
+        ret = -EINVAL;
+        goto error;
+    }
+
+    return 0;
+
+error:
+    g_free(left);
+    return ret;
+}
+
+static int visit_trace_decl(struct ctf_visitor_generate_ir *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_CPPLOGE_APPEND_CAUSE_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_CPPLOGE_APPEND_CAUSE_NODE(iter,
+                                          "Cannot visit trace's entry (`trace` block): "
+                                          "ret={}",
+                                          ret);
+            ctx_pop_scope(ctx);
+            goto error;
+        }
+    }
+
+    ctx_pop_scope(ctx);
+
+    if (!_IS_SET(&set, _TRACE_MAJOR_SET)) {
+        _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Missing `major` attribute in trace (`trace` block).");
+        ret = -EPERM;
+        goto error;
+    }
+
+    if (!_IS_SET(&set, _TRACE_MINOR_SET)) {
+        _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Missing `minor` attribute in trace (`trace` block).");
+        ret = -EPERM;
+        goto error;
+    }
+
+    if (!_IS_SET(&set, _TRACE_BYTE_ORDER_SET)) {
+        _BT_CPPLOGE_APPEND_CAUSE_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 ctf_visitor_generate_ir *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_CPPLOGE_APPEND_CAUSE_NODE(entry_node,
+                                          "Wrong expression in environment entry: "
+                                          "node-type={}",
+                                          entry_node->type);
+            ret = -EPERM;
+            goto error;
+        }
+
+        left = ctf_ast_concatenate_unary_strings(&entry_node->u.ctf_expression.left);
+        if (!left) {
+            _BT_CPPLOGE_APPEND_CAUSE_NODE(entry_node, "Cannot get environment entry's name.");
+            ret = -EINVAL;
+            goto error;
+        }
+
+        if (is_unary_string(right_head)) {
+            char *right = ctf_ast_concatenate_unary_strings(right_head);
+
+            if (!right) {
+                _BT_CPPLOGE_APPEND_CAUSE_NODE(
+                    entry_node,
+                    "Unexpected unary expression for environment entry's value: "
+                    "name=\"{}\"",
+                    left);
+                ret = -EINVAL;
+                goto error;
+            }
+
+            if (strcmp(left, "tracer_name") == 0) {
+                if (strncmp(right, "lttng", 5) == 0) {
+                    BT_CPPLOGI_SPEC(ctx->logger,
+                                    "Detected LTTng trace from `{}` environment value: "
+                                    "tracer-name=\"{}\"",
+                                    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(ctx, right_head, (uint64_t *) &v);
+            } else {
+                ret = get_unary_signed(right_head, &v);
+            }
+            if (ret) {
+                _BT_CPPLOGE_APPEND_CAUSE_NODE(
+                    entry_node,
+                    "Unexpected unary expression for environment entry's value: "
+                    "name=\"{}\"",
+                    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_CPPLOGW_NODE(entry_node,
+                             "Environment entry has unknown type: "
+                             "name=\"{}\"",
+                             left);
+        }
+
+        g_free(left);
+        left = NULL;
+    }
+
+end:
+    return 0;
+
+error:
+    g_free(left);
+    return ret;
+}
+
+static int set_trace_byte_order(struct ctf_visitor_generate_ir *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 = ctf_ast_concatenate_unary_strings(&node->u.ctf_expression.left);
+            if (!left) {
+                _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Cannot concatenate unary strings.");
+                ret = -EINVAL;
+                goto error;
+            }
+
+            if (strcmp(left, "byte_order") == 0) {
+                enum ctf_byte_order bo;
+
+                if (_IS_SET(&set, _TRACE_BYTE_ORDER_SET)) {
+                    _BT_CPPLOGE_APPEND_CAUSE_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(ctx, right_node);
+                if (bo == CTF_BYTE_ORDER_UNKNOWN) {
+                    _BT_CPPLOGE_APPEND_CAUSE_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_CPPLOGE_APPEND_CAUSE_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_CPPLOGE_APPEND_CAUSE_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 ctf_visitor_generate_ir *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_CPPLOGE_APPEND_CAUSE_NODE(entry_node, "Unexpected node type: node-type={}",
+                                      entry_node->type);
+        ret = -EPERM;
+        goto error;
+    }
+
+    left = ctf_ast_concatenate_unary_strings(&entry_node->u.ctf_expression.left);
+    if (!left) {
+        _BT_CPPLOGE_APPEND_CAUSE_NODE(entry_node, "Cannot concatenate unary strings.");
+        ret = -EINVAL;
+        goto error;
+    }
+
+    if (strcmp(left, "name") == 0) {
+        char *right;
+
+        if (_IS_SET(set, _CLOCK_NAME_SET)) {
+            _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "name", "clock class");
+            ret = -EPERM;
+            goto error;
+        }
+
+        right = ctf_ast_concatenate_unary_strings(&entry_node->u.ctf_expression.right);
+        if (!right) {
+            _BT_CPPLOGE_APPEND_CAUSE_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") == 0) {
+        bt_uuid_t uuid;
+
+        if (_IS_SET(set, _CLOCK_UUID_SET)) {
+            _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "uuid", "clock class");
+            ret = -EPERM;
+            goto error;
+        }
+
+        ret = get_unary_uuid(ctx, &entry_node->u.ctf_expression.right, uuid);
+        if (ret) {
+            _BT_CPPLOGE_APPEND_CAUSE_NODE(entry_node, "Invalid clock class's `uuid` attribute.");
+            goto error;
+        }
+
+        clock->has_uuid = true;
+        bt_uuid_copy(clock->uuid, uuid);
+        _SET(set, _CLOCK_UUID_SET);
+    } else if (strcmp(left, "description") == 0) {
+        char *right;
+
+        if (_IS_SET(set, _CLOCK_DESCRIPTION_SET)) {
+            _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "description", "clock class");
+            ret = -EPERM;
+            goto error;
+        }
+
+        right = ctf_ast_concatenate_unary_strings(&entry_node->u.ctf_expression.right);
+        if (!right) {
+            _BT_CPPLOGE_APPEND_CAUSE_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") == 0) {
+        uint64_t freq = UINT64_C(-1);
+
+        if (_IS_SET(set, _CLOCK_FREQ_SET)) {
+            _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "freq", "clock class");
+            ret = -EPERM;
+            goto error;
+        }
+
+        ret = get_unary_unsigned(ctx, &entry_node->u.ctf_expression.right, &freq);
+        if (ret) {
+            _BT_CPPLOGE_APPEND_CAUSE_NODE(
+                entry_node, "Unexpected unary expression for clock class's `freq` attribute.");
+            ret = -EINVAL;
+            goto error;
+        }
+
+        if (freq == UINT64_C(-1) || freq == 0) {
+            _BT_CPPLOGE_APPEND_CAUSE_NODE(entry_node, "Invalid clock class frequency: freq={}",
+                                          freq);
+            ret = -EINVAL;
+            goto error;
+        }
+
+        clock->frequency = freq;
+        _SET(set, _CLOCK_FREQ_SET);
+    } else if (strcmp(left, "precision") == 0) {
+        uint64_t precision;
+
+        if (_IS_SET(set, _CLOCK_PRECISION_SET)) {
+            _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "precision", "clock class");
+            ret = -EPERM;
+            goto error;
+        }
+
+        ret = get_unary_unsigned(ctx, &entry_node->u.ctf_expression.right, &precision);
+        if (ret) {
+            _BT_CPPLOGE_APPEND_CAUSE_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") == 0) {
+        if (_IS_SET(set, _CLOCK_OFFSET_S_SET)) {
+            _BT_CPPLOGE_APPEND_CAUSE_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_CPPLOGE_APPEND_CAUSE_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") == 0) {
+        if (_IS_SET(set, _CLOCK_OFFSET_SET)) {
+            _BT_CPPLOGE_APPEND_CAUSE_DUP_ATTR(entry_node, "offset", "clock class");
+            ret = -EPERM;
+            goto error;
+        }
+
+        ret = get_unary_unsigned(ctx, &entry_node->u.ctf_expression.right, offset_cycles);
+        if (ret) {
+            _BT_CPPLOGE_APPEND_CAUSE_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") == 0) {
+        struct ctf_node *right;
+
+        if (_IS_SET(set, _CLOCK_ABSOLUTE_SET)) {
+            _BT_CPPLOGE_APPEND_CAUSE_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(ctx, right);
+        if (ret < 0) {
+            _BT_CPPLOGE_APPEND_CAUSE_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_CPPLOGW_NODE(entry_node, "Unknown attribute in clock class: attr-name=\"{}\"", 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_is_absolute(struct ctf_visitor_generate_ir *ctx,
+                                          struct ctf_clock_class *clock)
+{
+    if (ctx->decoder_config.clkClsCfg.forceOriginIsUnixEpoch) {
+        clock->is_absolute = true;
+    }
+
+    return;
+}
+
+static void apply_clock_class_offset(struct ctf_visitor_generate_ir *ctx,
+                                     struct ctf_clock_class *clock)
+{
+    uint64_t freq;
+    int64_t offset_s_to_apply = ctx->decoder_config.clkClsCfg.offsetSec;
+    uint64_t offset_ns_to_apply;
+    int64_t cur_offset_s;
+    uint64_t cur_offset_cycles;
+
+    if (ctx->decoder_config.clkClsCfg.offsetSec == 0 &&
+        ctx->decoder_config.clkClsCfg.offsetNanoSec == 0) {
+        goto end;
+    }
+
+    /* Transfer nanoseconds to seconds as much as possible */
+    if (ctx->decoder_config.clkClsCfg.offsetNanoSec < 0) {
+        const int64_t abs_ns = -ctx->decoder_config.clkClsCfg.offsetNanoSec;
+        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.clkClsCfg.offsetNanoSec - (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.clkClsCfg.offsetNanoSec / INT64_C(1000000000);
+        const int64_t offset_ns =
+            ctx->decoder_config.clkClsCfg.offsetNanoSec - (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 ctf_visitor_generate_ir *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_CPPLOGE_APPEND_CAUSE_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_CPPLOGE_APPEND_CAUSE_NODE(entry_node, "Cannot visit clock class's entry: ret={}",
+                                          ret);
+            goto end;
+        }
+    }
+
+    if (!_IS_SET(&set, _CLOCK_NAME_SET)) {
+        _BT_CPPLOGE_APPEND_CAUSE_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);
+    apply_clock_class_is_absolute(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 ctf_visitor_generate_ir *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_CPPLOGE_APPEND_CAUSE_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_CPPLOGE_APPEND_CAUSE_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_CPPLOGE_APPEND_CAUSE_NODE(root_decl_node,
+                                          "Cannot visit root scope's field class: "
+                                          "ret={}",
+                                          ret);
+            BT_ASSERT(!decl);
+            goto end;
+        }
+
+        ctf_field_class_destroy(decl);
+        decl = NULL;
+        break;
+    }
+    default:
+        _BT_CPPLOGE_APPEND_CAUSE_NODE(root_decl_node, "Unexpected node type: node-type={}",
+                                      root_decl_node->type);
+        ret = -EPERM;
+        goto end;
+    }
+
+end:
+    return ret;
+}
+
+ctf_visitor_generate_ir::UP
+ctf_visitor_generate_ir_create(const struct ctf_metadata_decoder_config *decoder_config)
+{
+    bt2c::Logger logger {decoder_config->logger, "PLUGIN/CTF/META/IR-VISITOR"};
+
+    /* Create visitor's context */
+    ctf_visitor_generate_ir::UP ctx = ctx_create(decoder_config, logger);
+
+    if (!ctx) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "Cannot create visitor's context.");
+        goto error;
+    }
+
+    goto end;
+
+error:
+    ctx.reset();
+
+end:
+    return ctx;
+}
+
+bt2::TraceClass::Shared
+ctf_visitor_generate_ir_get_ir_trace_class(struct ctf_visitor_generate_ir *ctx)
+{
+    BT_ASSERT_DBG(ctx);
+
+    return ctx->trace_class;
+}
+
+struct ctf_trace_class *
+ctf_visitor_generate_ir_borrow_ctf_trace_class(struct ctf_visitor_generate_ir *ctx)
+{
+    BT_ASSERT_DBG(ctx);
+    BT_ASSERT_DBG(ctx->ctf_tc);
+    return ctx->ctf_tc;
+}
+
+int ctf_visitor_generate_ir_visit_node(struct ctf_visitor_generate_ir *ctx, struct ctf_node *node)
+{
+    int ret = 0;
+
+    BT_CPPLOGI_SPEC(ctx->logger, "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 == CTF_BYTE_ORDER_UNKNOWN) {
+            bt_list_for_each_entry (iter, &node->u.root.trace, siblings) {
+                if (got_trace_decl) {
+                    _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Duplicate trace (`trace` block).");
+                    ret = -1;
+                    goto end;
+                }
+
+                ret = set_trace_byte_order(ctx, iter);
+                if (ret) {
+                    _BT_CPPLOGE_APPEND_CAUSE_NODE(node,
+                                                  "Cannot set trace's native byte order: "
+                                                  "ret={}",
+                                                  ret);
+                    goto end;
+                }
+
+                got_trace_decl = true;
+            }
+
+            if (!got_trace_decl) {
+                BT_CPPLOGD_SPEC(ctx->logger, "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);
+
+        /* Environment */
+        bt_list_for_each_entry (iter, &node->u.root.env, siblings) {
+            ret = visit_env(ctx, iter);
+            if (ret) {
+                _BT_CPPLOGE_APPEND_CAUSE_NODE(
+                    iter,
+                    "Cannot visit trace's environment (`env` block) entry: "
+                    "ret={}",
+                    ret);
+                goto end;
+            }
+        }
+
+        BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope);
+
+        /*
+         * Visit clock blocks.
+         */
+        bt_list_for_each_entry (iter, &node->u.root.clock, siblings) {
+            ret = visit_clock_decl(ctx, iter);
+            if (ret) {
+                _BT_CPPLOGE_APPEND_CAUSE_NODE(iter, "Cannot visit clock class: ret={}", ret);
+                goto end;
+            }
+        }
+
+        BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope);
+
+        /*
+         * 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_CPPLOGE_APPEND_CAUSE_NODE(iter, "Cannot visit root entry: ret={}", ret);
+                goto end;
+            }
+        }
+
+        BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope);
+
+        /* Callsite blocks are not supported */
+        bt_list_for_each_entry (iter, &node->u.root.callsite, siblings) {
+            _BT_CPPLOGW_NODE(iter, "\"callsite\" blocks are not supported as of this version.");
+        }
+
+        BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope);
+
+        /* Trace */
+        bt_list_for_each_entry (iter, &node->u.root.trace, siblings) {
+            ret = visit_trace_decl(ctx, iter);
+            if (ret) {
+                _BT_CPPLOGE_APPEND_CAUSE_NODE(iter,
+                                              "Cannot visit trace (`trace` block): "
+                                              "ret={}",
+                                              ret);
+                goto end;
+            }
+        }
+
+        BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope);
+
+        /* Streams */
+        bt_list_for_each_entry (iter, &node->u.root.stream, siblings) {
+            ret = visit_stream_decl(ctx, iter);
+            if (ret) {
+                _BT_CPPLOGE_APPEND_CAUSE_NODE(iter, "Cannot visit stream class: ret={}", ret);
+                goto end;
+            }
+        }
+
+        BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope);
+
+        /* Events */
+        bt_list_for_each_entry (iter, &node->u.root.event, siblings) {
+            ret = visit_event_decl(ctx, iter);
+            if (ret) {
+                _BT_CPPLOGE_APPEND_CAUSE_NODE(iter, "Cannot visit event class: ret={}", ret);
+                goto end;
+            }
+        }
+
+        BT_ASSERT(ctx->current_scope && !ctx->current_scope->parent_scope);
+        break;
+    }
+    default:
+        _BT_CPPLOGE_APPEND_CAUSE_NODE(node, "Unexpected node type: node-type={}", node->type);
+        ret = -EINVAL;
+        goto end;
+    }
+
+    /* Update default clock classes */
+    ret = ctf_trace_class_update_default_clock_classes(ctx->ctf_tc, ctx->logger);
+    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;
+    }
+
+    /* Update structure/array/sequence alignments */
+    ret = ctf_trace_class_update_alignments(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, ctx->logger);
+    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, ctx->logger);
+    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, ctx->logger);
+
+    if (ctx->trace_class) {
+        /* Copy new CTF metadata -> new IR metadata */
+        ret = ctf_trace_class_translate(ctx->decoder_config.self_comp,
+                                        ctx->trace_class->libObjPtr(), ctx->ctf_tc);
+        if (ret) {
+            ret = -EINVAL;
+            goto end;
+        }
+    }
+
+end:
+    return ret;
+}
diff --git a/src/plugins/ctf/common/src/metadata/tsdl/visitor-parent-links.cpp b/src/plugins/ctf/common/src/metadata/tsdl/visitor-parent-links.cpp
new file mode 100644 (file)
index 0000000..90faaee
--- /dev/null
@@ -0,0 +1,442 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2010 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Common Trace Format Metadata Parent Link Creator.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+
+#include "logging.hpp"
+
+#include "common/list.h"
+
+#include "ast.hpp"
+
+static int ctf_visitor_unary_expression(int depth, struct ctf_node *node,
+                                        const bt2c::Logger& logger)
+{
+    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_CPPLOGE_APPEND_CAUSE_LINENO(logger, node->lineno,
+                                        "Unknown expression link type: type={}\n",
+                                        (int) 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, logger);
+        if (ret)
+            return ret;
+        break;
+
+    case UNARY_UNKNOWN:
+    default:
+        _BT_CPPLOGE_APPEND_CAUSE_LINENO(logger, node->lineno,
+                                        "Unknown expression link type: type={}\n",
+                                        (int) node->u.unary_expression.link);
+        return -EINVAL;
+    }
+    return 0;
+}
+
+static int ctf_visitor_type_specifier(int depth, struct ctf_node *node, const bt2c::Logger& logger)
+{
+    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, logger);
+        if (ret)
+            return ret;
+        break;
+
+    case TYPESPEC_UNKNOWN:
+    default:
+        _BT_CPPLOGE_APPEND_CAUSE_LINENO(logger, node->lineno, "Unknown type specifier: type={}\n",
+                                        (int) node->u.field_class_specifier.type);
+        return -EINVAL;
+    }
+    return 0;
+}
+
+static int ctf_visitor_field_class_declarator(int depth, struct ctf_node *node,
+                                              const bt2c::Logger& logger)
+{
+    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, logger);
+        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, logger);
+            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, logger);
+                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,
+                                           logger);
+            if (ret)
+                return ret;
+        }
+        break;
+    case TYPEDEC_UNKNOWN:
+    default:
+        _BT_CPPLOGE_APPEND_CAUSE_LINENO(logger, node->lineno, "Unknown type declarator: type={}\n",
+                                        (int) node->u.field_class_declarator.type);
+        return -EINVAL;
+    }
+    depth--;
+    return 0;
+}
+
+int ctf_visitor_parent_links(int depth, struct ctf_node *node, const bt2c::Logger& parentLogger)
+{
+    int ret = 0;
+    struct ctf_node *iter;
+
+    if (node->visited)
+        return 0;
+
+    bt2c::Logger logger {parentLogger, "PLUGIN/CTF/META/PARENT-LINKS-VISITOR"};
+
+    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, logger);
+            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, logger);
+            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, logger);
+            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, logger);
+            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, logger);
+            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, logger);
+            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, logger);
+            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, logger);
+            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, logger);
+            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, logger);
+            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, logger);
+            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, logger);
+            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, logger);
+            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, logger);
+            if (ret)
+                return ret;
+        }
+        depth--;
+        break;
+    case NODE_UNARY_EXPRESSION:
+        return ctf_visitor_unary_expression(depth, node, logger);
+
+    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, logger);
+        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, logger);
+            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, logger);
+        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, logger);
+            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, logger);
+        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, logger);
+            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, logger);
+        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, logger);
+        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, logger);
+            if (ret)
+                return ret;
+        }
+        break;
+
+    case NODE_TYPE_SPECIFIER:
+        ret = ctf_visitor_type_specifier(depth, node, logger);
+        if (ret)
+            return ret;
+        break;
+    case NODE_POINTER:
+        break;
+    case NODE_TYPE_DECLARATOR:
+        ret = ctf_visitor_field_class_declarator(depth, node, logger);
+        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, logger);
+            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, logger);
+            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, logger);
+            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, logger);
+            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, logger);
+            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, logger);
+            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, logger);
+        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, logger);
+            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, logger);
+            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, logger);
+            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, logger);
+            if (ret)
+                return ret;
+        }
+        break;
+
+    case NODE_UNKNOWN:
+    default:
+        _BT_CPPLOGE_APPEND_CAUSE_LINENO(logger, node->lineno, "Unknown node type: type={}\n",
+                                        (int) node->type);
+        return -EINVAL;
+    }
+    return ret;
+}
diff --git a/src/plugins/ctf/common/src/metadata/tsdl/visitor-semantic-validator.cpp b/src/plugins/ctf/common/src/metadata/tsdl/visitor-semantic-validator.cpp
new file mode 100644 (file)
index 0000000..59cec93
--- /dev/null
@@ -0,0 +1,999 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2010 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Common Trace Format Metadata Semantic Validator.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+
+#include "logging.hpp"
+
+#include "common/list.h"
+
+#include "ast.hpp"
+
+#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,
+                                       const bt2c::Logger& logger);
+
+static int ctf_visitor_unary_expression(int, struct ctf_node *node, const bt2c::Logger& logger)
+{
+    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_CPPLOGE_APPEND_CAUSE_LINENO(
+                        logger, 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_CPPLOGE_APPEND_CAUSE_LINENO(
+                logger, 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_CPPLOGE_APPEND_CAUSE_LINENO(
+                logger, 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_CPPLOGE_APPEND_CAUSE_LINENO(logger, 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_CPPLOGE_APPEND_CAUSE_LINENO(
+                logger, 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_CPPLOGE_APPEND_CAUSE_LINENO(
+                logger, 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_CPPLOGE_APPEND_CAUSE_LINENO(
+                logger, 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_CPPLOGE_APPEND_CAUSE_LINENO(
+                logger, 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_CPPLOGE_APPEND_CAUSE_LINENO(logger, 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_CPPLOGE_APPEND_CAUSE_LINENO(
+                logger, node->lineno,
+                "Link `...` is not allowed on the first node of the unary expression list.");
+            goto errperm;
+        }
+        break;
+    default:
+        _BT_CPPLOGE_APPEND_CAUSE_LINENO(logger, node->lineno,
+                                        "Unknown expression link type: type={}",
+                                        (int) node->u.unary_expression.link);
+        return -EINVAL;
+    }
+    return 0;
+
+errinval:
+    _BT_CPPLOGE_APPEND_CAUSE_LINENO(
+        logger, node->lineno, "Incoherent parent node's type: node-type={}, parent-node-type={}",
+        node_type(node), node_type(node->parent));
+    return -EINVAL; /* Incoherent structure */
+
+errperm:
+    _BT_CPPLOGE_APPEND_CAUSE_LINENO(logger, node->lineno,
+                                    "Semantic error: node-type={}, parent-node-type={}",
+                                    node_type(node), node_type(node->parent));
+    return -EPERM; /* Structure not allowed */
+}
+
+static int ctf_visitor_field_class_specifier_list(int, struct ctf_node *node,
+                                                  const bt2c::Logger& logger)
+{
+    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_CPPLOGE_APPEND_CAUSE_LINENO(
+        logger, node->lineno, "Incoherent parent node's type: node-type={}, parent-node-type={}",
+        node_type(node), node_type(node->parent));
+    return -EINVAL; /* Incoherent structure */
+}
+
+static int ctf_visitor_field_class_specifier(int, struct ctf_node *node, const bt2c::Logger& logger)
+{
+    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_CPPLOGE_APPEND_CAUSE_LINENO(
+        logger, node->lineno, "Incoherent parent node's type: node-type={}, parent-node-type={}",
+        node_type(node), node_type(node->parent));
+    return -EINVAL; /* Incoherent structure */
+}
+
+static int ctf_visitor_field_class_declarator(int depth, struct ctf_node *node,
+                                              const bt2c::Logger& logger)
+{
+    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)
+            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, logger);
+        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, logger);
+            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_CPPLOGE_APPEND_CAUSE_LINENO(
+                        logger, node->lineno, "Expecting unary expression as length: node-type={}",
+                        node_type(iter));
+                    return -EINVAL;
+                }
+                ret = _ctf_visitor_semantic_check(depth + 1, iter, logger);
+                if (ret)
+                    return ret;
+            }
+        } else {
+            if (node->parent->type == NODE_TYPEALIAS_TARGET) {
+                _BT_CPPLOGE_APPEND_CAUSE_LINENO(
+                    logger, 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, logger);
+            if (ret)
+                return ret;
+        }
+        break;
+    }
+    case TYPEDEC_UNKNOWN:
+    default:
+        _BT_CPPLOGE_APPEND_CAUSE_LINENO(logger, node->lineno,
+                                        "Unknown field class declarator: type={}",
+                                        (int) node->u.field_class_declarator.type);
+        return -EINVAL;
+    }
+    depth--;
+    return 0;
+
+errinval:
+    _BT_CPPLOGE_APPEND_CAUSE_LINENO(
+        logger, node->lineno, "Incoherent parent node's type: node-type={}, parent-node-type={}",
+        node_type(node), node_type(node->parent));
+    return -EINVAL; /* Incoherent structure */
+
+errperm:
+    _BT_CPPLOGE_APPEND_CAUSE_LINENO(logger, node->lineno,
+                                    "Semantic error: node-type={}, parent-node-type={}",
+                                    node_type(node), node_type(node->parent));
+    return -EPERM; /* Structure not allowed */
+}
+
+static int _ctf_visitor_semantic_check(int depth, struct ctf_node *node, const bt2c::Logger& logger)
+{
+    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, logger);
+            if (ret)
+                return ret;
+        }
+        bt_list_for_each_entry (iter, &node->u.root.trace, siblings) {
+            ret = _ctf_visitor_semantic_check(depth + 1, iter, logger);
+            if (ret)
+                return ret;
+        }
+        bt_list_for_each_entry (iter, &node->u.root.stream, siblings) {
+            ret = _ctf_visitor_semantic_check(depth + 1, iter, logger);
+            if (ret)
+                return ret;
+        }
+        bt_list_for_each_entry (iter, &node->u.root.event, siblings) {
+            ret = _ctf_visitor_semantic_check(depth + 1, iter, logger);
+            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, logger);
+            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, logger);
+            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, logger);
+            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, logger);
+            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, logger);
+            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, logger);
+            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, logger);
+            if (ret)
+                return ret;
+        }
+        bt_list_for_each_entry (iter, &node->u.ctf_expression.right, siblings) {
+            ret = _ctf_visitor_semantic_check(depth + 1, iter, logger);
+            if (ret)
+                return ret;
+        }
+        depth--;
+        break;
+    case NODE_UNARY_EXPRESSION:
+        return ctf_visitor_unary_expression(depth, node, logger);
+
+    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, logger);
+        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, logger);
+            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, logger);
+        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, logger);
+            if (ret)
+                return ret;
+            nr_declarators++;
+        }
+        if (nr_declarators > 1) {
+            _BT_CPPLOGE_APPEND_CAUSE_LINENO(
+                logger, node->lineno,
+                "Too many declarators in field class alias's name (maximum is 1): count={}",
+                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, logger);
+        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, logger);
+            if (ret)
+                return ret;
+            nr_declarators++;
+        }
+        if (nr_declarators > 1) {
+            _BT_CPPLOGE_APPEND_CAUSE_LINENO(
+                logger, node->lineno,
+                "Too many declarators in field class alias's name (maximum is 1): count={}",
+                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, logger);
+        if (ret)
+            return ret;
+        ret = _ctf_visitor_semantic_check(depth + 1, node->u.field_class_alias.alias, logger);
+        if (ret)
+            return ret;
+        break;
+
+    case NODE_TYPE_SPECIFIER_LIST:
+        ret = ctf_visitor_field_class_specifier_list(depth, node, logger);
+        if (ret)
+            return ret;
+        break;
+    case NODE_TYPE_SPECIFIER:
+        ret = ctf_visitor_field_class_specifier(depth, node, logger);
+        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, logger);
+        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, logger);
+            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, logger);
+            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, logger);
+            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_CPPLOGE_APPEND_CAUSE_LINENO(
+                            logger, 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_CPPLOGE_APPEND_CAUSE_LINENO(
+                            logger, 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, logger);
+            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, logger);
+        if (ret)
+            return ret;
+
+        bt_list_for_each_entry (iter, &node->u._enum.enumerator_list, siblings) {
+            ret = _ctf_visitor_semantic_check(depth + 1, iter, logger);
+            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, logger);
+        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, logger);
+            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, logger);
+            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, logger);
+            if (ret)
+                return ret;
+        }
+        break;
+
+    case NODE_UNKNOWN:
+    default:
+        _BT_CPPLOGE_APPEND_CAUSE_LINENO(logger, node->lineno, "Unknown node type: type={}",
+                                        (int) node->type);
+        return -EINVAL;
+    }
+    return ret;
+
+errinval:
+    _BT_CPPLOGE_APPEND_CAUSE_LINENO(
+        logger, node->lineno, "Incoherent parent node's type: node-type={}, parent-node-type={}",
+        node_type(node), node_type(node->parent));
+    return -EINVAL; /* Incoherent structure */
+
+errperm:
+    _BT_CPPLOGE_APPEND_CAUSE_LINENO(logger, node->lineno,
+                                    "Semantic error: node-type={}, parent-node-type={}",
+                                    node_type(node), node_type(node->parent));
+    return -EPERM; /* Structure not allowed */
+}
+
+int ctf_visitor_semantic_check(int depth, struct ctf_node *node, const bt2c::Logger& parentLogger)
+{
+    int ret = 0;
+    bt2c::Logger logger {parentLogger, "PLUGIN/CTF/META/SEMANTIC-VALIDATOR-VISITOR"};
+
+    /*
+     * 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, logger);
+    if (ret) {
+        _BT_CPPLOGE_APPEND_CAUSE_LINENO(logger, node->lineno,
+                                        "Cannot create parent links in metadata's AST: "
+                                        "ret={}",
+                                        ret);
+        goto end;
+    }
+
+    ret = _ctf_visitor_semantic_check(depth, node, logger);
+    if (ret) {
+        _BT_CPPLOGE_APPEND_CAUSE_LINENO(logger, node->lineno,
+                                        "Cannot check metadata's AST semantics: "
+                                        "ret={}",
+                                        ret);
+        goto end;
+    }
+
+end:
+    return ret;
+}
diff --git a/src/plugins/ctf/common/src/msg-iter/msg-iter.cpp b/src/plugins/ctf/common/src/msg-iter/msg-iter.cpp
new file mode 100644 (file)
index 0000000..50a545b
--- /dev/null
@@ -0,0 +1,3063 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright (c) 2015-2018 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2015-2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Babeltrace - CTF message iterator
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include "common/assert.h"
+#include "common/common.h"
+#include "cpp-common/bt2c/fmt.hpp"
+#include "cpp-common/bt2c/logging.hpp"
+#include "cpp-common/bt2c/make-span.hpp"
+#include "cpp-common/vendor/fmt/format.h"
+
+#include "../bfcr/bfcr.hpp"
+#include "msg-iter.hpp"
+
+/* 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
+{
+    struct ctf_msg_iter *msg_it;
+
+    /* Entries (struct stack_entry) */
+    GArray *entries;
+
+    /* Number of active entries */
+    size_t size;
+};
+
+/* State */
+enum state
+{
+    STATE_INIT,
+    STATE_SWITCH_PACKET,
+    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_EMIT_MSG_STREAM_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_EMIT_QUEUED_MSG_EVENT,
+    STATE_SKIP_PACKET_PADDING,
+    STATE_EMIT_MSG_PACKET_END_MULTI,
+    STATE_EMIT_MSG_PACKET_END_SINGLE,
+    STATE_EMIT_QUEUED_MSG_PACKET_END,
+    STATE_CHECK_EMIT_MSG_STREAM_END,
+    STATE_EMIT_MSG_STREAM_END,
+    STATE_DONE,
+};
+
+static __attribute__((used)) const char *format_as(state state)
+{
+    switch (state) {
+    case STATE_INIT:
+        return "STATE_INIT";
+
+    case STATE_SWITCH_PACKET:
+        return "STATE_SWITCH_PACKET";
+
+    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_CHECK_EMIT_MSG_DISCARDED_EVENTS:
+        return "STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS";
+
+    case STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS:
+        return "STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS";
+
+    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_EMIT_MSG_PACKET_BEGINNING:
+        return "STATE_EMIT_MSG_PACKET_BEGINNING";
+
+    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_EMIT_QUEUED_MSG_EVENT:
+        return "STATE_EMIT_QUEUED_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_QUEUED_MSG_PACKET_END:
+        return "STATE_EMIT_QUEUED_MSG_PACKET_END";
+
+    case STATE_CHECK_EMIT_MSG_STREAM_END:
+        return "STATE_CHECK_EMIT_MSG_STREAM_END";
+
+    case STATE_EMIT_MSG_STREAM_END:
+        return "STATE_EMIT_MSG_STREAM_END";
+
+    case STATE_DONE:
+        return "STATE_DONE";
+    }
+
+    bt_common_abort();
+}
+
+struct end_of_packet_snapshots
+{
+    uint64_t discarded_events = 0;
+    uint64_t packets = 0;
+    uint64_t beginning_clock = 0;
+    uint64_t end_clock = 0;
+};
+
+/* CTF message iterator */
+struct ctf_msg_iter
+{
+    explicit ctf_msg_iter(bt2c::Logger loggerParam) noexcept : logger {std::move(loggerParam)}
+    {
+    }
+
+    /* Visit stack */
+    struct stack *stack = nullptr;
+
+    /* Current message iterator to create messages (weak) */
+    bt_self_message_iterator *self_msg_iter = nullptr;
+
+    /*
+     * True if library objects are unavailable during the decoding and
+     * should not be created/used.
+     */
+    bool dry_run = false;
+
+    /*
+     * 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 = nullptr;
+
+    /*
+     * True if we're done filling a string field from a text
+     * array/sequence payload.
+     */
+    bool done_filling_string = false;
+
+    /* Trace and classes */
+    /* True to set IR fields */
+    bool set_ir_fields = false;
+
+    struct
+    {
+        struct ctf_trace_class *tc = nullptr;
+        struct ctf_stream_class *sc = nullptr;
+        struct ctf_event_class *ec = nullptr;
+    } meta;
+
+    /* Current packet (NULL if not created yet) */
+    bt_packet *packet = nullptr;
+
+    /* Current stream (NULL if not set yet) */
+    bt_stream *stream = nullptr;
+
+    /* Current event (NULL if not created yet) */
+    bt_event *event = nullptr;
+
+    /* Current event message (NULL if not created yet) */
+    bt_message *event_msg = nullptr;
+
+    /*
+     * True if we need to emit a packet beginning message before we emit
+     * the next event message or the packet end message.
+     */
+    bool emit_delayed_packet_beginning_msg = false;
+
+    /*
+     * True if this is the first packet we are reading, and therefore if we
+     * should emit a stream beginning message.
+     */
+    bool emit_stream_beginning_message = false;
+
+    /*
+     * True if we need to emit a stream end message at the end of the
+     * current stream. A live stream may never receive any data and thus
+     * never send a stream beginning message which removes the need to emit
+     * a stream end message.
+     */
+    bool emit_stream_end_message = false;
+
+    /* Database of current dynamic scopes */
+    struct
+    {
+        bt_field *stream_packet_context = nullptr;
+        bt_field *event_common_context = nullptr;
+        bt_field *event_spec_context = nullptr;
+        bt_field *event_payload = nullptr;
+    } dscopes;
+
+    /* Current state */
+    enum state state = STATE_INIT;
+
+    /* Current medium buffer data */
+    struct
+    {
+        /* Last address provided by medium */
+        const uint8_t *addr = nullptr;
+
+        /* Buffer size provided by medium (bytes) */
+        size_t sz = 0;
+
+        /* Offset within whole packet of addr (bits) */
+        size_t packet_offset = 0;
+
+        /* Current position from addr (bits) */
+        size_t at = 0;
+
+        /* Position of the last event header from addr (bits) */
+        size_t last_eh_at = 0;
+    } buf;
+
+    /* Binary type reader */
+    struct bt_bfcr *bfcr = nullptr;
+
+    /* Current medium data */
+    struct
+    {
+        struct ctf_msg_iter_medium_ops medops;
+        size_t max_request_sz = 0;
+        void *data = nullptr;
+    } medium;
+
+    /* Current packet size (bits) (-1 if unknown) */
+    int64_t cur_exp_packet_total_size = 0;
+
+    /* Current content size (bits) (-1 if unknown) */
+    int64_t cur_exp_packet_content_size = 0;
+
+    /* Current stream class ID */
+    int64_t cur_stream_class_id = 0;
+
+    /* Current event class ID */
+    int64_t cur_event_class_id = 0;
+
+    /* Current data stream ID */
+    int64_t cur_data_stream_id = 0;
+
+    /*
+     * Offset, in the underlying media, of the current packet's
+     * start (-1 if unknown).
+     */
+    off_t cur_packet_offset = 0;
+
+    /* Default clock's current value */
+    uint64_t default_clock_snapshot = 0;
+
+    /* 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 = nullptr;
+
+    bt2c::Logger logger;
+};
+
+static struct stack *stack_new(struct ctf_msg_iter *msg_it)
+{
+    struct stack *stack = NULL;
+
+    stack = g_new0(struct stack, 1);
+    if (!stack) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger, "Failed to allocate one stack.");
+        goto error;
+    }
+
+    stack->msg_it = msg_it;
+    stack->entries = g_array_new(FALSE, TRUE, sizeof(struct stack_entry));
+    if (!stack->entries) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger, "Failed to allocate a GArray.");
+        goto error;
+    }
+
+    BT_CPPLOGD_SPEC(msg_it->logger, "Created stack: msg-it-addr={}, stack-addr={}",
+                    fmt::ptr(msg_it), fmt::ptr(stack));
+    goto end;
+
+error:
+    g_free(stack);
+    stack = NULL;
+
+end:
+    return stack;
+}
+
+static void stack_destroy(struct stack *stack)
+{
+    struct ctf_msg_iter *msg_it;
+
+    BT_ASSERT_DBG(stack);
+    msg_it = stack->msg_it;
+    BT_CPPLOGD_SPEC(msg_it->logger, "Destroying stack: addr={}", fmt::ptr(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;
+    struct ctf_msg_iter *msg_it;
+
+    BT_ASSERT_DBG(stack);
+    msg_it = stack->msg_it;
+    BT_ASSERT_DBG(base);
+    BT_CPPLOGT_SPEC(msg_it->logger,
+                    "Pushing base field on stack: stack-addr={}, "
+                    "stack-size-before={}, stack-size-after={}",
+                    fmt::ptr(stack), stack->size, stack->size + 1);
+
+    if (stack->entries->len == stack->size) {
+        g_array_set_size(stack->entries, stack->size + 1);
+    }
+
+    entry = &bt_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_DBG(stack);
+    return stack->size;
+}
+
+static void stack_pop(struct stack *stack)
+{
+    struct ctf_msg_iter *msg_it;
+
+    BT_ASSERT_DBG(stack);
+    BT_ASSERT_DBG(stack_size(stack));
+    msg_it = stack->msg_it;
+    BT_CPPLOGT_SPEC(msg_it->logger,
+                    "Popping from stack: "
+                    "stack-addr={}, stack-size-before={}, stack-size-after={}",
+                    fmt::ptr(stack), stack->size, stack->size - 1);
+    stack->size--;
+}
+
+static inline struct stack_entry *stack_top(struct stack *stack)
+{
+    BT_ASSERT_DBG(stack);
+    BT_ASSERT_DBG(stack_size(stack));
+    return &bt_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_DBG(stack);
+    stack->size = 0;
+}
+
+static inline enum ctf_msg_iter_status
+msg_iter_status_from_m_status(enum ctf_msg_iter_medium_status m_status)
+{
+    /* They are the same */
+    return (ctf_msg_iter_status) m_status;
+}
+
+static inline size_t buf_size_bits(struct ctf_msg_iter *msg_it)
+{
+    return msg_it->buf.sz * 8;
+}
+
+static inline size_t buf_available_bits(struct ctf_msg_iter *msg_it)
+{
+    return buf_size_bits(msg_it) - msg_it->buf.at;
+}
+
+static inline size_t packet_at(struct ctf_msg_iter *msg_it)
+{
+    return msg_it->buf.packet_offset + msg_it->buf.at;
+}
+
+static inline void buf_consume_bits(struct ctf_msg_iter *msg_it, size_t incr)
+{
+    BT_CPPLOGT_SPEC(msg_it->logger, "Advancing cursor: msg-it-addr={}, cur-before={}, cur-after={}",
+                    fmt::ptr(msg_it), msg_it->buf.at, msg_it->buf.at + incr);
+    msg_it->buf.at += incr;
+}
+
+static enum ctf_msg_iter_status request_medium_bytes(struct ctf_msg_iter *msg_it)
+{
+    uint8_t *buffer_addr = NULL;
+    size_t buffer_sz = 0;
+    enum ctf_msg_iter_medium_status m_status;
+
+    BT_CPPLOGD_SPEC(msg_it->logger,
+                    "Calling user function (request bytes): msg-it-addr={}, "
+                    "request-size={}",
+                    fmt::ptr(msg_it), msg_it->medium.max_request_sz);
+    m_status = msg_it->medium.medops.request_bytes(msg_it->medium.max_request_sz, &buffer_addr,
+                                                   &buffer_sz, msg_it->medium.data);
+    BT_CPPLOGD_SPEC(msg_it->logger, "User function returned: status={}, buf-addr={}, buf-size={}",
+                    m_status, fmt::ptr(buffer_addr), buffer_sz);
+    if (m_status == CTF_MSG_ITER_MEDIUM_STATUS_OK) {
+        BT_ASSERT(buffer_sz != 0);
+
+        /* New packet offset is old one + old size (in bits) */
+        msg_it->buf.packet_offset += buf_size_bits(msg_it);
+
+        /* Restart at the beginning of the new medium buffer */
+        msg_it->buf.at = 0;
+        msg_it->buf.last_eh_at = SIZE_MAX;
+
+        /* New medium buffer size */
+        msg_it->buf.sz = buffer_sz;
+
+        /* New medium buffer address */
+        msg_it->buf.addr = buffer_addr;
+
+        BT_CPPLOGD_SPEC(msg_it->logger,
+                        "User function returned new bytes: "
+                        "packet-offset={}, cur={}, size={}, addr={}",
+                        msg_it->buf.packet_offset, msg_it->buf.at, msg_it->buf.sz,
+                        fmt::ptr(msg_it->buf.addr));
+        BT_CPPLOGT_MEM_SPEC(msg_it->logger, bt2c::makeSpan(buffer_addr, buffer_sz),
+                            "Returned bytes at {}:", fmt::ptr(buffer_addr));
+    } else if (m_status == CTF_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 (msg_it->cur_exp_packet_total_size >= 0) {
+            if (packet_at(msg_it) == msg_it->cur_exp_packet_total_size) {
+                goto end;
+            }
+        } else {
+            if (packet_at(msg_it) == 0) {
+                goto end;
+            }
+
+            if (msg_it->buf.last_eh_at != SIZE_MAX && msg_it->buf.at == msg_it->buf.last_eh_at) {
+                goto end;
+            }
+        }
+
+        /* All other states are invalid */
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(
+            msg_it->logger,
+            "User function returned {}, but message iterator is in an unexpected state: "
+            "state={}, cur-packet-size={}, cur={}, "
+            "packet-cur={}, last-eh-at={}",
+            m_status, msg_it->state, msg_it->cur_exp_packet_total_size, msg_it->buf.at,
+            packet_at(msg_it), msg_it->buf.last_eh_at);
+        m_status = CTF_MSG_ITER_MEDIUM_STATUS_ERROR;
+    } else if (m_status < 0) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
+                                     "User function failed: "
+                                     "status={}",
+                                     m_status);
+    }
+
+end:
+    return msg_iter_status_from_m_status(m_status);
+}
+
+static inline enum ctf_msg_iter_status buf_ensure_available_bits(struct ctf_msg_iter *msg_it)
+{
+    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
+
+    if (G_UNLIKELY(buf_available_bits(msg_it) == 0)) {
+        /*
+         * This _cannot_ return CTF_MSG_ITER_STATUS_OK
+         * _and_ no bits.
+         */
+        status = request_medium_bytes(msg_it);
+    }
+
+    return status;
+}
+
+static enum ctf_msg_iter_status
+read_dscope_begin_state(struct ctf_msg_iter *msg_it, struct ctf_field_class *dscope_fc,
+                        enum state done_state, enum state continue_state, bt_field *dscope_field)
+{
+    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
+    enum bt_bfcr_status bfcr_status;
+    size_t consumed_bits;
+
+    msg_it->cur_dscope_field = dscope_field;
+    BT_CPPLOGT_SPEC(msg_it->logger, "Starting BFCR: msg-it-addr={}, bfcr-addr={}, fc-addr={}",
+                    fmt::ptr(msg_it), fmt::ptr(msg_it->bfcr), fmt::ptr(dscope_fc));
+    consumed_bits = bt_bfcr_start(msg_it->bfcr, dscope_fc, msg_it->buf.addr, msg_it->buf.at,
+                                  packet_at(msg_it), msg_it->buf.sz, &bfcr_status);
+    BT_CPPLOGT_SPEC(msg_it->logger, "BFCR consumed bits: size={}", consumed_bits);
+
+    switch (bfcr_status) {
+    case BT_BFCR_STATUS_OK:
+        /* Field class was read completely */
+        BT_CPPLOGT_SPEC(msg_it->logger, "Field was completely decoded.");
+        msg_it->state = done_state;
+        break;
+    case BT_BFCR_STATUS_EOF:
+        BT_CPPLOGT_SPEC(msg_it->logger, "BFCR needs more data to decode field completely.");
+        msg_it->state = continue_state;
+        break;
+    default:
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
+                                     "BFCR failed to start: msg-it-addr={}, bfcr-addr={}, "
+                                     "status={}",
+                                     fmt::ptr(msg_it), fmt::ptr(msg_it->bfcr), bfcr_status);
+        status = CTF_MSG_ITER_STATUS_ERROR;
+        goto end;
+    }
+
+    /* Consume bits now since we know we're not in an error state */
+    buf_consume_bits(msg_it, consumed_bits);
+
+end:
+    return status;
+}
+
+static enum ctf_msg_iter_status read_dscope_continue_state(struct ctf_msg_iter *msg_it,
+                                                           enum state done_state)
+{
+    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
+    enum bt_bfcr_status bfcr_status;
+    size_t consumed_bits;
+
+    BT_CPPLOGT_SPEC(msg_it->logger, "Continuing BFCR: msg-it-addr={}, bfcr-addr={}",
+                    fmt::ptr(msg_it), fmt::ptr(msg_it->bfcr));
+
+    status = buf_ensure_available_bits(msg_it);
+    if (status != CTF_MSG_ITER_STATUS_OK) {
+        if (status < 0) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
+                                         "Cannot ensure that buffer has at least one byte: "
+                                         "msg-addr={}, status={}",
+                                         fmt::ptr(msg_it), status);
+        } else {
+            BT_CPPLOGT_SPEC(msg_it->logger,
+                            "Cannot ensure that buffer has at least one byte: "
+                            "msg-addr={}, status={}",
+                            fmt::ptr(msg_it), status);
+        }
+
+        goto end;
+    }
+
+    consumed_bits = bt_bfcr_continue(msg_it->bfcr, msg_it->buf.addr, msg_it->buf.sz, &bfcr_status);
+    BT_CPPLOGT_SPEC(msg_it->logger, "BFCR consumed bits: size={}", consumed_bits);
+
+    switch (bfcr_status) {
+    case BT_BFCR_STATUS_OK:
+        /* Type was read completely. */
+        BT_CPPLOGT_SPEC(msg_it->logger, "Field was completely decoded.");
+        msg_it->state = done_state;
+        break;
+    case BT_BFCR_STATUS_EOF:
+        /* Stay in this continue state. */
+        BT_CPPLOGT_SPEC(msg_it->logger, "BFCR needs more data to decode field completely.");
+        break;
+    default:
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
+                                     "BFCR failed to continue: msg-it-addr={}, bfcr-addr={}, "
+                                     "status={}",
+                                     fmt::ptr(msg_it), fmt::ptr(msg_it->bfcr), bfcr_status);
+        status = CTF_MSG_ITER_STATUS_ERROR;
+        goto end;
+    }
+
+    /* Consume bits now since we know we're not in an error state. */
+    buf_consume_bits(msg_it, consumed_bits);
+end:
+    return status;
+}
+
+static void release_event_dscopes(struct ctf_msg_iter *msg_it)
+{
+    msg_it->dscopes.event_common_context = NULL;
+    msg_it->dscopes.event_spec_context = NULL;
+    msg_it->dscopes.event_payload = NULL;
+}
+
+static void release_all_dscopes(struct ctf_msg_iter *msg_it)
+{
+    msg_it->dscopes.stream_packet_context = NULL;
+
+    release_event_dscopes(msg_it);
+}
+
+static enum ctf_msg_iter_status switch_packet_state(struct ctf_msg_iter *msg_it)
+{
+    enum ctf_msg_iter_status status;
+
+    /*
+     * 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(msg_it);
+
+    if (msg_it->cur_exp_packet_total_size != -1) {
+        msg_it->cur_packet_offset += msg_it->cur_exp_packet_total_size;
+    }
+
+    BT_CPPLOGD_SPEC(msg_it->logger,
+                    "Switching packet: msg-it-addr={}, cur={}, "
+                    "packet-offset={}",
+                    fmt::ptr(msg_it), msg_it->buf.at, msg_it->cur_packet_offset);
+    stack_clear(msg_it->stack);
+    msg_it->meta.ec = NULL;
+    BT_PACKET_PUT_REF_AND_RESET(msg_it->packet);
+    BT_MESSAGE_PUT_REF_AND_RESET(msg_it->event_msg);
+    release_all_dscopes(msg_it);
+    msg_it->cur_dscope_field = NULL;
+
+    if (msg_it->medium.medops.switch_packet) {
+        enum ctf_msg_iter_medium_status medium_status;
+
+        medium_status = msg_it->medium.medops.switch_packet(msg_it->medium.data);
+        if (medium_status == CTF_MSG_ITER_MEDIUM_STATUS_EOF) {
+            /* No more packets. */
+            msg_it->state = STATE_CHECK_EMIT_MSG_STREAM_END;
+            status = CTF_MSG_ITER_STATUS_OK;
+            goto end;
+        } else if (medium_status != CTF_MSG_ITER_MEDIUM_STATUS_OK) {
+            status = msg_iter_status_from_m_status(medium_status);
+            goto end;
+        }
+
+        /*
+         * After the packet switch, the medium might want to give us a
+         * different buffer for the new packet.
+         */
+        status = request_medium_bytes(msg_it);
+        if (status != CTF_MSG_ITER_STATUS_OK) {
+            goto end;
+        }
+    }
+
+    /*
+     * Adjust current buffer so that addr points to the beginning of the new
+     * packet.
+     */
+    if (msg_it->buf.addr) {
+        size_t consumed_bytes = (size_t) (msg_it->buf.at / CHAR_BIT);
+
+        /* Packets are assumed to start on a byte frontier. */
+        if (msg_it->buf.at % CHAR_BIT) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(
+                msg_it->logger,
+                "Cannot switch packet: current position is not a multiple of 8: "
+                "msg-it-addr={}, cur={}",
+                fmt::ptr(msg_it), msg_it->buf.at);
+            status = CTF_MSG_ITER_STATUS_ERROR;
+            goto end;
+        }
+
+        msg_it->buf.addr += consumed_bytes;
+        msg_it->buf.sz -= consumed_bytes;
+        msg_it->buf.at = 0;
+        msg_it->buf.packet_offset = 0;
+        BT_CPPLOGD_SPEC(msg_it->logger, "Adjusted buffer: addr={}, size={}",
+                        fmt::ptr(msg_it->buf.addr), msg_it->buf.sz);
+    }
+
+    msg_it->cur_exp_packet_content_size = -1;
+    msg_it->cur_exp_packet_total_size = -1;
+    msg_it->cur_stream_class_id = -1;
+    msg_it->cur_event_class_id = -1;
+    msg_it->cur_data_stream_id = -1;
+    msg_it->prev_packet_snapshots = msg_it->snapshots;
+    msg_it->snapshots.discarded_events = UINT64_C(-1);
+    msg_it->snapshots.packets = UINT64_C(-1);
+    msg_it->snapshots.beginning_clock = UINT64_C(-1);
+    msg_it->snapshots.end_clock = UINT64_C(-1);
+    msg_it->state = STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN;
+
+    status = CTF_MSG_ITER_STATUS_OK;
+end:
+    return status;
+}
+
+static enum ctf_msg_iter_status read_packet_header_begin_state(struct ctf_msg_iter *msg_it)
+{
+    struct ctf_field_class *packet_header_fc = NULL;
+    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
+
+    /*
+     * 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.
+     */
+    status = buf_ensure_available_bits(msg_it);
+    switch (status) {
+    case CTF_MSG_ITER_STATUS_OK:
+        break;
+    case CTF_MSG_ITER_STATUS_EOF:
+        status = CTF_MSG_ITER_STATUS_OK;
+        msg_it->state = STATE_CHECK_EMIT_MSG_STREAM_END;
+        goto end;
+    default:
+        goto end;
+    }
+
+    /* Packet header class is common to the whole trace class. */
+    packet_header_fc = msg_it->meta.tc->packet_header_fc;
+    if (!packet_header_fc) {
+        msg_it->state = STATE_AFTER_TRACE_PACKET_HEADER;
+        goto end;
+    }
+
+    msg_it->cur_stream_class_id = -1;
+    msg_it->cur_event_class_id = -1;
+    msg_it->cur_data_stream_id = -1;
+    BT_CPPLOGD_SPEC(msg_it->logger,
+                    "Decoding packet header field: "
+                    "msg-it-addr={}, trace-class-addr={}, fc-addr={}",
+                    fmt::ptr(msg_it), fmt::ptr(msg_it->meta.tc), fmt::ptr(packet_header_fc));
+    status = read_dscope_begin_state(msg_it, packet_header_fc, STATE_AFTER_TRACE_PACKET_HEADER,
+                                     STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE, NULL);
+    if (status < 0) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
+                                     "Cannot decode packet header field: "
+                                     "msg-it-addr={}, trace-class-addr={}, "
+                                     "fc-addr={}",
+                                     fmt::ptr(msg_it), fmt::ptr(msg_it->meta.tc),
+                                     fmt::ptr(packet_header_fc));
+    }
+
+end:
+    return status;
+}
+
+static enum ctf_msg_iter_status read_packet_header_continue_state(struct ctf_msg_iter *msg_it)
+{
+    return read_dscope_continue_state(msg_it, STATE_AFTER_TRACE_PACKET_HEADER);
+}
+
+static inline enum ctf_msg_iter_status set_current_stream_class(struct ctf_msg_iter *msg_it)
+{
+    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
+    struct ctf_stream_class *new_stream_class = NULL;
+
+    if (msg_it->cur_stream_class_id == -1) {
+        /*
+         * No current stream class ID field, therefore only one
+         * stream class.
+         */
+        if (msg_it->meta.tc->stream_classes->len != 1) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
+                                         "Need exactly one stream class since there's "
+                                         "no stream class ID field: "
+                                         "msg-it-addr={}",
+                                         fmt::ptr(msg_it));
+            status = CTF_MSG_ITER_STATUS_ERROR;
+            goto end;
+        }
+
+        new_stream_class = (ctf_stream_class *) msg_it->meta.tc->stream_classes->pdata[0];
+        msg_it->cur_stream_class_id = new_stream_class->id;
+    }
+
+    new_stream_class =
+        ctf_trace_class_borrow_stream_class_by_id(msg_it->meta.tc, msg_it->cur_stream_class_id);
+    if (!new_stream_class) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(
+            msg_it->logger,
+            "No stream class with ID of stream class ID to use in trace class: "
+            "msg-it-addr={}, stream-class-id={}, "
+            "trace-class-addr={}",
+            fmt::ptr(msg_it), msg_it->cur_stream_class_id, fmt::ptr(msg_it->meta.tc));
+        status = CTF_MSG_ITER_STATUS_ERROR;
+        goto end;
+    }
+
+    if (msg_it->meta.sc) {
+        if (new_stream_class != msg_it->meta.sc) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(
+                msg_it->logger,
+                "Two packets refer to two different stream classes within the same packet sequence: "
+                "msg-it-addr={}, prev-stream-class-addr={}, "
+                "prev-stream-class-id={}, "
+                "next-stream-class-addr={}, "
+                "next-stream-class-id={}, "
+                "trace-addr={}",
+                fmt::ptr(msg_it), fmt::ptr(msg_it->meta.sc), msg_it->meta.sc->id,
+                fmt::ptr(new_stream_class), new_stream_class->id, fmt::ptr(msg_it->meta.tc));
+            status = CTF_MSG_ITER_STATUS_ERROR;
+            goto end;
+        }
+    } else {
+        msg_it->meta.sc = new_stream_class;
+    }
+
+    BT_CPPLOGD_SPEC(msg_it->logger,
+                    "Set current stream class: "
+                    "msg-it-addr={}, stream-class-addr={}, "
+                    "stream-class-id={}",
+                    fmt::ptr(msg_it), fmt::ptr(msg_it->meta.sc), msg_it->meta.sc->id);
+
+end:
+    return status;
+}
+
+static inline enum ctf_msg_iter_status set_current_stream(struct ctf_msg_iter *msg_it)
+{
+    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
+    bt_stream *stream = NULL;
+
+    BT_CPPLOGD_SPEC(msg_it->logger,
+                    "Calling user function (get stream): msg-it-addr={}, "
+                    "stream-class-addr={}, stream-class-id={}",
+                    fmt::ptr(msg_it), fmt::ptr(msg_it->meta.sc), msg_it->meta.sc->id);
+    stream = msg_it->medium.medops.borrow_stream(msg_it->meta.sc->ir_sc, msg_it->cur_data_stream_id,
+                                                 msg_it->medium.data);
+    bt_stream_get_ref(stream);
+    BT_CPPLOGD_SPEC(msg_it->logger, "User function returned: stream-addr={}", fmt::ptr(stream));
+    if (!stream) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(
+            msg_it->logger,
+            "User function failed to return a stream object for the given stream class.");
+        status = CTF_MSG_ITER_STATUS_ERROR;
+        goto end;
+    }
+
+    if (msg_it->stream && stream != msg_it->stream) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(
+            msg_it->logger,
+            "User function returned a different stream than the previous one for the same sequence of packets.");
+        status = CTF_MSG_ITER_STATUS_ERROR;
+        goto end;
+    }
+
+    BT_STREAM_MOVE_REF(msg_it->stream, stream);
+
+end:
+    bt_stream_put_ref(stream);
+    return status;
+}
+
+static inline enum ctf_msg_iter_status set_current_packet(struct ctf_msg_iter *msg_it)
+{
+    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
+    bt_packet *packet = NULL;
+
+    BT_CPPLOGD_SPEC(msg_it->logger,
+                    "Creating packet from stream: "
+                    "msg-it-addr={}, stream-addr={}, "
+                    "stream-class-addr={}, "
+                    "stream-class-id={}",
+                    fmt::ptr(msg_it), fmt::ptr(msg_it->stream), fmt::ptr(msg_it->meta.sc),
+                    msg_it->meta.sc->id);
+
+    /* Create packet */
+    BT_ASSERT(msg_it->stream);
+    packet = bt_packet_create(msg_it->stream);
+    if (!packet) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
+                                     "Cannot create packet from stream: "
+                                     "msg-it-addr={}, stream-addr={}, "
+                                     "stream-class-addr={}, "
+                                     "stream-class-id={}",
+                                     fmt::ptr(msg_it), fmt::ptr(msg_it->stream),
+                                     fmt::ptr(msg_it->meta.sc), msg_it->meta.sc->id);
+        goto error;
+    }
+
+    goto end;
+
+error:
+    BT_PACKET_PUT_REF_AND_RESET(packet);
+    status = CTF_MSG_ITER_STATUS_ERROR;
+
+end:
+    BT_PACKET_MOVE_REF(msg_it->packet, packet);
+    return status;
+}
+
+static enum ctf_msg_iter_status after_packet_header_state(struct ctf_msg_iter *msg_it)
+{
+    enum ctf_msg_iter_status status;
+
+    status = set_current_stream_class(msg_it);
+    if (status != CTF_MSG_ITER_STATUS_OK) {
+        goto end;
+    }
+
+    if (!msg_it->dry_run) {
+        status = set_current_stream(msg_it);
+        if (status != CTF_MSG_ITER_STATUS_OK) {
+            goto end;
+        }
+
+        status = set_current_packet(msg_it);
+        if (status != CTF_MSG_ITER_STATUS_OK) {
+            goto end;
+        }
+    }
+
+    msg_it->state = STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN;
+
+    status = CTF_MSG_ITER_STATUS_OK;
+
+end:
+    return status;
+}
+
+static enum ctf_msg_iter_status read_packet_context_begin_state(struct ctf_msg_iter *msg_it)
+{
+    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
+    struct ctf_field_class *packet_context_fc;
+
+    BT_ASSERT(msg_it->meta.sc);
+    packet_context_fc = msg_it->meta.sc->packet_context_fc;
+    if (!packet_context_fc) {
+        BT_CPPLOGD_SPEC(msg_it->logger,
+                        "No packet packet context field class in stream class: continuing: "
+                        "msg-it-addr={}, stream-class-addr={}, "
+                        "stream-class-id={}",
+                        fmt::ptr(msg_it), fmt::ptr(msg_it->meta.sc), msg_it->meta.sc->id);
+        msg_it->state = STATE_AFTER_STREAM_PACKET_CONTEXT;
+        goto end;
+    }
+
+    if (packet_context_fc->in_ir && !msg_it->dry_run) {
+        BT_ASSERT(!msg_it->dscopes.stream_packet_context);
+        BT_ASSERT(msg_it->packet);
+        msg_it->dscopes.stream_packet_context = bt_packet_borrow_context_field(msg_it->packet);
+        BT_ASSERT(msg_it->dscopes.stream_packet_context);
+    }
+
+    BT_CPPLOGD_SPEC(msg_it->logger,
+                    "Decoding packet context field: "
+                    "msg-it-addr={}, stream-class-addr={}, "
+                    "stream-class-id={}, fc-addr={}",
+                    fmt::ptr(msg_it), fmt::ptr(msg_it->meta.sc), msg_it->meta.sc->id,
+                    fmt::ptr(packet_context_fc));
+    status = read_dscope_begin_state(msg_it, packet_context_fc, STATE_AFTER_STREAM_PACKET_CONTEXT,
+                                     STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE,
+                                     msg_it->dscopes.stream_packet_context);
+    if (status < 0) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
+                                     "Cannot decode packet context field: "
+                                     "msg-it-addr={}, stream-class-addr={}, "
+                                     "stream-class-id={}, fc-addr={}",
+                                     fmt::ptr(msg_it), fmt::ptr(msg_it->meta.sc),
+                                     msg_it->meta.sc->id, fmt::ptr(packet_context_fc));
+    }
+
+end:
+    return status;
+}
+
+static enum ctf_msg_iter_status read_packet_context_continue_state(struct ctf_msg_iter *msg_it)
+{
+    return read_dscope_continue_state(msg_it, STATE_AFTER_STREAM_PACKET_CONTEXT);
+}
+
+static enum ctf_msg_iter_status set_current_packet_content_sizes(struct ctf_msg_iter *msg_it)
+{
+    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
+
+    if (msg_it->cur_exp_packet_total_size == -1) {
+        if (msg_it->cur_exp_packet_content_size != -1) {
+            msg_it->cur_exp_packet_total_size = msg_it->cur_exp_packet_content_size;
+        }
+    } else {
+        if (msg_it->cur_exp_packet_content_size == -1) {
+            msg_it->cur_exp_packet_content_size = msg_it->cur_exp_packet_total_size;
+        }
+    }
+
+    BT_ASSERT(
+        (msg_it->cur_exp_packet_total_size >= 0 && msg_it->cur_exp_packet_content_size >= 0) ||
+        (msg_it->cur_exp_packet_total_size < 0 && msg_it->cur_exp_packet_content_size < 0));
+
+    if (msg_it->cur_exp_packet_content_size > msg_it->cur_exp_packet_total_size) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(
+            msg_it->logger,
+            "Invalid packet or content size: "
+            "content size is greater than packet size: "
+            "msg-it-addr={}, packet-context-field-addr={}, "
+            "packet-size={}, content-size={}",
+            fmt::ptr(msg_it), fmt::ptr(msg_it->dscopes.stream_packet_context),
+            msg_it->cur_exp_packet_total_size, msg_it->cur_exp_packet_content_size);
+        status = CTF_MSG_ITER_STATUS_ERROR;
+        goto end;
+    }
+
+    BT_CPPLOGD_SPEC(msg_it->logger,
+                    "Set current packet and content sizes: "
+                    "msg-it-addr={}, packet-size={}, content-size={}",
+                    fmt::ptr(msg_it), msg_it->cur_exp_packet_total_size,
+                    msg_it->cur_exp_packet_content_size);
+
+end:
+    return status;
+}
+
+static enum ctf_msg_iter_status after_packet_context_state(struct ctf_msg_iter *msg_it)
+{
+    enum ctf_msg_iter_status status;
+
+    status = set_current_packet_content_sizes(msg_it);
+    if (status != CTF_MSG_ITER_STATUS_OK) {
+        goto end;
+    }
+
+    if (msg_it->emit_stream_beginning_message) {
+        msg_it->state = STATE_EMIT_MSG_STREAM_BEGINNING;
+    } else {
+        msg_it->state = STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS;
+    }
+
+end:
+    return status;
+}
+
+static enum ctf_msg_iter_status read_event_header_begin_state(struct ctf_msg_iter *msg_it)
+{
+    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
+    struct ctf_field_class *event_header_fc = NULL;
+
+    /* Reset the position of the last event header */
+    msg_it->buf.last_eh_at = msg_it->buf.at;
+    msg_it->cur_event_class_id = -1;
+
+    /* Check if we have some content left */
+    if (msg_it->cur_exp_packet_content_size >= 0) {
+        if (G_UNLIKELY(packet_at(msg_it) == msg_it->cur_exp_packet_content_size)) {
+            /* No more events! */
+            BT_CPPLOGD_SPEC(msg_it->logger,
+                            "Reached end of packet: msg-it-addr={}, "
+                            "cur={}",
+                            fmt::ptr(msg_it), packet_at(msg_it));
+            msg_it->state = STATE_EMIT_MSG_PACKET_END_MULTI;
+            goto end;
+        } else if (G_UNLIKELY(packet_at(msg_it) > msg_it->cur_exp_packet_content_size)) {
+            /* That's not supposed to happen */
+            BT_CPPLOGD_SPEC(
+                msg_it->logger,
+                "Before decoding event header field: cursor is passed the packet's content: "
+                "msg-it-addr={}, content-size={}, "
+                "cur={}",
+                fmt::ptr(msg_it), msg_it->cur_exp_packet_content_size, packet_at(msg_it));
+            status = CTF_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(msg_it);
+        switch (status) {
+        case CTF_MSG_ITER_STATUS_OK:
+            break;
+        case CTF_MSG_ITER_STATUS_EOF:
+            status = CTF_MSG_ITER_STATUS_OK;
+            msg_it->state = STATE_EMIT_MSG_PACKET_END_SINGLE;
+            goto end;
+        default:
+            goto end;
+        }
+    }
+
+    release_event_dscopes(msg_it);
+    BT_ASSERT(msg_it->meta.sc);
+    event_header_fc = msg_it->meta.sc->event_header_fc;
+    if (!event_header_fc) {
+        msg_it->state = STATE_AFTER_EVENT_HEADER;
+        goto end;
+    }
+
+    BT_CPPLOGD_SPEC(msg_it->logger,
+                    "Decoding event header field: "
+                    "msg-it-addr={}, stream-class-addr={}, "
+                    "stream-class-id={}, "
+                    "fc-addr={}",
+                    fmt::ptr(msg_it), fmt::ptr(msg_it->meta.sc), msg_it->meta.sc->id,
+                    fmt::ptr(event_header_fc));
+    status = read_dscope_begin_state(msg_it, event_header_fc, STATE_AFTER_EVENT_HEADER,
+                                     STATE_DSCOPE_EVENT_HEADER_CONTINUE, NULL);
+    if (status < 0) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
+                                     "Cannot decode event header field: "
+                                     "msg-it-addr={}, stream-class-addr={}, "
+                                     "stream-class-id={}, fc-addr={}",
+                                     fmt::ptr(msg_it), fmt::ptr(msg_it->meta.sc),
+                                     msg_it->meta.sc->id, fmt::ptr(event_header_fc));
+    }
+
+end:
+    return status;
+}
+
+static enum ctf_msg_iter_status read_event_header_continue_state(struct ctf_msg_iter *msg_it)
+{
+    return read_dscope_continue_state(msg_it, STATE_AFTER_EVENT_HEADER);
+}
+
+static inline enum ctf_msg_iter_status set_current_event_class(struct ctf_msg_iter *msg_it)
+{
+    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
+
+    struct ctf_event_class *new_event_class = NULL;
+
+    if (msg_it->cur_event_class_id == -1) {
+        /*
+         * No current event class ID field, therefore only one
+         * event class.
+         */
+        if (msg_it->meta.sc->event_classes->len != 1) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(
+                msg_it->logger,
+                "Need exactly one event class since there's no event class ID field: "
+                "msg-it-addr={}",
+                fmt::ptr(msg_it));
+            status = CTF_MSG_ITER_STATUS_ERROR;
+            goto end;
+        }
+
+        new_event_class = (ctf_event_class *) msg_it->meta.sc->event_classes->pdata[0];
+        msg_it->cur_event_class_id = new_event_class->id;
+    }
+
+    new_event_class =
+        ctf_stream_class_borrow_event_class_by_id(msg_it->meta.sc, msg_it->cur_event_class_id);
+    if (!new_event_class) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(
+            msg_it->logger,
+            "No event class with ID of event class ID to use in stream class: "
+            "msg-it-addr={}, stream-class-id={}, "
+            "event-class-id={}, "
+            "trace-class-addr={}",
+            fmt::ptr(msg_it), msg_it->meta.sc->id, msg_it->cur_event_class_id,
+            fmt::ptr(msg_it->meta.tc));
+        status = CTF_MSG_ITER_STATUS_ERROR;
+        goto end;
+    }
+
+    msg_it->meta.ec = new_event_class;
+    BT_CPPLOGD_SPEC(msg_it->logger,
+                    "Set current event class: "
+                    "msg-it-addr={}, event-class-addr={}, "
+                    "event-class-id={}, "
+                    "event-class-name=\"{}\"",
+                    fmt::ptr(msg_it), fmt::ptr(msg_it->meta.ec), msg_it->meta.ec->id,
+                    msg_it->meta.ec->name->str);
+
+end:
+    return status;
+}
+
+static inline enum ctf_msg_iter_status set_current_event_message(struct ctf_msg_iter *msg_it)
+{
+    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
+    bt_message *msg = NULL;
+
+    BT_ASSERT_DBG(msg_it->meta.ec);
+    BT_ASSERT_DBG(msg_it->packet);
+    BT_CPPLOGD_SPEC(msg_it->logger,
+                    "Creating event message from event class and packet: "
+                    "msg-it-addr={}, ec-addr={}, ec-name=\"{}\", packet-addr={}",
+                    fmt::ptr(msg_it), fmt::ptr(msg_it->meta.ec), msg_it->meta.ec->name->str,
+                    fmt::ptr(msg_it->packet));
+    BT_ASSERT_DBG(msg_it->self_msg_iter);
+    BT_ASSERT_DBG(msg_it->meta.sc);
+
+    if (bt_stream_class_borrow_default_clock_class(msg_it->meta.sc->ir_sc)) {
+        msg = bt_message_event_create_with_packet_and_default_clock_snapshot(
+            msg_it->self_msg_iter, msg_it->meta.ec->ir_ec, msg_it->packet,
+            msg_it->default_clock_snapshot);
+    } else {
+        msg = bt_message_event_create_with_packet(msg_it->self_msg_iter, msg_it->meta.ec->ir_ec,
+                                                  msg_it->packet);
+    }
+
+    if (!msg) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
+                                     "Cannot create event message: "
+                                     "msg-it-addr={}, ec-addr={}, ec-name=\"{}\", "
+                                     "packet-addr={}",
+                                     fmt::ptr(msg_it), fmt::ptr(msg_it->meta.ec),
+                                     msg_it->meta.ec->name->str, fmt::ptr(msg_it->packet));
+        goto error;
+    }
+
+    goto end;
+
+error:
+    BT_MESSAGE_PUT_REF_AND_RESET(msg);
+    status = CTF_MSG_ITER_STATUS_ERROR;
+
+end:
+    BT_MESSAGE_MOVE_REF(msg_it->event_msg, msg);
+    return status;
+}
+
+static enum ctf_msg_iter_status after_event_header_state(struct ctf_msg_iter *msg_it)
+{
+    enum ctf_msg_iter_status status;
+
+    status = set_current_event_class(msg_it);
+    if (status != CTF_MSG_ITER_STATUS_OK) {
+        goto end;
+    }
+
+    if (G_UNLIKELY(msg_it->dry_run)) {
+        goto next_state;
+    }
+
+    status = set_current_event_message(msg_it);
+    if (status != CTF_MSG_ITER_STATUS_OK) {
+        goto end;
+    }
+
+    msg_it->event = bt_message_event_borrow_event(msg_it->event_msg);
+    BT_ASSERT_DBG(msg_it->event);
+
+next_state:
+    msg_it->state = STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN;
+
+end:
+    return status;
+}
+
+static enum ctf_msg_iter_status read_event_common_context_begin_state(struct ctf_msg_iter *msg_it)
+{
+    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
+    struct ctf_field_class *event_common_context_fc;
+
+    event_common_context_fc = msg_it->meta.sc->event_common_context_fc;
+    if (!event_common_context_fc) {
+        msg_it->state = STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN;
+        goto end;
+    }
+
+    if (event_common_context_fc->in_ir && !msg_it->dry_run) {
+        BT_ASSERT_DBG(!msg_it->dscopes.event_common_context);
+        msg_it->dscopes.event_common_context = bt_event_borrow_common_context_field(msg_it->event);
+        BT_ASSERT_DBG(msg_it->dscopes.event_common_context);
+    }
+
+    BT_CPPLOGT_SPEC(msg_it->logger,
+                    "Decoding event common context field: "
+                    "msg-it-addr={}, stream-class-addr={}, "
+                    "stream-class-id={}, "
+                    "fc-addr={}",
+                    fmt::ptr(msg_it), fmt::ptr(msg_it->meta.sc), msg_it->meta.sc->id,
+                    fmt::ptr(event_common_context_fc));
+    status = read_dscope_begin_state(
+        msg_it, event_common_context_fc, STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN,
+        STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE, msg_it->dscopes.event_common_context);
+    if (status < 0) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
+                                     "Cannot decode event common context field: "
+                                     "msg-it-addr={}, stream-class-addr={}, "
+                                     "stream-class-id={}, fc-addr={}",
+                                     fmt::ptr(msg_it), fmt::ptr(msg_it->meta.sc),
+                                     msg_it->meta.sc->id, fmt::ptr(event_common_context_fc));
+    }
+
+end:
+    return status;
+}
+
+static enum ctf_msg_iter_status
+read_event_common_context_continue_state(struct ctf_msg_iter *msg_it)
+{
+    return read_dscope_continue_state(msg_it, STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN);
+}
+
+static enum ctf_msg_iter_status read_event_spec_context_begin_state(struct ctf_msg_iter *msg_it)
+{
+    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
+    struct ctf_field_class *event_spec_context_fc;
+
+    event_spec_context_fc = msg_it->meta.ec->spec_context_fc;
+    if (!event_spec_context_fc) {
+        msg_it->state = STATE_DSCOPE_EVENT_PAYLOAD_BEGIN;
+        goto end;
+    }
+
+    if (event_spec_context_fc->in_ir && !msg_it->dry_run) {
+        BT_ASSERT_DBG(!msg_it->dscopes.event_spec_context);
+        msg_it->dscopes.event_spec_context = bt_event_borrow_specific_context_field(msg_it->event);
+        BT_ASSERT_DBG(msg_it->dscopes.event_spec_context);
+    }
+
+    BT_CPPLOGT_SPEC(msg_it->logger,
+                    "Decoding event specific context field: "
+                    "msg-it-addr={}, event-class-addr={}, "
+                    "event-class-name=\"{}\", event-class-id={}, "
+                    "fc-addr={}",
+                    fmt::ptr(msg_it), fmt::ptr(msg_it->meta.ec), msg_it->meta.ec->name->str,
+                    msg_it->meta.ec->id, fmt::ptr(event_spec_context_fc));
+    status = read_dscope_begin_state(
+        msg_it, event_spec_context_fc, STATE_DSCOPE_EVENT_PAYLOAD_BEGIN,
+        STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE, msg_it->dscopes.event_spec_context);
+    if (status < 0) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
+                                     "Cannot decode event specific context field: "
+                                     "msg-it-addr={}, event-class-addr={}, "
+                                     "event-class-name=\"{}\", "
+                                     "event-class-id={}, fc-addr={}",
+                                     fmt::ptr(msg_it), fmt::ptr(msg_it->meta.ec),
+                                     msg_it->meta.ec->name->str, msg_it->meta.ec->id,
+                                     fmt::ptr(event_spec_context_fc));
+    }
+
+end:
+    return status;
+}
+
+static enum ctf_msg_iter_status read_event_spec_context_continue_state(struct ctf_msg_iter *msg_it)
+{
+    return read_dscope_continue_state(msg_it, STATE_DSCOPE_EVENT_PAYLOAD_BEGIN);
+}
+
+static enum ctf_msg_iter_status read_event_payload_begin_state(struct ctf_msg_iter *msg_it)
+{
+    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
+    struct ctf_field_class *event_payload_fc;
+
+    event_payload_fc = msg_it->meta.ec->payload_fc;
+    if (!event_payload_fc) {
+        msg_it->state = STATE_EMIT_MSG_EVENT;
+        goto end;
+    }
+
+    if (event_payload_fc->in_ir && !msg_it->dry_run) {
+        BT_ASSERT_DBG(!msg_it->dscopes.event_payload);
+        msg_it->dscopes.event_payload = bt_event_borrow_payload_field(msg_it->event);
+        BT_ASSERT_DBG(msg_it->dscopes.event_payload);
+    }
+
+    BT_CPPLOGT_SPEC(msg_it->logger,
+                    "Decoding event payload field: "
+                    "msg-it-addr={}, event-class-addr={}, "
+                    "event-class-name=\"{}\", event-class-id={}, "
+                    "fc-addr={}",
+                    fmt::ptr(msg_it), fmt::ptr(msg_it->meta.ec), msg_it->meta.ec->name->str,
+                    msg_it->meta.ec->id, fmt::ptr(event_payload_fc));
+    status =
+        read_dscope_begin_state(msg_it, event_payload_fc, STATE_EMIT_MSG_EVENT,
+                                STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE, msg_it->dscopes.event_payload);
+    if (status < 0) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
+                                     "Cannot decode event payload field: "
+                                     "msg-it-addr={}, event-class-addr={}, "
+                                     "event-class-name=\"{}\", "
+                                     "event-class-id={}, fc-addr={}",
+                                     fmt::ptr(msg_it), fmt::ptr(msg_it->meta.ec),
+                                     msg_it->meta.ec->name->str, msg_it->meta.ec->id,
+                                     fmt::ptr(event_payload_fc));
+    }
+
+end:
+    return status;
+}
+
+static enum ctf_msg_iter_status read_event_payload_continue_state(struct ctf_msg_iter *msg_it)
+{
+    return read_dscope_continue_state(msg_it, STATE_EMIT_MSG_EVENT);
+}
+
+static enum ctf_msg_iter_status skip_packet_padding_state(struct ctf_msg_iter *msg_it)
+{
+    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
+    size_t bits_to_skip;
+    const enum state next_state = STATE_SWITCH_PACKET;
+
+    BT_ASSERT(msg_it->cur_exp_packet_total_size > 0);
+    bits_to_skip = msg_it->cur_exp_packet_total_size - packet_at(msg_it);
+    if (bits_to_skip == 0) {
+        msg_it->state = next_state;
+        goto end;
+    } else {
+        size_t bits_to_consume;
+
+        BT_CPPLOGD_SPEC(msg_it->logger,
+                        "Trying to skip {} bits of padding: msg-it-addr={}, size={}", bits_to_skip,
+                        fmt::ptr(msg_it), bits_to_skip);
+        status = buf_ensure_available_bits(msg_it);
+        if (status != CTF_MSG_ITER_STATUS_OK) {
+            goto end;
+        }
+
+        bits_to_consume = MIN(buf_available_bits(msg_it), bits_to_skip);
+        BT_CPPLOGD_SPEC(msg_it->logger, "Skipping {} bits of padding: msg-it-addr={}, size={}",
+                        bits_to_consume, fmt::ptr(msg_it), bits_to_consume);
+        buf_consume_bits(msg_it, bits_to_consume);
+        bits_to_skip = msg_it->cur_exp_packet_total_size - packet_at(msg_it);
+        if (bits_to_skip == 0) {
+            msg_it->state = next_state;
+            goto end;
+        }
+    }
+
+end:
+    return status;
+}
+
+static enum ctf_msg_iter_status check_emit_msg_discarded_events(struct ctf_msg_iter *msg_it)
+{
+    msg_it->state = STATE_EMIT_MSG_DISCARDED_EVENTS;
+
+    if (!msg_it->meta.sc->has_discarded_events) {
+        msg_it->state = STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS;
+        goto end;
+    }
+
+    if (msg_it->prev_packet_snapshots.discarded_events == UINT64_C(-1)) {
+        if (msg_it->snapshots.discarded_events == 0 ||
+            msg_it->snapshots.discarded_events == UINT64_C(-1)) {
+            /*
+             * Stream's first packet with no discarded
+             * events or no information about discarded
+             * events: do not emit.
+             */
+            msg_it->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(msg_it->snapshots.discarded_events != UINT64_C(-1));
+
+        if (msg_it->snapshots.discarded_events - msg_it->prev_packet_snapshots.discarded_events ==
+            0) {
+            /*
+             * No discarded events since previous packet: do
+             * not emit.
+             */
+            msg_it->state = STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS;
+        }
+    }
+
+end:
+    return CTF_MSG_ITER_STATUS_OK;
+}
+
+static enum ctf_msg_iter_status check_emit_msg_discarded_packets(struct ctf_msg_iter *msg_it)
+{
+    msg_it->state = STATE_EMIT_MSG_DISCARDED_PACKETS;
+
+    if (!msg_it->meta.sc->has_discarded_packets) {
+        msg_it->state = STATE_EMIT_MSG_PACKET_BEGINNING;
+        goto end;
+    }
+
+    if (msg_it->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).
+         */
+        msg_it->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(msg_it->snapshots.packets != UINT64_C(-1));
+
+        if (msg_it->snapshots.packets - msg_it->prev_packet_snapshots.packets <= 1) {
+            /*
+             * No discarded packets since previous packet:
+             * do not emit.
+             */
+            msg_it->state = STATE_EMIT_MSG_PACKET_BEGINNING;
+        }
+    }
+
+end:
+    return CTF_MSG_ITER_STATUS_OK;
+}
+
+static inline enum state check_emit_msg_stream_end(struct ctf_msg_iter *msg_it)
+{
+    enum state next_state;
+
+    if (msg_it->emit_stream_end_message) {
+        next_state = STATE_EMIT_MSG_STREAM_END;
+    } else {
+        next_state = STATE_DONE;
+    }
+
+    return next_state;
+}
+
+static inline enum ctf_msg_iter_status handle_state(struct ctf_msg_iter *msg_it)
+{
+    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
+    const enum state state = msg_it->state;
+
+    BT_CPPLOGT_SPEC(msg_it->logger, "Handling state: msg-it-addr={}, state={}", fmt::ptr(msg_it),
+                    state);
+
+    // TODO: optimalize!
+    switch (state) {
+    case STATE_INIT:
+        msg_it->state = STATE_SWITCH_PACKET;
+        break;
+    case STATE_SWITCH_PACKET:
+        status = switch_packet_state(msg_it);
+        break;
+    case STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN:
+        status = read_packet_header_begin_state(msg_it);
+        break;
+    case STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE:
+        status = read_packet_header_continue_state(msg_it);
+        break;
+    case STATE_AFTER_TRACE_PACKET_HEADER:
+        status = after_packet_header_state(msg_it);
+        break;
+    case STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN:
+        status = read_packet_context_begin_state(msg_it);
+        break;
+    case STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE:
+        status = read_packet_context_continue_state(msg_it);
+        break;
+    case STATE_AFTER_STREAM_PACKET_CONTEXT:
+        status = after_packet_context_state(msg_it);
+        break;
+    case STATE_EMIT_MSG_STREAM_BEGINNING:
+        msg_it->state = STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS;
+        break;
+    case STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS:
+        status = check_emit_msg_discarded_events(msg_it);
+        break;
+    case STATE_EMIT_MSG_DISCARDED_EVENTS:
+        msg_it->state = STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS;
+        break;
+    case STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS:
+        status = check_emit_msg_discarded_packets(msg_it);
+        break;
+    case STATE_EMIT_MSG_DISCARDED_PACKETS:
+        msg_it->state = STATE_EMIT_MSG_PACKET_BEGINNING;
+        break;
+    case STATE_EMIT_MSG_PACKET_BEGINNING:
+        msg_it->state = STATE_DSCOPE_EVENT_HEADER_BEGIN;
+        break;
+    case STATE_DSCOPE_EVENT_HEADER_BEGIN:
+        status = read_event_header_begin_state(msg_it);
+        break;
+    case STATE_DSCOPE_EVENT_HEADER_CONTINUE:
+        status = read_event_header_continue_state(msg_it);
+        break;
+    case STATE_AFTER_EVENT_HEADER:
+        status = after_event_header_state(msg_it);
+        break;
+    case STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN:
+        status = read_event_common_context_begin_state(msg_it);
+        break;
+    case STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE:
+        status = read_event_common_context_continue_state(msg_it);
+        break;
+    case STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN:
+        status = read_event_spec_context_begin_state(msg_it);
+        break;
+    case STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE:
+        status = read_event_spec_context_continue_state(msg_it);
+        break;
+    case STATE_DSCOPE_EVENT_PAYLOAD_BEGIN:
+        status = read_event_payload_begin_state(msg_it);
+        break;
+    case STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE:
+        status = read_event_payload_continue_state(msg_it);
+        break;
+    case STATE_EMIT_MSG_EVENT:
+        msg_it->state = STATE_DSCOPE_EVENT_HEADER_BEGIN;
+        break;
+    case STATE_EMIT_QUEUED_MSG_EVENT:
+        msg_it->state = STATE_EMIT_MSG_EVENT;
+        break;
+    case STATE_SKIP_PACKET_PADDING:
+        status = skip_packet_padding_state(msg_it);
+        break;
+    case STATE_EMIT_MSG_PACKET_END_MULTI:
+        msg_it->state = STATE_SKIP_PACKET_PADDING;
+        break;
+    case STATE_EMIT_MSG_PACKET_END_SINGLE:
+        msg_it->state = STATE_EMIT_MSG_STREAM_END;
+        break;
+    case STATE_EMIT_QUEUED_MSG_PACKET_END:
+        msg_it->state = STATE_EMIT_MSG_PACKET_END_SINGLE;
+        break;
+    case STATE_CHECK_EMIT_MSG_STREAM_END:
+        msg_it->state = check_emit_msg_stream_end(msg_it);
+        break;
+    case STATE_EMIT_MSG_STREAM_END:
+        msg_it->state = STATE_DONE;
+        break;
+    case STATE_DONE:
+        break;
+    default:
+        BT_CPPLOGF_SPEC(msg_it->logger,
+                        "Unknown CTF plugin message iterator state: "
+                        "msg-it-addr={}, state={}",
+                        fmt::ptr(msg_it), msg_it->state);
+        bt_common_abort();
+    }
+
+    BT_CPPLOGT_SPEC(msg_it->logger,
+                    "Handled state: msg-it-addr={}, status={}, "
+                    "prev-state={}, cur-state={}",
+                    fmt::ptr(msg_it), status, state, msg_it->state);
+    return status;
+}
+
+void ctf_msg_iter_reset_for_next_stream_file(struct ctf_msg_iter *msg_it)
+{
+    BT_ASSERT(msg_it);
+    BT_CPPLOGD_SPEC(msg_it->logger, "Resetting message iterator: addr={}", fmt::ptr(msg_it));
+    stack_clear(msg_it->stack);
+    msg_it->meta.sc = NULL;
+    msg_it->meta.ec = NULL;
+    BT_PACKET_PUT_REF_AND_RESET(msg_it->packet);
+    BT_STREAM_PUT_REF_AND_RESET(msg_it->stream);
+    BT_MESSAGE_PUT_REF_AND_RESET(msg_it->event_msg);
+    release_all_dscopes(msg_it);
+    msg_it->cur_dscope_field = NULL;
+
+    msg_it->buf.addr = NULL;
+    msg_it->buf.sz = 0;
+    msg_it->buf.at = 0;
+    msg_it->buf.last_eh_at = SIZE_MAX;
+    msg_it->buf.packet_offset = 0;
+    msg_it->state = STATE_INIT;
+    msg_it->cur_exp_packet_content_size = -1;
+    msg_it->cur_exp_packet_total_size = -1;
+    msg_it->cur_packet_offset = -1;
+    msg_it->cur_event_class_id = -1;
+    msg_it->snapshots.beginning_clock = UINT64_C(-1);
+    msg_it->snapshots.end_clock = UINT64_C(-1);
+}
+
+/**
+ * Resets the internal state of a CTF message iterator.
+ */
+void ctf_msg_iter_reset(struct ctf_msg_iter *msg_it)
+{
+    ctf_msg_iter_reset_for_next_stream_file(msg_it);
+    msg_it->cur_stream_class_id = -1;
+    msg_it->cur_data_stream_id = -1;
+    msg_it->snapshots.discarded_events = UINT64_C(-1);
+    msg_it->snapshots.packets = UINT64_C(-1);
+    msg_it->prev_packet_snapshots.discarded_events = UINT64_C(-1);
+    msg_it->prev_packet_snapshots.packets = UINT64_C(-1);
+    msg_it->prev_packet_snapshots.beginning_clock = UINT64_C(-1);
+    msg_it->prev_packet_snapshots.end_clock = UINT64_C(-1);
+    msg_it->emit_stream_beginning_message = true;
+    msg_it->emit_stream_end_message = false;
+}
+
+static bt_field *borrow_next_field(struct ctf_msg_iter *msg_it)
+{
+    bt_field *next_field = NULL;
+    bt_field *base_field;
+    const bt_field_class *base_fc;
+    bt_field_class_type base_fc_type;
+    size_t index;
+
+    BT_ASSERT_DBG(!stack_empty(msg_it->stack));
+    index = stack_top(msg_it->stack)->index;
+    base_field = stack_top(msg_it->stack)->base;
+    BT_ASSERT_DBG(base_field);
+    base_fc = bt_field_borrow_class_const(base_field);
+    BT_ASSERT_DBG(base_fc);
+    base_fc_type = bt_field_class_get_type(base_fc);
+
+    if (base_fc_type == BT_FIELD_CLASS_TYPE_STRUCTURE) {
+        BT_ASSERT_DBG(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);
+    } else if (bt_field_class_type_is(base_fc_type, BT_FIELD_CLASS_TYPE_ARRAY)) {
+        BT_ASSERT_DBG(index < bt_field_array_get_length(base_field));
+        next_field = bt_field_array_borrow_element_field_by_index(base_field, index);
+    } else if (bt_field_class_type_is(base_fc_type, BT_FIELD_CLASS_TYPE_VARIANT)) {
+        BT_ASSERT_DBG(index == 0);
+        next_field = bt_field_variant_borrow_selected_option_field(base_field);
+    } else {
+        bt_common_abort();
+    }
+
+    BT_ASSERT_DBG(next_field);
+    return next_field;
+}
+
+static void update_default_clock(struct ctf_msg_iter *msg_it, uint64_t new_val,
+                                 uint64_t new_val_size)
+{
+    uint64_t new_val_mask;
+    uint64_t cur_value_masked;
+
+    BT_ASSERT_DBG(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) {
+        msg_it->default_clock_snapshot = new_val;
+        goto end;
+    }
+
+    new_val_mask = (1ULL << new_val_size) - 1;
+    cur_value_masked = msg_it->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.
+         */
+        msg_it->default_clock_snapshot += new_val_mask + 1;
+    }
+
+    /* Clear the low bits of the current clock value. */
+    msg_it->default_clock_snapshot &= ~new_val_mask;
+
+    /* Set the low bits of the current clock value. */
+    msg_it->default_clock_snapshot |= new_val;
+
+end:
+    BT_CPPLOGT_SPEC(msg_it->logger,
+                    "Updated default clock's value from integer field's value: "
+                    "value={}",
+                    msg_it->default_clock_snapshot);
+}
+
+/*
+ * Ensure the message iterator's `stored_values` array is large enough to
+ * accommodate `storing_index`.
+ *
+ * We may need more slots in the array than initially allocated if more
+ * metadata arrives along the way.
+ */
+static void ensure_stored_values_size(ctf_msg_iter *msg_it, uint64_t storing_index)
+{
+    if (G_UNLIKELY(storing_index >= msg_it->stored_values->len)) {
+        g_array_set_size(msg_it->stored_values, msg_it->meta.tc->stored_value_count);
+    }
+}
+
+static enum bt_bfcr_status bfcr_unsigned_int_cb(uint64_t value, struct ctf_field_class *fc,
+                                                void *data)
+{
+    ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
+    enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
+
+    bt_field *field = NULL;
+
+    BT_CPPLOGT_SPEC(msg_it->logger,
+                    "Unsigned integer function called from BFCR: "
+                    "msg-it-addr={}, bfcr-addr={}, fc-addr={}, "
+                    "fc-type={}, fc-in-ir={}, value={}",
+                    fmt::ptr(msg_it), fmt::ptr(msg_it->bfcr), fmt::ptr(fc), fc->type, fc->in_ir,
+                    value);
+
+    ctf_field_class_int *int_fc = ctf_field_class_as_int(fc);
+
+    if (G_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:
+        msg_it->cur_event_class_id = value;
+        break;
+    case CTF_FIELD_CLASS_MEANING_DATA_STREAM_ID:
+        msg_it->cur_data_stream_id = value;
+        break;
+    case CTF_FIELD_CLASS_MEANING_PACKET_BEGINNING_TIME:
+        msg_it->snapshots.beginning_clock = value;
+        break;
+    case CTF_FIELD_CLASS_MEANING_PACKET_END_TIME:
+        msg_it->snapshots.end_clock = value;
+        break;
+    case CTF_FIELD_CLASS_MEANING_STREAM_CLASS_ID:
+        msg_it->cur_stream_class_id = value;
+        break;
+    case CTF_FIELD_CLASS_MEANING_MAGIC:
+        if (value != 0xc1fc1fc1) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
+                                         "Invalid CTF magic number: msg-it-addr={}, magic={}",
+                                         fmt::ptr(msg_it), value);
+            status = BT_BFCR_STATUS_ERROR;
+            goto end;
+        }
+
+        break;
+    case CTF_FIELD_CLASS_MEANING_PACKET_COUNTER_SNAPSHOT:
+        msg_it->snapshots.packets = value;
+        break;
+    case CTF_FIELD_CLASS_MEANING_DISC_EV_REC_COUNTER_SNAPSHOT:
+        msg_it->snapshots.discarded_events = value;
+        break;
+    case CTF_FIELD_CLASS_MEANING_EXP_PACKET_TOTAL_SIZE:
+        msg_it->cur_exp_packet_total_size = value;
+        break;
+    case CTF_FIELD_CLASS_MEANING_EXP_PACKET_CONTENT_SIZE:
+        msg_it->cur_exp_packet_content_size = value;
+        break;
+    default:
+        bt_common_abort();
+    }
+
+update_def_clock:
+    if (G_UNLIKELY(int_fc->mapped_clock_class)) {
+        update_default_clock(msg_it, value, int_fc->base.size);
+    }
+
+    if (G_UNLIKELY(int_fc->storing_index >= 0)) {
+        ensure_stored_values_size(msg_it, int_fc->storing_index);
+        bt_g_array_index(msg_it->stored_values, uint64_t, (uint64_t) int_fc->storing_index) = value;
+    }
+
+    if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) {
+        goto end;
+    }
+
+    field = borrow_next_field(msg_it);
+    BT_ASSERT_DBG(field);
+    BT_ASSERT_DBG(bt_field_borrow_class_const(field) == fc->ir_fc);
+    BT_ASSERT_DBG(bt_field_class_type_is(bt_field_get_class_type(field),
+                                         BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER));
+    bt_field_integer_unsigned_set_value(field, value);
+    stack_top(msg_it->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;
+    ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
+    enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
+    bt_field *string_field = NULL;
+    char str[2] = {'\0', '\0'};
+
+    BT_CPPLOGT_SPEC(msg_it->logger,
+                    "Unsigned integer character function called from BFCR: "
+                    "msg-it-addr={}, bfcr-addr={}, fc-addr={}, "
+                    "fc-type={}, fc-in-ir={}, value={}",
+                    fmt::ptr(msg_it), fmt::ptr(msg_it->bfcr), fmt::ptr(fc), fc->type, fc->in_ir,
+                    value);
+
+    ctf_field_class_int *int_fc = ctf_field_class_as_int(fc);
+    BT_ASSERT_DBG(int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE);
+    BT_ASSERT_DBG(!int_fc->mapped_clock_class);
+    BT_ASSERT_DBG(int_fc->storing_index < 0);
+
+    if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) {
+        goto end;
+    }
+
+    if (msg_it->done_filling_string) {
+        goto end;
+    }
+
+    if (value == 0) {
+        msg_it->done_filling_string = true;
+        goto end;
+    }
+
+    string_field = stack_top(msg_it->stack)->base;
+    BT_ASSERT_DBG(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_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
+                                     "Cannot append character to string field's value: "
+                                     "msg-it-addr={}, field-addr={}, ret={}",
+                                     fmt::ptr(msg_it), fmt::ptr(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;
+    ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
+
+    BT_CPPLOGT_SPEC(msg_it->logger,
+                    "Signed integer function called from BFCR: "
+                    "msg-it-addr={}, bfcr-addr={}, fc-addr={}, "
+                    "fc-type={}, fc-in-ir={}, value={}",
+                    fmt::ptr(msg_it), fmt::ptr(msg_it->bfcr), fmt::ptr(fc), fc->type, fc->in_ir,
+                    value);
+
+    ctf_field_class_int *int_fc = ctf_field_class_as_int(fc);
+    BT_ASSERT_DBG(int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE);
+
+    if (G_UNLIKELY(int_fc->storing_index >= 0)) {
+        ensure_stored_values_size(msg_it, int_fc->storing_index);
+        bt_g_array_index(msg_it->stored_values, uint64_t, (uint64_t) int_fc->storing_index) =
+            (uint64_t) value;
+    }
+
+    if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) {
+        goto end;
+    }
+
+    field = borrow_next_field(msg_it);
+    BT_ASSERT_DBG(field);
+    BT_ASSERT_DBG(bt_field_borrow_class_const(field) == fc->ir_fc);
+    BT_ASSERT_DBG(
+        bt_field_class_type_is(bt_field_get_class_type(field), BT_FIELD_CLASS_TYPE_SIGNED_INTEGER));
+    bt_field_integer_signed_set_value(field, value);
+    stack_top(msg_it->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;
+    ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
+    bt_field_class_type type;
+
+    BT_CPPLOGT_SPEC(msg_it->logger,
+                    "Floating point number function called from BFCR: "
+                    "msg-it-addr={}, bfcr-addr={}, fc-addr={}, "
+                    "fc-type={}, fc-in-ir={}, value={}",
+                    fmt::ptr(msg_it), fmt::ptr(msg_it->bfcr), fmt::ptr(fc), fc->type, fc->in_ir,
+                    value);
+
+    if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) {
+        goto end;
+    }
+
+    field = borrow_next_field(msg_it);
+    type = bt_field_get_class_type(field);
+    BT_ASSERT_DBG(field);
+    BT_ASSERT_DBG(bt_field_borrow_class_const(field) == fc->ir_fc);
+    BT_ASSERT_DBG(bt_field_class_type_is(type, BT_FIELD_CLASS_TYPE_REAL));
+
+    if (type == BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL) {
+        bt_field_real_single_precision_set_value(field, (float) value);
+    } else {
+        bt_field_real_double_precision_set_value(field, value);
+    }
+    stack_top(msg_it->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;
+    ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
+
+    BT_CPPLOGT_SPEC(msg_it->logger,
+                    "String (beginning) function called from BFCR: "
+                    "msg-it-addr={}, bfcr-addr={}, fc-addr={}, "
+                    "fc-type={}, fc-in-ir={}",
+                    fmt::ptr(msg_it), fmt::ptr(msg_it->bfcr), fmt::ptr(fc), fc->type, fc->in_ir);
+
+    if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) {
+        goto end;
+    }
+
+    field = borrow_next_field(msg_it);
+    BT_ASSERT_DBG(field);
+    BT_ASSERT_DBG(bt_field_borrow_class_const(field) == fc->ir_fc);
+    BT_ASSERT_DBG(bt_field_get_class_type(field) == BT_FIELD_CLASS_TYPE_STRING);
+    bt_field_string_clear(field);
+
+    /*
+     * 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(msg_it->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;
+    ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
+    int ret;
+
+    BT_CPPLOGT_SPEC(msg_it->logger,
+                    "String (substring) function called from BFCR: "
+                    "msg-it-addr={}, bfcr-addr={}, fc-addr={}, "
+                    "fc-type={}, fc-in-ir={}, string-length={}",
+                    fmt::ptr(msg_it), fmt::ptr(msg_it->bfcr), fmt::ptr(fc), fc->type, fc->in_ir,
+                    len);
+
+    if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) {
+        goto end;
+    }
+
+    field = stack_top(msg_it->stack)->base;
+    BT_ASSERT_DBG(field);
+
+    /* Append current substring */
+    ret = bt_field_string_append_with_length(field, value, len);
+    if (ret) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
+                                     "Cannot append substring to string field's value: "
+                                     "msg-it-addr={}, field-addr={}, string-length={}, "
+                                     "ret={}",
+                                     fmt::ptr(msg_it), fmt::ptr(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)
+{
+    ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
+
+    BT_CPPLOGT_SPEC(msg_it->logger,
+                    "String (end) function called from BFCR: "
+                    "msg-it-addr={}, bfcr-addr={}, fc-addr={}, "
+                    "fc-type={}, fc-in-ir={}",
+                    fmt::ptr(msg_it), fmt::ptr(msg_it->bfcr), fmt::ptr(fc), fc->type, fc->in_ir);
+
+    if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) {
+        goto end;
+    }
+
+    /* Pop string field */
+    stack_pop(msg_it->stack);
+
+    /* Go to next field */
+    stack_top(msg_it->stack)->index++;
+
+end:
+    return BT_BFCR_STATUS_OK;
+}
+
+static enum bt_bfcr_status bfcr_compound_begin_cb(struct ctf_field_class *fc, void *data)
+{
+    ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
+    bt_field *field;
+
+    BT_CPPLOGT_SPEC(msg_it->logger,
+                    "Compound (beginning) function called from BFCR: "
+                    "msg-it-addr={}, bfcr-addr={}, fc-addr={}, "
+                    "fc-type={}, fc-in-ir={}",
+                    fmt::ptr(msg_it), fmt::ptr(msg_it->bfcr), fmt::ptr(fc), fc->type, fc->in_ir);
+
+    if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) {
+        goto end;
+    }
+
+    /* Borrow field */
+    if (stack_empty(msg_it->stack)) {
+        /* Root: already set by read_dscope_begin_state() */
+        field = msg_it->cur_dscope_field;
+    } else {
+        field = borrow_next_field(msg_it);
+        BT_ASSERT_DBG(field);
+    }
+
+    /* Push field */
+    BT_ASSERT_DBG(field);
+    BT_ASSERT_DBG(bt_field_borrow_class_const(field) == fc->ir_fc);
+    stack_push(msg_it->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) {
+        ctf_field_class_array_base *array_fc = ctf_field_class_as_array_base(fc);
+
+        if (array_fc->is_text) {
+            BT_ASSERT_DBG(bt_field_get_class_type(field) == BT_FIELD_CLASS_TYPE_STRING);
+            msg_it->done_filling_string = false;
+            bt_field_string_clear(field);
+            bt_bfcr_set_unsigned_int_cb(msg_it->bfcr, bfcr_unsigned_int_char_cb);
+        }
+    }
+
+end:
+    return BT_BFCR_STATUS_OK;
+}
+
+static enum bt_bfcr_status bfcr_compound_end_cb(struct ctf_field_class *fc, void *data)
+{
+    ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
+
+    BT_CPPLOGT_SPEC(msg_it->logger,
+                    "Compound (end) function called from BFCR: "
+                    "msg-it-addr={}, bfcr-addr={}, fc-addr={}, "
+                    "fc-type={}, fc-in-ir={}",
+                    fmt::ptr(msg_it), fmt::ptr(msg_it->bfcr), fmt::ptr(fc), fc->type, fc->in_ir);
+
+    if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) {
+        goto end;
+    }
+
+    BT_ASSERT_DBG(!stack_empty(msg_it->stack));
+    BT_ASSERT_DBG(bt_field_borrow_class_const(stack_top(msg_it->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) {
+        ctf_field_class_array_base *array_fc = ctf_field_class_as_array_base(fc);
+
+        if (array_fc->is_text) {
+            BT_ASSERT_DBG(bt_field_get_class_type(stack_top(msg_it->stack)->base) ==
+                          BT_FIELD_CLASS_TYPE_STRING);
+            bt_bfcr_set_unsigned_int_cb(msg_it->bfcr, bfcr_unsigned_int_cb);
+        }
+    }
+
+    /* Pop stack */
+    stack_pop(msg_it->stack);
+
+    /* If the stack is not empty, increment the base's index */
+    if (!stack_empty(msg_it->stack)) {
+        stack_top(msg_it->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;
+    ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
+    struct ctf_field_class_sequence *seq_fc = ctf_field_class_as_sequence(fc);
+    int64_t length;
+    int ret;
+
+    length =
+        (uint64_t) bt_g_array_index(msg_it->stored_values, uint64_t, seq_fc->stored_length_index);
+
+    if (G_UNLIKELY(msg_it->dry_run)) {
+        goto end;
+    }
+
+    seq_field = stack_top(msg_it->stack)->base;
+    BT_ASSERT_DBG(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_DBG(bt_field_class_type_is(bt_field_get_class_type(seq_field),
+                                             BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY));
+        ret = bt_field_array_dynamic_set_length(seq_field, (uint64_t) length);
+        if (ret) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
+                                         "Cannot set dynamic array field's length field: "
+                                         "msg-it-addr={}, field-addr={}, "
+                                         "length={}",
+                                         fmt::ptr(msg_it), fmt::ptr(seq_field), length);
+            length = -1;
+        }
+    }
+
+end:
+    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;
+    ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
+    ctf_field_class_variant *var_fc = ctf_field_class_as_variant(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 = bt_g_array_index(msg_it->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_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
+                                     "Cannot find variant field class's option: "
+                                     "msg-it-addr={}, var-fc-addr={}, u-tag={}, "
+                                     "i-tag={}",
+                                     fmt::ptr(msg_it), fmt::ptr(var_fc), tag.u, tag.i);
+        ret_fc = NULL;
+        goto end;
+    }
+
+    selected_option =
+        ctf_field_class_variant_borrow_option_by_index(var_fc, (uint64_t) option_index);
+
+    if (selected_option->fc->in_ir && !msg_it->dry_run) {
+        bt_field *var_field = stack_top(msg_it->stack)->base;
+
+        ret = bt_field_variant_select_option_by_index(var_field, option_index);
+        if (ret) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
+                                         "Cannot select variant field's option field: "
+                                         "msg-it-addr={}, var-field-addr={}, "
+                                         "opt-index={}",
+                                         fmt::ptr(msg_it), fmt::ptr(var_field), option_index);
+            ret_fc = NULL;
+            goto end;
+        }
+    }
+
+    ret_fc = selected_option->fc;
+
+end:
+    return ret_fc;
+}
+
+static bt_message *create_msg_stream_beginning(struct ctf_msg_iter *msg_it)
+{
+    bt_message *msg;
+
+    BT_ASSERT(msg_it->stream);
+    BT_ASSERT(msg_it->self_msg_iter);
+    msg = bt_message_stream_beginning_create(msg_it->self_msg_iter, msg_it->stream);
+    if (!msg) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
+                                     "Cannot create stream beginning message: "
+                                     "msg-it-addr={}, stream-addr={}",
+                                     fmt::ptr(msg_it), fmt::ptr(msg_it->stream));
+    }
+
+    return msg;
+}
+
+static bt_message *create_msg_stream_end(struct ctf_msg_iter *msg_it)
+{
+    bt_message *msg;
+
+    if (!msg_it->stream) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
+                                     "Cannot create stream end message because stream is NULL: "
+                                     "msg-it-addr={}",
+                                     fmt::ptr(msg_it));
+        msg = NULL;
+        goto end;
+    }
+
+    BT_ASSERT(msg_it->self_msg_iter);
+    msg = bt_message_stream_end_create(msg_it->self_msg_iter, msg_it->stream);
+    if (!msg) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
+                                     "Cannot create stream end message: "
+                                     "msg-it-addr={}, stream-addr={}",
+                                     fmt::ptr(msg_it), fmt::ptr(msg_it->stream));
+    }
+
+end:
+    return msg;
+}
+
+static bt_message *create_msg_packet_beginning(struct ctf_msg_iter *msg_it, bool use_default_cs)
+{
+    bt_message *msg;
+    const bt_stream_class *sc = msg_it->meta.sc->ir_sc;
+
+    BT_ASSERT(msg_it->packet);
+    BT_ASSERT(sc);
+    BT_ASSERT(msg_it->self_msg_iter);
+
+    if (msg_it->meta.sc->packets_have_ts_begin) {
+        BT_ASSERT(msg_it->snapshots.beginning_clock != UINT64_C(-1));
+        uint64_t raw_cs_value;
+
+        /*
+         * Either use the decoded packet `timestamp_begin` field or the
+         * current stream's default clock_snapshot.
+         */
+        if (use_default_cs) {
+            raw_cs_value = msg_it->default_clock_snapshot;
+        } else {
+            raw_cs_value = msg_it->snapshots.beginning_clock;
+        }
+
+        msg = bt_message_packet_beginning_create_with_default_clock_snapshot(
+            msg_it->self_msg_iter, msg_it->packet, raw_cs_value);
+    } else {
+        msg = bt_message_packet_beginning_create(msg_it->self_msg_iter, msg_it->packet);
+    }
+
+    if (!msg) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
+                                     "Cannot create packet beginning message: "
+                                     "msg-it-addr={}, packet-addr={}",
+                                     fmt::ptr(msg_it), fmt::ptr(msg_it->packet));
+        goto end;
+    }
+
+end:
+    return msg;
+}
+
+static bt_message *emit_delayed_packet_beg_msg(struct ctf_msg_iter *msg_it)
+{
+    bool packet_beg_ts_need_fix_up;
+
+    msg_it->emit_delayed_packet_beginning_msg = false;
+
+    /*
+     * Only fix the packet's timestamp_begin if it's larger than the first
+     * event of the packet. If there was no event in the packet, the
+     * `default_clock_snapshot` field will be either equal or greater than
+     * `snapshots.beginning_clock` so there is not fix needed.
+     */
+    packet_beg_ts_need_fix_up = msg_it->default_clock_snapshot < msg_it->snapshots.beginning_clock;
+
+    /* create_msg_packet_beginning() logs errors */
+    return create_msg_packet_beginning(msg_it, packet_beg_ts_need_fix_up);
+}
+
+static bt_message *create_msg_packet_end(struct ctf_msg_iter *msg_it)
+{
+    bt_message *msg;
+    bool update_default_cs = true;
+
+    if (!msg_it->packet) {
+        msg = NULL;
+        goto end;
+    }
+
+    /*
+     * Check if we need to emit the delayed packet
+     * beginning message instead of the packet end message.
+     */
+    if (G_UNLIKELY(msg_it->emit_delayed_packet_beginning_msg)) {
+        msg = emit_delayed_packet_beg_msg(msg_it);
+        /* Don't forget to emit the packet end message. */
+        msg_it->state = STATE_EMIT_QUEUED_MSG_PACKET_END;
+        goto end;
+    }
+
+    /* Check if may be affected by lttng-crash timestamp_end quirk. */
+    if (G_UNLIKELY(msg_it->meta.tc->quirks.lttng_crash)) {
+        /*
+         * Check if the `timestamp_begin` field is non-zero but
+         * `timestamp_end` is zero. It means the trace is affected by
+         * the lttng-crash packet `timestamp_end` quirk and must be
+         * fixed up by omitting to update the default clock snapshot to
+         * the `timestamp_end` as is typically done.
+         */
+        if (msg_it->snapshots.beginning_clock != 0 && msg_it->snapshots.end_clock == 0) {
+            update_default_cs = false;
+        }
+    }
+
+    /*
+     * Check if may be affected by lttng event-after-packet `timestamp_end`
+     * quirk.
+     */
+    if (msg_it->meta.tc->quirks.lttng_event_after_packet) {
+        /*
+         * Check if `timestamp_end` is smaller then the current
+         * default_clock_snapshot (which is set to the last event
+         * decoded). It means the trace is affected by the lttng
+         * `event-after-packet` packet `timestamp_end` quirk and must
+         * be fixed up by omitting to update the default clock snapshot
+         * to the `timestamp_end` as is typically done.
+         */
+        if (msg_it->snapshots.end_clock < msg_it->default_clock_snapshot) {
+            update_default_cs = false;
+        }
+    }
+
+    /* Update default clock from packet's end time. */
+    if (msg_it->snapshots.end_clock != UINT64_C(-1) && update_default_cs) {
+        msg_it->default_clock_snapshot = msg_it->snapshots.end_clock;
+    }
+
+    BT_ASSERT(msg_it->self_msg_iter);
+
+    if (msg_it->meta.sc->packets_have_ts_end) {
+        BT_ASSERT(msg_it->snapshots.end_clock != UINT64_C(-1));
+        msg = bt_message_packet_end_create_with_default_clock_snapshot(
+            msg_it->self_msg_iter, msg_it->packet, msg_it->default_clock_snapshot);
+    } else {
+        msg = bt_message_packet_end_create(msg_it->self_msg_iter, msg_it->packet);
+    }
+
+    if (!msg) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
+                                     "Cannot create packet end message: "
+                                     "msg-it-addr={}, packet-addr={}",
+                                     fmt::ptr(msg_it), fmt::ptr(msg_it->packet));
+        goto end;
+    }
+
+    BT_PACKET_PUT_REF_AND_RESET(msg_it->packet);
+
+end:
+    return msg;
+}
+
+static bt_message *create_msg_discarded_events(struct ctf_msg_iter *msg_it)
+{
+    bt_message *msg;
+    uint64_t beginning_raw_value = UINT64_C(-1);
+    uint64_t end_raw_value = UINT64_C(-1);
+
+    BT_ASSERT(msg_it->self_msg_iter);
+    BT_ASSERT(msg_it->stream);
+    BT_ASSERT(msg_it->meta.sc->has_discarded_events);
+
+    if (msg_it->meta.sc->discarded_events_have_default_cs) {
+        if (msg_it->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 = msg_it->snapshots.beginning_clock;
+            end_raw_value = msg_it->snapshots.end_clock;
+        } else {
+            beginning_raw_value = msg_it->prev_packet_snapshots.end_clock;
+            end_raw_value = msg_it->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(
+            msg_it->self_msg_iter, msg_it->stream, beginning_raw_value, end_raw_value);
+    } else {
+        msg = bt_message_discarded_events_create(msg_it->self_msg_iter, msg_it->stream);
+    }
+
+    if (!msg) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
+                                     "Cannot create discarded events message: "
+                                     "msg-it-addr={}, stream-addr={}",
+                                     fmt::ptr(msg_it), fmt::ptr(msg_it->stream));
+        goto end;
+    }
+
+    if (msg_it->prev_packet_snapshots.discarded_events != UINT64_C(-1)) {
+        bt_message_discarded_events_set_count(msg,
+                                              msg_it->snapshots.discarded_events -
+                                                  msg_it->prev_packet_snapshots.discarded_events);
+    }
+
+end:
+    return msg;
+}
+
+static bt_message *create_msg_discarded_packets(struct ctf_msg_iter *msg_it)
+{
+    bt_message *msg;
+
+    BT_ASSERT(msg_it->self_msg_iter);
+    BT_ASSERT(msg_it->stream);
+    BT_ASSERT(msg_it->meta.sc->has_discarded_packets);
+    BT_ASSERT(msg_it->prev_packet_snapshots.packets != UINT64_C(-1));
+
+    if (msg_it->meta.sc->discarded_packets_have_default_cs) {
+        BT_ASSERT(msg_it->prev_packet_snapshots.end_clock != UINT64_C(-1));
+        BT_ASSERT(msg_it->snapshots.beginning_clock != UINT64_C(-1));
+        msg = bt_message_discarded_packets_create_with_default_clock_snapshots(
+            msg_it->self_msg_iter, msg_it->stream, msg_it->prev_packet_snapshots.end_clock,
+            msg_it->snapshots.beginning_clock);
+    } else {
+        msg = bt_message_discarded_packets_create(msg_it->self_msg_iter, msg_it->stream);
+    }
+
+    if (!msg) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
+                                     "Cannot create discarded packets message: "
+                                     "msg-it-addr={}, stream-addr={}",
+                                     fmt::ptr(msg_it), fmt::ptr(msg_it->stream));
+        goto end;
+    }
+
+    bt_message_discarded_packets_set_count(msg, msg_it->snapshots.packets -
+                                                    msg_it->prev_packet_snapshots.packets - 1);
+
+end:
+    return msg;
+}
+
+ctf_msg_iter_up ctf_msg_iter_create(struct ctf_trace_class *tc, size_t max_request_sz,
+                                    struct ctf_msg_iter_medium_ops medops, void *data,
+                                    bt_self_message_iterator *self_msg_iter,
+                                    const bt2c::Logger& parentLogger)
+{
+    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_ASSERT(max_request_sz > 0);
+
+    bt2c::Logger logger {parentLogger, "PLUGIN/CTF/MSG-ITER"};
+    BT_CPPLOGD_SPEC(logger,
+                    "Creating CTF plugin message iterator: "
+                    "trace-addr={}, max-request-size={}, "
+                    "data={}, log-level={}",
+                    fmt::ptr(tc), max_request_sz, fmt::ptr(data), logger.level());
+
+    ctf_msg_iter_up msg_it {new ctf_msg_iter {std::move(logger)}};
+    msg_it->self_msg_iter = self_msg_iter;
+    msg_it->meta.tc = tc;
+    msg_it->medium.medops = medops;
+    msg_it->medium.max_request_sz = max_request_sz;
+    msg_it->medium.data = data;
+    msg_it->stack = stack_new(msg_it.get());
+    msg_it->stored_values = g_array_new(FALSE, TRUE, sizeof(uint64_t));
+    g_array_set_size(msg_it->stored_values, tc->stored_value_count);
+
+    if (!msg_it->stack) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger, "Failed to create field stack.");
+        goto error;
+    }
+
+    msg_it->bfcr = bt_bfcr_create(cbs, msg_it.get(), msg_it->logger);
+    if (!msg_it->bfcr) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
+                                     "Failed to create binary class reader (BFCR).");
+        goto error;
+    }
+
+    ctf_msg_iter_reset(msg_it.get());
+    BT_CPPLOGD_SPEC(msg_it->logger,
+                    "Created CTF plugin message iterator: "
+                    "trace-addr={}, max-request-size={}, "
+                    "data={}, msg-it-addr={}, log-level={}",
+                    fmt::ptr(tc), max_request_sz, fmt::ptr(data), fmt::ptr(msg_it),
+                    msg_it->logger.level());
+    msg_it->cur_packet_offset = 0;
+
+end:
+    return msg_it;
+
+error:
+    msg_it.reset();
+    goto end;
+}
+
+void ctf_msg_iter_destroy(struct ctf_msg_iter *msg_it)
+{
+    BT_PACKET_PUT_REF_AND_RESET(msg_it->packet);
+    BT_STREAM_PUT_REF_AND_RESET(msg_it->stream);
+    release_all_dscopes(msg_it);
+
+    BT_CPPLOGD_SPEC(msg_it->logger, "Destroying CTF plugin message iterator: addr={}",
+                    fmt::ptr(msg_it));
+
+    if (msg_it->stack) {
+        BT_CPPLOGD_SPEC(msg_it->logger, "Destroying field stack.");
+        stack_destroy(msg_it->stack);
+    }
+
+    if (msg_it->bfcr) {
+        BT_CPPLOGD_SPEC(msg_it->logger, "Destroying BFCR: bfcr-addr={}", fmt::ptr(msg_it->bfcr));
+        bt_bfcr_destroy(msg_it->bfcr);
+    }
+
+    if (msg_it->stored_values) {
+        g_array_free(msg_it->stored_values, TRUE);
+    }
+
+    delete msg_it;
+}
+
+void ctf_msg_iter_deleter::operator()(ctf_msg_iter *iter) noexcept
+{
+    ctf_msg_iter_destroy(iter);
+}
+
+enum ctf_msg_iter_status ctf_msg_iter_get_next_message(struct ctf_msg_iter *msg_it,
+                                                       const bt_message **message)
+{
+    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
+
+    BT_ASSERT_DBG(msg_it);
+    BT_ASSERT_DBG(message);
+    BT_CPPLOGD_SPEC(msg_it->logger, "Getting next message: msg-it-addr={}", fmt::ptr(msg_it));
+
+    while (true) {
+        status = handle_state(msg_it);
+        if (G_UNLIKELY(status == CTF_MSG_ITER_STATUS_AGAIN)) {
+            BT_CPPLOGD_SPEC(msg_it->logger, "Medium returned CTF_MSG_ITER_STATUS_AGAIN.");
+            goto end;
+        } else if (G_UNLIKELY(status != CTF_MSG_ITER_STATUS_OK)) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
+                                         "Cannot handle state: msg-it-addr={}, state={}",
+                                         fmt::ptr(msg_it), msg_it->state);
+            goto end;
+        }
+
+        switch (msg_it->state) {
+        case STATE_EMIT_MSG_EVENT:
+            BT_ASSERT_DBG(msg_it->event_msg);
+
+            /*
+             * Check if we need to emit the delayed packet
+             * beginning message instead of the event message.
+             */
+            if (G_UNLIKELY(msg_it->emit_delayed_packet_beginning_msg)) {
+                *message = emit_delayed_packet_beg_msg(msg_it);
+                if (!*message) {
+                    status = CTF_MSG_ITER_STATUS_ERROR;
+                }
+
+                /*
+                 * Don't forget to emit the event message of
+                 * the event record that was just decoded.
+                 */
+                msg_it->state = STATE_EMIT_QUEUED_MSG_EVENT;
+
+            } else {
+                *message = msg_it->event_msg;
+                msg_it->event_msg = NULL;
+            }
+            goto end;
+        case STATE_EMIT_MSG_DISCARDED_EVENTS:
+            /* create_msg_discarded_events() logs errors */
+            *message = create_msg_discarded_events(msg_it);
+
+            if (!*message) {
+                status = CTF_MSG_ITER_STATUS_ERROR;
+            }
+
+            goto end;
+        case STATE_EMIT_MSG_DISCARDED_PACKETS:
+            /* create_msg_discarded_packets() logs errors */
+            *message = create_msg_discarded_packets(msg_it);
+
+            if (!*message) {
+                status = CTF_MSG_ITER_STATUS_ERROR;
+            }
+
+            goto end;
+        case STATE_EMIT_MSG_PACKET_BEGINNING:
+            if (G_UNLIKELY(msg_it->meta.tc->quirks.barectf_event_before_packet)) {
+                msg_it->emit_delayed_packet_beginning_msg = true;
+                /*
+                 * There is no message to return yet as this
+                 * packet beginning message is delayed until we
+                 * decode the first event message of the
+                 * packet.
+                 */
+                break;
+            } else {
+                /* create_msg_packet_beginning() logs errors */
+                *message = create_msg_packet_beginning(msg_it, false);
+                if (!*message) {
+                    status = CTF_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 */
+            *message = create_msg_packet_end(msg_it);
+
+            if (!*message) {
+                status = CTF_MSG_ITER_STATUS_ERROR;
+            }
+
+            goto end;
+        case STATE_EMIT_MSG_STREAM_BEGINNING:
+            /* create_msg_stream_beginning() logs errors */
+            *message = create_msg_stream_beginning(msg_it);
+            msg_it->emit_stream_beginning_message = false;
+            msg_it->emit_stream_end_message = true;
+
+            if (!*message) {
+                status = CTF_MSG_ITER_STATUS_ERROR;
+            }
+
+            goto end;
+        case STATE_EMIT_MSG_STREAM_END:
+            /* create_msg_stream_end() logs errors */
+            *message = create_msg_stream_end(msg_it);
+            msg_it->emit_stream_end_message = false;
+
+            if (!*message) {
+                status = CTF_MSG_ITER_STATUS_ERROR;
+            }
+
+            goto end;
+        case STATE_DONE:
+            status = CTF_MSG_ITER_STATUS_EOF;
+            goto end;
+        default:
+            /* Non-emitting state: continue */
+            break;
+        }
+    }
+
+end:
+    return status;
+}
+
+static enum ctf_msg_iter_status decode_until_state(struct ctf_msg_iter *msg_it,
+                                                   enum state target_state_1,
+                                                   enum state target_state_2)
+{
+    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
+
+    BT_ASSERT_DBG(msg_it);
+
+    do {
+        /*
+         * Check if we reached the state at which we want to stop
+         * decoding.
+         */
+        if (msg_it->state == target_state_1 || msg_it->state == target_state_2) {
+            goto end;
+        }
+
+        status = handle_state(msg_it);
+        if (G_UNLIKELY(status == CTF_MSG_ITER_STATUS_AGAIN)) {
+            BT_CPPLOGD_SPEC(msg_it->logger, "Medium returned CTF_MSG_ITER_STATUS_AGAIN.");
+            goto end;
+        } else if (G_UNLIKELY(status != CTF_MSG_ITER_STATUS_OK)) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
+                                         "Cannot handle state: msg-it-addr={}, state={}",
+                                         fmt::ptr(msg_it), msg_it->state);
+            goto end;
+        }
+
+        switch (msg_it->state) {
+        case STATE_INIT:
+        case STATE_SWITCH_PACKET:
+        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_EMIT_MSG_STREAM_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:
+        case STATE_EMIT_MSG_PACKET_BEGINNING:
+        case STATE_DSCOPE_EVENT_HEADER_BEGIN:
+        case STATE_DSCOPE_EVENT_HEADER_CONTINUE:
+        case STATE_AFTER_EVENT_HEADER:
+        case STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN:
+        case STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE:
+        case STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN:
+        case STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE:
+        case STATE_DSCOPE_EVENT_PAYLOAD_BEGIN:
+        case STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE:
+        case STATE_EMIT_MSG_EVENT:
+        case STATE_EMIT_QUEUED_MSG_EVENT:
+        case STATE_SKIP_PACKET_PADDING:
+        case STATE_EMIT_MSG_PACKET_END_MULTI:
+        case STATE_EMIT_MSG_PACKET_END_SINGLE:
+        case STATE_EMIT_QUEUED_MSG_PACKET_END:
+        case STATE_EMIT_MSG_STREAM_END:
+            break;
+        case STATE_DONE:
+            /* fall-through */
+        default:
+            /* We should never get to the STATE_DONE state. */
+            BT_CPPLOGF_SPEC(msg_it->logger, "Unexpected state: msg-it-addr={}, state={}",
+                            fmt::ptr(msg_it), msg_it->state);
+            bt_common_abort();
+        }
+    } while (true);
+
+end:
+    return status;
+}
+
+static enum ctf_msg_iter_status read_packet_header_context_fields(struct ctf_msg_iter *msg_it)
+{
+    int ret;
+    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
+
+    status = decode_until_state(msg_it, STATE_EMIT_MSG_PACKET_BEGINNING, (state) -1);
+    if (status != CTF_MSG_ITER_STATUS_OK) {
+        goto end;
+    }
+
+    ret = set_current_packet_content_sizes(msg_it);
+    if (ret) {
+        status = CTF_MSG_ITER_STATUS_ERROR;
+        goto end;
+    }
+
+end:
+    return status;
+}
+
+enum ctf_msg_iter_status ctf_msg_iter_seek(struct ctf_msg_iter *msg_it, off_t offset)
+{
+    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
+    enum ctf_msg_iter_medium_status medium_status;
+
+    BT_ASSERT(msg_it);
+    BT_ASSERT(offset >= 0);
+    BT_ASSERT(msg_it->medium.medops.seek);
+
+    medium_status = msg_it->medium.medops.seek(offset, msg_it->medium.data);
+    if (medium_status != CTF_MSG_ITER_MEDIUM_STATUS_OK) {
+        if (medium_status == CTF_MSG_ITER_MEDIUM_STATUS_EOF) {
+            status = CTF_MSG_ITER_STATUS_EOF;
+        } else {
+            status = CTF_MSG_ITER_STATUS_ERROR;
+            goto end;
+        }
+    }
+
+    ctf_msg_iter_reset(msg_it);
+    msg_it->cur_packet_offset = offset;
+
+end:
+    return status;
+}
+
+static enum ctf_msg_iter_status clock_snapshot_at_msg_iter_state(struct ctf_msg_iter *msg_it,
+                                                                 enum state target_state_1,
+                                                                 enum state target_state_2,
+                                                                 uint64_t *clock_snapshot)
+{
+    enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
+
+    BT_ASSERT_DBG(msg_it);
+    BT_ASSERT_DBG(clock_snapshot);
+    status = decode_until_state(msg_it, target_state_1, target_state_2);
+    if (status != CTF_MSG_ITER_STATUS_OK) {
+        goto end;
+    }
+
+    *clock_snapshot = msg_it->default_clock_snapshot;
+end:
+    return status;
+}
+
+enum ctf_msg_iter_status
+ctf_msg_iter_curr_packet_first_event_clock_snapshot(struct ctf_msg_iter *msg_it,
+                                                    uint64_t *first_clock_snapshot)
+{
+    return clock_snapshot_at_msg_iter_state(msg_it, STATE_AFTER_EVENT_HEADER, (state) -1,
+                                            first_clock_snapshot);
+}
+
+enum ctf_msg_iter_status
+ctf_msg_iter_curr_packet_last_event_clock_snapshot(struct ctf_msg_iter *msg_it,
+                                                   uint64_t *last_clock_snapshot)
+{
+    return clock_snapshot_at_msg_iter_state(msg_it, STATE_EMIT_MSG_PACKET_END_SINGLE,
+                                            STATE_EMIT_MSG_PACKET_END_MULTI, last_clock_snapshot);
+}
+
+enum ctf_msg_iter_status
+ctf_msg_iter_get_packet_properties(struct ctf_msg_iter *msg_it,
+                                   struct ctf_msg_iter_packet_properties *props)
+{
+    enum ctf_msg_iter_status status;
+
+    BT_ASSERT_DBG(msg_it);
+    BT_ASSERT_DBG(props);
+    status = read_packet_header_context_fields(msg_it);
+    if (status != CTF_MSG_ITER_STATUS_OK) {
+        goto end;
+    }
+
+    props->exp_packet_total_size = msg_it->cur_exp_packet_total_size;
+    props->exp_packet_content_size = msg_it->cur_exp_packet_content_size;
+    props->stream_class_id = (uint64_t) msg_it->cur_stream_class_id;
+    props->data_stream_id = msg_it->cur_data_stream_id;
+    props->snapshots.discarded_events = msg_it->snapshots.discarded_events;
+    props->snapshots.packets = msg_it->snapshots.packets;
+    props->snapshots.beginning_clock = msg_it->snapshots.beginning_clock;
+    props->snapshots.end_clock = msg_it->snapshots.end_clock;
+
+end:
+    return status;
+}
+
+void ctf_msg_iter_set_dry_run(struct ctf_msg_iter *msg_it, bool val)
+{
+    msg_it->dry_run = val;
+}
diff --git a/src/plugins/ctf/common/src/msg-iter/msg-iter.hpp b/src/plugins/ctf/common/src/msg-iter/msg-iter.hpp
new file mode 100644 (file)
index 0000000..f9bb7f2
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2015-2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Babeltrace - CTF message iterator
+ */
+
+#ifndef CTF_MSG_ITER_H
+#define CTF_MSG_ITER_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <babeltrace2/babeltrace.h>
+
+#include "../metadata/tsdl/ctf-meta.hpp"
+
+namespace bt2c {
+
+class Logger;
+
+} /* namespace bt2c */
+
+/**
+ * @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.  These use the same values as
+ * libbabeltrace2.
+ */
+enum ctf_msg_iter_medium_status
+{
+    /**
+     * End of file.
+     *
+     * The medium function called by the message iterator
+     * function reached the end of the file.
+     */
+    CTF_MSG_ITER_MEDIUM_STATUS_EOF = 1,
+
+    /**
+     * There is no data available right now, try again later.
+     */
+    CTF_MSG_ITER_MEDIUM_STATUS_AGAIN = 11,
+
+    /** General error. */
+    CTF_MSG_ITER_MEDIUM_STATUS_ERROR = -1,
+
+    /** Memory error. */
+    CTF_MSG_ITER_MEDIUM_STATUS_MEMORY_ERROR = -12,
+
+    /** Everything okay. */
+    CTF_MSG_ITER_MEDIUM_STATUS_OK = 0,
+};
+
+inline const char *format_as(const ctf_msg_iter_medium_status status) noexcept
+{
+    switch (status) {
+    case CTF_MSG_ITER_MEDIUM_STATUS_EOF:
+        return "EOF";
+
+    case CTF_MSG_ITER_MEDIUM_STATUS_AGAIN:
+        return "AGAIN";
+
+    case CTF_MSG_ITER_MEDIUM_STATUS_ERROR:
+        return "ERROR";
+
+    case CTF_MSG_ITER_MEDIUM_STATUS_MEMORY_ERROR:
+        return "MEMORY_ERROR";
+
+    case CTF_MSG_ITER_MEDIUM_STATUS_OK:
+        return "OK";
+    }
+
+    bt_common_abort();
+}
+
+/**
+ * CTF message iterator API status code.
+ */
+enum ctf_msg_iter_status
+{
+    /**
+     * End of file.
+     *
+     * The medium function called by the message iterator
+     * function reached the end of the file.
+     */
+    CTF_MSG_ITER_STATUS_EOF = CTF_MSG_ITER_MEDIUM_STATUS_EOF,
+
+    /**
+     * There is no data available right now, try again later.
+     *
+     * Some condition resulted in the
+     * ctf_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.
+     */
+    CTF_MSG_ITER_STATUS_AGAIN = CTF_MSG_ITER_MEDIUM_STATUS_AGAIN,
+
+    /** General error. */
+    CTF_MSG_ITER_STATUS_ERROR = CTF_MSG_ITER_MEDIUM_STATUS_ERROR,
+
+    /** Memory error. */
+    CTF_MSG_ITER_STATUS_MEMORY_ERROR = CTF_MSG_ITER_MEDIUM_STATUS_MEMORY_ERROR,
+
+    /** Everything okay. */
+    CTF_MSG_ITER_STATUS_OK = CTF_MSG_ITER_MEDIUM_STATUS_OK,
+};
+
+inline const char *format_as(ctf_msg_iter_status status) noexcept
+{
+    switch (status) {
+    case CTF_MSG_ITER_STATUS_EOF:
+        return "EOF";
+
+    case CTF_MSG_ITER_STATUS_AGAIN:
+        return "AGAIN";
+
+    case CTF_MSG_ITER_STATUS_ERROR:
+        return "ERROR";
+
+    case CTF_MSG_ITER_STATUS_MEMORY_ERROR:
+        return "MEMORY_ERROR";
+
+    case CTF_MSG_ITER_STATUS_OK:
+        return "OK";
+    }
+
+    bt_common_abort();
+}
+
+/**
+ * Medium operations.
+ *
+ * Those user functions are called by the message iterator
+ * functions to request medium actions.
+ */
+struct ctf_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>#CTF_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>#CTF_MSG_ITER_MEDIUM_STATUS_AGAIN</b>: No data is
+     *     available right now. In this case, the message
+     *     iterator function called by the user returns
+     *     #CTF_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>#CTF_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
+     *     #CTF_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
+     *     #CTF_MSG_ITER_MEDIUM_STATUS_EOF on the \em following
+     *     call.
+     *   - <b>#CTF_MSG_ITER_MEDIUM_STATUS_ERROR</b>: A fatal
+     *     error occurred during this operation. In this case, the
+     *     message iterator function called by the user returns
+     *     #CTF_MSG_ITER_STATUS_ERROR.
+     *
+     * If #CTF_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 ctf_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 position in the medium.
+     *
+     * @param offset   Offset to use for the given directive
+     * @param data             User data
+     * @returns                One of #ctf_msg_iter_medium_status values
+     */
+    enum ctf_msg_iter_medium_status (*seek)(off_t offset, void *data);
+
+    /**
+     * Called when the message iterator wishes to inform the medium that it
+     * is about to start a new packet.
+     *
+     * After the iterator has called switch_packet, the following call to
+     * request_bytes must return the content at the start of the next
+     * packet.  */
+    enum ctf_msg_iter_medium_status (*switch_packet)(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 ctf_msg_iter;
+
+struct ctf_msg_iter_deleter
+{
+    void operator()(ctf_msg_iter *iter) noexcept;
+};
+
+using ctf_msg_iter_up = std::unique_ptr<ctf_msg_iter, ctf_msg_iter_deleter>;
+
+/**
+ * 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
+ *                             ctf_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
+ */
+ctf_msg_iter_up ctf_msg_iter_create(struct ctf_trace_class *tc, size_t max_request_sz,
+                                    struct ctf_msg_iter_medium_ops medops, void *medops_data,
+                                    bt_self_message_iterator *self_msg_iter,
+                                    const bt2c::Logger& logger);
+
+/**
+ * Destroys a CTF message iterator, freeing all internal resources.
+ *
+ * The registered trace's reference count is decremented.
+ *
+ * @param msg_iter             CTF message iterator
+ */
+void ctf_msg_iter_destroy(struct ctf_msg_iter *msg_iter);
+
+/**
+ * Returns the next message from a CTF message iterator.
+ *
+ * Upon successful completion, #CTF_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 #CTF_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 #CTF_MSG_ITER_STATUS_OK
+ * @returns                    One of #ctf_msg_iter_status values
+ */
+enum ctf_msg_iter_status ctf_msg_iter_get_next_message(struct ctf_msg_iter *msg_it,
+                                                       const bt_message **message);
+
+struct ctf_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;
+};
+
+enum ctf_msg_iter_status
+ctf_msg_iter_get_packet_properties(struct ctf_msg_iter *msg_it,
+                                   struct ctf_msg_iter_packet_properties *props);
+
+enum ctf_msg_iter_status
+ctf_msg_iter_curr_packet_first_event_clock_snapshot(struct ctf_msg_iter *msg_it,
+                                                    uint64_t *first_event_cs);
+
+enum ctf_msg_iter_status
+ctf_msg_iter_curr_packet_last_event_clock_snapshot(struct ctf_msg_iter *msg_it,
+                                                   uint64_t *last_event_cs);
+
+enum ctf_msg_iter_status ctf_msg_iter_seek(struct ctf_msg_iter *msg_it, 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
+ * ctf_msg_iter_set_emit_stream_beginning_message(), the first message
+ * which this iterator emits after calling ctf_msg_iter_reset() is of
+ * type `CTF_MESSAGE_TYPE_STREAM_BEGINNING`.
+ */
+void ctf_msg_iter_reset(struct ctf_msg_iter *msg_it);
+
+/*
+ * Like ctf_msg_iter_reset(), but preserves stream-dependent state.
+ */
+void ctf_msg_iter_reset_for_next_stream_file(struct ctf_msg_iter *msg_it);
+
+void ctf_msg_iter_set_dry_run(struct ctf_msg_iter *msg_it, bool val);
+
+#endif /* CTF_MSG_ITER_H */
index 6cde44fe914ae298b451c288c98fdd0bd88b5ada..7161fb35c52770c06d20988578e48876970f58e4 100644 (file)
@@ -39,9 +39,6 @@ struct fs_sink_ctf_field_class
     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
@@ -288,33 +285,31 @@ static inline void fs_sink_ctf_field_class_destroy(struct fs_sink_ctf_field_clas
 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)
+                                                 unsigned int alignment)
 {
     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)
+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)
 {
-    _fs_sink_ctf_field_class_init(&fc->base, type, ir_fc, size % 8 == 0 ? 8 : 1, index_in_parent);
+    _fs_sink_ctf_field_class_init(&fc->base, type, ir_fc, size % 8 == 0 ? 8 : 1);
     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)
+                                                     const bt_field_class *ir_fc)
 {
     bt_field_class_type ir_fc_type = bt_field_class_get_type(ir_fc);
 
     _fs_sink_ctf_field_class_bit_array_init(
-        &fc->base, type, ir_fc, (unsigned int) bt_field_class_integer_get_field_value_range(ir_fc),
-        index_in_parent);
+        &fc->base, type, ir_fc, (unsigned int) bt_field_class_integer_get_field_value_range(ir_fc));
     fc->is_signed = bt_field_class_type_is(ir_fc_type, BT_FIELD_CLASS_TYPE_SIGNED_INTEGER);
 }
 
@@ -341,7 +336,7 @@ _fs_sink_ctf_named_field_class_fini(struct fs_sink_ctf_named_field_class *named_
 }
 
 static inline struct fs_sink_ctf_field_class_bit_array *
-fs_sink_ctf_field_class_bit_array_create(const bt_field_class *ir_fc, uint64_t index_in_parent)
+fs_sink_ctf_field_class_bit_array_create(const bt_field_class *ir_fc)
 {
     struct fs_sink_ctf_field_class_bit_array *fc =
         g_new0(struct fs_sink_ctf_field_class_bit_array, 1);
@@ -349,12 +344,12 @@ fs_sink_ctf_field_class_bit_array_create(const bt_field_class *ir_fc, uint64_t i
     BT_ASSERT(fc);
     _fs_sink_ctf_field_class_bit_array_init(
         fc, FS_SINK_CTF_FIELD_CLASS_TYPE_BIT_ARRAY, ir_fc,
-        (unsigned int) bt_field_class_bit_array_get_length(ir_fc), index_in_parent);
+        (unsigned int) bt_field_class_bit_array_get_length(ir_fc));
     return fc;
 }
 
 static inline struct fs_sink_ctf_field_class_bool *
-fs_sink_ctf_field_class_bool_create(const bt_field_class *ir_fc, uint64_t index_in_parent)
+fs_sink_ctf_field_class_bool_create(const bt_field_class *ir_fc)
 {
     struct fs_sink_ctf_field_class_bool *fc = g_new0(struct fs_sink_ctf_field_class_bool, 1);
 
@@ -364,79 +359,73 @@ fs_sink_ctf_field_class_bool_create(const bt_field_class *ir_fc, uint64_t index_
      * CTF 1.8 has no boolean field class type, so this component
      * translates it to an 8-bit unsigned integer field class.
      */
-    _fs_sink_ctf_field_class_bit_array_init(&fc->base, FS_SINK_CTF_FIELD_CLASS_TYPE_BOOL, ir_fc, 8,
-                                            index_in_parent);
+    _fs_sink_ctf_field_class_bit_array_init(&fc->base, FS_SINK_CTF_FIELD_CLASS_TYPE_BOOL, ir_fc, 8);
     return fc;
 }
 
 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)
+fs_sink_ctf_field_class_int_create(const bt_field_class *ir_fc)
 {
     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);
+    _fs_sink_ctf_field_class_int_init(fc, FS_SINK_CTF_FIELD_CLASS_TYPE_INT, ir_fc);
     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)
+fs_sink_ctf_field_class_float_create(const bt_field_class *ir_fc)
 {
     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(
         &fc->base, FS_SINK_CTF_FIELD_CLASS_TYPE_FLOAT, ir_fc,
-        bt_field_class_get_type(ir_fc) == BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL ? 32 : 64,
-        index_in_parent);
+        bt_field_class_get_type(ir_fc) == BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL ? 32 : 64);
     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)
+fs_sink_ctf_field_class_string_create(const bt_field_class *ir_fc)
 {
     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(&fc->base, FS_SINK_CTF_FIELD_CLASS_TYPE_STRING, ir_fc, 8,
-                                  index_in_parent);
+    _fs_sink_ctf_field_class_init(&fc->base, FS_SINK_CTF_FIELD_CLASS_TYPE_STRING, ir_fc, 8);
     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)
+fs_sink_ctf_field_class_struct_create_empty(const bt_field_class *ir_fc)
 {
     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(&fc->base, FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT, ir_fc, 1,
-                                  index_in_parent);
+    _fs_sink_ctf_field_class_init(&fc->base, FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT, ir_fc, 1);
     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_option *
-fs_sink_ctf_field_class_option_create_empty(const bt_field_class *ir_fc, uint64_t index_in_parent)
+fs_sink_ctf_field_class_option_create_empty(const bt_field_class *ir_fc)
 {
     struct fs_sink_ctf_field_class_option *fc = g_new0(struct fs_sink_ctf_field_class_option, 1);
 
     BT_ASSERT(fc);
-    _fs_sink_ctf_field_class_init(&fc->base, FS_SINK_CTF_FIELD_CLASS_TYPE_OPTION, ir_fc, 1,
-                                  index_in_parent);
+    _fs_sink_ctf_field_class_init(&fc->base, FS_SINK_CTF_FIELD_CLASS_TYPE_OPTION, ir_fc, 1);
     fc->tag_ref = g_string_new(NULL);
     BT_ASSERT(fc->tag_ref);
     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)
+fs_sink_ctf_field_class_variant_create_empty(const bt_field_class *ir_fc)
 {
     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(&fc->base, FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT, ir_fc, 1,
-                                  index_in_parent);
+    _fs_sink_ctf_field_class_init(&fc->base, FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT, ir_fc, 1);
     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);
@@ -447,26 +436,24 @@ fs_sink_ctf_field_class_variant_create_empty(const bt_field_class *ir_fc, uint64
 }
 
 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)
+fs_sink_ctf_field_class_array_create_empty(const bt_field_class *ir_fc)
 {
     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(&fc->base.base, FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY, ir_fc, 1,
-                                  index_in_parent);
+    _fs_sink_ctf_field_class_init(&fc->base.base, FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY, ir_fc, 1);
     fc->length = bt_field_class_array_static_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)
+fs_sink_ctf_field_class_sequence_create_empty(const bt_field_class *ir_fc)
 {
     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(&fc->base.base, FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE, ir_fc, 1,
-                                  index_in_parent);
+    _fs_sink_ctf_field_class_init(&fc->base.base, FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE, ir_fc, 1);
     fc->length_ref = g_string_new(NULL);
     BT_ASSERT(fc->length_ref);
     fc->length_is_before =
index 6611744b5b9c1acec87b6140fcaa0a55e81a5681..e070e435aa5c4233c4979ae24f13e297a1a14c90 100644 (file)
@@ -9,11 +9,6 @@
 
 #include <babeltrace2/babeltrace.h>
 
-#define BT_COMP_LOG_SELF_COMP (stream->trace->fs_sink->self_comp)
-#define BT_LOG_OUTPUT_LEVEL   (stream->log_level)
-#define BT_LOG_TAG            "PLUGIN/SINK.CTF.FS/STREAM"
-#include "logging/comp-logging.h"
-
 #include "common/assert.h"
 #include "compat/endian.h" /* IWYU pragma: keep  */
 #include "ctfser/ctfser.h"
@@ -21,7 +16,6 @@
 #include "fs-sink-ctf-meta.hpp"
 #include "fs-sink-stream.hpp"
 #include "fs-sink-trace.hpp"
-#include "fs-sink.hpp"
 #include "translate-trace-ir-to-ctf-ir.hpp"
 
 void fs_sink_stream_destroy(struct fs_sink_stream *stream)
@@ -38,7 +32,7 @@ void fs_sink_stream_destroy(struct fs_sink_stream *stream)
     }
 
     bt_packet_put_ref(stream->packet_state.packet);
-    g_free(stream);
+    delete stream;
 
 end:
     return;
@@ -124,15 +118,10 @@ static void set_stream_file_name(struct fs_sink_stream *stream)
 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);
+    fs_sink_stream *stream = new fs_sink_stream {trace->logger};
     int ret;
     GString *path = g_string_new(trace->path->str);
 
-    if (!stream) {
-        goto end;
-    }
-
-    stream->log_level = trace->log_level;
     stream->trace = trace;
     stream->ir_stream = ir_stream;
     stream->packet_state.beginning_cs = UINT64_C(-1);
@@ -148,7 +137,7 @@ struct fs_sink_stream *fs_sink_stream_create(struct fs_sink_trace *trace,
 
     set_stream_file_name(stream);
     g_string_append_printf(path, "/%s", stream->file_name->str);
-    ret = bt_ctfser_init(&stream->ctfser, path->str, stream->log_level);
+    ret = bt_ctfser_init(&stream->ctfser, path->str, static_cast<int>(stream->logger.level()));
     if (ret) {
         goto error;
     }
@@ -574,8 +563,8 @@ int fs_sink_stream_open_packet(struct fs_sink_stream *stream, const bt_clock_sna
     ret = bt_ctfser_write_byte_aligned_unsigned_int(&stream->ctfser, UINT64_C(0xc1fc1fc1), 8, 32,
                                                     BYTE_ORDER);
     if (ret) {
-        BT_COMP_LOGE("Error writing packet header magic: stream-file-name=%s",
-                     stream->file_name->str);
+        BT_CPPLOGE_SPEC(stream->logger, "Error writing packet header magic: stream-file-name={}",
+                        stream->file_name->str);
         goto end;
     }
 
@@ -584,8 +573,8 @@ int fs_sink_stream_open_packet(struct fs_sink_stream *stream, const bt_clock_sna
         ret = bt_ctfser_write_byte_aligned_unsigned_int(
             &stream->ctfser, (uint64_t) stream->sc->trace->uuid[i], 8, 8, BYTE_ORDER);
         if (ret) {
-            BT_COMP_LOGE("Error writing packet header UUID: stream-file-name=%s",
-                         stream->file_name->str);
+            BT_CPPLOGE_SPEC(stream->logger, "Error writing packet header UUID: stream-file-name={}",
+                            stream->file_name->str);
             goto end;
         }
     }
@@ -594,9 +583,10 @@ int fs_sink_stream_open_packet(struct fs_sink_stream *stream, const bt_clock_sna
     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_COMP_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));
+        BT_CPPLOGE_SPEC(stream->logger,
+                        "Error writing packet header stream class id: "
+                        "stream-file-name={}, stream-class-id={}",
+                        stream->file_name->str, bt_stream_class_get_id(stream->sc->ir_sc));
         goto end;
     }
 
@@ -604,9 +594,10 @@ int fs_sink_stream_open_packet(struct fs_sink_stream *stream, const bt_clock_sna
     ret = bt_ctfser_write_byte_aligned_unsigned_int(
         &stream->ctfser, bt_stream_get_id(stream->ir_stream), 8, 64, BYTE_ORDER);
     if (ret) {
-        BT_COMP_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));
+        BT_CPPLOGE_SPEC(stream->logger,
+                        "Error writing packet header stream id: "
+                        "stream-file-name={}, stream-id={}",
+                        stream->file_name->str, bt_stream_get_id(stream->ir_stream));
         goto end;
     }
 
index 8d559c6a8bac95547cdacc06ed5316f5eaeae20d..8c309525c5619f55b1643cc5c148cadb9c8f3781 100644 (file)
 
 #include <babeltrace2/babeltrace.h>
 
+#include "cpp-common/bt2c/logging.hpp"
 #include "ctfser/ctfser.h"
 
+struct fs_sink_trace;
+struct fs_sink_ctf_stream_class;
+
 struct fs_sink_stream
 {
-    bt_logging_level log_level;
-    struct fs_sink_trace *trace;
-    struct bt_ctfser ctfser;
+    explicit fs_sink_stream(const bt2c::Logger& parentLogger) :
+        logger {parentLogger, "PLUGIN/SINK.CTF.FS/STREAM"}
+    {
+    }
+
+    bt2c::Logger logger;
+    fs_sink_trace *trace = nullptr;
+    bt_ctfser ctfser {};
 
     /* Stream's file name */
-    GString *file_name;
+    GString *file_name = nullptr;
 
     /* Weak */
-    const bt_stream *ir_stream;
+    const bt_stream *ir_stream = nullptr;
 
-    struct fs_sink_ctf_stream_class *sc;
+    fs_sink_ctf_stream_class *sc = nullptr;
 
     /* Current packet's state */
     struct
@@ -36,65 +45,65 @@ struct fs_sink_stream
          * packet (got a packet beginning message, but no
          * packet end message yet).
          */
-        bool is_open;
+        bool is_open = false;
 
         /*
          * Current beginning default clock snapshot for the
          * current packet (`UINT64_C(-1)` if not set).
          */
-        uint64_t beginning_cs;
+        uint64_t beginning_cs = 0;
 
         /*
          * Current end default clock snapshot for the current
          * packet (`UINT64_C(-1)` if not set).
          */
-        uint64_t end_cs;
+        uint64_t end_cs = 0;
 
         /*
          * Current packet's content size (bits) for the current
          * packet.
          */
-        uint64_t content_size;
+        uint64_t content_size = 0;
 
         /*
          * Current packet's total size (bits) for the current
          * packet.
          */
-        uint64_t total_size;
+        uint64_t total_size = 0;
 
         /*
          * Discarded events (free running) counter for the
          * current packet.
          */
-        uint64_t discarded_events_counter;
+        uint64_t discarded_events_counter = 0;
 
         /* Sequence number (free running) of the current packet */
-        uint64_t seq_num;
+        uint64_t seq_num = 0;
 
         /*
          * Offset of the packet context structure within the
          * current packet (bits).
          */
-        uint64_t context_offset_bits;
+        uint64_t context_offset_bits = 0;
 
         /*
          * Owned by this; `NULL` if the current packet is closed
          * or if the trace IR stream does not support packets.
          */
-        const bt_packet *packet;
+        const bt_packet *packet = nullptr;
     } packet_state;
 
     /* Previous packet's state */
     struct
     {
         /* End default clock snapshot (`UINT64_C(-1)` if not set) */
-        uint64_t end_cs;
+        uint64_t end_cs = 0;
 
         /* Discarded events (free running) counter */
-        uint64_t discarded_events_counter;
+        uint64_t discarded_events_counter = 0;
 
         /* Sequence number (free running) */
-        uint64_t seq_num;
+        uint64_t seq_num = 0;
     } prev_packet_state;
 
     /* State to handle discarded events */
@@ -116,14 +125,14 @@ struct fs_sink_stream
          *
          * * Its end time is the current packet's end time.
          */
-        bool in_range;
+        bool in_range = false;
 
         /*
          * Beginning and end times of the time range given by a
          * previously received discarded events message.
          */
-        uint64_t beginning_cs;
-        uint64_t end_cs;
+        uint64_t beginning_cs = 0;
+        uint64_t end_cs = 0;
     } discarded_events_state;
 
     /* State to handle discarded packets */
@@ -146,14 +155,14 @@ struct fs_sink_stream
          * * Its end time is the current packet's beginning
          *   time.
          */
-        bool in_range;
+        bool in_range = false;
 
         /*
          * Beginning and end times of the time range given by a
          * previously received discarded packets message.
          */
-        uint64_t beginning_cs;
-        uint64_t end_cs;
+        uint64_t beginning_cs = 0;
+        uint64_t end_cs = 0;
     } discarded_packets_state;
 };
 
index 5466dd645a9b38274de43fcce3250d1f4e047226..cebf19f61a5aee7097cbb8181611646a43456184 100644 (file)
@@ -9,11 +9,6 @@
 
 #include <babeltrace2/babeltrace.h>
 
-#define BT_COMP_LOG_SELF_COMP (trace->fs_sink->self_comp)
-#define BT_LOG_OUTPUT_LEVEL   (trace->log_level)
-#define BT_LOG_TAG            "PLUGIN/SINK.CTF.FS/TRACE"
-#include "logging/comp-logging.h"
-
 #include "common/assert.h"
 
 #include "fs-sink-ctf-meta.hpp"
@@ -141,7 +136,8 @@ static int lttng_validate_datetime(const struct fs_sink_trace *trace, const char
      * the format.
      */
     if (!g_time_val_from_iso8601(datetime, &tv)) {
-        BT_COMP_LOGI("Couldn't parse datetime as ISO 8601: date=\"%s\"", datetime);
+        BT_CPPLOGI_SPEC(trace->logger, "Couldn't parse datetime as ISO 8601: date=\"{}\"",
+                        datetime);
         goto end;
     }
 
@@ -161,7 +157,8 @@ static int append_lttng_trace_path_ust_uid(const struct fs_sink_trace *trace, GS
 
     v = bt_trace_borrow_environment_entry_value_by_name_const(tc, "tracer_buffering_id");
     if (!v || !bt_value_is_signed_integer(v)) {
-        BT_COMP_LOGI_STR("Couldn't get environment value: name=\"tracer_buffering_id\"");
+        BT_CPPLOGI_SPEC(trace->logger,
+                        "Couldn't get environment value: name=\"tracer_buffering_id\"");
         goto error;
     }
 
@@ -169,7 +166,8 @@ static int append_lttng_trace_path_ust_uid(const struct fs_sink_trace *trace, GS
 
     v = bt_trace_borrow_environment_entry_value_by_name_const(tc, "architecture_bit_width");
     if (!v || !bt_value_is_signed_integer(v)) {
-        BT_COMP_LOGI_STR("Couldn't get environment value: name=\"architecture_bit_width\"");
+        BT_CPPLOGI_SPEC(trace->logger,
+                        "Couldn't get environment value: name=\"architecture_bit_width\"");
         goto error;
     }
 
@@ -195,7 +193,7 @@ static int append_lttng_trace_path_ust_pid(const struct fs_sink_trace *trace, GS
 
     v = bt_trace_borrow_environment_entry_value_by_name_const(tc, "procname");
     if (!v || !bt_value_is_string(v)) {
-        BT_COMP_LOGI_STR("Couldn't get environment value: name=\"procname\"");
+        BT_CPPLOGI_SPEC(trace->logger, "Couldn't get environment value: name=\"procname\"");
         goto error;
     }
 
@@ -203,7 +201,7 @@ static int append_lttng_trace_path_ust_pid(const struct fs_sink_trace *trace, GS
 
     v = bt_trace_borrow_environment_entry_value_by_name_const(tc, "vpid");
     if (!v || !bt_value_is_signed_integer(v)) {
-        BT_COMP_LOGI_STR("Couldn't get environment value: name=\"vpid\"");
+        BT_CPPLOGI_SPEC(trace->logger, "Couldn't get environment value: name=\"vpid\"");
         goto error;
     }
 
@@ -211,7 +209,7 @@ static int append_lttng_trace_path_ust_pid(const struct fs_sink_trace *trace, GS
 
     v = bt_trace_borrow_environment_entry_value_by_name_const(tc, "vpid_datetime");
     if (!v || !bt_value_is_string(v)) {
-        BT_COMP_LOGI_STR("Couldn't get environment value: name=\"vpid_datetime\"");
+        BT_CPPLOGI_SPEC(trace->logger, "Couldn't get environment value: name=\"vpid_datetime\"");
         goto error;
     }
 
@@ -251,20 +249,20 @@ static GString *make_lttng_trace_path_rel(const struct fs_sink_trace *trace)
 
     v = bt_trace_borrow_environment_entry_value_by_name_const(trace->ir_trace, "tracer_name");
     if (!v || !bt_value_is_string(v)) {
-        BT_COMP_LOGI_STR("Couldn't get environment value: name=\"tracer_name\"");
+        BT_CPPLOGI_SPEC(trace->logger, "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_COMP_LOGI("Unrecognized tracer name: name=\"%s\"", tracer_name);
+        BT_CPPLOGI_SPEC(trace->logger, "Unrecognized tracer name: name=\"{}\"", tracer_name);
         goto error;
     }
 
     v = bt_trace_borrow_environment_entry_value_by_name_const(trace->ir_trace, "tracer_major");
     if (!v || !bt_value_is_signed_integer(v)) {
-        BT_COMP_LOGI_STR("Couldn't get environment value: name=\"tracer_major\"");
+        BT_CPPLOGI_SPEC(trace->logger, "Couldn't get environment value: name=\"tracer_major\"");
         goto error;
     }
 
@@ -272,22 +270,22 @@ static GString *make_lttng_trace_path_rel(const struct fs_sink_trace *trace)
 
     v = bt_trace_borrow_environment_entry_value_by_name_const(trace->ir_trace, "tracer_minor");
     if (!v || !bt_value_is_signed_integer(v)) {
-        BT_COMP_LOGI_STR("Couldn't get environment value: name=\"tracer_minor\"");
+        BT_CPPLOGI_SPEC(trace->logger, "Couldn't get environment value: name=\"tracer_minor\"");
         goto error;
     }
 
     tracer_minor = bt_value_integer_signed_get(v);
 
     if (!(tracer_major >= 3 || (tracer_major == 2 && tracer_minor >= 11))) {
-        BT_COMP_LOGI("Unsupported LTTng version for automatic trace path: major=%" PRId64
-                     ", minor=%" PRId64,
-                     tracer_major, tracer_minor);
+        BT_CPPLOGI_SPEC(trace->logger,
+                        "Unsupported LTTng version for automatic trace path: major={}, minor={}",
+                        tracer_major, tracer_minor);
         goto error;
     }
 
     v = bt_trace_borrow_environment_entry_value_by_name_const(trace->ir_trace, "hostname");
     if (!v || !bt_value_is_string(v)) {
-        BT_COMP_LOGI_STR("Couldn't get environment value: name=\"tracer_hostname\"");
+        BT_CPPLOGI_SPEC(trace->logger, "Couldn't get environment value: name=\"tracer_hostname\"");
         goto error;
     }
 
@@ -295,7 +293,7 @@ static GString *make_lttng_trace_path_rel(const struct fs_sink_trace *trace)
 
     v = bt_trace_borrow_environment_entry_value_by_name_const(trace->ir_trace, "trace_name");
     if (!v || !bt_value_is_string(v)) {
-        BT_COMP_LOGI_STR("Couldn't get environment value: name=\"trace_name\"");
+        BT_CPPLOGI_SPEC(trace->logger, "Couldn't get environment value: name=\"trace_name\"");
         goto error;
     }
 
@@ -304,7 +302,8 @@ static GString *make_lttng_trace_path_rel(const struct fs_sink_trace *trace)
     v = bt_trace_borrow_environment_entry_value_by_name_const(trace->ir_trace,
                                                               "trace_creation_datetime");
     if (!v || !bt_value_is_string(v)) {
-        BT_COMP_LOGI_STR("Couldn't get environment value: name=\"trace_creation_datetime\"");
+        BT_CPPLOGI_SPEC(trace->logger,
+                        "Couldn't get environment value: name=\"trace_creation_datetime\"");
         goto error;
     }
 
@@ -318,7 +317,7 @@ static GString *make_lttng_trace_path_rel(const struct fs_sink_trace *trace)
 
     v = bt_trace_borrow_environment_entry_value_by_name_const(trace->ir_trace, "domain");
     if (!v || !bt_value_is_string(v)) {
-        BT_COMP_LOGI_STR("Couldn't get environment value: name=\"domain\"");
+        BT_CPPLOGI_SPEC(trace->logger, "Couldn't get environment value: name=\"domain\"");
         goto error;
     }
 
@@ -331,7 +330,8 @@ static GString *make_lttng_trace_path_rel(const struct fs_sink_trace *trace)
         v = bt_trace_borrow_environment_entry_value_by_name_const(trace->ir_trace,
                                                                   "tracer_buffering_scheme");
         if (!v || !bt_value_is_string(v)) {
-            BT_COMP_LOGI_STR("Couldn't get environment value: name=\"tracer_buffering_scheme\"");
+            BT_CPPLOGI_SPEC(trace->logger,
+                            "Couldn't get environment value: name=\"tracer_buffering_scheme\"");
             goto error;
         }
 
@@ -348,13 +348,14 @@ static GString *make_lttng_trace_path_rel(const struct fs_sink_trace *trace)
             }
         } else {
             /* Unknown buffering scheme. */
-            BT_COMP_LOGI("Unknown buffering scheme: tracer_buffering_scheme=\"%s\"",
-                         tracer_buffering_scheme);
+            BT_CPPLOGI_SPEC(trace->logger,
+                            "Unknown buffering scheme: tracer_buffering_scheme=\"{}\"",
+                            tracer_buffering_scheme);
             goto error;
         }
     } else if (!g_str_equal(domain, "kernel")) {
         /* Unknown domain. */
-        BT_COMP_LOGI("Unknown domain: domain=\"%s\"", domain);
+        BT_CPPLOGI_SPEC(trace->logger, "Unknown domain: domain=\"{}\"", domain);
         goto error;
     }
 
@@ -488,17 +489,19 @@ void fs_sink_trace_destroy(struct fs_sink_trace *trace)
     BT_ASSERT(trace->metadata_path);
     fh = fopen(trace->metadata_path->str, "wb");
     if (!fh) {
-        BT_COMP_LOGF_ERRNO("In trace destruction listener: "
-                           "cannot open metadata file for writing",
-                           ": path=\"%s\"", trace->metadata_path->str);
+        BT_CPPLOGF_ERRNO_SPEC(trace->logger,
+                              "In trace destruction listener: "
+                              "cannot open metadata file for writing",
+                              ": path=\"{}\"", trace->metadata_path->str);
         bt_common_abort();
     }
 
     len = fwrite(tsdl->str, sizeof(*tsdl->str), tsdl->len, fh);
     if (len != tsdl->len) {
-        BT_COMP_LOGF_ERRNO("In trace destruction listener: "
-                           "cannot write metadata file",
-                           ": path=\"%s\"", trace->metadata_path->str);
+        BT_CPPLOGF_ERRNO_SPEC(trace->logger,
+                              "In trace destruction listener: "
+                              "cannot write metadata file",
+                              ": path=\"{}\"", trace->metadata_path->str);
         bt_common_abort();
     }
 
@@ -515,9 +518,10 @@ void fs_sink_trace_destroy(struct fs_sink_trace *trace)
         int ret = fclose(fh);
 
         if (ret != 0) {
-            BT_COMP_LOGW_ERRNO("In trace destruction listener: "
-                               "cannot close metadata file",
-                               ": path=\"%s\"", trace->metadata_path->str);
+            BT_CPPLOGW_ERRNO_SPEC(trace->logger,
+                                  "In trace destruction listener: "
+                                  "cannot close metadata file",
+                                  ": path=\"{}\"", trace->metadata_path->str);
         }
     }
 
@@ -526,7 +530,7 @@ void fs_sink_trace_destroy(struct fs_sink_trace *trace)
 
     fs_sink_ctf_trace_destroy(trace->trace);
     trace->trace = NULL;
-    g_free(trace);
+    delete trace;
 
     g_string_free(tsdl, TRUE);
 
@@ -550,14 +554,9 @@ static void ir_trace_destruction_listener(const bt_trace *ir_trace, void *data)
 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);
+    fs_sink_trace *trace = new fs_sink_trace {fs_sink->logger};
     bt_trace_add_listener_status trace_status;
 
-    if (!trace) {
-        goto end;
-    }
-
-    trace->log_level = fs_sink->log_level;
     trace->fs_sink = fs_sink;
     trace->ir_trace = ir_trace;
     trace->ir_trace_destruction_listener_id = UINT64_C(-1);
@@ -570,8 +569,8 @@ struct fs_sink_trace *fs_sink_trace_create(struct fs_sink_comp *fs_sink, const b
     BT_ASSERT(trace->path);
     ret = g_mkdir_with_parents(trace->path->str, 0755);
     if (ret) {
-        BT_COMP_LOGE_ERRNO("Cannot create directories for trace directory", ": path=\"%s\"",
-                           trace->path->str);
+        BT_CPPLOGE_ERRNO_SPEC(trace->logger, "Cannot create directories for trace directory",
+                              ": path=\"{}\"", trace->path->str);
         goto error;
     }
 
index 0da8b4b04955b2abd7df0f3216fd3009ae114b51..c9b164367f46158d4fde85f78176754cbad3acbc 100644 (file)
 
 #include <babeltrace2/babeltrace.h>
 
+#include "cpp-common/bt2c/logging.hpp"
+
+struct fs_sink_comp;
+struct fs_sink_ctf_trace;
+
 struct fs_sink_trace
 {
-    bt_logging_level log_level;
-    struct fs_sink_comp *fs_sink;
+    explicit fs_sink_trace(const bt2c::Logger& parentLogger) :
+        logger {parentLogger, "PLUGIN/SINK.CTF.FS/TRACE"}
+    {
+    }
+
+    bt2c::Logger logger;
+    fs_sink_comp *fs_sink = nullptr;
 
     /* Owned by this */
-    struct fs_sink_ctf_trace *trace;
+    fs_sink_ctf_trace *trace = nullptr;
 
     /*
      * Weak reference: this object does not own it, and `trace`
@@ -31,21 +41,21 @@ struct fs_sink_trace
      * could "leak" resources (memory, file descriptors) associated
      * to traces and streams which otherwise would not exist.
      */
-    const bt_trace *ir_trace;
+    const bt_trace *ir_trace = nullptr;
 
-    bt_listener_id ir_trace_destruction_listener_id;
+    bt_listener_id ir_trace_destruction_listener_id = 0;
 
     /* Trace's directory */
-    GString *path;
+    GString *path = nullptr;
 
     /* `metadata` file path */
-    GString *metadata_path;
+    GString *metadata_path = nullptr;
 
     /*
      * Hash table of `const bt_stream *` (weak) to
      * `struct fs_sink_stream *` (owned by hash table).
      */
-    GHashTable *streams;
+    GHashTable *streams = nullptr;
 };
 
 struct fs_sink_trace *fs_sink_trace_create(struct fs_sink_comp *fs_sink, const bt_trace *ir_trace);
index 00084b796526e22527fd959651886565e9a782b8..6b0c88da9b0c59e0b127b36e84f27c4e5f6ce3e4 100644 (file)
@@ -9,12 +9,8 @@
 
 #include <babeltrace2/babeltrace.h>
 
-#define BT_COMP_LOG_SELF_COMP (fs_sink->self_comp)
-#define BT_LOG_OUTPUT_LEVEL   (fs_sink->log_level)
-#define BT_LOG_TAG            "PLUGIN/SINK.CTF.FS"
-#include "logging/comp-logging.h"
-
 #include "common/assert.h"
+#include "cpp-common/vendor/fmt/format.h"
 #include "ctfser/ctfser.h"
 
 #include "plugins/common/param-validation/param-validation.h"
@@ -36,9 +32,9 @@ ensure_output_dir_exists(struct fs_sink_comp *fs_sink)
 
     ret = g_mkdir_with_parents(fs_sink->output_dir_path->str, 0755);
     if (ret) {
-        BT_COMP_LOGE_APPEND_CAUSE_ERRNO(fs_sink->self_comp,
-                                        "Cannot create directories for output directory",
-                                        ": output-dir-path=\"%s\"", fs_sink->output_dir_path->str);
+        BT_CPPLOGE_ERRNO_APPEND_CAUSE_SPEC(
+            fs_sink->logger, "Cannot create directories for output directory",
+            ": output-dir-path=\"{}\"", fs_sink->output_dir_path->str);
         status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
         goto end;
     }
@@ -72,7 +68,7 @@ static bt_component_class_initialize_method_status configure_component(struct fs
         bt_param_validation_validate(params, fs_sink_params_descr, &validation_error);
     if (validation_status == BT_PARAM_VALIDATION_STATUS_VALIDATION_ERROR) {
         status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
-        BT_COMP_LOGE_APPEND_CAUSE(fs_sink->self_comp, "%s", validation_error);
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "{}", validation_error);
         goto end;
     } else if (validation_status == BT_PARAM_VALIDATION_STATUS_MEMORY_ERROR) {
         status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
@@ -126,7 +122,7 @@ static void destroy_fs_sink_comp(struct fs_sink_comp *fs_sink)
     }
 
     BT_MESSAGE_ITERATOR_PUT_REF_AND_RESET(fs_sink->upstream_iter);
-    g_free(fs_sink);
+    delete fs_sink;
 
 end:
     return;
@@ -136,71 +132,64 @@ bt_component_class_initialize_method_status ctf_fs_sink_init(bt_self_component_s
                                                              bt_self_component_sink_configuration *,
                                                              const bt_value *params, void *)
 {
-    bt_component_class_initialize_method_status status;
-    bt_self_component_add_port_status add_port_status;
-    struct fs_sink_comp *fs_sink = NULL;
-    bt_self_component *self_comp = bt_self_component_sink_as_self_component(self_comp_sink);
-    bt_logging_level log_level =
-        bt_component_get_logging_level(bt_self_component_as_component(self_comp));
-
-    fs_sink = g_new0(struct fs_sink_comp, 1);
-    if (!fs_sink) {
-        BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_comp,
-                            "Failed to allocate one CTF FS sink structure.");
-        BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(
-            self_comp, "Failed to allocate one CTF FS sink structure.");
-        status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
-        goto end;
-    }
-
-    fs_sink->log_level = log_level;
-    fs_sink->self_comp = self_comp;
-    fs_sink->output_dir_path = g_string_new(NULL);
-    status = configure_component(fs_sink, params);
-    if (status != BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK) {
-        /* configure_component() logs errors */
-        goto end;
-    }
+    try {
+        bt_component_class_initialize_method_status status;
+        bt_self_component_add_port_status add_port_status;
+        struct fs_sink_comp *fs_sink = NULL;
+        bt_self_component *self_comp = bt_self_component_sink_as_self_component(self_comp_sink);
+
+        fs_sink = new fs_sink_comp {bt2::SelfSinkComponent {self_comp_sink}};
+        fs_sink->output_dir_path = g_string_new(NULL);
+        status = configure_component(fs_sink, params);
+        if (status != BT_COMPONENT_CLASS_INITIALIZE_METHOD_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_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "Single trace mode, but output path exists: output-path=\"%s\"",
-                                  fs_sink->output_dir_path->str);
-        status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
-        goto end;
-    }
+        if (fs_sink->assume_single_trace &&
+            g_file_test(fs_sink->output_dir_path->str, G_FILE_TEST_EXISTS)) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(
+                fs_sink->logger, "Single trace mode, but output path exists: output-path=\"{}\"",
+                fs_sink->output_dir_path->str);
+            status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
+            goto end;
+        }
 
-    status = ensure_output_dir_exists(fs_sink);
-    if (status != BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK) {
-        /* ensure_output_dir_exists() logs errors */
-        goto end;
-    }
+        status = ensure_output_dir_exists(fs_sink);
+        if (status != BT_COMPONENT_CLASS_INITIALIZE_METHOD_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_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to allocate one GHashTable.");
-        status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
-        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_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to allocate one GHashTable.");
+            status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
+            goto end;
+        }
 
-    add_port_status =
-        bt_self_component_sink_add_input_port(self_comp_sink, in_port_name, NULL, NULL);
-    if (add_port_status != BT_SELF_COMPONENT_ADD_PORT_STATUS_OK) {
-        status = (bt_component_class_initialize_method_status) add_port_status;
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to add input port.");
-        goto end;
-    }
+        add_port_status =
+            bt_self_component_sink_add_input_port(self_comp_sink, in_port_name, NULL, NULL);
+        if (add_port_status != BT_SELF_COMPONENT_ADD_PORT_STATUS_OK) {
+            status = (bt_component_class_initialize_method_status) add_port_status;
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to add input port.");
+            goto end;
+        }
 
-    bt_self_component_set_data(self_comp, fs_sink);
+        bt_self_component_set_data(self_comp, fs_sink);
 
 end:
-    if (status != BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK) {
-        destroy_fs_sink_comp(fs_sink);
-    }
+        if (status != BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK) {
+            destroy_fs_sink_comp(fs_sink);
+        }
 
-    return status;
+        return status;
+    } catch (const std::bad_alloc&) {
+        return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
+    } catch (const bt2::Error&) {
+        return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
+    }
 }
 
 static inline struct fs_sink_stream *borrow_stream(struct fs_sink_comp *fs_sink,
@@ -213,10 +202,10 @@ static inline struct fs_sink_stream *borrow_stream(struct fs_sink_comp *fs_sink,
     trace = (fs_sink_trace *) g_hash_table_lookup(fs_sink->traces, ir_trace);
     if (G_UNLIKELY(!trace)) {
         if (fs_sink->assume_single_trace && g_hash_table_size(fs_sink->traces) > 0) {
-            BT_COMP_LOGE_APPEND_CAUSE(fs_sink->self_comp,
-                                      "Single trace mode, but getting more than one trace: "
-                                      "stream-name=\"%s\"",
-                                      bt_stream_get_name(ir_stream));
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger,
+                                         "Single trace mode, but getting more than one trace: "
+                                         "stream-name=\"{}\"",
+                                         bt2c::maybeNull(bt_stream_get_name(ir_stream)));
             goto end;
         }
 
@@ -241,37 +230,39 @@ end:
 static inline bt_component_class_sink_consume_method_status
 handle_event_msg(struct fs_sink_comp *fs_sink, const bt_message *msg)
 {
-    int ret;
-    bt_component_class_sink_consume_method_status status =
-        BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_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 (G_UNLIKELY(!stream)) {
-        BT_COMP_LOGE_APPEND_CAUSE(fs_sink->self_comp, "Failed to borrow stream.");
-        status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
-        goto end;
-    }
+    try {
+        int ret;
+        bt_component_class_sink_consume_method_status status =
+            BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_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 (G_UNLIKELY(!stream)) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to borrow stream.");
+            status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
+            goto end;
+        }
 
-    ret = try_translate_event_class_trace_ir_to_ctf_ir(fs_sink, stream->sc,
-                                                       bt_event_borrow_class_const(ir_event), &ec);
-    if (ret) {
-        BT_COMP_LOGE_APPEND_CAUSE(fs_sink->self_comp, "Failed to translate event class to CTF IR.");
-        status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
-        goto end;
-    }
+        ret = try_translate_event_class_trace_ir_to_ctf_ir(
+            fs_sink, stream->sc, bt_event_borrow_class_const(ir_event), &ec);
+        if (ret) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger,
+                                         "Failed to translate event class to CTF IR.");
+            status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
+            goto end;
+        }
 
-    BT_ASSERT_DBG(ec);
+        BT_ASSERT_DBG(ec);
 
-    if (stream->sc->default_clock_class) {
-        cs = bt_message_event_borrow_default_clock_snapshot_const(msg);
-    }
+        if (stream->sc->default_clock_class) {
+            cs = bt_message_event_borrow_default_clock_snapshot_const(msg);
+        }
 
-    /*
+        /*
      * If this event's stream does not support packets, then we
      * lazily create artificial packets.
      *
@@ -280,43 +271,49 @@ handle_event_msg(struct fs_sink_comp *fs_sink, const bt_message *msg)
      * comes the time to write a new event and the packet's content
      * size is >= 4 MiB), except the last one which can be smaller.
      */
-    if (G_UNLIKELY(!stream->sc->has_packets)) {
-        if (stream->packet_state.is_open &&
-            bt_ctfser_get_offset_in_current_packet_bits(&stream->ctfser) / 8 >= 4 * 1024 * 1024) {
-            /*
+        if (G_UNLIKELY(!stream->sc->has_packets)) {
+            if (stream->packet_state.is_open &&
+                bt_ctfser_get_offset_in_current_packet_bits(&stream->ctfser) / 8 >=
+                    4 * 1024 * 1024) {
+                /*
              * Stream's current packet is larger than 4 MiB:
              * close it. A new packet will be opened just
              * below.
              */
-            ret = fs_sink_stream_close_packet(stream, NULL);
-            if (ret) {
-                BT_COMP_LOGE_APPEND_CAUSE(fs_sink->self_comp, "Failed to close packet.");
-                status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
-                goto end;
+                ret = fs_sink_stream_close_packet(stream, NULL);
+                if (ret) {
+                    BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to close packet.");
+                    status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
+                    goto end;
+                }
             }
-        }
 
-        if (!stream->packet_state.is_open) {
-            /* Stream's packet is not currently opened: open it */
-            ret = fs_sink_stream_open_packet(stream, NULL, NULL);
-            if (ret) {
-                BT_COMP_LOGE_APPEND_CAUSE(fs_sink->self_comp, "Failed to open packet.");
-                status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
-                goto end;
+            if (!stream->packet_state.is_open) {
+                /* Stream's packet is not currently opened: open it */
+                ret = fs_sink_stream_open_packet(stream, NULL, NULL);
+                if (ret) {
+                    BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to open packet.");
+                    status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
+                    goto end;
+                }
             }
         }
-    }
 
-    BT_ASSERT_DBG(stream->packet_state.is_open);
-    ret = fs_sink_stream_write_event(stream, cs, ir_event, ec);
-    if (G_UNLIKELY(ret)) {
-        BT_COMP_LOGE_APPEND_CAUSE(fs_sink->self_comp, "Failed to write event.");
-        status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
-        goto end;
-    }
+        BT_ASSERT_DBG(stream->packet_state.is_open);
+        ret = fs_sink_stream_write_event(stream, cs, ir_event, ec);
+        if (G_UNLIKELY(ret)) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to write event.");
+            status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
+            goto end;
+        }
 
 end:
-    return status;
+        return status;
+    } catch (const std::bad_alloc&) {
+        return BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_MEMORY_ERROR;
+    } catch (const bt2::Error&) {
+        return BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
+    }
 }
 
 static inline bt_component_class_sink_consume_method_status
@@ -332,7 +329,7 @@ handle_packet_beginning_msg(struct fs_sink_comp *fs_sink, const bt_message *msg)
 
     stream = borrow_stream(fs_sink, ir_stream);
     if (G_UNLIKELY(!stream)) {
-        BT_COMP_LOGE_APPEND_CAUSE(fs_sink->self_comp, "Failed to borrow stream.");
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to borrow stream.");
         status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
         goto end;
     }
@@ -382,17 +379,18 @@ handle_packet_beginning_msg(struct fs_sink_comp *fs_sink, const bt_message *msg)
         }
 
         if (stream->discarded_events_state.beginning_cs != expected_cs) {
-            BT_COMP_LOGE_APPEND_CAUSE(fs_sink->self_comp,
-                                      "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);
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(
+                fs_sink->logger,
+                "Incompatible discarded events message: "
+                "unexpected beginning time: "
+                "beginning-cs-val={}, "
+                "expected-beginning-cs-val={}, "
+                "stream-id={}, stream-name=\"{}\", "
+                "trace-name=\"{}\", path=\"{}/{}\"",
+                stream->discarded_events_state.beginning_cs, expected_cs,
+                bt_stream_get_id(ir_stream), bt2c::maybeNull(bt_stream_get_name(ir_stream)),
+                bt2c::maybeNull(bt_trace_get_name(bt_stream_borrow_trace_const(ir_stream))),
+                stream->trace->path->str, stream->file_name->str);
             status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
             goto end;
         }
@@ -430,31 +428,32 @@ handle_packet_beginning_msg(struct fs_sink_comp *fs_sink, const bt_message *msg)
          * this case.
          */
         if (stream->prev_packet_state.end_cs == UINT64_C(-1)) {
-            BT_COMP_LOGE_APPEND_CAUSE(fs_sink->self_comp,
-                                      "Incompatible discarded packets message "
-                                      "occurring 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);
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(
+                fs_sink->logger,
+                "Incompatible discarded packets message "
+                "occurring before the stream's first packet: "
+                "stream-id={}, stream-name=\"{}\", "
+                "trace-name=\"{}\", path=\"{}/{}\"",
+                bt_stream_get_id(ir_stream), bt2c::maybeNull(bt_stream_get_name(ir_stream)),
+                bt2c::maybeNull(bt_trace_get_name(bt_stream_borrow_trace_const(ir_stream))),
+                stream->trace->path->str, stream->file_name->str);
             status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
             goto end;
         }
 
         if (stream->discarded_packets_state.beginning_cs != stream->prev_packet_state.end_cs) {
-            BT_COMP_LOGE_APPEND_CAUSE(fs_sink->self_comp,
-                                      "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);
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(
+                fs_sink->logger,
+                "Incompatible discarded packets message: "
+                "unexpected beginning time: "
+                "beginning-cs-val={}, "
+                "expected-beginning-cs-val={}, "
+                "stream-id={}, stream-name=\"{}\", "
+                "trace-name=\"{}\", path=\"{}/{}\"",
+                stream->discarded_packets_state.beginning_cs, stream->prev_packet_state.end_cs,
+                bt_stream_get_id(ir_stream), bt2c::maybeNull(bt_stream_get_name(ir_stream)),
+                bt2c::maybeNull(bt_trace_get_name(bt_stream_borrow_trace_const(ir_stream))),
+                stream->trace->path->str, stream->file_name->str);
             status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
             goto end;
         }
@@ -462,17 +461,18 @@ handle_packet_beginning_msg(struct fs_sink_comp *fs_sink, const bt_message *msg)
         expected_end_cs = bt_clock_snapshot_get_value(cs);
 
         if (stream->discarded_packets_state.end_cs != expected_end_cs) {
-            BT_COMP_LOGE_APPEND_CAUSE(fs_sink->self_comp,
-                                      "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);
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(
+                fs_sink->logger,
+                "Incompatible discarded packets message: "
+                "unexpected end time: "
+                "end-cs-val={}, "
+                "expected-end-cs-val={}, "
+                "stream-id={}, stream-name=\"{}\", "
+                "trace-name=\"{}\", path=\"{}/{}\"",
+                stream->discarded_packets_state.end_cs, expected_end_cs,
+                bt_stream_get_id(ir_stream), bt2c::maybeNull(bt_stream_get_name(ir_stream)),
+                bt2c::maybeNull(bt_trace_get_name(bt_stream_borrow_trace_const(ir_stream))),
+                stream->trace->path->str, stream->file_name->str);
             status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
             goto end;
         }
@@ -488,7 +488,7 @@ handle_packet_beginning_msg(struct fs_sink_comp *fs_sink, const bt_message *msg)
 
     ret = fs_sink_stream_open_packet(stream, cs, ir_packet);
     if (ret) {
-        BT_COMP_LOGE_APPEND_CAUSE(fs_sink->self_comp, "Failed to open packet.");
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to open packet.");
         status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
         goto end;
     }
@@ -510,7 +510,7 @@ handle_packet_end_msg(struct fs_sink_comp *fs_sink, const bt_message *msg)
 
     stream = borrow_stream(fs_sink, ir_stream);
     if (G_UNLIKELY(!stream)) {
-        BT_COMP_LOGE_APPEND_CAUSE(fs_sink->self_comp, "Failed to borrow stream.");
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to borrow stream.");
         status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
         goto end;
     }
@@ -549,17 +549,18 @@ handle_packet_end_msg(struct fs_sink_comp *fs_sink, const bt_message *msg)
         expected_cs = bt_clock_snapshot_get_value(cs);
 
         if (stream->discarded_events_state.end_cs != expected_cs) {
-            BT_COMP_LOGE_APPEND_CAUSE(fs_sink->self_comp,
-                                      "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);
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(
+                fs_sink->logger,
+                "Incompatible discarded events message: "
+                "unexpected end time: "
+                "end-cs-val={}, "
+                "expected-end-cs-val={}, "
+                "stream-id={}, stream-name=\"{}\", "
+                "trace-name=\"{}\", path=\"{}/{}\"",
+                stream->discarded_events_state.end_cs, expected_cs, bt_stream_get_id(ir_stream),
+                bt2c::maybeNull(bt_stream_get_name(ir_stream)),
+                bt2c::maybeNull(bt_trace_get_name(bt_stream_borrow_trace_const(ir_stream))),
+                stream->trace->path->str, stream->file_name->str);
             status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
             goto end;
         }
@@ -567,7 +568,7 @@ handle_packet_end_msg(struct fs_sink_comp *fs_sink, const bt_message *msg)
 
     ret = fs_sink_stream_close_packet(stream, cs);
     if (ret) {
-        BT_COMP_LOGE_APPEND_CAUSE(fs_sink->self_comp, "Failed to close packet.");
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to close packet.");
         status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
         goto end;
     }
@@ -605,15 +606,15 @@ handle_stream_beginning_msg(struct fs_sink_comp *fs_sink, const bt_message *msg)
         BT_ASSERT(!bt_stream_class_supports_discarded_packets(ir_sc));
 
         if (!fs_sink->ignore_discarded_events && bt_stream_class_supports_discarded_events(ir_sc)) {
-            BT_COMP_LOGE_APPEND_CAUSE(fs_sink->self_comp,
-                                      "Unsupported stream: "
-                                      "stream does not support packets, "
-                                      "but supports discarded events: "
-                                      "stream-addr=%p, "
-                                      "stream-id=%" PRIu64 ", "
-                                      "stream-name=\"%s\"",
-                                      ir_stream, bt_stream_get_id(ir_stream),
-                                      bt_stream_get_name(ir_stream));
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger,
+                                         "Unsupported stream: "
+                                         "stream does not support packets, "
+                                         "but supports discarded events: "
+                                         "stream-addr={}, "
+                                         "stream-id={}, "
+                                         "stream-name=\"{}\"",
+                                         fmt::ptr(ir_stream), bt_stream_get_id(ir_stream),
+                                         bt2c::maybeNull(bt_stream_get_name(ir_stream)));
             status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
             goto end;
         }
@@ -626,15 +627,15 @@ handle_stream_beginning_msg(struct fs_sink_comp *fs_sink, const bt_message *msg)
     if (!fs_sink->ignore_discarded_events &&
         bt_stream_class_discarded_events_have_default_clock_snapshots(ir_sc) &&
         !packets_have_beginning_end_cs) {
-        BT_COMP_LOGE_APPEND_CAUSE(fs_sink->self_comp,
-                                  "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));
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger,
+                                     "Unsupported stream: discarded events have "
+                                     "default clock snapshots, but packets have no "
+                                     "beginning and/or end default clock snapshots: "
+                                     "stream-addr={}, "
+                                     "stream-id={}, "
+                                     "stream-name=\"{}\"",
+                                     fmt::ptr(ir_stream), bt_stream_get_id(ir_stream),
+                                     bt2c::maybeNull(bt_stream_get_name(ir_stream)));
         status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
         goto end;
     }
@@ -647,32 +648,33 @@ handle_stream_beginning_msg(struct fs_sink_comp *fs_sink, const bt_message *msg)
     if (!fs_sink->ignore_discarded_packets &&
         bt_stream_class_discarded_packets_have_default_clock_snapshots(ir_sc) &&
         !packets_have_beginning_end_cs) {
-        BT_COMP_LOGE_APPEND_CAUSE(fs_sink->self_comp,
-                                  "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));
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger,
+                                     "Unsupported stream: discarded packets have "
+                                     "default clock snapshots, but packets have no "
+                                     "beginning and/or end default clock snapshots: "
+                                     "stream-addr={}, "
+                                     "stream-id={}, "
+                                     "stream-name=\"{}\"",
+                                     fmt::ptr(ir_stream), bt_stream_get_id(ir_stream),
+                                     bt2c::maybeNull(bt_stream_get_name(ir_stream)));
         status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
         goto end;
     }
 
     stream = borrow_stream(fs_sink, ir_stream);
     if (!stream) {
-        BT_COMP_LOGE_APPEND_CAUSE(fs_sink->self_comp, "Failed to borrow stream.");
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to borrow stream.");
         status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
         goto end;
     }
 
-    BT_COMP_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);
+    BT_CPPLOGI_SPEC(fs_sink->logger,
+                    "Created new, empty stream file: "
+                    "stream-id={}, stream-name=\"{}\", "
+                    "trace-name=\"{}\", path=\"{}/{}\"",
+                    bt_stream_get_id(ir_stream), bt2c::maybeNull(bt_stream_get_name(ir_stream)),
+                    bt2c::maybeNull(bt_trace_get_name(bt_stream_borrow_trace_const(ir_stream))),
+                    stream->trace->path->str, stream->file_name->str);
 
 end:
     return status;
@@ -688,7 +690,7 @@ handle_stream_end_msg(struct fs_sink_comp *fs_sink, const bt_message *msg)
 
     stream = borrow_stream(fs_sink, ir_stream);
     if (!stream) {
-        BT_COMP_LOGE_APPEND_CAUSE(fs_sink->self_comp, "Failed to borrow stream.");
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to borrow stream.");
         status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
         goto end;
     }
@@ -698,18 +700,19 @@ handle_stream_end_msg(struct fs_sink_comp *fs_sink, const bt_message *msg)
         int ret = fs_sink_stream_close_packet(stream, NULL);
 
         if (ret) {
-            BT_COMP_LOGE_APPEND_CAUSE(fs_sink->self_comp, "Failed to close packet.");
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to close packet.");
             status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
             goto end;
         }
     }
 
-    BT_COMP_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);
+    BT_CPPLOGI_SPEC(fs_sink->logger,
+                    "Closing stream file: "
+                    "stream-id={}, stream-name=\"{}\", "
+                    "trace-name=\"{}\", path=\"{}/{}\"",
+                    bt_stream_get_id(ir_stream), bt2c::maybeNull(bt_stream_get_name(ir_stream)),
+                    bt2c::maybeNull(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,
@@ -734,29 +737,31 @@ handle_discarded_events_msg(struct fs_sink_comp *fs_sink, const bt_message *msg)
 
     stream = borrow_stream(fs_sink, ir_stream);
     if (!stream) {
-        BT_COMP_LOGE_APPEND_CAUSE(fs_sink->self_comp, "Failed to borrow stream.");
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to borrow stream.");
         status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
         goto end;
     }
 
     if (fs_sink->ignore_discarded_events) {
-        BT_COMP_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);
+        BT_CPPLOGI_SPEC(fs_sink->logger,
+                        "Ignoring discarded events message: "
+                        "stream-id={}, stream-name=\"{}\", "
+                        "trace-name=\"{}\", path=\"{}/{}\"",
+                        bt_stream_get_id(ir_stream), bt2c::maybeNull(bt_stream_get_name(ir_stream)),
+                        bt2c::maybeNull(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_COMP_LOGE_APPEND_CAUSE(fs_sink->self_comp,
-                                  "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);
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(
+            fs_sink->logger,
+            "Unsupported contiguous discarded events message: "
+            "stream-id={}, stream-name=\"{}\", "
+            "trace-name=\"{}\", path=\"{}/{}\"",
+            bt_stream_get_id(ir_stream), bt2c::maybeNull(bt_stream_get_name(ir_stream)),
+            bt2c::maybeNull(bt_trace_get_name(bt_stream_borrow_trace_const(ir_stream))),
+            stream->trace->path->str, stream->file_name->str);
         status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
         goto end;
     }
@@ -770,14 +775,15 @@ handle_discarded_events_msg(struct fs_sink_comp *fs_sink, const bt_message *msg)
      * time.
      */
     if (stream->packet_state.is_open && stream->sc->discarded_events_has_ts) {
-        BT_COMP_LOGE_APPEND_CAUSE(fs_sink->self_comp,
-                                  "Unsupported discarded events message with "
-                                  "default clock snapshots occurring 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);
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(
+            fs_sink->logger,
+            "Unsupported discarded events message with "
+            "default clock snapshots occurring within a packet: "
+            "stream-id={}, stream-name=\"{}\", "
+            "trace-name=\"{}\", path=\"{}/{}\"",
+            bt_stream_get_id(ir_stream), bt2c::maybeNull(bt_stream_get_name(ir_stream)),
+            bt2c::maybeNull(bt_trace_get_name(bt_stream_borrow_trace_const(ir_stream))),
+            stream->trace->path->str, stream->file_name->str);
         status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
         goto end;
     }
@@ -833,29 +839,31 @@ handle_discarded_packets_msg(struct fs_sink_comp *fs_sink, const bt_message *msg
 
     stream = borrow_stream(fs_sink, ir_stream);
     if (!stream) {
-        BT_COMP_LOGE_APPEND_CAUSE(fs_sink->self_comp, "Failed to borrow stream.");
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to borrow stream.");
         status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
         goto end;
     }
 
     if (fs_sink->ignore_discarded_packets) {
-        BT_COMP_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);
+        BT_CPPLOGI_SPEC(fs_sink->logger,
+                        "Ignoring discarded packets message: "
+                        "stream-id={}, stream-name=\"{}\", "
+                        "trace-name=\"{}\", path=\"{}/{}\"",
+                        bt_stream_get_id(ir_stream), bt2c::maybeNull(bt_stream_get_name(ir_stream)),
+                        bt2c::maybeNull(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_COMP_LOGE_APPEND_CAUSE(fs_sink->self_comp,
-                                  "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);
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(
+            fs_sink->logger,
+            "Unsupported contiguous discarded packets message: "
+            "stream-id={}, stream-name=\"{}\", "
+            "trace-name=\"{}\", path=\"{}/{}\"",
+            bt_stream_get_id(ir_stream), bt2c::maybeNull(bt_stream_get_name(ir_stream)),
+            bt2c::maybeNull(bt_trace_get_name(bt_stream_borrow_trace_const(ir_stream))),
+            stream->trace->path->str, stream->file_name->str);
         status = BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
         goto end;
     }
@@ -930,8 +938,8 @@ bt_component_class_sink_consume_method_status ctf_fs_sink_consume(bt_self_compon
     next_status = bt_message_iterator_next(fs_sink->upstream_iter, &msgs, &msg_count);
     if (next_status < 0) {
         status = (bt_component_class_sink_consume_method_status) next_status;
-        BT_COMP_LOGE_APPEND_CAUSE(fs_sink->self_comp,
-                                  "Failed to get next message from upstream iterator.");
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger,
+                                     "Failed to get next message from upstream iterator.");
         goto end;
     }
 
@@ -957,7 +965,7 @@ bt_component_class_sink_consume_method_status ctf_fs_sink_consume(bt_self_compon
                 break;
             case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY:
                 /* Ignore */
-                BT_COMP_LOGD_STR("Ignoring message iterator inactivity message.");
+                BT_CPPLOGD_SPEC(fs_sink->logger, "Ignoring message iterator inactivity message.");
                 break;
             case BT_MESSAGE_TYPE_STREAM_BEGINNING:
                 status = handle_stream_beginning_msg(fs_sink, msg);
@@ -978,11 +986,11 @@ bt_component_class_sink_consume_method_status ctf_fs_sink_consume(bt_self_compon
             BT_MESSAGE_PUT_REF_AND_RESET(msgs[i]);
 
             if (status != BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_OK) {
-                BT_COMP_LOGE_APPEND_CAUSE(fs_sink->self_comp,
-                                          "Failed to handle message: "
-                                          "generated CTF traces could be incomplete: "
-                                          "output-dir-path=\"%s\"",
-                                          fs_sink->output_dir_path->str);
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger,
+                                             "Failed to handle message: "
+                                             "generated CTF traces could be incomplete: "
+                                             "output-dir-path=\"{}\"",
+                                             fs_sink->output_dir_path->str);
                 goto error;
             }
         }
@@ -1013,23 +1021,29 @@ end:
 bt_component_class_sink_graph_is_configured_method_status
 ctf_fs_sink_graph_is_configured(bt_self_component_sink *self_comp)
 {
-    bt_component_class_sink_graph_is_configured_method_status status;
-    bt_message_iterator_create_from_sink_component_status msg_iter_status;
-    fs_sink_comp *fs_sink = (fs_sink_comp *) bt_self_component_get_data(
-        bt_self_component_sink_as_self_component(self_comp));
-
-    msg_iter_status = bt_message_iterator_create_from_sink_component(
-        self_comp, bt_self_component_sink_borrow_input_port_by_name(self_comp, in_port_name),
-        &fs_sink->upstream_iter);
-    if (msg_iter_status != BT_MESSAGE_ITERATOR_CREATE_FROM_SINK_COMPONENT_STATUS_OK) {
-        status = (bt_component_class_sink_graph_is_configured_method_status) msg_iter_status;
-        BT_COMP_LOGE_APPEND_CAUSE(fs_sink->self_comp, "Failed to create upstream iterator.");
-        goto end;
-    }
+    try {
+        bt_component_class_sink_graph_is_configured_method_status status;
+        bt_message_iterator_create_from_sink_component_status msg_iter_status;
+        fs_sink_comp *fs_sink = (fs_sink_comp *) bt_self_component_get_data(
+            bt_self_component_sink_as_self_component(self_comp));
+
+        msg_iter_status = bt_message_iterator_create_from_sink_component(
+            self_comp, bt_self_component_sink_borrow_input_port_by_name(self_comp, in_port_name),
+            &fs_sink->upstream_iter);
+        if (msg_iter_status != BT_MESSAGE_ITERATOR_CREATE_FROM_SINK_COMPONENT_STATUS_OK) {
+            status = (bt_component_class_sink_graph_is_configured_method_status) msg_iter_status;
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(fs_sink->logger, "Failed to create upstream iterator.");
+            goto end;
+        }
 
-    status = BT_COMPONENT_CLASS_SINK_GRAPH_IS_CONFIGURED_METHOD_STATUS_OK;
+        status = BT_COMPONENT_CLASS_SINK_GRAPH_IS_CONFIGURED_METHOD_STATUS_OK;
 end:
-    return status;
+        return status;
+    } catch (const std::bad_alloc&) {
+        return BT_COMPONENT_CLASS_SINK_GRAPH_IS_CONFIGURED_METHOD_STATUS_MEMORY_ERROR;
+    } catch (const bt2c::Error&) {
+        return BT_COMPONENT_CLASS_SINK_GRAPH_IS_CONFIGURED_METHOD_STATUS_ERROR;
+    }
 }
 
 void ctf_fs_sink_finalize(bt_self_component_sink *self_comp)
index 3c1e01282f323e2ef6cc397579afc76d0c734c92..529ae346027a4b0a3f544a6864077668d5777655 100644 (file)
 
 #include <babeltrace2/babeltrace.h>
 
+#include "cpp-common/bt2c/logging.hpp"
+
 struct fs_sink_comp
 {
-    bt_logging_level log_level;
-    bt_self_component *self_comp;
+    explicit fs_sink_comp(const bt2::SelfSinkComponent selfSinkComp) :
+        logger {selfSinkComp, "PLUGIN/SINK.CTF.FS/COMP"}
+    {
+    }
+
+    bt2c::Logger logger;
 
     /* Owned by this */
-    bt_message_iterator *upstream_iter;
+    bt_message_iterator *upstream_iter = nullptr;
 
     /* Base output directory path */
-    GString *output_dir_path;
+    GString *output_dir_path = nullptr;
 
     /*
      * True if the component assumes that it will only write a
@@ -28,25 +34,25 @@ struct fs_sink_comp
      * streams). This makes the component write the stream files
      * directly in the output directory (`output_dir_path` above).
      */
-    bool assume_single_trace;
+    bool assume_single_trace = false;
 
     /* True to completely ignore discarded events messages */
-    bool ignore_discarded_events;
+    bool ignore_discarded_events = false;
 
     /* True to completely ignore discarded packets messages */
-    bool ignore_discarded_packets;
+    bool ignore_discarded_packets = false;
 
     /*
      * True to make the component quiet (nothing printed to the
      * standard output).
      */
-    bool quiet;
+    bool quiet = false;
 
     /*
      * Hash table of `const bt_trace *` (weak) to
      * `struct fs_sink_trace *` (owned by hash table).
      */
-    GHashTable *traces;
+    GHashTable *traces = nullptr;
 };
 
 bt_component_class_initialize_method_status
index db7af8658fd15436aaeb361dcd482fb1bdd31f5d..c45a16857a07dbc93045d71000ef78bef3681836 100644 (file)
 #include "fs-sink-ctf-meta.hpp"
 #include "translate-ctf-ir-to-tsdl.hpp"
 
-struct ctx
+namespace ctf {
+namespace sink {
+
+struct CtfIrToTsdlCtx
 {
     unsigned int indent_level;
     GString *tsdl;
 };
 
-static inline void append_indent(struct ctx *ctx)
+} /* namespace sink */
+} /* namespace ctf */
+
+static inline void append_indent(ctf::sink::CtfIrToTsdlCtx *ctx)
 {
     unsigned int i;
 
@@ -30,12 +36,12 @@ static inline void append_indent(struct ctx *ctx)
     }
 }
 
-static void append_uuid(struct ctx *ctx, bt_uuid uuid)
+static void append_uuid(ctf::sink::CtfIrToTsdlCtx *ctx, bt_uuid uuid)
 {
     g_string_append_printf(ctx->tsdl, "\"" BT_UUID_FMT "\"", BT_UUID_FMT_VALUES(uuid));
 }
 
-static void append_quoted_string_content(struct ctx *ctx, const char *str)
+static void append_quoted_string_content(ctf::sink::CtfIrToTsdlCtx *ctx, const char *str)
 {
     const char *ch;
 
@@ -78,7 +84,7 @@ static void append_quoted_string_content(struct ctx *ctx, const char *str)
     }
 }
 
-static void append_quoted_string(struct ctx *ctx, const char *str)
+static void append_quoted_string(ctf::sink::CtfIrToTsdlCtx *ctx, const char *str)
 {
     g_string_append_c(ctx->tsdl, '"');
     append_quoted_string_content(ctx, str);
@@ -86,7 +92,7 @@ static void append_quoted_string(struct ctx *ctx, const char *str)
 }
 
 static void append_integer_field_class_from_props(
-    struct ctx *ctx, unsigned int size, unsigned int alignment, bool is_signed,
+    ctf::sink::CtfIrToTsdlCtx *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)
 {
@@ -131,27 +137,27 @@ static void append_integer_field_class_from_props(
     }
 }
 
-static void append_end_block(struct ctx *ctx)
+static void append_end_block(ctf::sink::CtfIrToTsdlCtx *ctx)
 {
     ctx->indent_level--;
     append_indent(ctx);
     g_string_append(ctx->tsdl, "}");
 }
 
-static void append_end_block_semi_nl(struct ctx *ctx)
+static void append_end_block_semi_nl(ctf::sink::CtfIrToTsdlCtx *ctx)
 {
     ctx->indent_level--;
     append_indent(ctx);
     g_string_append(ctx->tsdl, "};\n");
 }
 
-static void append_end_block_semi_nl_nl(struct ctx *ctx)
+static void append_end_block_semi_nl_nl(ctf::sink::CtfIrToTsdlCtx *ctx)
 {
     append_end_block_semi_nl(ctx);
     g_string_append_c(ctx->tsdl, '\n');
 }
 
-static void append_bool_field_class(struct ctx *ctx,
+static void append_bool_field_class(ctf::sink::CtfIrToTsdlCtx *ctx,
                                     __attribute__((unused)) struct fs_sink_ctf_field_class_bool *fc)
 {
     /*
@@ -163,7 +169,7 @@ static void append_bool_field_class(struct ctx *ctx,
                                           NULL, NULL, false);
 }
 
-static void append_bit_array_field_class(struct ctx *ctx,
+static void append_bit_array_field_class(ctf::sink::CtfIrToTsdlCtx *ctx,
                                          struct fs_sink_ctf_field_class_bit_array *fc)
 {
     /*
@@ -176,7 +182,8 @@ static void append_bit_array_field_class(struct ctx *ctx,
                                           NULL, NULL, false);
 }
 
-static void append_integer_field_class(struct ctx *ctx, struct fs_sink_ctf_field_class_int *fc)
+static void append_integer_field_class(ctf::sink::CtfIrToTsdlCtx *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);
@@ -269,7 +276,8 @@ static void append_integer_field_class(struct ctx *ctx, struct fs_sink_ctf_field
     }
 }
 
-static void append_float_field_class(struct ctx *ctx, struct fs_sink_ctf_field_class_float *fc)
+static void append_float_field_class(ctf::sink::CtfIrToTsdlCtx *ctx,
+                                     struct fs_sink_ctf_field_class_float *fc)
 {
     unsigned int mant_dig, exp_dig;
 
@@ -285,14 +293,15 @@ static void append_float_field_class(struct ctx *ctx, struct fs_sink_ctf_field_c
                            mant_dig, exp_dig, fc->base.base.alignment);
 }
 
-static void append_string_field_class(struct ctx *ctx)
+static void append_string_field_class(ctf::sink::CtfIrToTsdlCtx *ctx)
 {
     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_field_class(ctf::sink::CtfIrToTsdlCtx *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)
+static void append_member(ctf::sink::CtfIrToTsdlCtx *ctx, const char *name,
+                          struct fs_sink_ctf_field_class *fc)
 {
     GString *lengths = NULL;
     const char *lengths_str = "";
@@ -333,7 +342,7 @@ static void append_member(struct ctx *ctx, const char *name, struct fs_sink_ctf_
     }
 }
 
-static void append_struct_field_class_members(struct ctx *ctx,
+static void append_struct_field_class_members(ctf::sink::CtfIrToTsdlCtx *ctx,
                                               struct fs_sink_ctf_field_class_struct *struct_fc)
 {
     uint64_t i;
@@ -431,7 +440,8 @@ static void append_struct_field_class_members(struct ctx *ctx,
     }
 }
 
-static void append_struct_field_class(struct ctx *ctx, struct fs_sink_ctf_field_class_struct *fc)
+static void append_struct_field_class(ctf::sink::CtfIrToTsdlCtx *ctx,
+                                      struct fs_sink_ctf_field_class_struct *fc)
 {
     g_string_append(ctx->tsdl, "struct {\n");
     ctx->indent_level++;
@@ -440,7 +450,7 @@ static void append_struct_field_class(struct ctx *ctx, struct fs_sink_ctf_field_
     g_string_append_printf(ctx->tsdl, " align(%u)", fc->base.alignment);
 }
 
-static void append_option_field_class(struct ctx *ctx,
+static void append_option_field_class(ctf::sink::CtfIrToTsdlCtx *ctx,
                                       struct fs_sink_ctf_field_class_option *opt_fc)
 {
     g_string_append_printf(ctx->tsdl, "variant <%s> {\n", opt_fc->tag_ref->str);
@@ -452,7 +462,7 @@ static void append_option_field_class(struct ctx *ctx,
     append_end_block(ctx);
 }
 
-static void append_variant_field_class(struct ctx *ctx,
+static void append_variant_field_class(ctf::sink::CtfIrToTsdlCtx *ctx,
                                        struct fs_sink_ctf_field_class_variant *var_fc)
 {
     uint64_t i;
@@ -471,7 +481,7 @@ static void append_variant_field_class(struct ctx *ctx,
     append_end_block(ctx);
 }
 
-static void append_field_class(struct ctx *ctx, struct fs_sink_ctf_field_class *fc)
+static void append_field_class(ctf::sink::CtfIrToTsdlCtx *ctx, struct fs_sink_ctf_field_class *fc)
 {
     switch (fc->type) {
     case FS_SINK_CTF_FIELD_CLASS_TYPE_BOOL:
@@ -503,7 +513,7 @@ static void append_field_class(struct ctx *ctx, struct fs_sink_ctf_field_class *
     }
 }
 
-static void append_event_class(struct ctx *ctx, struct fs_sink_ctf_event_class *ec)
+static void append_event_class(ctf::sink::CtfIrToTsdlCtx *ctx, struct fs_sink_ctf_event_class *ec)
 {
     const char *str;
     bt_event_class_log_level log_level;
@@ -615,7 +625,7 @@ static void append_event_class(struct ctx *ctx, struct fs_sink_ctf_event_class *
     append_end_block_semi_nl_nl(ctx);
 }
 
-static void append_stream_class(struct ctx *ctx, struct fs_sink_ctf_stream_class *sc)
+static void append_stream_class(ctf::sink::CtfIrToTsdlCtx *ctx, struct fs_sink_ctf_stream_class *sc)
 {
     uint64_t i;
 
@@ -776,7 +786,7 @@ static void append_stream_class(struct ctx *ctx, struct fs_sink_ctf_stream_class
 
 void translate_trace_ctf_ir_to_tsdl(struct fs_sink_ctf_trace *trace, GString *tsdl)
 {
-    struct ctx ctx = {
+    ctf::sink::CtfIrToTsdlCtx ctx = {
         .indent_level = 0,
         .tsdl = tsdl,
     };
index 72a29140a4d39509dc5b4156ccebcba85e647144..ca634b952aba11b45143748c9b34a37824c0ca46 100644 (file)
 
 #include <babeltrace2/babeltrace.h>
 
-#define BT_COMP_LOG_SELF_COMP (ctx->self_comp)
-#define BT_LOG_OUTPUT_LEVEL   (ctx->log_level)
-#define BT_LOG_TAG            "PLUGIN/SINK.CTF.FS/TRANSLATE-TRACE-IR-TO-CTF-IR"
-#include "logging/comp-logging.h"
-
 #include "common/assert.h"
 #include "common/common.h"
+#include "cpp-common/bt2/field-path.hpp"
+#include "cpp-common/bt2c/fmt.hpp"
 
 #include "fs-sink-ctf-meta.hpp"
 #include "fs-sink.hpp"
@@ -26,7 +23,6 @@
 
 struct field_path_elem
 {
-    uint64_t index_in_parent;
     GString *name;
 
     /* Weak */
@@ -36,31 +32,42 @@ struct field_path_elem
     struct fs_sink_ctf_field_class *parent_fc;
 };
 
-struct ctx
+namespace ctf {
+namespace sink {
+
+struct TraceIrToCtfIrCtx
 {
-    bt_logging_level log_level;
-    bt_self_component *self_comp;
+    explicit TraceIrToCtfIrCtx(const bt2c::Logger& parentLogger) :
+        logger {parentLogger, "PLUGIN/SINK.CTF.FS/TRANSLATE-TRACE-IR-TO-CTF-IR"}
+    {
+    }
+
+    bt2c::Logger logger;
 
     /* Weak */
-    struct fs_sink_ctf_stream_class *cur_sc;
+    struct fs_sink_ctf_stream_class *cur_sc = nullptr;
 
     /* Weak */
-    struct fs_sink_ctf_event_class *cur_ec;
+    struct fs_sink_ctf_event_class *cur_ec = nullptr;
 
-    bt_field_path_scope cur_scope;
+    bt_field_path_scope cur_scope = BT_FIELD_PATH_SCOPE_PACKET_CONTEXT;
 
     /*
      * Array of `struct field_path_elem` */
-    GArray *cur_path;
+    GArray *cur_path = nullptr;
 };
 
-static inline struct field_path_elem *cur_path_stack_at(struct ctx *ctx, uint64_t i)
+} /* namespace sink */
+} /* namespace ctf */
+
+static inline struct field_path_elem *cur_path_stack_at(ctf::sink::TraceIrToCtfIrCtx *ctx,
+                                                        uint64_t i)
 {
     BT_ASSERT(i < ctx->cur_path->len);
     return &bt_g_array_index(ctx->cur_path, struct field_path_elem, i);
 }
 
-static inline struct field_path_elem *cur_path_stack_top(struct ctx *ctx)
+static inline struct field_path_elem *cur_path_stack_top(ctf::sink::TraceIrToCtfIrCtx *ctx)
 {
     BT_ASSERT(ctx->cur_path->len > 0);
     return cur_path_stack_at(ctx, ctx->cur_path->len - 1);
@@ -152,7 +159,7 @@ end:
     return must_protect;
 }
 
-static inline int cur_path_stack_push(struct ctx *ctx, uint64_t index_in_parent, const char *name,
+static inline int cur_path_stack_push(ctf::sink::TraceIrToCtfIrCtx *ctx, const char *name,
                                       bool force_protect_name, const bt_field_class *ir_fc,
                                       struct fs_sink_ctf_field_class *parent_fc)
 {
@@ -161,7 +168,6 @@ static inline int cur_path_stack_push(struct ctx *ctx, uint64_t index_in_parent,
 
     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(NULL);
 
     if (name) {
@@ -178,9 +184,10 @@ static inline int cur_path_stack_push(struct ctx *ctx, uint64_t index_in_parent,
                 is_reserved_member_name(name, "timestamp_end") ||
                 is_reserved_member_name(name, "events_discarded") ||
                 is_reserved_member_name(name, "packet_seq_num")) {
-                BT_COMP_LOGE("Unsupported reserved TSDL structure field class member "
-                             "or variant field class option name: name=\"%s\"",
-                             name);
+                BT_CPPLOGE_SPEC(ctx->logger,
+                                "Unsupported reserved TSDL structure field class member "
+                                "or variant field class option name: name=\"{}\"",
+                                name);
                 ret = -1;
                 goto end;
             }
@@ -188,9 +195,10 @@ static inline int cur_path_stack_push(struct ctx *ctx, uint64_t index_in_parent,
 
         if (!ist_valid_identifier(field_path_elem->name->str)) {
             ret = -1;
-            BT_COMP_LOGE("Unsupported non-TSDL structure field class member "
-                         "or variant field class option name: name=\"%s\"",
-                         field_path_elem->name->str);
+            BT_CPPLOGE_SPEC(ctx->logger,
+                            "Unsupported non-TSDL structure field class member "
+                            "or variant field class option name: name=\"{}\"",
+                            field_path_elem->name->str);
             goto end;
         }
     }
@@ -202,7 +210,7 @@ end:
     return ret;
 }
 
-static inline void cur_path_stack_pop(struct ctx *ctx)
+static inline void cur_path_stack_pop(ctf::sink::TraceIrToCtfIrCtx *ctx)
 {
     struct field_path_elem *field_path_elem;
 
@@ -229,8 +237,8 @@ static inline void cur_path_stack_pop(struct ctx *ctx)
  *
  * 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,
+static int create_relative_field_ref(ctf::sink::TraceIrToCtfIrCtx *ctx,
+                                     const bt_field_path *tgt_ir_field_path, GString *tgt_field_ref,
                                      struct fs_sink_ctf_field_class **user_tgt_fc)
 {
     int ret = 0;
@@ -394,8 +402,8 @@ end:
  *
  * 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,
+static int create_absolute_field_ref(ctf::sink::TraceIrToCtfIrCtx *ctx,
+                                     const bt_field_path *tgt_ir_field_path, GString *tgt_field_ref,
                                      struct fs_sink_ctf_field_class **user_tgt_fc)
 {
     int ret = 0;
@@ -477,9 +485,9 @@ end:
  * 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,
-                                struct fs_sink_ctf_field_class **user_tgt_fc)
+static void resolve_field_class(ctf::sink::TraceIrToCtfIrCtx *ctx,
+                                const bt_field_path *tgt_ir_field_path, GString *tgt_field_ref,
+                                bool *create_before, struct fs_sink_ctf_field_class **user_tgt_fc)
 {
     int ret;
     bt_field_path_scope tgt_scope;
@@ -527,9 +535,10 @@ end:
     return;
 }
 
-static int translate_field_class(struct ctx *ctx);
+static int translate_field_class(ctf::sink::TraceIrToCtfIrCtx *ctx);
 
-static inline void append_to_parent_field_class(struct ctx *ctx, struct fs_sink_ctf_field_class *fc)
+static inline void append_to_parent_field_class(ctf::sink::TraceIrToCtfIrCtx *ctx,
+                                                struct fs_sink_ctf_field_class *fc)
 {
     struct fs_sink_ctf_field_class *parent_fc = cur_path_stack_top(ctx)->parent_fc;
 
@@ -568,7 +577,8 @@ static inline void append_to_parent_field_class(struct ctx *ctx, struct fs_sink_
     }
 }
 
-static inline void update_parent_field_class_alignment(struct ctx *ctx, unsigned int alignment)
+static inline void update_parent_field_class_alignment(ctf::sink::TraceIrToCtfIrCtx *ctx,
+                                                       unsigned int alignment)
 {
     struct fs_sink_ctf_field_class *parent_fc = cur_path_stack_top(ctx)->parent_fc;
 
@@ -591,8 +601,10 @@ static inline void update_parent_field_class_alignment(struct ctx *ctx, unsigned
     }
 }
 
-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)
+static inline int
+translate_structure_field_class_members(ctf::sink::TraceIrToCtfIrCtx *ctx,
+                                        struct fs_sink_ctf_field_class_struct *struct_fc,
+                                        const bt_field_class *ir_fc)
 {
     int ret = 0;
     uint64_t i;
@@ -605,19 +617,21 @@ static inline int translate_structure_field_class_members(
         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, true, memb_ir_fc, &struct_fc->base);
+        ret = cur_path_stack_push(ctx, name, true, memb_ir_fc, &struct_fc->base);
         if (ret) {
-            BT_COMP_LOGE("Cannot translate structure field class member: "
-                         "name=\"%s\"",
-                         name);
+            BT_CPPLOGE_SPEC(ctx->logger,
+                            "Cannot translate structure field class member: "
+                            "name=\"{}\"",
+                            name);
             goto end;
         }
 
         ret = translate_field_class(ctx);
         if (ret) {
-            BT_COMP_LOGE("Cannot translate structure field class member: "
-                         "name=\"%s\"",
-                         name);
+            BT_CPPLOGE_SPEC(ctx->logger,
+                            "Cannot translate structure field class member: "
+                            "name=\"{}\"",
+                            name);
             goto end;
         }
 
@@ -628,11 +642,11 @@ end:
     return ret;
 }
 
-static inline int translate_structure_field_class(struct ctx *ctx)
+static inline int translate_structure_field_class(ctf::sink::TraceIrToCtfIrCtx *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);
+    struct fs_sink_ctf_field_class_struct *fc =
+        fs_sink_ctf_field_class_struct_create_empty(cur_path_stack_top(ctx)->ir_fc);
 
     BT_ASSERT(fc);
     append_to_parent_field_class(ctx, &fc->base);
@@ -842,10 +856,10 @@ end:
     return ret;
 }
 
-static inline int translate_option_field_class(struct ctx *ctx)
+static inline int translate_option_field_class(ctf::sink::TraceIrToCtfIrCtx *ctx)
 {
-    struct fs_sink_ctf_field_class_option *fc = fs_sink_ctf_field_class_option_create_empty(
-        cur_path_stack_top(ctx)->ir_fc, cur_path_stack_top(ctx)->index_in_parent);
+    struct fs_sink_ctf_field_class_option *fc =
+        fs_sink_ctf_field_class_option_create_empty(cur_path_stack_top(ctx)->ir_fc);
     const bt_field_class *content_ir_fc =
         bt_field_class_option_borrow_field_class_const(fc->base.ir_fc);
     int ret;
@@ -864,15 +878,15 @@ static inline int translate_option_field_class(struct ctx *ctx)
      * unsigned enumeration field class).
      */
     append_to_parent_field_class(ctx, &fc->base);
-    ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, false, content_ir_fc, &fc->base);
+    ret = cur_path_stack_push(ctx, NULL, false, content_ir_fc, &fc->base);
     if (ret) {
-        BT_COMP_LOGE_STR("Cannot translate option field class content.");
+        BT_CPPLOGE_SPEC(ctx->logger, "Cannot translate option field class content.");
         goto end;
     }
 
     ret = translate_field_class(ctx);
     if (ret) {
-        BT_COMP_LOGE_STR("Cannot translate option field class content.");
+        BT_CPPLOGE_SPEC(ctx->logger, "Cannot translate option field class content.");
         goto end;
     }
 
@@ -883,12 +897,12 @@ end:
     return ret;
 }
 
-static inline int translate_variant_field_class(struct ctx *ctx)
+static inline int translate_variant_field_class(ctf::sink::TraceIrToCtfIrCtx *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);
+    struct fs_sink_ctf_field_class_variant *fc =
+        fs_sink_ctf_field_class_variant_create_empty(cur_path_stack_top(ctx)->ir_fc);
     bt_field_class_type ir_fc_type;
     const bt_field_path *ir_selector_field_path = NULL;
     struct fs_sink_ctf_field_class *tgt_fc = NULL;
@@ -1015,19 +1029,21 @@ append_to_parent:
          * option name because it's already protected at this
          * point.
          */
-        ret = cur_path_stack_push(ctx, i, prot_opt_name, false, opt_ir_fc, &fc->base);
+        ret = cur_path_stack_push(ctx, prot_opt_name, false, opt_ir_fc, &fc->base);
         if (ret) {
-            BT_COMP_LOGE("Cannot translate variant field class option: "
-                         "name=\"%s\"",
-                         prot_opt_name);
+            BT_CPPLOGE_SPEC(ctx->logger,
+                            "Cannot translate variant field class option: "
+                            "name=\"{}\"",
+                            prot_opt_name);
             goto end;
         }
 
         ret = translate_field_class(ctx);
         if (ret) {
-            BT_COMP_LOGE("Cannot translate variant field class option: "
-                         "name=\"%s\"",
-                         prot_opt_name);
+            BT_CPPLOGE_SPEC(ctx->logger,
+                            "Cannot translate variant field class option: "
+                            "name=\"{}\"",
+                            prot_opt_name);
             goto end;
         }
 
@@ -1043,25 +1059,25 @@ end:
     return ret;
 }
 
-static inline int translate_static_array_field_class(struct ctx *ctx)
+static inline int translate_static_array_field_class(ctf::sink::TraceIrToCtfIrCtx *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);
+    struct fs_sink_ctf_field_class_array *fc =
+        fs_sink_ctf_field_class_array_create_empty(cur_path_stack_top(ctx)->ir_fc);
     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, &fc->base.base);
-    ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, false, elem_ir_fc, &fc->base.base);
+    ret = cur_path_stack_push(ctx, NULL, false, elem_ir_fc, &fc->base.base);
     if (ret) {
-        BT_COMP_LOGE_STR("Cannot translate static array field class element.");
+        BT_CPPLOGE_SPEC(ctx->logger, "Cannot translate static array field class element.");
         goto end;
     }
 
     ret = translate_field_class(ctx);
     if (ret) {
-        BT_COMP_LOGE_STR("Cannot translate static array field class element.");
+        BT_CPPLOGE_SPEC(ctx->logger, "Cannot translate static array field class element.");
         goto end;
     }
 
@@ -1072,10 +1088,10 @@ end:
     return ret;
 }
 
-static inline int translate_dynamic_array_field_class(struct ctx *ctx)
+static inline int translate_dynamic_array_field_class(ctf::sink::TraceIrToCtfIrCtx *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);
+    struct fs_sink_ctf_field_class_sequence *fc =
+        fs_sink_ctf_field_class_sequence_create_empty(cur_path_stack_top(ctx)->ir_fc);
     const bt_field_class *elem_ir_fc =
         bt_field_class_array_borrow_element_field_class_const(fc->base.base.ir_fc);
     int ret;
@@ -1093,15 +1109,15 @@ static inline int translate_dynamic_array_field_class(struct ctx *ctx)
     }
 
     append_to_parent_field_class(ctx, &fc->base.base);
-    ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, false, elem_ir_fc, &fc->base.base);
+    ret = cur_path_stack_push(ctx, NULL, false, elem_ir_fc, &fc->base.base);
     if (ret) {
-        BT_COMP_LOGE_STR("Cannot translate dynamic array field class element.");
+        BT_CPPLOGE_SPEC(ctx->logger, "Cannot translate dynamic array field class element.");
         goto end;
     }
 
     ret = translate_field_class(ctx);
     if (ret) {
-        BT_COMP_LOGE_STR("Cannot translate dynamic array field class element.");
+        BT_CPPLOGE_SPEC(ctx->logger, "Cannot translate dynamic array field class element.");
         goto end;
     }
 
@@ -1112,50 +1128,50 @@ end:
     return ret;
 }
 
-static inline int translate_bool_field_class(struct ctx *ctx)
+static inline int translate_bool_field_class(ctf::sink::TraceIrToCtfIrCtx *ctx)
 {
-    struct fs_sink_ctf_field_class_bool *fc = fs_sink_ctf_field_class_bool_create(
-        cur_path_stack_top(ctx)->ir_fc, cur_path_stack_top(ctx)->index_in_parent);
+    struct fs_sink_ctf_field_class_bool *fc =
+        fs_sink_ctf_field_class_bool_create(cur_path_stack_top(ctx)->ir_fc);
 
     BT_ASSERT(fc);
     append_to_parent_field_class(ctx, &fc->base.base);
     return 0;
 }
 
-static inline int translate_bit_array_field_class(struct ctx *ctx)
+static inline int translate_bit_array_field_class(ctf::sink::TraceIrToCtfIrCtx *ctx)
 {
-    struct fs_sink_ctf_field_class_bit_array *fc = fs_sink_ctf_field_class_bit_array_create(
-        cur_path_stack_top(ctx)->ir_fc, cur_path_stack_top(ctx)->index_in_parent);
+    struct fs_sink_ctf_field_class_bit_array *fc =
+        fs_sink_ctf_field_class_bit_array_create(cur_path_stack_top(ctx)->ir_fc);
 
     BT_ASSERT(fc);
     append_to_parent_field_class(ctx, &fc->base);
     return 0;
 }
 
-static inline int translate_integer_field_class(struct ctx *ctx)
+static inline int translate_integer_field_class(ctf::sink::TraceIrToCtfIrCtx *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);
+    struct fs_sink_ctf_field_class_int *fc =
+        fs_sink_ctf_field_class_int_create(cur_path_stack_top(ctx)->ir_fc);
 
     BT_ASSERT(fc);
     append_to_parent_field_class(ctx, &fc->base.base);
     return 0;
 }
 
-static inline int translate_real_field_class(struct ctx *ctx)
+static inline int translate_real_field_class(ctf::sink::TraceIrToCtfIrCtx *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);
+    struct fs_sink_ctf_field_class_float *fc =
+        fs_sink_ctf_field_class_float_create(cur_path_stack_top(ctx)->ir_fc);
 
     BT_ASSERT(fc);
     append_to_parent_field_class(ctx, &fc->base.base);
     return 0;
 }
 
-static inline int translate_string_field_class(struct ctx *ctx)
+static inline int translate_string_field_class(ctf::sink::TraceIrToCtfIrCtx *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);
+    struct fs_sink_ctf_field_class_string *fc =
+        fs_sink_ctf_field_class_string_create(cur_path_stack_top(ctx)->ir_fc);
 
     BT_ASSERT(fc);
     append_to_parent_field_class(ctx, &fc->base);
@@ -1169,7 +1185,7 @@ static inline int translate_string_field_class(struct ctx *ctx)
  * 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)
+static int translate_field_class(ctf::sink::TraceIrToCtfIrCtx *ctx)
 {
     int ret;
     bt_field_class_type ir_fc_type = bt_field_class_get_type(cur_path_stack_top(ctx)->ir_fc);
@@ -1419,7 +1435,7 @@ end:
  * class and then calls translate_structure_field_class_members() to
  * fill it.
  */
-static int translate_scope_field_class(struct ctx *ctx, bt_field_path_scope scope,
+static int translate_scope_field_class(ctf::sink::TraceIrToCtfIrCtx *ctx, bt_field_path_scope scope,
                                        struct fs_sink_ctf_field_class **fc,
                                        const bt_field_class *ir_fc)
 {
@@ -1431,24 +1447,22 @@ static int translate_scope_field_class(struct ctx *ctx, bt_field_path_scope scop
 
     BT_ASSERT(bt_field_class_get_type(ir_fc) == BT_FIELD_CLASS_TYPE_STRUCTURE);
     BT_ASSERT(fc);
-    *fc = &fs_sink_ctf_field_class_struct_create_empty(ir_fc, UINT64_C(-1))->base;
+    *fc = &fs_sink_ctf_field_class_struct_create_empty(ir_fc)->base;
     BT_ASSERT(*fc);
     ctx->cur_scope = scope;
     BT_ASSERT(ctx->cur_path->len == 0);
-    ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, false, ir_fc, NULL);
+    ret = cur_path_stack_push(ctx, NULL, false, ir_fc, NULL);
     if (ret) {
-        BT_COMP_LOGE("Cannot translate scope structure field class: "
-                     "scope=%d",
-                     scope);
+        BT_CPPLOGE_SPEC(ctx->logger, "Cannot translate scope structure field class: scope={}",
+                        static_cast<bt2::FieldPathScope>(scope));
         goto end;
     }
 
     ret =
         translate_structure_field_class_members(ctx, fs_sink_ctf_field_class_as_struct(*fc), ir_fc);
     if (ret) {
-        BT_COMP_LOGE("Cannot translate scope structure field class: "
-                     "scope=%d",
-                     scope);
+        BT_CPPLOGE_SPEC(ctx->logger, "Cannot translate scope structure field class: scope={}",
+                        static_cast<bt2::FieldPathScope>(scope));
         goto end;
     }
 
@@ -1461,16 +1475,13 @@ end:
     return ret;
 }
 
-static inline void ctx_init(struct ctx *ctx, struct fs_sink_comp *fs_sink)
+static inline void ctx_init(ctf::sink::TraceIrToCtfIrCtx *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);
-    ctx->log_level = fs_sink->log_level;
-    ctx->self_comp = fs_sink->self_comp;
 }
 
-static inline void ctx_fini(struct ctx *ctx)
+static inline void ctx_fini(ctf::sink::TraceIrToCtfIrCtx *ctx)
 {
     if (ctx->cur_path) {
         g_array_free(ctx->cur_path, TRUE);
@@ -1483,13 +1494,13 @@ static int translate_event_class(struct fs_sink_comp *fs_sink, struct fs_sink_ct
                                  struct fs_sink_ctf_event_class **out_ec)
 {
     int ret = 0;
-    struct ctx ctx;
+    ctf::sink::TraceIrToCtfIrCtx ctx {fs_sink->logger};
     struct fs_sink_ctf_event_class *ec;
 
     BT_ASSERT(sc);
     BT_ASSERT(ir_ec);
 
-    ctx_init(&ctx, fs_sink);
+    ctx_init(&ctx);
     ec = fs_sink_ctf_event_class_create(sc, ir_ec);
     BT_ASSERT(ec);
     ctx.cur_sc = sc;
@@ -1578,11 +1589,11 @@ static int translate_stream_class(struct fs_sink_comp *fs_sink, struct fs_sink_c
                                   struct fs_sink_ctf_stream_class **out_sc)
 {
     int ret = 0;
-    struct ctx ctx;
+    ctf::sink::TraceIrToCtfIrCtx ctx {fs_sink->logger};
 
     BT_ASSERT(trace);
     BT_ASSERT(ir_sc);
-    ctx_init(&ctx, fs_sink);
+    ctx_init(&ctx);
     *out_sc = fs_sink_ctf_stream_class_create(trace, ir_sc);
     BT_ASSERT(*out_sc);
 
@@ -1686,10 +1697,10 @@ struct fs_sink_ctf_trace *translate_trace_trace_ir_to_ctf_ir(struct fs_sink_comp
         bt_trace_borrow_environment_entry_by_index_const(ir_trace, i, &name, &val);
 
         if (!ist_valid_identifier(name)) {
-            BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, fs_sink->log_level, fs_sink->self_comp,
-                                "Unsupported trace class's environment entry name: "
-                                "name=\"%s\"",
-                                name);
+            BT_CPPLOGE_SPEC(fs_sink->logger,
+                            "Unsupported trace class's environment entry name: "
+                            "name=\"{}\"",
+                            name);
             goto end;
         }
 
@@ -1698,10 +1709,10 @@ struct fs_sink_ctf_trace *translate_trace_trace_ir_to_ctf_ir(struct fs_sink_comp
         case BT_VALUE_TYPE_STRING:
             break;
         default:
-            BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, fs_sink->log_level, fs_sink->self_comp,
-                                "Unsupported trace class's environment entry value type: "
-                                "type=%s",
-                                bt_common_value_type_string(bt_value_get_type(val)));
+            BT_CPPLOGE_SPEC(fs_sink->logger,
+                            "Unsupported trace class's environment entry value type: "
+                            "type={}",
+                            static_cast<bt2::ValueType>(bt_value_get_type(val)));
             goto end;
         }
     }
index 4a500221ec387c3369dbe14913562b1fa7a7a16f..d2f7e102eb85734881aa90dbc4ca9e899632e835 100644 (file)
@@ -7,28 +7,20 @@
  */
 
 #include <glib.h>
-#include <inttypes.h>
 #include <stdint.h>
 #include <stdio.h>
-#include <string.h>
 
-#include <babeltrace2/babeltrace.h>
-
-#define BT_COMP_LOG_SELF_COMP (self_comp)
-#define BT_LOG_OUTPUT_LEVEL   (log_level)
-#define BT_LOG_TAG            "PLUGIN/SRC.CTF.FS/DS"
-#include "logging/comp-logging.h"
-
-#include "common/assert.h"
 #include "compat/endian.h" /* IWYU pragma: keep  */
-#include "compat/mman.h"   /* IWYU pragma: keep  */
+#include "compat/mman.h"   /* IWYU: pragma keep  */
+#include "cpp-common/bt2c/glib-up.hpp"
+#include "cpp-common/bt2s/make-unique.hpp"
+#include "cpp-common/vendor/fmt/format.h"
 
-#include "../common/msg-iter/msg-iter.hpp"
+#include "../common/src/msg-iter/msg-iter.hpp"
 #include "data-stream-file.hpp"
 #include "file.hpp"
 #include "fs.hpp"
 #include "lttng-index.hpp"
-#include "plugins/ctf/common/metadata/ctf-meta.hpp"
 
 static inline size_t remaining_mmap_bytes(struct ctf_fs_ds_file *ds_file)
 {
@@ -48,31 +40,24 @@ static bool offset_ist_mapped(struct ctf_fs_ds_file *ds_file, off_t offset_in_fi
 
 static enum ctf_msg_iter_medium_status ds_file_munmap(struct ctf_fs_ds_file *ds_file)
 {
-    enum ctf_msg_iter_medium_status status;
-    bt_self_component *self_comp = ds_file->self_comp;
-    bt_logging_level log_level = ds_file->log_level;
-
     BT_ASSERT(ds_file);
 
     if (!ds_file->mmap_addr) {
-        status = CTF_MSG_ITER_MEDIUM_STATUS_OK;
-        goto end;
+        return CTF_MSG_ITER_MEDIUM_STATUS_OK;
     }
 
     if (bt_munmap(ds_file->mmap_addr, ds_file->mmap_len)) {
-        BT_COMP_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);
-        status = CTF_MSG_ITER_MEDIUM_STATUS_ERROR;
-        goto end;
+        BT_CPPLOGE_ERRNO_SPEC(ds_file->logger, "Cannot memory-unmap file",
+                              ": address={}, size={}, file_path=\"{}\", file={}",
+                              fmt::ptr(ds_file->mmap_addr), ds_file->mmap_len,
+                              ds_file->file ? ds_file->file->path : "NULL",
+                              ds_file->file ? fmt::ptr(ds_file->file->fp) : NULL);
+        return CTF_MSG_ITER_MEDIUM_STATUS_ERROR;
     }
 
     ds_file->mmap_addr = NULL;
 
-    status = CTF_MSG_ITER_MEDIUM_STATUS_OK;
-end:
-    return status;
+    return CTF_MSG_ITER_MEDIUM_STATUS_OK;
 }
 
 /*
@@ -89,10 +74,6 @@ end:
 static enum ctf_msg_iter_medium_status ds_file_mmap(struct ctf_fs_ds_file *ds_file,
                                                     off_t requested_offset_in_file)
 {
-    enum ctf_msg_iter_medium_status status;
-    bt_self_component *self_comp = ds_file->self_comp;
-    bt_logging_level log_level = ds_file->log_level;
-
     /* Ensure the requested offset is in the file range. */
     BT_ASSERT(requested_offset_in_file >= 0);
     BT_ASSERT(requested_offset_in_file < ds_file->file->size);
@@ -104,14 +85,13 @@ static enum ctf_msg_iter_medium_status ds_file_mmap(struct ctf_fs_ds_file *ds_fi
     if (offset_ist_mapped(ds_file, requested_offset_in_file)) {
         ds_file->request_offset_in_mapping =
             requested_offset_in_file - ds_file->mmap_offset_in_file;
-        status = CTF_MSG_ITER_MEDIUM_STATUS_OK;
-        goto end;
+        return CTF_MSG_ITER_MEDIUM_STATUS_OK;
     }
 
     /* Unmap old region */
-    status = ds_file_munmap(ds_file);
+    ctf_msg_iter_medium_status status = ds_file_munmap(ds_file);
     if (status != CTF_MSG_ITER_MEDIUM_STATUS_OK) {
-        goto end;
+        return status;
     }
 
     /*
@@ -119,7 +99,8 @@ static enum ctf_msg_iter_medium_status ds_file_mmap(struct ctf_fs_ds_file *ds_fi
      * contains `requested_offset_in_file`.
      */
     ds_file->request_offset_in_mapping =
-        requested_offset_in_file % bt_mmap_get_offset_align_size(ds_file->log_level);
+        requested_offset_in_file %
+        bt_mmap_get_offset_align_size(static_cast<int>(ds_file->logger.level()));
     ds_file->mmap_offset_in_file = requested_offset_in_file - ds_file->request_offset_in_mapping;
     ds_file->mmap_len =
         MIN(ds_file->file->size - ds_file->mmap_offset_in_file, ds_file->mmap_max_len);
@@ -127,20 +108,17 @@ static enum ctf_msg_iter_medium_status ds_file_mmap(struct ctf_fs_ds_file *ds_fi
     BT_ASSERT(ds_file->mmap_len > 0);
 
     ds_file->mmap_addr =
-        bt_mmap(ds_file->mmap_len, PROT_READ, MAP_PRIVATE, fileno(ds_file->file->fp),
-                ds_file->mmap_offset_in_file, ds_file->log_level);
+        bt_mmap(ds_file->mmap_len, PROT_READ, MAP_PRIVATE, fileno(ds_file->file->fp.get()),
+                ds_file->mmap_offset_in_file, static_cast<int>(ds_file->logger.level()));
     if (ds_file->mmap_addr == MAP_FAILED) {
-        BT_COMP_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_in_file, strerror(errno));
-        status = CTF_MSG_ITER_MEDIUM_STATUS_ERROR;
-        goto end;
+        BT_CPPLOGE_SPEC(ds_file->logger,
+                        "Cannot memory-map address (size {}) of file \"{}\" ({}) at offset {}: {}",
+                        ds_file->mmap_len, ds_file->file->path, fmt::ptr(ds_file->file->fp),
+                        (intmax_t) ds_file->mmap_offset_in_file, strerror(errno));
+        return CTF_MSG_ITER_MEDIUM_STATUS_ERROR;
     }
 
-    status = CTF_MSG_ITER_MEDIUM_STATUS_OK;
-
-end:
-    return status;
+    return CTF_MSG_ITER_MEDIUM_STATUS_OK;
 }
 
 /*
@@ -156,8 +134,6 @@ end:
 
 static enum ctf_msg_iter_medium_status ds_file_mmap_next(struct ctf_fs_ds_file *ds_file)
 {
-    enum ctf_msg_iter_medium_status status;
-
     /*
      * If we're called, it's because more bytes are requested but we have
      * given all the bytes of the current mapping.
@@ -169,23 +145,16 @@ static enum ctf_msg_iter_medium_status ds_file_mmap_next(struct ctf_fs_ds_file *
      * no next mapping.
      */
     if (ds_file->mmap_offset_in_file + ds_file->mmap_len == ds_file->file->size) {
-        status = CTF_MSG_ITER_MEDIUM_STATUS_EOF;
-        goto end;
+        return CTF_MSG_ITER_MEDIUM_STATUS_EOF;
     }
 
-    status = ds_file_mmap(ds_file, ds_file->mmap_offset_in_file + ds_file->mmap_len);
-
-end:
-    return status;
+    return ds_file_mmap(ds_file, ds_file->mmap_offset_in_file + ds_file->mmap_len);
 }
 
 static enum ctf_msg_iter_medium_status medop_request_bytes(size_t request_sz, uint8_t **buffer_addr,
                                                            size_t *buffer_sz, void *data)
 {
-    enum ctf_msg_iter_medium_status status = CTF_MSG_ITER_MEDIUM_STATUS_OK;
     struct ctf_fs_ds_file *ds_file = (struct ctf_fs_ds_file *) data;
-    bt_self_component *self_comp = ds_file->self_comp;
-    bt_logging_level log_level = ds_file->log_level;
 
     BT_ASSERT(request_sz > 0);
 
@@ -196,22 +165,21 @@ static enum ctf_msg_iter_medium_status medop_request_bytes(size_t request_sz, ui
     if (remaining_mmap_bytes(ds_file) == 0) {
         /* Are we at the end of the file? */
         if (ds_file->mmap_offset_in_file >= ds_file->file->size) {
-            BT_COMP_LOGD("Reached end of file \"%s\" (%p)", ds_file->file->path->str,
-                         ds_file->file->fp);
-            status = CTF_MSG_ITER_MEDIUM_STATUS_EOF;
-            goto end;
+            BT_CPPLOGD_SPEC(ds_file->logger, "Reached end of file \"{}\" ({})", ds_file->file->path,
+                            fmt::ptr(ds_file->file->fp));
+            return CTF_MSG_ITER_MEDIUM_STATUS_EOF;
         }
 
-        status = ds_file_mmap_next(ds_file);
+        ctf_msg_iter_medium_status status = ds_file_mmap_next(ds_file);
         switch (status) {
         case CTF_MSG_ITER_MEDIUM_STATUS_OK:
             break;
         case CTF_MSG_ITER_MEDIUM_STATUS_EOF:
-            goto end;
+            return CTF_MSG_ITER_MEDIUM_STATUS_EOF;
         default:
-            BT_COMP_LOGE("Cannot memory-map next region of file \"%s\" (%p)",
-                         ds_file->file->path->str, ds_file->file->fp);
-            goto error;
+            BT_CPPLOGE_SPEC(ds_file->logger, "Cannot memory-map next region of file \"{}\" ({})",
+                            ds_file->file->path, fmt::ptr(ds_file->file->fp));
+            return status;
         }
     }
 
@@ -222,35 +190,26 @@ static enum ctf_msg_iter_medium_status medop_request_bytes(size_t request_sz, ui
     *buffer_addr = ((uint8_t *) ds_file->mmap_addr) + ds_file->request_offset_in_mapping;
 
     ds_file->request_offset_in_mapping += *buffer_sz;
-    goto end;
-
-error:
-    status = CTF_MSG_ITER_MEDIUM_STATUS_ERROR;
 
-end:
-    return status;
+    return CTF_MSG_ITER_MEDIUM_STATUS_OK;
 }
 
 static bt_stream *medop_borrow_stream(bt_stream_class *stream_class, int64_t, void *data)
 {
     struct ctf_fs_ds_file *ds_file = (struct ctf_fs_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);
+    ds_file_stream_class = ds_file->stream->cls().libObjPtr();
 
     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;
+        return nullptr;
     }
 
-    stream = ds_file->stream;
-
-end:
-    return stream;
+    return ds_file->stream->libObjPtr();
 }
 
 static enum ctf_msg_iter_medium_status medop_seek(off_t offset, void *data)
@@ -272,27 +231,31 @@ struct ctf_msg_iter_medium_ops ctf_fs_ds_file_medops = {
 
 struct ctf_fs_ds_group_medops_data
 {
+    explicit ctf_fs_ds_group_medops_data(const bt2c::Logger& parentLogger) :
+        logger {parentLogger, "PLUGIN/SRC.CTF.FS/DS-GROUP-MEDOPS"}
+    {
+    }
+
+    bt2c::Logger logger;
+
     /* Weak, set once at creation time. */
-    struct ctf_fs_ds_file_group *ds_file_group;
+    struct ctf_fs_ds_file_group *ds_file_group = nullptr;
 
     /*
      * Index (as in element rank) of the index entry of ds_file_groups'
      * index we will read next (so, the one after the one we are reading
      * right now).
      */
-    guint next_index_entry_index;
+    guint next_index_entry_index = 0;
 
     /*
      * File we are currently reading.  Changes whenever we switch to
      * reading another data file.
-     *
-     * Owned by this.
      */
-    struct ctf_fs_ds_file *file;
+    ctf_fs_ds_file::UP file;
 
     /* Weak, for context / logging / appending causes. */
-    bt_self_message_iterator *self_msg_iter;
-    bt_logging_level log_level;
+    bt_self_message_iterator *self_msg_iter = nullptr;
 };
 
 static enum ctf_msg_iter_medium_status medop_group_request_bytes(size_t request_sz,
@@ -302,7 +265,7 @@ static enum ctf_msg_iter_medium_status medop_group_request_bytes(size_t request_
     struct ctf_fs_ds_group_medops_data *data = (struct ctf_fs_ds_group_medops_data *) void_data;
 
     /* Return bytes from the current file. */
-    return medop_request_bytes(request_sz, buffer_addr, buffer_sz, data->file);
+    return medop_request_bytes(request_sz, buffer_addr, buffer_sz, data->file.get());
 }
 
 static bt_stream *medop_group_borrow_stream(bt_stream_class *stream_class, int64_t stream_id,
@@ -310,7 +273,7 @@ static bt_stream *medop_group_borrow_stream(bt_stream_class *stream_class, int64
 {
     struct ctf_fs_ds_group_medops_data *data = (struct ctf_fs_ds_group_medops_data *) void_data;
 
-    return medop_borrow_stream(stream_class, stream_id, data->file);
+    return medop_borrow_stream(stream_class, stream_id, data->file.get());
 }
 
 /*
@@ -320,27 +283,20 @@ static bt_stream *medop_group_borrow_stream(bt_stream_class *stream_class, int64
 
 static enum ctf_msg_iter_medium_status
 ctf_fs_ds_group_medops_set_file(struct ctf_fs_ds_group_medops_data *data,
-                                struct ctf_fs_ds_index_entry *index_entry,
-                                bt_self_message_iterator *self_msg_iter, bt_logging_level log_level)
+                                struct ctf_fs_ds_index_entry *index_entry)
 {
-    enum ctf_msg_iter_medium_status status;
-
     BT_ASSERT(data);
     BT_ASSERT(index_entry);
 
     /* Check if that file is already the one mapped. */
-    if (!data->file || strcmp(index_entry->path, data->file->file->path->str) != 0) {
-        /* Destroy the previously used file. */
-        ctf_fs_ds_file_destroy(data->file);
-
+    if (!data->file || data->file->file->path != index_entry->path) {
         /* Create the new file. */
         data->file =
             ctf_fs_ds_file_create(data->ds_file_group->ctf_fs_trace, data->ds_file_group->stream,
-                                  index_entry->path, log_level);
+                                  index_entry->path, data->logger);
         if (!data->file) {
-            BT_MSG_ITER_LOGE_APPEND_CAUSE(self_msg_iter, "failed to create ctf_fs_ds_file.");
-            status = CTF_MSG_ITER_MEDIUM_STATUS_ERROR;
-            goto end;
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(data->logger, "failed to create ctf_fs_ds_file.");
+            return CTF_MSG_ITER_MEDIUM_STATUS_ERROR;
         }
     }
 
@@ -348,86 +304,50 @@ ctf_fs_ds_group_medops_set_file(struct ctf_fs_ds_group_medops_data *data,
      * Ensure the right portion of the file will be returned on the next
      * request_bytes call.
      */
-    status = ds_file_mmap(data->file, index_entry->offset);
-    if (status != CTF_MSG_ITER_MEDIUM_STATUS_OK) {
-        goto end;
-    }
-
-    status = CTF_MSG_ITER_MEDIUM_STATUS_OK;
-
-end:
-    return status;
+    return ds_file_mmap(data->file.get(), index_entry->offset.bytes());
 }
 
 static enum ctf_msg_iter_medium_status medop_group_switch_packet(void *void_data)
 {
     struct ctf_fs_ds_group_medops_data *data = (struct ctf_fs_ds_group_medops_data *) void_data;
-    struct ctf_fs_ds_index_entry *index_entry;
-    enum ctf_msg_iter_medium_status status;
 
     /* If we have gone through all index entries, we are done. */
-    if (data->next_index_entry_index >= data->ds_file_group->index->entries->len) {
-        status = CTF_MSG_ITER_MEDIUM_STATUS_EOF;
-        goto end;
+    if (data->next_index_entry_index >= data->ds_file_group->index.entries.size()) {
+        return CTF_MSG_ITER_MEDIUM_STATUS_EOF;
     }
 
     /*
      * Otherwise, look up the next index entry / packet and prepare it
      *  for reading.
      */
-    index_entry = (struct ctf_fs_ds_index_entry *) g_ptr_array_index(
-        data->ds_file_group->index->entries, data->next_index_entry_index);
-
-    status =
-        ctf_fs_ds_group_medops_set_file(data, index_entry, data->self_msg_iter, data->log_level);
+    ctf_msg_iter_medium_status status = ctf_fs_ds_group_medops_set_file(
+        data, &data->ds_file_group->index.entries[data->next_index_entry_index]);
     if (status != CTF_MSG_ITER_MEDIUM_STATUS_OK) {
-        goto end;
+        return status;
     }
 
     data->next_index_entry_index++;
 
-    status = CTF_MSG_ITER_MEDIUM_STATUS_OK;
-end:
-    return status;
+    return CTF_MSG_ITER_MEDIUM_STATUS_OK;
 }
 
-void ctf_fs_ds_group_medops_data_destroy(struct ctf_fs_ds_group_medops_data *data)
+void ctf_fs_ds_group_medops_data_deleter::operator()(ctf_fs_ds_group_medops_data *data) noexcept
 {
-    if (!data) {
-        goto end;
-    }
-
-    ctf_fs_ds_file_destroy(data->file);
-
-    g_free(data);
-
-end:
-    return;
+    delete data;
 }
 
 enum ctf_msg_iter_medium_status ctf_fs_ds_group_medops_data_create(
     struct ctf_fs_ds_file_group *ds_file_group, bt_self_message_iterator *self_msg_iter,
-    bt_logging_level log_level, struct ctf_fs_ds_group_medops_data **out)
+    const bt2c::Logger& parentLogger, ctf_fs_ds_group_medops_data_up& out)
 {
-    struct ctf_fs_ds_group_medops_data *data;
-    enum ctf_msg_iter_medium_status status;
-
     BT_ASSERT(self_msg_iter);
     BT_ASSERT(ds_file_group);
-    BT_ASSERT(ds_file_group->index);
-    BT_ASSERT(ds_file_group->index->entries->len > 0);
-
-    data = g_new0(struct ctf_fs_ds_group_medops_data, 1);
-    if (!data) {
-        BT_MSG_ITER_LOGE_APPEND_CAUSE(self_msg_iter,
-                                      "Failed to allocate a struct ctf_fs_ds_group_medops_data");
-        status = CTF_MSG_ITER_MEDIUM_STATUS_MEMORY_ERROR;
-        goto error;
-    }
+    BT_ASSERT(!ds_file_group->index.entries.empty());
 
-    data->ds_file_group = ds_file_group;
-    data->self_msg_iter = self_msg_iter;
-    data->log_level = log_level;
+    out.reset(new ctf_fs_ds_group_medops_data {parentLogger});
+
+    out->ds_file_group = ds_file_group;
+    out->self_msg_iter = self_msg_iter;
 
     /*
      * No need to prepare the first file.  ctf_msg_iter will call
@@ -435,15 +355,7 @@ enum ctf_msg_iter_medium_status ctf_fs_ds_group_medops_data_create(
      * done then.
      */
 
-    *out = data;
-    status = CTF_MSG_ITER_MEDIUM_STATUS_OK;
-    goto end;
-
-error:
-    ctf_fs_ds_group_medops_data_destroy(data);
-
-end:
-    return status;
+    return CTF_MSG_ITER_MEDIUM_STATUS_OK;
 }
 
 void ctf_fs_ds_group_medops_data_reset(struct ctf_fs_ds_group_medops_data *data)
@@ -464,23 +376,6 @@ struct ctf_msg_iter_medium_ops ctf_fs_ds_group_medops = {
     .borrow_stream = medop_group_borrow_stream,
 };
 
-static struct ctf_fs_ds_index_entry *ctf_fs_ds_index_entry_create(bt_self_component *self_comp,
-                                                                  bt_logging_level log_level)
-{
-    struct ctf_fs_ds_index_entry *entry;
-
-    entry = g_new0(struct ctf_fs_ds_index_entry, 1);
-    if (!entry) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to allocate a ctf_fs_ds_index_entry.");
-        goto end;
-    }
-
-    entry->packet_seq_num = UINT64_MAX;
-
-end:
-    return entry;
-}
-
 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,
@@ -488,70 +383,49 @@ static int convert_cycles_to_ns(struct ctf_clock_class *clock_class, uint64_t cy
                                                   clock_class->offset_cycles, ns);
 }
 
-static struct ctf_fs_ds_index *build_index_from_idx_file(struct ctf_fs_ds_file *ds_file,
-                                                         struct ctf_fs_ds_file_info *file_info,
-                                                         struct ctf_msg_iter *msg_iter)
+static bt2s::optional<ctf_fs_ds_index>
+build_index_from_idx_file(struct ctf_fs_ds_file *ds_file, struct ctf_fs_ds_file_info *file_info,
+                          struct ctf_msg_iter *msg_iter)
 {
-    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, *prev_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 ctf_msg_iter_packet_properties props;
-    uint32_t version_major, version_minor;
-    bt_self_component *self_comp = ds_file->self_comp;
-    bt_logging_level log_level = ds_file->log_level;
-
-    BT_COMP_LOGI("Building index from .idx file of stream file %s", ds_file->file->path->str);
-    ret = ctf_msg_iter_get_packet_properties(msg_iter, &props);
+    BT_CPPLOGI_SPEC(ds_file->logger, "Building index from .idx file of stream file {}",
+                    ds_file->file->path);
+    ctf_msg_iter_packet_properties props;
+    int ret = ctf_msg_iter_get_packet_properties(msg_iter, &props);
     if (ret) {
-        BT_COMP_LOGI_STR("Cannot read first packet's header and context fields.");
-        goto error;
+        BT_CPPLOGI_SPEC(ds_file->logger, "Cannot read first packet's header and context fields.");
+        return bt2s::nullopt;
     }
 
-    sc = ctf_trace_class_borrow_stream_class_by_id(ds_file->metadata->tc, props.stream_class_id);
+    ctf_stream_class *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_COMP_LOGI_STR("Cannot find stream class's default clock class.");
-        goto error;
+        BT_CPPLOGI_SPEC(ds_file->logger, "Cannot find stream class's default clock class.");
+        return bt2s::nullopt;
     }
 
     /* Look for index file in relative path index/name.idx. */
-    basename = g_path_get_basename(ds_file->file->path->str);
+    bt2c::GCharUP basename {g_path_get_basename(ds_file->file->path.c_str())};
     if (!basename) {
-        BT_COMP_LOGE("Cannot get the basename of datastream file %s", ds_file->file->path->str);
-        goto error;
+        BT_CPPLOGE_SPEC(ds_file->logger, "Cannot get the basename of datastream file {}",
+                        ds_file->file->path);
+        return bt2s::nullopt;
     }
 
-    directory = g_path_get_dirname(ds_file->file->path->str);
+    bt2c::GCharUP directory {g_path_get_dirname(ds_file->file->path.c_str())};
     if (!directory) {
-        BT_COMP_LOGE("Cannot get dirname of datastream file %s", ds_file->file->path->str);
-        goto error;
+        BT_CPPLOGE_SPEC(ds_file->logger, "Cannot get dirname of datastream file {}",
+                        ds_file->file->path);
+        return bt2s::nullopt;
     }
 
-    index_basename = g_string_new(basename);
-    if (!index_basename) {
-        BT_COMP_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);
+    std::string index_basename = fmt::format("{}.idx", basename.get());
+    bt2c::GCharUP index_file_path {
+        g_build_filename(directory.get(), "index", index_basename.c_str(), NULL)};
+    bt2c::GMappedFileUP mapped_file {g_mapped_file_new(index_file_path.get(), FALSE, NULL)};
     if (!mapped_file) {
-        BT_COMP_LOGD("Cannot create new mapped file %s", index_file_path);
-        goto error;
+        BT_CPPLOGD_SPEC(ds_file->logger, "Cannot create new mapped file {}", index_file_path.get());
+        return bt2s::nullopt;
     }
 
     /*
@@ -559,406 +433,306 @@ static struct ctf_fs_ds_index *build_index_from_idx_file(struct ctf_fs_ds_file *
      * 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_COMP_LOGW("Invalid LTTng trace index file: "
-                     "file size (%zu bytes) < header size (%zu bytes)",
-                     filesize, sizeof(*header));
-        goto error;
+    gsize filesize = g_mapped_file_get_length(mapped_file.get());
+    if (filesize < sizeof(ctf_packet_index_file_hdr)) {
+        BT_CPPLOGW_SPEC(ds_file->logger,
+                        "Invalid LTTng trace index file: "
+                        "file size ({} bytes) < header size ({} bytes)",
+                        filesize, sizeof(ctf_packet_index_file_hdr));
+        return bt2s::nullopt;
     }
 
-    mmap_begin = g_mapped_file_get_contents(mapped_file);
-    header = (struct ctf_packet_index_file_hdr *) mmap_begin;
+    const char *mmap_begin = g_mapped_file_get_contents(mapped_file.get());
+    const ctf_packet_index_file_hdr *header = (const ctf_packet_index_file_hdr *) mmap_begin;
 
-    file_pos = g_mapped_file_get_contents(mapped_file) + sizeof(*header);
+    const char *file_pos = g_mapped_file_get_contents(mapped_file.get()) + sizeof(*header);
     if (be32toh(header->magic) != CTF_INDEX_MAGIC) {
-        BT_COMP_LOGW_STR("Invalid LTTng trace index: \"magic\" field validation failed");
-        goto error;
+        BT_CPPLOGW_SPEC(ds_file->logger,
+                        "Invalid LTTng trace index: \"magic\" field validation failed");
+        return bt2s::nullopt;
     }
 
-    version_major = be32toh(header->index_major);
-    version_minor = be32toh(header->index_minor);
+    uint32_t version_major = be32toh(header->index_major);
+    uint32_t version_minor = be32toh(header->index_minor);
     if (version_major != 1) {
-        BT_COMP_LOGW("Unknown LTTng trace index version: "
-                     "major=%" PRIu32 ", minor=%" PRIu32,
-                     version_major, version_minor);
-        goto error;
+        BT_CPPLOGW_SPEC(ds_file->logger, "Unknown LTTng trace index version: major={}, minor={}",
+                        version_major, version_minor);
+        return bt2s::nullopt;
     }
 
-    file_index_entry_size = be32toh(header->packet_index_len);
+    size_t file_index_entry_size = be32toh(header->packet_index_len);
     if (file_index_entry_size < CTF_INDEX_1_0_SIZE) {
-        BT_COMP_LOGW(
+        BT_CPPLOGW_SPEC(
+            ds_file->logger,
             "Invalid `packet_index_len` in LTTng trace index file (`packet_index_len` < CTF index 1.0 index entry size): "
-            "packet_index_len=%zu, CTF_INDEX_1_0_SIZE=%zu",
+            "packet_index_len={}, CTF_INDEX_1_0_SIZE={}",
             file_index_entry_size, CTF_INDEX_1_0_SIZE);
-        goto error;
+        return bt2s::nullopt;
     }
 
-    file_entry_count = (filesize - sizeof(*header)) / file_index_entry_size;
+    size_t file_entry_count = (filesize - sizeof(*header)) / file_index_entry_size;
     if ((filesize - sizeof(*header)) % file_index_entry_size) {
-        BT_COMP_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;
+        BT_CPPLOGW_SPEC(ds_file->logger,
+                        "Invalid LTTng trace index: the index's size after the header "
+                        "({} bytes) is not a multiple of the index entry size "
+                        "({} bytes)",
+                        (filesize - sizeof(*header)), sizeof(*header));
+        return bt2s::nullopt;
     }
 
-    index = ctf_fs_ds_index_create(ds_file->log_level, ds_file->self_comp);
-    if (!index) {
-        goto error;
-    }
+    ctf_fs_ds_index index;
+    ctf_fs_ds_index_entry *prev_index_entry = nullptr;
+    auto totalPacketsSize = bt2c::DataLen::fromBytes(0);
 
-    for (i = 0; i < file_entry_count; i++) {
+    for (size_t 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_COMP_LOGW("Invalid packet size encountered in LTTng trace index file");
-            goto error;
-        }
+        const auto packetSize = bt2c::DataLen::fromBits(be64toh(file_index->packet_size));
 
-        index_entry = ctf_fs_ds_index_entry_create(ds_file->self_comp, ds_file->log_level);
-        if (!index_entry) {
-            BT_COMP_LOGE_APPEND_CAUSE(ds_file->self_comp,
-                                      "Failed to create a ctf_fs_ds_index_entry.");
-            goto error;
+        if (packetSize.hasExtraBits()) {
+            BT_CPPLOGW_SPEC(ds_file->logger,
+                            "Invalid packet size encountered in LTTng trace index file");
+            return bt2s::nullopt;
         }
 
-        /* Set path to stream file. */
-        index_entry->path = file_info->path->str;
-
-        /* Convert size in bits to bytes. */
-        packet_size /= CHAR_BIT;
-        index_entry->packet_size = packet_size;
+        const auto offset = bt2c::DataLen::fromBytes(be64toh(file_index->offset));
 
-        index_entry->offset = be64toh(file_index->offset);
-        if (i != 0 && index_entry->offset < prev_index_entry->offset) {
-            BT_COMP_LOGW(
+        if (i != 0 && offset < prev_index_entry->offset) {
+            BT_CPPLOGW_SPEC(
+                ds_file->logger,
                 "Invalid, non-monotonic, packet offset encountered in LTTng trace index file: "
-                "previous offset=%" PRIu64 ", current offset=%" PRIu64,
-                prev_index_entry->offset, index_entry->offset);
-            goto error;
+                "previous offset={} bytes, current offset={} bytes",
+                prev_index_entry->offset.bytes(), offset.bytes());
+            return bt2s::nullopt;
         }
 
-        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_COMP_LOGW(
+        ctf_fs_ds_index_entry index_entry {file_info->path.c_str(), offset, packetSize};
+        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_CPPLOGW_SPEC(
+                ds_file->logger,
                 "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;
+                "timestamp_begin={}, timestamp_end={}",
+                index_entry.timestamp_begin, index_entry.timestamp_end);
+            return bt2s::nullopt;
         }
 
         /* 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);
+        ret = convert_cycles_to_ns(sc->default_clock_class, index_entry.timestamp_begin,
+                                   &index_entry.timestamp_begin_ns);
         if (ret) {
-            BT_COMP_LOGI_STR(
+            BT_CPPLOGI_SPEC(
+                ds_file->logger,
                 "Failed to convert raw timestamp to nanoseconds since Epoch during index parsing");
-            goto error;
+            return bt2s::nullopt;
         }
-        ret = convert_cycles_to_ns(sc->default_clock_class, index_entry->timestamp_end,
-                                   &index_entry->timestamp_end_ns);
+        ret = convert_cycles_to_ns(sc->default_clock_class, index_entry.timestamp_end,
+                                   &index_entry.timestamp_end_ns);
         if (ret) {
-            BT_COMP_LOGI_STR(
+            BT_CPPLOGI_SPEC(
+                ds_file->logger,
                 "Failed to convert raw timestamp to nanoseconds since Epoch during LTTng trace index parsing");
-            goto error;
+            return bt2s::nullopt;
         }
 
         if (version_minor >= 1) {
-            index_entry->packet_seq_num = be64toh(file_index->packet_seq_num);
+            index_entry.packet_seq_num = be64toh(file_index->packet_seq_num);
         }
 
-        total_packets_size += packet_size;
+        totalPacketsSize += packetSize;
         file_pos += file_index_entry_size;
 
-        prev_index_entry = index_entry;
+        index.entries.emplace_back(index_entry);
 
-        /* Give ownership of `index_entry` to `index->entries`. */
-        g_ptr_array_add(index->entries, index_entry);
-        index_entry = NULL;
+        prev_index_entry = &index.entries.back();
     }
 
     /* Validate that the index addresses the complete stream. */
-    if (ds_file->file->size != total_packets_size) {
-        BT_COMP_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);
+    if (ds_file->file->size != totalPacketsSize.bytes()) {
+        BT_CPPLOGW_SPEC(ds_file->logger,
+                        "Invalid LTTng trace index file; indexed size != stream file size: "
+                        "file-size={} bytes, total-packets-size={} bytes",
+                        ds_file->file->size, totalPacketsSize.bytes());
+        return bt2s::nullopt;
     }
+
     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 ctf_msg_iter_packet_properties *props, off_t packet_size,
-                            off_t packet_offset)
+static int init_index_entry(ctf_fs_ds_index_entry& entry, struct ctf_fs_ds_file *ds_file,
+                            struct ctf_msg_iter_packet_properties *props)
 {
-    int ret = 0;
-    struct ctf_stream_class *sc;
-    bt_self_component *self_comp = ds_file->self_comp;
-    bt_logging_level log_level = ds_file->log_level;
-
-    sc = ctf_trace_class_borrow_stream_class_by_id(ds_file->metadata->tc, props->stream_class_id);
+    ctf_stream_class *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)) {
-        entry->timestamp_begin = props->snapshots.beginning_clock;
+        entry.timestamp_begin = props->snapshots.beginning_clock;
 
         /* 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);
+        int ret = convert_cycles_to_ns(sc->default_clock_class, props->snapshots.beginning_clock,
+                                       &entry.timestamp_begin_ns);
         if (ret) {
-            BT_COMP_LOGI_STR("Failed to convert raw timestamp to nanoseconds since Epoch.");
-            goto end;
+            BT_CPPLOGI_SPEC(ds_file->logger,
+                            "Failed to convert raw timestamp to nanoseconds since Epoch.");
+            return ret;
         }
     } else {
-        entry->timestamp_begin = UINT64_C(-1);
-        entry->timestamp_begin_ns = UINT64_C(-1);
+        entry.timestamp_begin = UINT64_C(-1);
+        entry.timestamp_begin_ns = UINT64_C(-1);
     }
 
     if (props->snapshots.end_clock != UINT64_C(-1)) {
-        entry->timestamp_end = props->snapshots.end_clock;
+        entry.timestamp_end = props->snapshots.end_clock;
 
         /* Convert the packet's bound to nanoseconds since Epoch. */
-        ret = convert_cycles_to_ns(sc->default_clock_class, props->snapshots.end_clock,
-                                   &entry->timestamp_end_ns);
+        int ret = convert_cycles_to_ns(sc->default_clock_class, props->snapshots.end_clock,
+                                       &entry.timestamp_end_ns);
         if (ret) {
-            BT_COMP_LOGI_STR("Failed to convert raw timestamp to nanoseconds since Epoch.");
-            goto end;
+            BT_CPPLOGI_SPEC(ds_file->logger,
+                            "Failed to convert raw timestamp to nanoseconds since Epoch.");
+            return ret;
         }
     } else {
-        entry->timestamp_end = UINT64_C(-1);
-        entry->timestamp_end_ns = UINT64_C(-1);
+        entry.timestamp_end = UINT64_C(-1);
+        entry.timestamp_end_ns = UINT64_C(-1);
     }
 
-end:
-    return ret;
+    return 0;
 }
 
-static struct ctf_fs_ds_index *build_index_from_stream_file(struct ctf_fs_ds_file *ds_file,
-                                                            struct ctf_fs_ds_file_info *file_info,
-                                                            struct ctf_msg_iter *msg_iter)
+static bt2s::optional<ctf_fs_ds_index>
+build_index_from_stream_file(struct ctf_fs_ds_file *ds_file, struct ctf_fs_ds_file_info *file_info,
+                             struct ctf_msg_iter *msg_iter)
 {
-    int ret;
-    struct ctf_fs_ds_index *index = NULL;
-    enum ctf_msg_iter_status iter_status = CTF_MSG_ITER_STATUS_OK;
-    off_t current_packet_offset_bytes = 0;
-    bt_self_component *self_comp = ds_file->self_comp;
-    bt_logging_level log_level = ds_file->log_level;
-
-    BT_COMP_LOGI("Indexing stream file %s", ds_file->file->path->str);
-
-    index = ctf_fs_ds_index_create(ds_file->log_level, ds_file->self_comp);
-    if (!index) {
-        goto error;
-    }
+    BT_CPPLOGI_SPEC(ds_file->logger, "Indexing stream file {}", ds_file->file->path);
+
+    ctf_fs_ds_index index;
+    auto currentPacketOffset = bt2c::DataLen::fromBytes(0);
 
     while (true) {
-        off_t current_packet_size_bytes;
-        struct ctf_fs_ds_index_entry *index_entry;
         struct ctf_msg_iter_packet_properties props;
 
-        if (current_packet_offset_bytes < 0) {
-            BT_COMP_LOGE_STR("Cannot get the current packet's offset.");
-            goto error;
-        } else if (current_packet_offset_bytes > ds_file->file->size) {
-            BT_COMP_LOGE_STR("Unexpected current packet's offset (larger than file).");
-            goto error;
-        } else if (current_packet_offset_bytes == ds_file->file->size) {
+        if (currentPacketOffset.bytes() > ds_file->file->size) {
+            BT_CPPLOGE_SPEC(ds_file->logger,
+                            "Unexpected current packet's offset (larger than file).");
+            return bt2s::nullopt;
+        } else if (currentPacketOffset.bytes() == ds_file->file->size) {
             /* No more data */
             break;
         }
 
-        iter_status = ctf_msg_iter_seek(msg_iter, current_packet_offset_bytes);
+        ctf_msg_iter_status iter_status = ctf_msg_iter_seek(msg_iter, currentPacketOffset.bytes());
         if (iter_status != CTF_MSG_ITER_STATUS_OK) {
-            goto error;
+            return bt2s::nullopt;
         }
 
         iter_status = ctf_msg_iter_get_packet_properties(msg_iter, &props);
         if (iter_status != CTF_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;
+            return bt2s::nullopt;
         }
 
-        if (current_packet_offset_bytes + current_packet_size_bytes > ds_file->file->size) {
-            BT_COMP_LOGW("Invalid packet size reported in file: stream=\"%s\", "
-                         "packet-offset=%jd, packet-size-bytes=%jd, "
-                         "file-size=%jd",
-                         ds_file->file->path->str, (intmax_t) current_packet_offset_bytes,
-                         (intmax_t) current_packet_size_bytes, (intmax_t) ds_file->file->size);
-            goto error;
-        }
-
-        index_entry = ctf_fs_ds_index_entry_create(ds_file->self_comp, ds_file->log_level);
-        if (!index_entry) {
-            BT_COMP_LOGE_APPEND_CAUSE(ds_file->self_comp,
-                                      "Failed to create a ctf_fs_ds_index_entry.");
-            goto error;
+        /*
+         * Get the current packet size from the packet header, if set.  Else,
+         * assume there is a single packet in the file, so take the file size
+         * as the packet size.
+         */
+        const auto currentPacketSize = props.exp_packet_total_size >= 0 ?
+                                           bt2c::DataLen::fromBits(props.exp_packet_total_size) :
+                                           bt2c::DataLen::fromBytes(ds_file->file->size);
+
+        if ((currentPacketOffset + currentPacketSize).bytes() > ds_file->file->size) {
+            BT_CPPLOGW_SPEC(ds_file->logger,
+                            "Invalid packet size reported in file: stream=\"{}\", "
+                            "packet-offset-bytes={}, packet-size-bytes={}, "
+                            "file-size-bytes={}",
+                            ds_file->file->path, currentPacketOffset.bytes(),
+                            currentPacketSize.bytes(), ds_file->file->size);
+            return bt2s::nullopt;
         }
 
-        /* Set path to stream file. */
-        index_entry->path = file_info->path->str;
+        ctf_fs_ds_index_entry index_entry {file_info->path, currentPacketOffset, currentPacketSize};
 
-        ret = init_index_entry(index_entry, ds_file, &props, current_packet_size_bytes,
-                               current_packet_offset_bytes);
+        int ret = init_index_entry(index_entry, ds_file, &props);
         if (ret) {
-            g_free(index_entry);
-            goto error;
+            return bt2s::nullopt;
         }
 
-        g_ptr_array_add(index->entries, index_entry);
+        index.entries.emplace_back(index_entry);
 
-        current_packet_offset_bytes += current_packet_size_bytes;
-        BT_COMP_LOGD("Seeking to next packet: current-packet-offset=%jd, "
-                     "next-packet-offset=%jd",
-                     (intmax_t) (current_packet_offset_bytes - current_packet_size_bytes),
-                     (intmax_t) current_packet_offset_bytes);
+        currentPacketOffset += currentPacketSize;
+        BT_CPPLOGD_SPEC(ds_file->logger,
+                        "Seeking to next packet: current-packet-offset-bytes={}, "
+                        "next-packet-offset-bytes={}",
+                        (currentPacketOffset - currentPacketSize).bytes(),
+                        currentPacketOffset.bytes());
     }
 
-end:
     return index;
-
-error:
-    ctf_fs_ds_index_destroy(index);
-    index = NULL;
-    goto end;
 }
 
-struct ctf_fs_ds_file *ctf_fs_ds_file_create(struct ctf_fs_trace *ctf_fs_trace, bt_stream *stream,
-                                             const char *path, bt_logging_level log_level)
+ctf_fs_ds_file::UP ctf_fs_ds_file_create(struct ctf_fs_trace *ctf_fs_trace,
+                                         bt2::Stream::Shared stream, const char *path,
+                                         const bt2c::Logger& parentLogger)
 {
-    int ret;
-    const size_t offset_align = bt_mmap_get_offset_align_size(log_level);
-    struct ctf_fs_ds_file *ds_file = g_new0(struct ctf_fs_ds_file, 1);
+    auto ds_file = bt2s::make_unique<ctf_fs_ds_file>(parentLogger);
 
-    if (!ds_file) {
-        goto error;
-    }
-
-    ds_file->log_level = log_level;
-    ds_file->self_comp = ctf_fs_trace->self_comp;
-    ds_file->file = ctf_fs_file_create(log_level, ds_file->self_comp);
-    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");
+    ds_file->file = bt2s::make_unique<ctf_fs_file>(parentLogger);
+    ds_file->stream = std::move(stream);
+    ds_file->metadata = ctf_fs_trace->metadata.get();
+    ds_file->file->path = path;
+    int ret = ctf_fs_file_open(ds_file->file.get(), "rb");
     if (ret) {
-        goto error;
+        return nullptr;
     }
 
+    const size_t offset_align =
+        bt_mmap_get_offset_align_size(static_cast<int>(ds_file->logger.level()));
     ds_file->mmap_max_len = offset_align * 2048;
 
-    goto end;
-
-error:
-    /* Do not touch "borrowed" file. */
-    ctf_fs_ds_file_destroy(ds_file);
-    ds_file = NULL;
-
-end:
     return ds_file;
 }
 
-struct ctf_fs_ds_index *ctf_fs_ds_file_build_index(struct ctf_fs_ds_file *ds_file,
-                                                   struct ctf_fs_ds_file_info *file_info,
-                                                   struct ctf_msg_iter *msg_iter)
+bt2s::optional<ctf_fs_ds_index> ctf_fs_ds_file_build_index(struct ctf_fs_ds_file *ds_file,
+                                                           struct ctf_fs_ds_file_info *file_info,
+                                                           struct ctf_msg_iter *msg_iter)
 {
-    struct ctf_fs_ds_index *index;
-    bt_self_component *self_comp = ds_file->self_comp;
-    bt_logging_level log_level = ds_file->log_level;
-
-    index = build_index_from_idx_file(ds_file, file_info, msg_iter);
+    auto index = build_index_from_idx_file(ds_file, file_info, msg_iter);
     if (index) {
-        goto end;
+        return index;
     }
 
-    BT_COMP_LOGI("Failed to build index from .index file; "
-                 "falling back to stream indexing.");
-    index = build_index_from_stream_file(ds_file, file_info, msg_iter);
-end:
-    return index;
+    BT_CPPLOGI_SPEC(ds_file->logger, "Failed to build index from .index file; "
+                                     "falling back to stream indexing.");
+    return build_index_from_stream_file(ds_file, file_info, msg_iter);
 }
 
-struct ctf_fs_ds_index *ctf_fs_ds_index_create(bt_logging_level log_level,
-                                               bt_self_component *self_comp)
+ctf_fs_ds_file::~ctf_fs_ds_file()
 {
-    struct ctf_fs_ds_index *index = g_new0(struct ctf_fs_ds_index, 1);
-
-    if (!index) {
-        BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_comp, "Failed to allocate index");
-        goto error;
-    }
-
-    index->entries = g_ptr_array_new_with_free_func((GDestroyNotify) g_free);
-    if (!index->entries) {
-        BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_comp,
-                            "Failed to allocate index entries.");
-        goto error;
-    }
-
-    goto end;
-
-error:
-    ctf_fs_ds_index_destroy(index);
-    index = NULL;
-end:
-    return index;
+    (void) ds_file_munmap(this);
 }
 
-void ctf_fs_ds_file_destroy(struct ctf_fs_ds_file *ds_file)
+ctf_fs_ds_file_info::UP ctf_fs_ds_file_info_create(const char *path, int64_t begin_ns)
 {
-    if (!ds_file) {
-        return;
-    }
-
-    bt_stream_put_ref(ds_file->stream);
-    (void) ds_file_munmap(ds_file);
+    ctf_fs_ds_file_info::UP ds_file_info = bt2s::make_unique<ctf_fs_ds_file_info>();
 
-    if (ds_file->file) {
-        ctf_fs_file_destroy(ds_file->file);
-    }
-
-    g_free(ds_file);
+    ds_file_info->path = path;
+    ds_file_info->begin_ns = begin_ns;
+    return ds_file_info;
 }
 
-void ctf_fs_ds_index_destroy(struct ctf_fs_ds_index *index)
+void ctf_fs_ds_file_group::insert_ds_file_info_sorted(ctf_fs_ds_file_info::UP ds_file_info)
 {
-    if (!index) {
-        return;
-    }
+    /* Find the spot where to insert this ds_file_info. */
+    auto it = this->ds_file_infos.begin();
 
-    if (index->entries) {
-        g_ptr_array_free(index->entries, TRUE);
+    for (; it != this->ds_file_infos.end(); ++it) {
+        const ctf_fs_ds_file_info& other_ds_file_info = **it;
+
+        if (ds_file_info->begin_ns < other_ds_file_info.begin_ns) {
+            break;
+        }
     }
-    g_free(index);
+
+    this->ds_file_infos.insert(it, std::move(ds_file_info));
 }
index 297c859fc451c1a79f1f69c4d6da93e5dd8b0056..05a6db13538049d4ab194dd0695e03fa9a3f852e 100644 (file)
 #ifndef CTF_FS_DS_FILE_H
 #define CTF_FS_DS_FILE_H
 
+#include <memory>
+#include <string>
+#include <vector>
+
 #include <glib.h>
 #include <stdio.h>
 
 #include <babeltrace2/babeltrace.h>
 
-#include "../common/msg-iter/msg-iter.hpp"
+#include "cpp-common/bt2/trace-ir.hpp"
+#include "cpp-common/bt2c/data-len.hpp"
+#include "cpp-common/bt2c/logging.hpp"
+
+#include "../common/src/msg-iter/msg-iter.hpp"
+#include "file.hpp"
 
 struct ctf_fs_ds_file_info
 {
-    /* Owned by this. */
-    GString *path;
+    using UP = std::unique_ptr<ctf_fs_ds_file_info>;
+
+    std::string path;
 
     /* Guaranteed to be set, as opposed to the index. */
-    int64_t begin_ns;
+    int64_t begin_ns = 0;
 };
 
 struct ctf_fs_ds_file
 {
-    bt_logging_level log_level;
+    using UP = std::unique_ptr<ctf_fs_ds_file>;
 
-    /* Weak */
-    bt_self_component *self_comp;
+    explicit ctf_fs_ds_file(const bt2c::Logger& parentLogger) :
+        logger {parentLogger, "PLUGIN/SRC.CTF.FS/DS"}
+    {
+    }
+
+    ctf_fs_ds_file(const ctf_fs_ds_file&) = delete;
+    ctf_fs_ds_file& operator=(const ctf_fs_ds_file&) = delete;
+    ~ctf_fs_ds_file();
+
+    bt2c::Logger logger;
 
     /* Weak */
-    struct ctf_fs_metadata *metadata;
+    struct ctf_fs_metadata *metadata = nullptr;
 
-    /* Owned by this */
-    struct ctf_fs_file *file;
+    ctf_fs_file::UP file;
 
-    /* Owned by this */
-    bt_stream *stream;
+    bt2::Stream::Shared stream;
 
-    void *mmap_addr;
+    void *mmap_addr = nullptr;
 
     /*
      * Max length of chunk to mmap() when updating the current mapping.
      * This value must be page-aligned.
      */
-    size_t mmap_max_len;
+    size_t mmap_max_len = 0;
 
     /* Length of the current mapping. Never exceeds the file's length. */
-    size_t mmap_len;
+    size_t mmap_len = 0;
 
     /* Offset in the file where the current mapping starts. */
-    off_t mmap_offset_in_file;
+    off_t mmap_offset_in_file = 0;
 
     /*
      * Offset, in the current mapping, of the address to return on the next
      * request.
      */
-    off_t request_offset_in_mapping;
+    off_t request_offset_in_mapping = 0;
 };
 
-struct ctf_fs_ds_file *ctf_fs_ds_file_create(struct ctf_fs_trace *ctf_fs_trace, bt_stream *stream,
-                                             const char *path, bt_logging_level log_level);
+struct ctf_fs_ds_index_entry
+{
+    ctf_fs_ds_index_entry(const bt2c::CStringView pathParam, const bt2c::DataLen offsetParam,
+                          const bt2c::DataLen packetSizeParam) noexcept :
+        path {pathParam},
+        offset {offsetParam}, packetSize {packetSizeParam}
+    {
+    }
+
+    /* Weak, belongs to ctf_fs_ds_file_info. */
+    const char *path;
+
+    /* Position of the packet from the beginning of the file. */
+    bt2c::DataLen offset;
+
+    /* Size of the packet. */
+    bt2c::DataLen packetSize;
 
-void ctf_fs_ds_file_destroy(struct ctf_fs_ds_file *stream);
+    /*
+     * Extracted from the packet context, relative to the respective fields'
+     * mapped clock classes (in cycles).
+     */
+    uint64_t timestamp_begin = 0, timestamp_end = 0;
+
+    /*
+     * Converted from the packet context, relative to the trace's EPOCH
+     * (in ns since EPOCH).
+     */
+    int64_t timestamp_begin_ns = 0, timestamp_end_ns = 0;
+
+    /*
+     * Packet sequence number, or UINT64_MAX if not present in the index.
+     */
+    uint64_t packet_seq_num = UINT64_MAX;
+};
 
-struct ctf_fs_ds_index *ctf_fs_ds_file_build_index(struct ctf_fs_ds_file *ds_file,
-                                                   struct ctf_fs_ds_file_info *ds_file_info,
-                                                   struct ctf_msg_iter *msg_iter);
+struct ctf_fs_ds_index
+{
+    std::vector<ctf_fs_ds_index_entry> entries;
+};
 
-struct ctf_fs_ds_index *ctf_fs_ds_index_create(bt_logging_level log_level,
-                                               bt_self_component *self_comp);
+struct ctf_fs_ds_file_group
+{
+    using UP = std::unique_ptr<ctf_fs_ds_file_group>;
 
-void ctf_fs_ds_index_destroy(struct ctf_fs_ds_index *index);
+    explicit ctf_fs_ds_file_group(struct ctf_fs_trace * const trace,
+                                  ctf_stream_class * const scParam, const uint64_t streamInstanceId,
+                                  ctf_fs_ds_index indexParam) noexcept :
+
+        sc {scParam},
+        stream_id(streamInstanceId), ctf_fs_trace {trace}, index {std::move(indexParam)}
+
+    {
+    }
+
+    /*
+     * Insert ds_file_info in the list of ds_file_infos at the right
+     * place to keep it sorted.
+     */
+    void insert_ds_file_info_sorted(ctf_fs_ds_file_info::UP ds_file_info);
+
+    /*
+     * 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.
+     */
+    std::vector<ctf_fs_ds_file_info::UP> ds_file_infos;
+
+    /* Owned by this */
+    struct ctf_stream_class *sc = nullptr;
+
+    bt2::Stream::Shared stream;
+
+    /* Stream (instance) ID; -1ULL means none */
+    uint64_t stream_id = 0;
+
+    /* Weak, belongs to component */
+    struct ctf_fs_trace *ctf_fs_trace = nullptr;
+
+    ctf_fs_ds_index index;
+};
+
+ctf_fs_ds_file::UP ctf_fs_ds_file_create(ctf_fs_trace *ctf_fs_trace, bt2::Stream::Shared stream,
+                                         const char *path, const bt2c::Logger& logger);
+
+bt2s::optional<ctf_fs_ds_index> ctf_fs_ds_file_build_index(struct ctf_fs_ds_file *ds_file,
+                                                           struct ctf_fs_ds_file_info *ds_file_info,
+                                                           struct ctf_msg_iter *msg_iter);
+
+ctf_fs_ds_file_info::UP ctf_fs_ds_file_info_create(const char *path, int64_t begin_ns);
 
 /*
  * Medium operations to iterate on a single ctf_fs_ds_file.
@@ -91,12 +186,19 @@ extern struct ctf_msg_iter_medium_ops ctf_fs_ds_file_medops;
  */
 extern struct ctf_msg_iter_medium_ops ctf_fs_ds_group_medops;
 
-enum ctf_msg_iter_medium_status ctf_fs_ds_group_medops_data_create(
-    struct ctf_fs_ds_file_group *ds_file_group, bt_self_message_iterator *self_msg_iter,
-    bt_logging_level log_level, struct ctf_fs_ds_group_medops_data **out);
+struct ctf_fs_ds_group_medops_data_deleter
+{
+    void operator()(struct ctf_fs_ds_group_medops_data *data) noexcept;
+};
 
-void ctf_fs_ds_group_medops_data_reset(struct ctf_fs_ds_group_medops_data *data);
+using ctf_fs_ds_group_medops_data_up =
+    std::unique_ptr<ctf_fs_ds_group_medops_data, ctf_fs_ds_group_medops_data_deleter>;
 
-void ctf_fs_ds_group_medops_data_destroy(struct ctf_fs_ds_group_medops_data *data);
+enum ctf_msg_iter_medium_status
+ctf_fs_ds_group_medops_data_create(struct ctf_fs_ds_file_group *ds_file_group,
+                                   bt_self_message_iterator *self_msg_iter,
+                                   const bt2c::Logger& logger, ctf_fs_ds_group_medops_data_up& out);
+
+void ctf_fs_ds_group_medops_data_reset(struct ctf_fs_ds_group_medops_data *data);
 
 #endif /* CTF_FS_DS_FILE_H */
index 25a29d0a5e17407b1f9bf396466617f3950a2a5b..13e279cd38b1fb085318f36c2bbb31555ea3995d 100644 (file)
@@ -8,95 +8,38 @@
 #include <stdio.h>
 #include <sys/stat.h>
 
-#define BT_COMP_LOG_SELF_COMP (file->self_comp)
-#define BT_LOG_OUTPUT_LEVEL   (file->log_level)
-#define BT_LOG_TAG            "PLUGIN/SRC.CTF.FS/FILE"
-#include "logging/comp-logging.h"
+#include "cpp-common/vendor/fmt/format.h"
 
 #include "file.hpp"
-#include "fs.hpp"
-
-void ctf_fs_file_destroy(struct ctf_fs_file *file)
-{
-    if (!file) {
-        return;
-    }
-
-    if (file->fp) {
-        BT_COMP_LOGD("Closing file \"%s\" (%p)", file->path ? file->path->str : NULL, file->fp);
-
-        if (fclose(file->fp)) {
-            BT_COMP_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);
-}
-
-struct ctf_fs_file *ctf_fs_file_create(bt_logging_level log_level, bt_self_component *self_comp)
-{
-    struct ctf_fs_file *file = g_new0(struct ctf_fs_file, 1);
-
-    if (!file) {
-        goto error;
-    }
-
-    file->log_level = log_level;
-    file->self_comp = self_comp;
-    file->path = g_string_new(NULL);
-    if (!file->path) {
-        goto error;
-    }
-
-    goto end;
-
-error:
-    ctf_fs_file_destroy(file);
-    file = NULL;
-
-end:
-    return file;
-}
 
 int ctf_fs_file_open(struct ctf_fs_file *file, const char *mode)
 {
     int ret = 0;
     struct stat stat;
 
-    BT_COMP_LOGI("Opening file \"%s\" with mode \"%s\"", file->path->str, mode);
-    file->fp = fopen(file->path->str, mode);
+    BT_CPPLOGI_SPEC(file->logger, "Opening file \"{}\" with mode \"{}\"", file->path, mode);
+    file->fp.reset(fopen(file->path.c_str(), mode));
     if (!file->fp) {
-        BT_COMP_LOGE_APPEND_CAUSE_ERRNO(file->self_comp, "Cannot open file", ": path=%s, mode=%s",
-                                        file->path->str, mode);
+        BT_CPPLOGE_ERRNO_APPEND_CAUSE_SPEC(file->logger, "Cannot open file", ": path={}, mode={}",
+                                           file->path, mode);
         goto error;
     }
 
-    BT_COMP_LOGI("Opened file: %p", file->fp);
+    BT_CPPLOGI_SPEC(file->logger, "Opened file: {}", fmt::ptr(file->fp));
 
-    if (fstat(fileno(file->fp), &stat)) {
-        BT_COMP_LOGE_APPEND_CAUSE_ERRNO(file->self_comp, "Cannot get file information", ": path=%s",
-                                        file->path->str);
+    if (fstat(fileno(file->fp.get()), &stat)) {
+        BT_CPPLOGE_ERRNO_APPEND_CAUSE_SPEC(file->logger, "Cannot get file information", ": path={}",
+                                           file->path);
         goto error;
     }
 
     file->size = stat.st_size;
-    BT_COMP_LOGI("File is %jd bytes", (intmax_t) file->size);
+    BT_CPPLOGI_SPEC(file->logger, "File is {} bytes", (intmax_t) file->size);
     goto end;
 
 error:
     ret = -1;
 
-    if (file->fp) {
-        if (fclose(file->fp)) {
-            BT_COMP_LOGE("Cannot close file \"%s\": %s", file->path->str, strerror(errno));
-        }
-    }
-
 end:
     return ret;
 }
index 779c9177c48163959719e3420a346b849dc11c1b..ee6441cbe6bdaa9c8887d49ec7e30e5baea6d1aa 100644 (file)
@@ -7,11 +7,31 @@
 #ifndef CTF_FS_FILE_H
 #define CTF_FS_FILE_H
 
+#include <memory>
+#include <string>
+
 #include <babeltrace2/babeltrace.h>
 
-void ctf_fs_file_destroy(struct ctf_fs_file *file);
+#include "cpp-common/bt2c/libc-up.hpp"
+#include "cpp-common/bt2c/logging.hpp"
+
+struct ctf_fs_file
+{
+    using UP = std::unique_ptr<ctf_fs_file>;
+
+    explicit ctf_fs_file(const bt2c::Logger& parentLogger) :
+        logger {parentLogger, "PLUGIN/SRC.CTF.FS/FILE"}
+    {
+    }
+
+    bt2c::Logger logger;
+
+    std::string path;
+
+    bt2c::FileUP fp;
 
-struct ctf_fs_file *ctf_fs_file_create(bt_logging_level log_level, bt_self_component *self_comp);
+    off_t size = 0;
+};
 
 int ctf_fs_file_open(struct ctf_fs_file *file, const char *mode);
 
index 5306b421dc98d3254d87656260d9b159a7c572df..e86d30cecf8544041365c4d23890b44722c01fe4 100644 (file)
@@ -7,29 +7,26 @@
  * Babeltrace CTF file system Reader Component
  */
 
+#include <sstream>
+
 #include <glib.h>
-#include <inttypes.h>
 
 #include <babeltrace2/babeltrace.h>
 
-#define BT_COMP_LOG_SELF_COMP self_comp
-#define BT_LOG_OUTPUT_LEVEL   ((enum bt_log_level) log_level)
-#define BT_LOG_TAG            "PLUGIN/SRC.CTF.FS"
-#include "logging/comp-logging.h"
-
 #include "common/assert.h"
 #include "common/common.h"
 #include "common/uuid.h"
+#include "cpp-common/bt2c/glib-up.hpp"
+#include "cpp-common/bt2s/make-unique.hpp"
 
 #include "plugins/common/param-validation/param-validation.h"
 
-#include "../common/metadata/ctf-meta-configure-ir-trace.hpp"
-#include "../common/msg-iter/msg-iter.hpp"
+#include "../common/src/metadata/tsdl/ctf-meta-configure-ir-trace.hpp"
+#include "../common/src/msg-iter/msg-iter.hpp"
 #include "data-stream-file.hpp"
 #include "file.hpp"
 #include "fs.hpp"
 #include "metadata.hpp"
-#include "plugins/ctf/common/metadata/ctf-meta.hpp"
 #include "query.hpp"
 
 struct tracer_info
@@ -40,31 +37,12 @@ struct tracer_info
     int64_t patch;
 };
 
-static void ctf_fs_msg_iter_data_destroy(struct ctf_fs_msg_iter_data *msg_iter_data)
-{
-    if (!msg_iter_data) {
-        return;
-    }
-
-    if (msg_iter_data->msg_iter) {
-        ctf_msg_iter_destroy(msg_iter_data->msg_iter);
-    }
-
-    if (msg_iter_data->msg_iter_medops_data) {
-        ctf_fs_ds_group_medops_data_destroy(msg_iter_data->msg_iter_medops_data);
-    }
-
-    g_free(msg_iter_data);
-}
-
 static bt_message_iterator_class_next_method_status
 ctf_fs_iterator_next_one(struct ctf_fs_msg_iter_data *msg_iter_data, const bt_message **out_msg)
 {
+    const auto msg_iter_status =
+        ctf_msg_iter_get_next_message(msg_iter_data->msg_iter.get(), out_msg);
     bt_message_iterator_class_next_method_status status;
-    enum ctf_msg_iter_status msg_iter_status;
-    bt_logging_level log_level = msg_iter_data->log_level;
-
-    msg_iter_status = ctf_msg_iter_get_next_message(msg_iter_data->msg_iter, out_msg);
 
     switch (msg_iter_status) {
     case CTF_MSG_ITER_STATUS_OK:
@@ -85,14 +63,14 @@ ctf_fs_iterator_next_one(struct ctf_fs_msg_iter_data *msg_iter_data, const bt_me
         bt_common_abort();
 
     case CTF_MSG_ITER_STATUS_ERROR:
-        BT_MSG_ITER_LOGE_APPEND_CAUSE(msg_iter_data->self_msg_iter,
-                                      "Failed to get next message from CTF message iterator.");
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_iter_data->logger,
+                                     "Failed to get next message from CTF message iterator.");
         status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_ERROR;
         break;
 
     case CTF_MSG_ITER_STATUS_MEMORY_ERROR:
-        BT_MSG_ITER_LOGE_APPEND_CAUSE(msg_iter_data->self_msg_iter,
-                                      "Failed to get next message from CTF message iterator.");
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_iter_data->logger,
+                                     "Failed to get next message from CTF message iterator.");
         status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_MEMORY_ERROR;
         break;
 
@@ -107,31 +85,32 @@ bt_message_iterator_class_next_method_status
 ctf_fs_iterator_next(bt_self_message_iterator *iterator, bt_message_array_const msgs,
                      uint64_t capacity, uint64_t *count)
 {
-    bt_message_iterator_class_next_method_status status;
-    struct ctf_fs_msg_iter_data *msg_iter_data =
-        (struct ctf_fs_msg_iter_data *) bt_self_message_iterator_get_data(iterator);
-    uint64_t i = 0;
+    try {
+        struct ctf_fs_msg_iter_data *msg_iter_data =
+            (struct ctf_fs_msg_iter_data *) bt_self_message_iterator_get_data(iterator);
 
-    if (G_UNLIKELY(msg_iter_data->next_saved_error)) {
-        /*
+        if (G_UNLIKELY(msg_iter_data->next_saved_error)) {
+            /*
          * Last time we were called, we hit an error but had some
          * messages to deliver, so we stashed the error here.  Return
          * it now.
          */
-        BT_CURRENT_THREAD_MOVE_ERROR_AND_RESET(msg_iter_data->next_saved_error);
-        status = msg_iter_data->next_saved_status;
-        goto end;
-    }
-
-    do {
-        status = ctf_fs_iterator_next_one(msg_iter_data, &msgs[i]);
-        if (status == BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK) {
-            i++;
+            BT_CURRENT_THREAD_MOVE_ERROR_AND_RESET(msg_iter_data->next_saved_error);
+            return msg_iter_data->next_saved_status;
         }
-    } while (i < capacity && status == BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK);
 
-    if (i > 0) {
-        /*
+        bt_message_iterator_class_next_method_status status;
+        uint64_t i = 0;
+
+        do {
+            status = ctf_fs_iterator_next_one(msg_iter_data, &msgs[i]);
+            if (status == BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK) {
+                i++;
+            }
+        } while (i < capacity && status == BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK);
+
+        if (i > 0) {
+            /*
          * Even if ctf_fs_iterator_next_one() returned something
          * else than BT_MESSAGE_ITERATOR_NEXT_METHOD_STATUS_OK, we
          * accumulated message objects in the output
@@ -142,44 +121,55 @@ ctf_fs_iterator_next(bt_self_message_iterator *iterator, bt_message_array_const
          * called, possibly without any accumulated
          * message, in which case we'll return it.
          */
-        if (status < 0) {
-            /*
+            if (status < 0) {
+                /*
              * Save this error for the next _next call.  Assume that
              * this component always appends error causes when
              * returning an error status code, which will cause the
              * current thread error to be non-NULL.
              */
-            msg_iter_data->next_saved_error = bt_current_thread_take_error();
-            BT_ASSERT(msg_iter_data->next_saved_error);
-            msg_iter_data->next_saved_status = status;
+                msg_iter_data->next_saved_error = bt_current_thread_take_error();
+                BT_ASSERT(msg_iter_data->next_saved_error);
+                msg_iter_data->next_saved_status = status;
+            }
+
+            *count = i;
+            status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK;
         }
 
-        *count = i;
-        status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK;
+        return status;
+        return status;
+    } catch (const std::bad_alloc&) {
+        return BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_MEMORY_ERROR;
+    } catch (const bt2::Error&) {
+        return BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_ERROR;
     }
-
-end:
-    return status;
 }
 
 bt_message_iterator_class_seek_beginning_method_status
 ctf_fs_iterator_seek_beginning(bt_self_message_iterator *it)
 {
-    struct ctf_fs_msg_iter_data *msg_iter_data =
-        (struct ctf_fs_msg_iter_data *) bt_self_message_iterator_get_data(it);
+    try {
+        struct ctf_fs_msg_iter_data *msg_iter_data =
+            (struct ctf_fs_msg_iter_data *) bt_self_message_iterator_get_data(it);
 
-    BT_ASSERT(msg_iter_data);
+        BT_ASSERT(msg_iter_data);
 
-    ctf_msg_iter_reset(msg_iter_data->msg_iter);
-    ctf_fs_ds_group_medops_data_reset(msg_iter_data->msg_iter_medops_data);
+        ctf_msg_iter_reset(msg_iter_data->msg_iter.get());
+        ctf_fs_ds_group_medops_data_reset(msg_iter_data->msg_iter_medops_data.get());
 
-    return BT_MESSAGE_ITERATOR_CLASS_SEEK_BEGINNING_METHOD_STATUS_OK;
+        return BT_MESSAGE_ITERATOR_CLASS_SEEK_BEGINNING_METHOD_STATUS_OK;
+    } catch (const std::bad_alloc&) {
+        return BT_MESSAGE_ITERATOR_CLASS_SEEK_BEGINNING_METHOD_STATUS_MEMORY_ERROR;
+    } catch (const bt2::Error&) {
+        return BT_MESSAGE_ITERATOR_CLASS_SEEK_BEGINNING_METHOD_STATUS_ERROR;
+    }
 }
 
 void ctf_fs_iterator_finalize(bt_self_message_iterator *it)
 {
-    ctf_fs_msg_iter_data_destroy(
-        (struct ctf_fs_msg_iter_data *) bt_self_message_iterator_get_data(it));
+    ctf_fs_msg_iter_data::UP {
+        (static_cast<ctf_fs_msg_iter_data *>(bt_self_message_iterator_get_data(it)))};
 }
 
 static bt_message_iterator_class_initialize_method_status
@@ -204,165 +194,64 @@ ctf_fs_iterator_init(bt_self_message_iterator *self_msg_iter,
                      bt_self_message_iterator_configuration *config,
                      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_message_iterator_class_initialize_method_status status;
-    bt_logging_level log_level;
-    enum ctf_msg_iter_medium_status medium_status;
-    bt_self_component *self_comp = bt_self_message_iterator_borrow_component(self_msg_iter);
-
-    port_data = (struct ctf_fs_port_data *) bt_self_component_port_get_data(
-        bt_self_component_port_output_as_self_component_port(self_port));
-    BT_ASSERT(port_data);
-    log_level = port_data->ctf_fs->log_level;
-    msg_iter_data = g_new0(struct ctf_fs_msg_iter_data, 1);
-    if (!msg_iter_data) {
-        status = BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
-        goto error;
-    }
-
-    msg_iter_data->log_level = log_level;
-    msg_iter_data->self_comp = self_comp;
-    msg_iter_data->self_msg_iter = self_msg_iter;
-    msg_iter_data->ds_file_group = port_data->ds_file_group;
-
-    medium_status =
-        ctf_fs_ds_group_medops_data_create(msg_iter_data->ds_file_group, self_msg_iter, log_level,
-                                           &msg_iter_data->msg_iter_medops_data);
-    BT_ASSERT(medium_status == CTF_MSG_ITER_MEDIUM_STATUS_OK ||
-              medium_status == CTF_MSG_ITER_MEDIUM_STATUS_ERROR ||
-              medium_status == CTF_MSG_ITER_MEDIUM_STATUS_MEMORY_ERROR);
-    if (medium_status != CTF_MSG_ITER_MEDIUM_STATUS_OK) {
-        BT_MSG_ITER_LOGE_APPEND_CAUSE(self_msg_iter, "Failed to create ctf_fs_ds_group_medops");
-        status = ctf_msg_iter_medium_status_to_msg_iter_initialize_status(medium_status);
-        goto error;
-    }
-
-    msg_iter_data->msg_iter = ctf_msg_iter_create(
-        msg_iter_data->ds_file_group->ctf_fs_trace->metadata->tc,
-        bt_common_get_page_size(msg_iter_data->log_level) * 8, ctf_fs_ds_group_medops,
-        msg_iter_data->msg_iter_medops_data, msg_iter_data->log_level, self_comp, self_msg_iter);
-    if (!msg_iter_data->msg_iter) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot create a CTF message iterator.");
-        status = BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
-        goto error;
-    }
+    try {
+        ctf_fs_port_data *port_data = (struct ctf_fs_port_data *) bt_self_component_port_get_data(
+            bt_self_component_port_output_as_self_component_port(self_port));
+        BT_ASSERT(port_data);
+
+        auto msg_iter_data = bt2s::make_unique<ctf_fs_msg_iter_data>(self_msg_iter);
+        msg_iter_data->ds_file_group = port_data->ds_file_group;
+
+        ctf_msg_iter_medium_status medium_status = ctf_fs_ds_group_medops_data_create(
+            msg_iter_data->ds_file_group, self_msg_iter, msg_iter_data->logger,
+            msg_iter_data->msg_iter_medops_data);
+        BT_ASSERT(medium_status == CTF_MSG_ITER_MEDIUM_STATUS_OK ||
+                  medium_status == CTF_MSG_ITER_MEDIUM_STATUS_ERROR ||
+                  medium_status == CTF_MSG_ITER_MEDIUM_STATUS_MEMORY_ERROR);
+        if (medium_status != CTF_MSG_ITER_MEDIUM_STATUS_OK) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_iter_data->logger,
+                                         "Failed to create ctf_fs_ds_group_medops");
+            return ctf_msg_iter_medium_status_to_msg_iter_initialize_status(medium_status);
+        }
 
-    /*
+        msg_iter_data->msg_iter = ctf_msg_iter_create(
+            msg_iter_data->ds_file_group->ctf_fs_trace->metadata->tc,
+            bt_common_get_page_size(static_cast<int>(msg_iter_data->logger.level())) * 8,
+            ctf_fs_ds_group_medops, msg_iter_data->msg_iter_medops_data.get(), self_msg_iter,
+            msg_iter_data->logger);
+        if (!msg_iter_data->msg_iter) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_iter_data->logger,
+                                         "Cannot create a CTF message iterator.");
+            return BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
+        }
+
+        /*
      * This iterator can seek forward if its stream class has a default
      * clock class.
      */
-    if (msg_iter_data->ds_file_group->sc->default_clock_class) {
-        bt_self_message_iterator_configuration_set_can_seek_forward(config, true);
-    }
-
-    bt_self_message_iterator_set_data(self_msg_iter, msg_iter_data);
-    msg_iter_data = NULL;
-
-    status = BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_OK;
-    goto end;
-
-error:
-    bt_self_message_iterator_set_data(self_msg_iter, NULL);
-
-end:
-    ctf_fs_msg_iter_data_destroy(msg_iter_data);
-    return status;
-}
-
-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->metadata) {
-        ctf_fs_metadata_fini(ctf_fs_trace->metadata);
-        g_free(ctf_fs_trace->metadata);
-    }
-
-    g_free(ctf_fs_trace);
-}
-
-void ctf_fs_destroy(struct ctf_fs_component *ctf_fs)
-{
-    if (!ctf_fs) {
-        return;
-    }
-
-    ctf_fs_trace_destroy(ctf_fs->trace);
-
-    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((struct ctf_fs_port_data *) data);
-}
-
-static void ctf_fs_trace_destroy_notifier(void *data)
-{
-    struct ctf_fs_trace *trace = (struct ctf_fs_trace *) data;
-    ctf_fs_trace_destroy(trace);
-}
-
-struct ctf_fs_component *ctf_fs_component_create(bt_logging_level log_level)
-{
-    struct ctf_fs_component *ctf_fs;
+        if (msg_iter_data->ds_file_group->sc->default_clock_class) {
+            bt_self_message_iterator_configuration_set_can_seek_forward(config, true);
+        }
 
-    ctf_fs = g_new0(struct ctf_fs_component, 1);
-    if (!ctf_fs) {
-        goto error;
-    }
+        bt_self_message_iterator_set_data(self_msg_iter, msg_iter_data.release());
 
-    ctf_fs->log_level = log_level;
-    ctf_fs->port_data = g_ptr_array_new_with_free_func(port_data_destroy_notifier);
-    if (!ctf_fs->port_data) {
-        goto error;
+        return BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_OK;
+    } catch (const std::bad_alloc&) {
+        return BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
+    } catch (const bt2::Error&) {
+        return BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
     }
-
-    goto end;
-
-error:
-    ctf_fs_destroy(ctf_fs);
-    ctf_fs = NULL;
-
-end:
-    return ctf_fs;
 }
 
 void ctf_fs_finalize(bt_self_component_source *component)
 {
-    ctf_fs_destroy((struct ctf_fs_component *) bt_self_component_get_data(
-        bt_self_component_source_as_self_component(component)));
+    ctf_fs_component::UP {static_cast<ctf_fs_component *>(
+        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)
+std::string ctf_fs_make_port_name(ctf_fs_ds_file_group *ds_file_group)
 {
-    GString *name = g_string_new(NULL);
+    std::stringstream name;
 
     /*
      * The unique port name is generated by concatenating unique identifiers
@@ -378,9 +267,9 @@ gchar *ctf_fs_make_port_name(struct ctf_fs_ds_file_group *ds_file_group)
         char uuid_str[BT_UUID_STR_LEN + 1];
 
         bt_uuid_to_str(ds_file_group->ctf_fs_trace->metadata->tc->uuid, uuid_str);
-        g_string_assign(name, uuid_str);
+        name << uuid_str;
     } else {
-        g_string_assign(name, ds_file_group->ctf_fs_trace->path->str);
+        name << ds_file_group->ctf_fs_trace->path;
     }
 
     /*
@@ -388,234 +277,75 @@ gchar *ctf_fs_make_port_name(struct ctf_fs_ds_file_group *ds_file_group)
      * 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);
+        name << " | " << 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);
+        name << " | " << 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 =
-            (struct ctf_fs_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);
+        BT_ASSERT(ds_file_group->ds_file_infos.size() == 1);
+        const auto& ds_file_info = *ds_file_group->ds_file_infos[0];
+        name << " | " << ds_file_info.path;
     }
 
-    return g_string_free(name, FALSE);
+    return name.str();
 }
 
 static int create_one_port_for_trace(struct ctf_fs_component *ctf_fs,
                                      struct ctf_fs_ds_file_group *ds_file_group,
                                      bt_self_component_source *self_comp_src)
 {
-    int ret = 0;
-    struct ctf_fs_port_data *port_data = NULL;
-    gchar *port_name;
-    bt_logging_level log_level = ctf_fs->log_level;
-    bt_self_component *self_comp = bt_self_component_source_as_self_component(self_comp_src);
-
-    port_name = ctf_fs_make_port_name(ds_file_group);
-    if (!port_name) {
-        goto error;
-    }
+    const auto port_name = ctf_fs_make_port_name(ds_file_group);
+    auto port_data = bt2s::make_unique<ctf_fs_port_data>();
 
-    BT_COMP_LOGI("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;
-    }
+    BT_CPPLOGI_SPEC(ctf_fs->logger, "Creating one port named `{}`", port_name);
 
     port_data->ctf_fs = ctf_fs;
     port_data->ds_file_group = ds_file_group;
-    ret = bt_self_component_source_add_output_port(self_comp_src, port_name, port_data, NULL);
+
+    int ret = bt_self_component_source_add_output_port(self_comp_src, port_name.c_str(),
+                                                       port_data.get(), NULL);
     if (ret) {
-        goto error;
+        return ret;
     }
 
-    g_ptr_array_add(ctf_fs->port_data, port_data);
-    port_data = NULL;
-    goto end;
-
-error:
-    ret = -1;
-
-end:
-    g_free(port_name);
-
-    port_data_destroy(port_data);
-    return ret;
+    ctf_fs->port_data.emplace_back(std::move(port_data));
+    return 0;
 }
 
 static int create_ports_for_trace(struct ctf_fs_component *ctf_fs,
                                   struct ctf_fs_trace *ctf_fs_trace,
                                   bt_self_component_source *self_comp_src)
 {
-    int ret = 0;
-    size_t i;
-    bt_logging_level log_level = ctf_fs_trace->log_level;
-    bt_self_component *self_comp = bt_self_component_source_as_self_component(self_comp_src);
-
     /* 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 =
-            (struct ctf_fs_ds_file_group *) g_ptr_array_index(ctf_fs_trace->ds_file_groups, i);
-
-        ret = create_one_port_for_trace(ctf_fs, ds_file_group, self_comp_src);
+    for (const auto& ds_file_group : ctf_fs_trace->ds_file_groups) {
+        int ret = create_one_port_for_trace(ctf_fs, ds_file_group.get(), self_comp_src);
         if (ret) {
-            BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Cannot create output port.");
-            goto end;
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(ctf_fs->logger, "Cannot create output port.");
+            return ret;
         }
     }
 
-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;
+    return 0;
 }
 
-static void ctf_fs_ds_file_group_destroy(struct ctf_fs_ds_file_group *ds_file_group)
+static bool ds_index_entries_equal(const ctf_fs_ds_index_entry& left,
+                                   const ctf_fs_ds_index_entry& right)
 {
-    if (!ds_file_group) {
-        return;
-    }
-
-    if (ds_file_group->ds_file_infos) {
-        g_ptr_array_free(ds_file_group->ds_file_infos, TRUE);
-    }
-
-    ctf_fs_ds_index_destroy(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 =
-            (struct ctf_fs_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 bool ds_index_entries_equal(const struct ctf_fs_ds_index_entry *left,
-                                   const struct ctf_fs_ds_index_entry *right)
-{
-    if (left->packet_size != right->packet_size) {
+    if (left.packetSize != right.packetSize) {
         return false;
     }
 
-    if (left->timestamp_begin != right->timestamp_begin) {
+    if (left.timestamp_begin != right.timestamp_begin) {
         return false;
     }
 
-    if (left->timestamp_end != right->timestamp_end) {
+    if (left.timestamp_end != right.timestamp_end) {
         return false;
     }
 
-    if (left->packet_seq_num != right->packet_seq_num) {
+    if (left.packet_seq_num != right.packet_seq_num) {
         return false;
     }
 
@@ -626,22 +356,15 @@ static bool ds_index_entries_equal(const struct ctf_fs_ds_index_entry *left,
  * Insert `entry` into `index`, without duplication.
  *
  * The entry is inserted only if there isn't an identical entry already.
- *
- * In any case, the ownership of `entry` is transferred to this function.  So if
- * the entry is not inserted, it is freed.
  */
 
-static void ds_index_insert_ds_index_entry_sorted(struct ctf_fs_ds_index *index,
-                                                  struct ctf_fs_ds_index_entry *entry)
+static void ds_index_insert_ds_index_entry_sorted(ctf_fs_ds_index& index,
+                                                  const ctf_fs_ds_index_entry& entry)
 {
-    guint i;
-    struct ctf_fs_ds_index_entry *other_entry = NULL;
-
     /* Find the spot where to insert this index entry. */
-    for (i = 0; i < index->entries->len; i++) {
-        other_entry = (struct ctf_fs_ds_index_entry *) g_ptr_array_index(index->entries, i);
-
-        if (entry->timestamp_begin_ns <= other_entry->timestamp_begin_ns) {
+    auto otherEntry = index.entries.begin();
+    for (; otherEntry != index.entries.end(); ++otherEntry) {
+        if (entry.timestamp_begin_ns <= otherEntry->timestamp_begin_ns) {
             break;
         }
     }
@@ -653,79 +376,56 @@ static void ds_index_insert_ds_index_entry_sorted(struct ctf_fs_ds_index *index,
      * snapshots of the same trace.  We then want the index to contain
      * a reference to only one copy of that packet.
      */
-    if (i == index->entries->len || !ds_index_entries_equal(entry, other_entry)) {
-        array_insert(index->entries, entry, i);
-    } else {
-        g_free(entry);
+    if (otherEntry == index.entries.end() || !ds_index_entries_equal(entry, *otherEntry)) {
+        index.entries.emplace(otherEntry, entry);
     }
 }
 
-static void merge_ctf_fs_ds_indexes(struct ctf_fs_ds_index *dest, struct ctf_fs_ds_index *src)
+static void merge_ctf_fs_ds_indexes(ctf_fs_ds_index& dest, const ctf_fs_ds_index& src)
 {
-    guint i;
-
-    for (i = 0; i < src->entries->len; i++) {
-        struct ctf_fs_ds_index_entry *entry =
-            (struct ctf_fs_ds_index_entry *) g_ptr_array_index(src->entries, i);
-
-        /*
-               * Ownership of the ctf_fs_ds_index_entry is transferred to
-               * ds_index_insert_ds_index_entry_sorted.
-               */
-        g_ptr_array_index(src->entries, i) = NULL;
+    for (const auto& entry : src.entries) {
         ds_index_insert_ds_index_entry_sorted(dest, entry);
     }
 }
 
 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_file_info *ds_file_info = NULL;
-    struct ctf_fs_ds_index *index = NULL;
-    struct ctf_msg_iter *msg_iter = NULL;
-    struct ctf_stream_class *sc = NULL;
-    struct ctf_msg_iter_packet_properties props;
-    bt_logging_level log_level = ctf_fs_trace->log_level;
-    bt_self_component *self_comp = ctf_fs_trace->self_comp;
-    bt_self_component_class *self_comp_class = ctf_fs_trace->self_comp_class;
-
     /*
      * Create a temporary ds_file to read some properties about the data
      * stream file.
      */
-    ds_file = ctf_fs_ds_file_create(ctf_fs_trace, NULL, path, log_level);
+    const auto ds_file =
+        ctf_fs_ds_file_create(ctf_fs_trace, bt2::Stream::Shared {}, path, ctf_fs_trace->logger);
     if (!ds_file) {
-        goto error;
+        return -1;
     }
 
     /* Create a temporary iterator to read the ds_file. */
-    msg_iter =
-        ctf_msg_iter_create(ctf_fs_trace->metadata->tc, bt_common_get_page_size(log_level) * 8,
-                            ctf_fs_ds_file_medops, ds_file, log_level, self_comp, NULL);
+    ctf_msg_iter_up msg_iter = ctf_msg_iter_create(
+        ctf_fs_trace->metadata->tc,
+        bt_common_get_page_size(static_cast<int>(ctf_fs_trace->logger.level())) * 8,
+        ctf_fs_ds_file_medops, ds_file.get(), nullptr, ctf_fs_trace->logger);
     if (!msg_iter) {
-        BT_COMP_LOGE_STR("Cannot create a CTF message iterator.");
-        goto error;
+        BT_CPPLOGE_SPEC(ctf_fs_trace->logger, "Cannot create a CTF message iterator.");
+        return -1;
     }
 
-    ctf_msg_iter_set_dry_run(msg_iter, true);
+    ctf_msg_iter_set_dry_run(msg_iter.get(), true);
 
-    ret = ctf_msg_iter_get_packet_properties(msg_iter, &props);
+    ctf_msg_iter_packet_properties props;
+    int ret = ctf_msg_iter_get_packet_properties(msg_iter.get(), &props);
     if (ret) {
-        BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-            self_comp, self_comp_class,
-            "Cannot get stream file's first packet's header and context fields (`%s`).", path);
-        goto error;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(
+            ctf_fs_trace->logger,
+            "Cannot get stream file's first packet's header and context fields (`{}`).", path);
+        return ret;
     }
 
-    sc = ctf_trace_class_borrow_stream_class_by_id(ds_file->metadata->tc, props.stream_class_id);
+    ctf_stream_class *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;
+    int64_t stream_instance_id = props.data_stream_id;
+    int64_t begin_ns = -1;
 
     if (props.snapshots.beginning_clock != UINT64_C(-1)) {
         BT_ASSERT(sc->default_clock_class);
@@ -734,24 +434,23 @@ static int add_ds_file_to_ds_file_group(struct ctf_fs_trace *ctf_fs_trace, const
             sc->default_clock_class->offset_seconds, sc->default_clock_class->offset_cycles,
             &begin_ns);
         if (ret) {
-            BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                self_comp, self_comp_class,
-                "Cannot convert clock cycles to nanoseconds from origin (`%s`).", path);
-            goto error;
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(
+                ctf_fs_trace->logger,
+                "Cannot convert clock cycles to nanoseconds from origin (`{}`).", path);
+            return ret;
         }
     }
 
-    ds_file_info = ctf_fs_ds_file_info_create(path, begin_ns);
+    ctf_fs_ds_file_info::UP ds_file_info = ctf_fs_ds_file_info_create(path, begin_ns);
     if (!ds_file_info) {
-        goto error;
+        return -1;
     }
 
-    index = ctf_fs_ds_file_build_index(ds_file, ds_file_info, msg_iter);
+    auto index = ctf_fs_ds_file_build_index(ds_file.get(), ds_file_info.get(), msg_iter.get());
     if (!index) {
-        BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
-                                                "Failed to index CTF stream file \'%s\'",
-                                                ds_file->file->path->str);
-        goto error;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(ctf_fs_trace->logger, "Failed to index CTF stream file \'{}\'",
+                                     ds_file->file->path);
+        return -1;
     }
 
     if (begin_ns == -1) {
@@ -771,380 +470,214 @@ static int add_ds_file_to_ds_file_group(struct ctf_fs_trace *ctf_fs_trace, const
          * 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;
-        }
-
-        ds_file_group_insert_ds_file_info_sorted(ds_file_group, BT_MOVE_REF(ds_file_info));
-
-        add_group = true;
-        goto end;
+        ctf_fs_trace->ds_file_groups.emplace_back(bt2s::make_unique<ctf_fs_ds_file_group>(
+            ctf_fs_trace, sc, UINT64_C(-1), std::move(*index)));
+        ctf_fs_trace->ds_file_groups.back()->insert_ds_file_info_sorted(std::move(ds_file_info));
+        return 0;
     }
 
     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 =
-            (struct ctf_fs_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) {
+    ctf_fs_ds_file_group *ds_file_group = NULL;
+    for (const auto& candidate : ctf_fs_trace->ds_file_groups) {
+        if (candidate->sc == sc && candidate->stream_id == stream_instance_id) {
+            ds_file_group = candidate.get();
             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;
+        ctf_fs_trace->ds_file_groups.emplace_back(bt2s::make_unique<ctf_fs_ds_file_group>(
+            ctf_fs_trace, sc, static_cast<std::uint64_t>(stream_instance_id), std::move(*index)));
+        ds_file_group = ctf_fs_trace->ds_file_groups.back().get();
     } else {
-        merge_ctf_fs_ds_indexes(ds_file_group->index, index);
-    }
-
-    ds_file_group_insert_ds_file_info_sorted(ds_file_group, BT_MOVE_REF(ds_file_info));
-
-    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);
+        merge_ctf_fs_ds_indexes(ds_file_group->index, *index);
     }
 
-    ctf_fs_ds_file_destroy(ds_file);
-    ctf_fs_ds_file_info_destroy(ds_file_info);
+    ds_file_group->insert_ds_file_info_sorted(std::move(ds_file_info));
 
-    if (msg_iter) {
-        ctf_msg_iter_destroy(msg_iter);
-    }
-
-    ctf_fs_ds_index_destroy(index);
-    return ret;
+    return 0;
 }
 
 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;
-    bt_logging_level log_level = ctf_fs_trace->log_level;
-    bt_self_component *self_comp = ctf_fs_trace->self_comp;
-    bt_self_component_class *self_comp_class = ctf_fs_trace->self_comp_class;
-
     /* Check each file in the path directory, except specific ones */
-    dir = g_dir_open(ctf_fs_trace->path->str, 0, &error);
+    GError *error = NULL;
+    const bt2c::GDirUP dir {g_dir_open(ctf_fs_trace->path.c_str(), 0, &error)};
     if (!dir) {
-        BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-            self_comp, self_comp_class, "Cannot open directory `%s`: %s (code %d)",
-            ctf_fs_trace->path->str, error->message, error->code);
-        goto error;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(ctf_fs_trace->logger,
+                                     "Cannot open directory `{}`: {} (code {})", ctf_fs_trace->path,
+                                     error->message, error->code);
+        if (error) {
+            g_error_free(error);
+        }
+        return -1;
     }
 
-    while ((basename = g_dir_read_name(dir))) {
-        struct ctf_fs_file *file;
-
+    while (const char *basename = g_dir_read_name(dir.get())) {
         if (strcmp(basename, CTF_FS_METADATA_FILENAME) == 0) {
             /* Ignore the metadata stream. */
-            BT_COMP_LOGI("Ignoring metadata file `%s" G_DIR_SEPARATOR_S "%s`",
-                         ctf_fs_trace->path->str, basename);
+            BT_CPPLOGI_SPEC(ctf_fs_trace->logger,
+                            "Ignoring metadata file `{}" G_DIR_SEPARATOR_S "{}`",
+                            ctf_fs_trace->path, basename);
             continue;
         }
 
         if (basename[0] == '.') {
-            BT_COMP_LOGI("Ignoring hidden file `%s" G_DIR_SEPARATOR_S "%s`",
-                         ctf_fs_trace->path->str, basename);
+            BT_CPPLOGI_SPEC(ctf_fs_trace->logger,
+                            "Ignoring hidden file `{}" G_DIR_SEPARATOR_S "{}`", ctf_fs_trace->path,
+                            basename);
             continue;
         }
 
         /* Create the file. */
-        file = ctf_fs_file_create(log_level, self_comp);
-        if (!file) {
-            BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                self_comp, self_comp_class,
-                "Cannot create stream file object for file `%s" G_DIR_SEPARATOR_S "%s`",
-                ctf_fs_trace->path->str, basename);
-            goto error;
-        }
+        ctf_fs_file file {ctf_fs_trace->logger};
 
         /* 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_COMP_LOGI("Ignoring non-regular file `%s`", file->path->str);
-            ctf_fs_file_destroy(file);
-            file = NULL;
+        file.path = fmt::format("{}" G_DIR_SEPARATOR_S "{}", ctf_fs_trace->path, basename);
+
+        if (!g_file_test(file.path.c_str(), G_FILE_TEST_IS_REGULAR)) {
+            BT_CPPLOGI_SPEC(ctf_fs_trace->logger, "Ignoring non-regular file `{}`", file.path);
             continue;
         }
 
-        ret = ctf_fs_file_open(file, "rb");
+        int ret = ctf_fs_file_open(&file, "rb");
         if (ret) {
-            BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                self_comp, self_comp_class, "Cannot open stream file `%s`", file->path->str);
-            goto error;
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(ctf_fs_trace->logger, "Cannot open stream file `{}`",
+                                         file.path);
+            return ret;
         }
 
-        if (file->size == 0) {
+        if (file.size == 0) {
             /* Skip empty stream. */
-            BT_COMP_LOGI("Ignoring empty file `%s`", file->path->str);
-            ctf_fs_file_destroy(file);
+            BT_CPPLOGI_SPEC(ctf_fs_trace->logger, "Ignoring empty file `{}`", file.path);
             continue;
         }
 
-        ret = add_ds_file_to_ds_file_group(ctf_fs_trace, file->path->str);
+        ret = add_ds_file_to_ds_file_group(ctf_fs_trace, file.path.c_str());
         if (ret) {
-            BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                self_comp, self_comp_class, "Cannot add stream file `%s` to stream file group",
-                file->path->str);
-            ctf_fs_file_destroy(file);
-            goto error;
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(ctf_fs_trace->logger,
+                                         "Cannot add stream file `{}` to stream file group",
+                                         file.path);
+            return ret;
         }
-
-        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;
+    return 0;
 }
 
-static int set_trace_name(bt_trace *trace, const char *name_suffix, bt_logging_level log_level,
-                          bt_self_component *self_comp)
+static void set_trace_name(const bt2::Trace trace, const char *name_suffix)
 {
-    int ret = 0;
-    const bt_value *val;
-    GString *name;
-
-    name = g_string_new(NULL);
-    if (!name) {
-        BT_COMP_LOGE_STR("Failed to allocate a GString.");
-        ret = -1;
-        goto end;
-    }
+    std::string name;
 
     /*
      * Check if we have a trace environment string value named `hostname`.
      * If so, use it as the trace name's prefix.
      */
-    val = bt_trace_borrow_environment_entry_value_by_name_const(trace, "hostname");
-    if (val && bt_value_is_string(val)) {
-        g_string_append(name, bt_value_string_get(val));
+    const auto val = trace.environmentEntry("hostname");
+    if (val && val->isString()) {
+        name += val->asString().value();
 
         if (name_suffix) {
-            g_string_append_c(name, G_DIR_SEPARATOR);
+            name += G_DIR_SEPARATOR;
         }
     }
 
     if (name_suffix) {
-        g_string_append(name, name_suffix);
+        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;
+    trace.name(name);
 }
 
-static struct ctf_fs_trace *ctf_fs_trace_create(bt_self_component *self_comp,
-                                                bt_self_component_class *self_comp_class,
-                                                const char *path, const char *name,
-                                                struct ctf_fs_metadata_config *metadata_config,
-                                                bt_logging_level log_level)
+static ctf_fs_trace::UP ctf_fs_trace_create(const char *path, const char *name,
+                                            const ctf::src::ClkClsCfg& clkClsCfg,
+                                            bt_self_component *selfComp,
+                                            const bt2c::Logger& parentLogger)
 {
-    struct ctf_fs_trace *ctf_fs_trace;
-    int ret;
-
-    /* Only one of them must be set. */
-    BT_ASSERT(!self_comp != !self_comp_class);
-
-    ctf_fs_trace = g_new0(struct ctf_fs_trace, 1);
-    if (!ctf_fs_trace) {
-        goto end;
-    }
+    ctf_fs_trace::UP ctf_fs_trace = bt2s::make_unique<struct ctf_fs_trace>(parentLogger);
+    ctf_fs_trace->path = path;
+    ctf_fs_trace->metadata = bt2s::make_unique<ctf_fs_metadata>();
 
-    ctf_fs_trace->log_level = log_level;
-    ctf_fs_trace->self_comp = self_comp;
-    ctf_fs_trace->self_comp_class = self_comp_class;
-    ctf_fs_trace->path = g_string_new(path);
-    if (!ctf_fs_trace->path) {
-        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);
+    int ret = ctf_fs_metadata_set_trace_class(selfComp, ctf_fs_trace.get(), clkClsCfg);
     if (ret) {
-        goto error;
+        return nullptr;
     }
 
     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;
+        bt_trace *trace = bt_trace_create(ctf_fs_trace->metadata->trace_class->libObjPtr());
+        if (!trace) {
+            return nullptr;
         }
+
+        ctf_fs_trace->trace = bt2::Trace::Shared::createWithoutRef(trace);
     }
 
     if (ctf_fs_trace->trace) {
-        ret = ctf_trace_class_configure_ir_trace(ctf_fs_trace->metadata->tc, ctf_fs_trace->trace);
-        if (ret) {
-            goto error;
-        }
+        ctf_trace_class_configure_ir_trace(ctf_fs_trace->metadata->tc, *ctf_fs_trace->trace);
 
-        ret = set_trace_name(ctf_fs_trace->trace, name, log_level, self_comp);
-        if (ret) {
-            goto error;
-        }
+        set_trace_name(*ctf_fs_trace->trace, name);
     }
 
-    ret = create_ds_file_groups(ctf_fs_trace);
+    ret = create_ds_file_groups(ctf_fs_trace.get());
     if (ret) {
-        goto error;
+        return nullptr;
     }
 
-    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;
+    return g_file_test(fmt::format("{}" G_DIR_SEPARATOR_S CTF_FS_METADATA_FILENAME, path).c_str(),
+                       G_FILE_TEST_IS_REGULAR);
 }
 
 /* Helper for ctf_fs_component_create_ctf_fs_trace, to handle a single path. */
 
 static int ctf_fs_component_create_ctf_fs_trace_one_path(struct ctf_fs_component *ctf_fs,
                                                          const char *path_param,
-                                                         const char *trace_name, GPtrArray *traces,
-                                                         bt_self_component *self_comp,
-                                                         bt_self_component_class *self_comp_class)
+                                                         const char *trace_name,
+                                                         std::vector<ctf_fs_trace::UP>& traces,
+                                                         bt_self_component *selfComp)
 {
-    struct ctf_fs_trace *ctf_fs_trace;
-    int ret;
-    GString *norm_path;
-    bt_logging_level log_level = ctf_fs->log_level;
-
-    norm_path = bt_common_normalize_path(path_param, NULL);
+    bt2c::GStringUP norm_path {bt_common_normalize_path(path_param, NULL)};
     if (!norm_path) {
-        BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
-                                                "Failed to normalize path: `%s`.", path_param);
-        goto error;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(ctf_fs->logger, "Failed to normalize path: `{}`.", path_param);
+        return -1;
     }
 
-    ret = path_is_ctf_trace(norm_path->str);
+    int ret = path_is_ctf_trace(norm_path->str);
     if (ret < 0) {
-        BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
-                                                "Failed to check if path is a CTF trace: path=%s",
-                                                norm_path->str);
-        goto error;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(
+            ctf_fs->logger, "Failed to check if path is a CTF trace: path={}", norm_path->str);
+        return ret;
     } else if (ret == 0) {
-        BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-            self_comp, self_comp_class,
-            "Path is not a CTF trace (does not contain a metadata file): `%s`.", norm_path->str);
-        goto error;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(
+            ctf_fs->logger, "Path is not a CTF trace (does not contain a metadata file): `{}`.",
+            norm_path->str);
+        return -1;
     }
 
     // FIXME: Remove or ifdef for __MINGW32__
     if (strcmp(norm_path->str, "/") == 0) {
-        BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
-                                                "Opening a trace in `/` is not supported.");
-        ret = -1;
-        goto end;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(ctf_fs->logger, "Opening a trace in `/` is not supported.");
+        return -1;
     }
 
-    ctf_fs_trace = ctf_fs_trace_create(self_comp, self_comp_class, norm_path->str, trace_name,
-                                       &ctf_fs->metadata_config, log_level);
+    ctf_fs_trace::UP ctf_fs_trace = ctf_fs_trace_create(
+        norm_path->str, trace_name, ctf_fs->clkClsCfg, selfComp, ctf_fs->logger);
     if (!ctf_fs_trace) {
-        BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
-                                                "Cannot create trace for `%s`.", norm_path->str);
-        goto error;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(ctf_fs->logger, "Cannot create trace for `{}`.",
+                                     norm_path->str);
+        return -1;
     }
 
-    g_ptr_array_add(traces, ctf_fs_trace);
-    ctf_fs_trace = NULL;
+    traces.emplace_back(std::move(ctf_fs_trace));
 
-    ret = 0;
-    goto end;
-
-error:
-    ret = -1;
-
-end:
-    if (norm_path) {
-        g_string_free(norm_path, TRUE);
-    }
-
-    return ret;
+    return 0;
 }
 
 /*
@@ -1159,9 +692,8 @@ end:
 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++) {
+    for (guint i = 0; i < trace->metadata->tc->stream_classes->len; i++) {
         struct ctf_stream_class *sc =
             (struct ctf_stream_class *) trace->metadata->tc->stream_classes->pdata[i];
         num += sc->event_classes->len;
@@ -1176,52 +708,38 @@ static unsigned int metadata_count_stream_and_event_classes(struct ctf_fs_trace
  */
 
 static void merge_ctf_fs_ds_file_groups(struct ctf_fs_ds_file_group *dest,
-                                        struct ctf_fs_ds_file_group *src)
+                                        ctf_fs_ds_file_group::UP src)
 {
-    guint i;
-
-    for (i = 0; i < src->ds_file_infos->len; i++) {
-        struct ctf_fs_ds_file_info *ds_file_info =
-            (struct ctf_fs_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);
+    for (auto& ds_file_info : src->ds_file_infos) {
+        dest->insert_ds_file_info_sorted(std::move(ds_file_info));
     }
 
     /* Merge both indexes. */
     merge_ctf_fs_ds_indexes(dest->index, src->index);
 }
+
 /* 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)
+                                                ctf_fs_trace::UP src_trace)
 {
-    GPtrArray *dest = dest_trace->ds_file_groups;
-    GPtrArray *src = src_trace->ds_file_groups;
-    guint s_i;
-    int ret = 0;
+    std::vector<ctf_fs_ds_file_group::UP>& dest = dest_trace->ds_file_groups;
+    std::vector<ctf_fs_ds_file_group::UP>& src = src_trace->ds_file_groups;
 
     /*
      * 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;
+    size_t dest_len = dest.size();
 
-    for (s_i = 0; s_i < src->len; s_i++) {
-        struct ctf_fs_ds_file_group *src_group =
-            (struct ctf_fs_ds_file_group *) g_ptr_array_index(src, s_i);
+    for (auto& src_group : src) {
         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 =
-                    (struct ctf_fs_ds_file_group *) g_ptr_array_index(dest, d_i);
+            for (size_t d_i = 0; d_i < dest_len; ++d_i) {
+                ctf_fs_ds_file_group *candidate_dest = dest[d_i].get();
 
                 /* Can't match a stream instance without ID.  */
                 if (candidate_dest->stream_id == -1) {
@@ -1251,36 +769,20 @@ static int merge_matching_ctf_fs_ds_file_groups(struct ctf_fs_trace *dest_trace,
          * 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);
+            ctf_stream_class *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(dest_trace->log_level, dest_trace->self_comp);
-            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);
+            dest_trace->ds_file_groups.emplace_back(bt2s::make_unique<ctf_fs_ds_file_group>(
+                dest_trace, sc, src_group->stream_id, ctf_fs_ds_index {}));
+            dest_group = dest_trace->ds_file_groups.back().get();
         }
 
         BT_ASSERT(dest_group);
-        merge_ctf_fs_ds_file_groups(dest_group, src_group);
+        merge_ctf_fs_ds_file_groups(dest_group, std::move(src_group));
     }
 
-end:
-    return ret;
+    return 0;
 }
 
 /*
@@ -1288,32 +790,23 @@ end:
  * 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.
+ * are merged into that one.  On return, the elements of `traces` are nullptr
+ * and the merged trace is placed in `out_trace`.
  */
 
-static int merge_ctf_fs_traces(struct ctf_fs_trace **traces, unsigned int num_traces,
-                               struct ctf_fs_trace **out_trace)
+static int merge_ctf_fs_traces(std::vector<ctf_fs_trace::UP> traces, ctf_fs_trace::UP& out_trace)
 {
-    unsigned int winner_count;
-    struct ctf_fs_trace *winner;
-    guint i, winner_i;
-    int ret = 0;
+    BT_ASSERT(traces.size() >= 2);
 
-    BT_ASSERT(num_traces >= 2);
-
-    winner_count = metadata_count_stream_and_event_classes(traces[0]);
-    winner = traces[0];
-    winner_i = 0;
+    unsigned int winner_count = metadata_count_stream_and_event_classes(traces[0].get());
+    ctf_fs_trace *winner = traces[0].get();
+    guint winner_i = 0;
 
     /* Find the trace with the largest metadata. */
-    for (i = 1; i < num_traces; i++) {
-        struct ctf_fs_trace *candidate;
+    for (guint i = 1; i < traces.size(); i++) {
+        ctf_fs_trace *candidate = traces[i].get();
         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);
 
@@ -1327,29 +820,25 @@ static int merge_ctf_fs_traces(struct ctf_fs_trace **traces, unsigned int num_tr
     }
 
     /* Merge all the other traces in the winning trace. */
-    for (i = 0; i < num_traces; i++) {
-        struct ctf_fs_trace *trace = traces[i];
-
+    for (ctf_fs_trace::UP& trace : traces) {
         /* Don't merge the winner into itself. */
-        if (trace == winner) {
+        if (trace.get() == winner) {
             continue;
         }
 
         /* Merge trace's data stream file groups into winner's. */
-        ret = merge_matching_ctf_fs_ds_file_groups(winner, trace);
+        int ret = merge_matching_ctf_fs_ds_file_groups(winner, std::move(trace));
         if (ret) {
-            goto end;
+            return ret;
         }
     }
 
     /*
      * Move the winner out of the array, into `*out_trace`.
      */
-    *out_trace = winner;
-    traces[winner_i] = NULL;
+    out_trace = std::move(traces[winner_i]);
 
-end:
-    return ret;
+    return 0;
 }
 
 enum target_event
@@ -1360,52 +849,45 @@ enum target_event
 
 static int decode_clock_snapshot_after_event(struct ctf_fs_trace *ctf_fs_trace,
                                              struct ctf_clock_class *default_cc,
-                                             struct ctf_fs_ds_index_entry *index_entry,
+                                             const ctf_fs_ds_index_entry& index_entry,
                                              enum target_event target_event, uint64_t *cs,
                                              int64_t *ts_ns)
 {
-    enum ctf_msg_iter_status iter_status = CTF_MSG_ITER_STATUS_OK;
-    struct ctf_fs_ds_file *ds_file = NULL;
-    struct ctf_msg_iter *msg_iter = NULL;
-    bt_logging_level log_level = ctf_fs_trace->log_level;
-    bt_self_component *self_comp = ctf_fs_trace->self_comp;
-    int ret = 0;
-
     BT_ASSERT(ctf_fs_trace);
-    BT_ASSERT(index_entry);
-    BT_ASSERT(index_entry->path);
+    BT_ASSERT(index_entry.path);
 
-    ds_file = ctf_fs_ds_file_create(ctf_fs_trace, NULL, index_entry->path, log_level);
+    const auto ds_file = ctf_fs_ds_file_create(ctf_fs_trace, bt2::Stream::Shared {},
+                                               index_entry.path, ctf_fs_trace->logger);
     if (!ds_file) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to create a ctf_fs_ds_file");
-        ret = -1;
-        goto end;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(ctf_fs_trace->logger, "Failed to create a ctf_fs_ds_file");
+        return -1;
     }
 
     BT_ASSERT(ctf_fs_trace->metadata);
     BT_ASSERT(ctf_fs_trace->metadata->tc);
 
-    msg_iter =
-        ctf_msg_iter_create(ctf_fs_trace->metadata->tc, bt_common_get_page_size(log_level) * 8,
-                            ctf_fs_ds_file_medops, ds_file, log_level, self_comp, NULL);
+    ctf_msg_iter_up msg_iter = ctf_msg_iter_create(
+        ctf_fs_trace->metadata->tc,
+        bt_common_get_page_size(static_cast<int>(ctf_fs_trace->logger.level())) * 8,
+
+        ctf_fs_ds_file_medops, ds_file.get(), NULL, ctf_fs_trace->logger);
     if (!msg_iter) {
         /* ctf_msg_iter_create() logs errors. */
-        ret = -1;
-        goto end;
+        return -1;
     }
 
     /*
      * Turn on dry run mode to prevent the creation and usage of Babeltrace
      * library objects (bt_field, bt_message_*, etc.).
      */
-    ctf_msg_iter_set_dry_run(msg_iter, true);
+    ctf_msg_iter_set_dry_run(msg_iter.get(), true);
 
     /* Seek to the beginning of the target packet. */
-    iter_status = ctf_msg_iter_seek(msg_iter, index_entry->offset);
+    enum ctf_msg_iter_status iter_status =
+        ctf_msg_iter_seek(msg_iter.get(), index_entry.offset.bytes());
     if (iter_status) {
         /* ctf_msg_iter_seek() logs errors. */
-        ret = -1;
-        goto end;
+        return -1;
     }
 
     switch (target_event) {
@@ -1415,42 +897,34 @@ static int decode_clock_snapshot_after_event(struct ctf_fs_trace *ctf_fs_trace,
          * the first event. To extract the first event's clock
          * snapshot.
          */
-        iter_status = ctf_msg_iter_curr_packet_first_event_clock_snapshot(msg_iter, cs);
+        iter_status = ctf_msg_iter_curr_packet_first_event_clock_snapshot(msg_iter.get(), cs);
         break;
     case LAST_EVENT:
         /* Decode the packet to extract the last event's clock snapshot. */
-        iter_status = ctf_msg_iter_curr_packet_last_event_clock_snapshot(msg_iter, cs);
+        iter_status = ctf_msg_iter_curr_packet_last_event_clock_snapshot(msg_iter.get(), cs);
         break;
     default:
         bt_common_abort();
     }
     if (iter_status) {
-        ret = -1;
-        goto end;
+        return -1;
     }
 
     /* Convert clock snapshot to timestamp. */
-    ret = bt_util_clock_cycles_to_ns_from_origin(
+    int ret = bt_util_clock_cycles_to_ns_from_origin(
         *cs, default_cc->frequency, default_cc->offset_seconds, default_cc->offset_cycles, ts_ns);
     if (ret) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to convert clock snapshot to timestamp");
-        goto end;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(ctf_fs_trace->logger,
+                                     "Failed to convert clock snapshot to timestamp");
+        return ret;
     }
 
-end:
-    if (ds_file) {
-        ctf_fs_ds_file_destroy(ds_file);
-    }
-    if (msg_iter) {
-        ctf_msg_iter_destroy(msg_iter);
-    }
-
-    return ret;
+    return 0;
 }
 
 static int decode_packet_first_event_timestamp(struct ctf_fs_trace *ctf_fs_trace,
                                                struct ctf_clock_class *default_cc,
-                                               struct ctf_fs_ds_index_entry *index_entry,
+                                               const ctf_fs_ds_index_entry& index_entry,
                                                uint64_t *cs, int64_t *ts_ns)
 {
     return decode_clock_snapshot_after_event(ctf_fs_trace, default_cc, index_entry, FIRST_EVENT, cs,
@@ -1459,7 +933,7 @@ static int decode_packet_first_event_timestamp(struct ctf_fs_trace *ctf_fs_trace
 
 static int decode_packet_last_event_timestamp(struct ctf_fs_trace *ctf_fs_trace,
                                               struct ctf_clock_class *default_cc,
-                                              struct ctf_fs_ds_index_entry *index_entry,
+                                              const ctf_fs_ds_index_entry& index_entry,
                                               uint64_t *cs, int64_t *ts_ns)
 {
     return decode_clock_snapshot_after_event(ctf_fs_trace, default_cc, index_entry, LAST_EVENT, cs,
@@ -1473,10 +947,10 @@ static int decode_packet_last_event_timestamp(struct ctf_fs_trace *ctf_fs_trace,
  *
  * To fix up this erroneous data we do the following:
  *  1. If it's not the stream file's last packet: set the packet index entry's
- *     end time to the next packet's beginning time.
+ *     end time to the next packet's beginning time.
  *  2. If it's the stream file's last packet, set the packet index entry's end
- *     time to the packet's last event's time, if any, or to the packet's
- *     beginning time otherwise.
+ *     time to the packet's last event's time, if any, or to the packet's
+ *     beginning time otherwise.
  *
  * Known buggy tracer versions:
  *  - before lttng-ust 2.11.0
@@ -1486,73 +960,52 @@ static int decode_packet_last_event_timestamp(struct ctf_fs_trace *ctf_fs_trace,
  */
 static int fix_index_lttng_event_after_packet_bug(struct ctf_fs_trace *trace)
 {
-    int ret = 0;
-    guint ds_file_group_i;
-    GPtrArray *ds_file_groups = trace->ds_file_groups;
-    bt_logging_level log_level = trace->log_level;
-
-    for (ds_file_group_i = 0; ds_file_group_i < ds_file_groups->len; ds_file_group_i++) {
-        guint entry_i;
-        struct ctf_clock_class *default_cc;
-        struct ctf_fs_ds_index_entry *last_entry;
-        struct ctf_fs_ds_index *index;
-
-        struct ctf_fs_ds_file_group *ds_file_group =
-            (struct ctf_fs_ds_file_group *) g_ptr_array_index(ds_file_groups, ds_file_group_i);
-
+    for (const auto& ds_file_group : trace->ds_file_groups) {
         BT_ASSERT(ds_file_group);
-        index = ds_file_group->index;
+        auto& index = ds_file_group->index;
 
-        BT_ASSERT(index);
-        BT_ASSERT(index->entries);
-        BT_ASSERT(index->entries->len > 0);
+        BT_ASSERT(!index.entries.empty());
 
         /*
          * Iterate over all entries but the last one. The last one is
          * fixed differently after.
          */
-        for (entry_i = 0; entry_i < index->entries->len - 1; entry_i++) {
-            struct ctf_fs_ds_index_entry *curr_entry, *next_entry;
-
-            curr_entry = (ctf_fs_ds_index_entry *) g_ptr_array_index(index->entries, entry_i);
-            next_entry = (ctf_fs_ds_index_entry *) g_ptr_array_index(index->entries, entry_i + 1);
+        for (size_t entry_i = 0; entry_i < index.entries.size() - 1; ++entry_i) {
+            auto& curr_entry = index.entries[entry_i];
+            const auto& next_entry = index.entries[entry_i + 1];
 
             /*
              * 1. Set the current index entry `end` timestamp to
              * the next index entry `begin` timestamp.
              */
-            curr_entry->timestamp_end = next_entry->timestamp_begin;
-            curr_entry->timestamp_end_ns = next_entry->timestamp_begin_ns;
+            curr_entry.timestamp_end = next_entry.timestamp_begin;
+            curr_entry.timestamp_end_ns = next_entry.timestamp_begin_ns;
         }
 
         /*
          * 2. Fix the last entry by decoding the last event of the last
          * packet.
          */
-        last_entry =
-            (ctf_fs_ds_index_entry *) g_ptr_array_index(index->entries, index->entries->len - 1);
-        BT_ASSERT(last_entry);
+        auto& last_entry = index.entries.back();
 
         BT_ASSERT(ds_file_group->sc->default_clock_class);
-        default_cc = ds_file_group->sc->default_clock_class;
+        ctf_clock_class *default_cc = ds_file_group->sc->default_clock_class;
 
         /*
          * Decode packet to read the timestamp of the last event of the
          * entry.
          */
-        ret = decode_packet_last_event_timestamp(trace, default_cc, last_entry,
-                                                 &last_entry->timestamp_end,
-                                                 &last_entry->timestamp_end_ns);
+        int ret = decode_packet_last_event_timestamp(
+            trace, default_cc, last_entry, &last_entry.timestamp_end, &last_entry.timestamp_end_ns);
         if (ret) {
-            BT_COMP_LOGE_APPEND_CAUSE(
-                trace->self_comp,
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(
+                trace->logger,
                 "Failed to decode stream's last packet to get its last event's clock snapshot.");
-            goto end;
+            return ret;
         }
     }
 
-end:
-    return ret;
+    return 0;
 }
 
 /*
@@ -1571,58 +1024,44 @@ end:
  */
 static int fix_index_barectf_event_before_packet_bug(struct ctf_fs_trace *trace)
 {
-    int ret = 0;
-    guint ds_file_group_i;
-    GPtrArray *ds_file_groups = trace->ds_file_groups;
-    bt_logging_level log_level = trace->log_level;
-
-    for (ds_file_group_i = 0; ds_file_group_i < ds_file_groups->len; ds_file_group_i++) {
-        guint entry_i;
-        struct ctf_clock_class *default_cc;
-        ctf_fs_ds_file_group *ds_file_group =
-            (ctf_fs_ds_file_group *) g_ptr_array_index(ds_file_groups, ds_file_group_i);
-
-        struct ctf_fs_ds_index *index = ds_file_group->index;
+    for (const auto& ds_file_group : trace->ds_file_groups) {
+        auto& index = ds_file_group->index;
 
-        BT_ASSERT(index);
-        BT_ASSERT(index->entries);
-        BT_ASSERT(index->entries->len > 0);
+        BT_ASSERT(!index.entries.empty());
 
         BT_ASSERT(ds_file_group->sc->default_clock_class);
-        default_cc = ds_file_group->sc->default_clock_class;
+        ctf_clock_class *default_cc = ds_file_group->sc->default_clock_class;
 
         /*
          * 1. Iterate over the index, starting from the second entry
          * (index = 1).
          */
-        for (entry_i = 1; entry_i < index->entries->len; entry_i++) {
-            ctf_fs_ds_index_entry *prev_entry =
-                (ctf_fs_ds_index_entry *) g_ptr_array_index(index->entries, entry_i - 1);
-            ctf_fs_ds_index_entry *curr_entry =
-                (ctf_fs_ds_index_entry *) g_ptr_array_index(index->entries, entry_i);
+        for (size_t entry_i = 1; entry_i < index.entries.size(); ++entry_i) {
+            auto& prev_entry = index.entries[entry_i - 1];
+            auto& curr_entry = index.entries[entry_i];
             /*
              * 2. Set the current entry `begin` timestamp to the
              * timestamp of the first event of the current packet.
              */
-            ret = decode_packet_first_event_timestamp(trace, default_cc, curr_entry,
-                                                      &curr_entry->timestamp_begin,
-                                                      &curr_entry->timestamp_begin_ns);
+            int ret = decode_packet_first_event_timestamp(trace, default_cc, curr_entry,
+                                                          &curr_entry.timestamp_begin,
+                                                          &curr_entry.timestamp_begin_ns);
             if (ret) {
-                BT_COMP_LOGE_APPEND_CAUSE(trace->self_comp,
-                                          "Failed to decode first event's clock snapshot");
-                goto end;
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(trace->logger,
+                                             "Failed to decode first event's clock snapshot");
+                return ret;
             }
 
             /*
              * 3. Set the previous entry `end` timestamp to the
              * timestamp of the first event of the current packet.
              */
-            prev_entry->timestamp_end = curr_entry->timestamp_begin;
-            prev_entry->timestamp_end_ns = curr_entry->timestamp_begin_ns;
+            prev_entry.timestamp_end = curr_entry.timestamp_begin;
+            prev_entry.timestamp_end_ns = curr_entry.timestamp_begin_ns;
         }
     }
-end:
-    return ret;
+
+    return 0;
 }
 
 /*
@@ -1644,69 +1083,52 @@ end:
  */
 static int fix_index_lttng_crash_quirk(struct ctf_fs_trace *trace)
 {
-    int ret = 0;
-    guint ds_file_group_idx;
-    GPtrArray *ds_file_groups = trace->ds_file_groups;
-    bt_logging_level log_level = trace->log_level;
-
-    for (ds_file_group_idx = 0; ds_file_group_idx < ds_file_groups->len; ds_file_group_idx++) {
-        guint entry_idx;
+    for (const auto& ds_file_group : trace->ds_file_groups) {
         struct ctf_clock_class *default_cc;
-        struct ctf_fs_ds_index *index;
-
-        ctf_fs_ds_file_group *ds_file_group =
-            (ctf_fs_ds_file_group *) g_ptr_array_index(ds_file_groups, ds_file_group_idx);
 
         BT_ASSERT(ds_file_group);
-        index = ds_file_group->index;
+        auto& index = ds_file_group->index;
 
         BT_ASSERT(ds_file_group->sc->default_clock_class);
         default_cc = ds_file_group->sc->default_clock_class;
 
-        BT_ASSERT(index);
-        BT_ASSERT(index->entries);
-        BT_ASSERT(index->entries->len > 0);
+        BT_ASSERT(!index.entries.empty());
 
-        ctf_fs_ds_index_entry *last_entry =
-            (ctf_fs_ds_index_entry *) g_ptr_array_index(index->entries, index->entries->len - 1);
-        BT_ASSERT(last_entry);
+        auto& last_entry = index.entries.back();
 
         /* 1. Fix the last entry first. */
-        if (last_entry->timestamp_end == 0 && last_entry->timestamp_begin != 0) {
+        if (last_entry.timestamp_end == 0 && last_entry.timestamp_begin != 0) {
             /*
              * Decode packet to read the timestamp of the
              * last event of the stream file.
              */
-            ret = decode_packet_last_event_timestamp(trace, default_cc, last_entry,
-                                                     &last_entry->timestamp_end,
-                                                     &last_entry->timestamp_end_ns);
+            int ret = decode_packet_last_event_timestamp(trace, default_cc, last_entry,
+                                                         &last_entry.timestamp_end,
+                                                         &last_entry.timestamp_end_ns);
             if (ret) {
-                BT_COMP_LOGE_APPEND_CAUSE(trace->self_comp,
-                                          "Failed to decode last event's clock snapshot");
-                goto end;
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(trace->logger,
+                                             "Failed to decode last event's clock snapshot");
+                return ret;
             }
         }
 
         /* Iterate over all entries but the last one. */
-        for (entry_idx = 0; entry_idx < index->entries->len - 1; entry_idx++) {
-            ctf_fs_ds_index_entry *curr_entry =
-                (ctf_fs_ds_index_entry *) g_ptr_array_index(index->entries, entry_idx);
-            ctf_fs_ds_index_entry *next_entry =
-                (ctf_fs_ds_index_entry *) g_ptr_array_index(index->entries, entry_idx + 1);
+        for (size_t entry_idx = 0; entry_idx < index.entries.size() - 1; ++entry_idx) {
+            auto& curr_entry = index.entries[entry_idx];
+            const auto& next_entry = index.entries[entry_idx + 1];
 
-            if (curr_entry->timestamp_end == 0 && curr_entry->timestamp_begin != 0) {
+            if (curr_entry.timestamp_end == 0 && curr_entry.timestamp_begin != 0) {
                 /*
                  * 2. Set the current index entry `end` timestamp to
                  * the next index entry `begin` timestamp.
                  */
-                curr_entry->timestamp_end = next_entry->timestamp_begin;
-                curr_entry->timestamp_end_ns = next_entry->timestamp_begin_ns;
+                curr_entry.timestamp_end = next_entry.timestamp_begin;
+                curr_entry.timestamp_end_ns = next_entry.timestamp_begin_ns;
             }
         }
     }
 
-end:
-    return ret;
+    return 0;
 }
 
 /*
@@ -1716,9 +1138,6 @@ end:
  */
 static int extract_tracer_info(struct ctf_fs_trace *trace, struct tracer_info *current_tracer_info)
 {
-    int ret = 0;
-    struct ctf_trace_class_env_entry *entry;
-
     /* Clear the current_tracer_info struct */
     memset(current_tracer_info, 0, sizeof(*current_tracer_info));
 
@@ -1727,9 +1146,10 @@ static int extract_tracer_info(struct ctf_fs_trace *trace, struct tracer_info *c
      * major version are needed. If one of these is missing, consider it an
      * extraction failure.
      */
-    entry = ctf_trace_class_borrow_env_entry_by_name(trace->metadata->tc, "tracer_name");
+    ctf_trace_class_env_entry *entry =
+        ctf_trace_class_borrow_env_entry_by_name(trace->metadata->tc, "tracer_name");
     if (!entry || entry->type != CTF_TRACE_CLASS_ENV_ENTRY_TYPE_STR) {
-        goto missing_bare_minimum;
+        return -1;
     }
 
     /* Set tracer name. */
@@ -1737,7 +1157,7 @@ static int extract_tracer_info(struct ctf_fs_trace *trace, struct tracer_info *c
 
     entry = ctf_trace_class_borrow_env_entry_by_name(trace->metadata->tc, "tracer_major");
     if (!entry || entry->type != CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT) {
-        goto missing_bare_minimum;
+        return -1;
     }
 
     /* Set major version number. */
@@ -1745,7 +1165,7 @@ static int extract_tracer_info(struct ctf_fs_trace *trace, struct tracer_info *c
 
     entry = ctf_trace_class_borrow_env_entry_by_name(trace->metadata->tc, "tracer_minor");
     if (!entry || entry->type != CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT) {
-        goto end;
+        return 0;
     }
 
     /* Set minor version number. */
@@ -1762,18 +1182,13 @@ static int extract_tracer_info(struct ctf_fs_trace *trace, struct tracer_info *c
     }
 
     if (!entry || entry->type != CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT) {
-        goto end;
+        return 0;
     }
 
     /* Set patch version number. */
     current_tracer_info->patch = entry->value.i;
 
-    goto end;
-
-missing_bare_minimum:
-    ret = -1;
-end:
-    return ret;
+    return 0;
 }
 
 static bool is_tracer_affected_by_lttng_event_after_packet_bug(struct tracer_info *curr_tracer_info)
@@ -1854,15 +1269,11 @@ static bool is_tracer_affected_by_lttng_crash_quirk(struct tracer_info *curr_tra
  * Looks for trace produced by known buggy tracers and fix up the index
  * produced earlier.
  */
-static int fix_packet_index_tracer_bugs(struct ctf_fs_component *ctf_fs,
-                                        bt_self_component *self_comp,
-                                        bt_self_component_class *self_comp_class)
+static int fix_packet_index_tracer_bugs(ctf_fs_trace *trace)
 {
-    int ret = 0;
     struct tracer_info current_tracer_info;
-    bt_logging_level log_level = ctf_fs->log_level;
 
-    ret = extract_tracer_info(ctf_fs->trace, &current_tracer_info);
+    int ret = extract_tracer_info(trace, &current_tracer_info);
     if (ret) {
         /*
          * A trace may not have all the necessary environment
@@ -1871,156 +1282,109 @@ static int fix_packet_index_tracer_bugs(struct ctf_fs_component *ctf_fs,
          * are needed. Failing to extract these entries is not
          * an error.
          */
-        ret = 0;
-        BT_LOGI_STR("Cannot extract tracer information necessary to compare with buggy versions.");
-        goto end;
-        ;
+        BT_CPPLOGI_SPEC(
+            trace->logger,
+            "Cannot extract tracer information necessary to compare with buggy versions.");
+        return 0;
     }
 
     /* Check if the trace may be affected by old tracer bugs. */
     if (is_tracer_affected_by_lttng_event_after_packet_bug(&current_tracer_info)) {
-        BT_LOGI_STR("Trace may be affected by LTTng tracer packet timestamp bug. Fixing up.");
-        ret = fix_index_lttng_event_after_packet_bug(ctf_fs->trace);
+        BT_CPPLOGI_SPEC(trace->logger,
+                        "Trace may be affected by LTTng tracer packet timestamp bug. Fixing up.");
+        ret = fix_index_lttng_event_after_packet_bug(trace);
         if (ret) {
-            BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
-                                                    "Failed to fix LTTng event-after-packet bug.");
-            goto end;
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(trace->logger,
+                                         "Failed to fix LTTng event-after-packet bug.");
+            return ret;
         }
-        ctf_fs->trace->metadata->tc->quirks.lttng_event_after_packet = true;
+        trace->metadata->tc->quirks.lttng_event_after_packet = true;
     }
 
     if (is_tracer_affected_by_barectf_event_before_packet_bug(&current_tracer_info)) {
-        BT_LOGI_STR("Trace may be affected by barectf tracer packet timestamp bug. Fixing up.");
-        ret = fix_index_barectf_event_before_packet_bug(ctf_fs->trace);
+        BT_CPPLOGI_SPEC(trace->logger,
+                        "Trace may be affected by barectf tracer packet timestamp bug. Fixing up.");
+        ret = fix_index_barectf_event_before_packet_bug(trace);
         if (ret) {
-            BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                self_comp, self_comp_class, "Failed to fix barectf event-before-packet bug.");
-            goto end;
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(trace->logger,
+                                         "Failed to fix barectf event-before-packet bug.");
+            return ret;
         }
-        ctf_fs->trace->metadata->tc->quirks.barectf_event_before_packet = true;
+        trace->metadata->tc->quirks.barectf_event_before_packet = true;
     }
 
     if (is_tracer_affected_by_lttng_crash_quirk(&current_tracer_info)) {
-        ret = fix_index_lttng_crash_quirk(ctf_fs->trace);
+        ret = fix_index_lttng_crash_quirk(trace);
         if (ret) {
-            BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
-                                                    "Failed to fix lttng-crash timestamp quirks.");
-            goto end;
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(trace->logger,
+                                         "Failed to fix lttng-crash timestamp quirks.");
+            return ret;
         }
-        ctf_fs->trace->metadata->tc->quirks.lttng_crash = true;
+        trace->metadata->tc->quirks.lttng_crash = true;
     }
 
-end:
-    return ret;
+    return 0;
 }
 
-static gint compare_ds_file_groups_by_first_path(gconstpointer a, gconstpointer b)
+static bool compare_ds_file_groups_by_first_path(const ctf_fs_ds_file_group::UP& ds_file_group_a,
+                                                 const ctf_fs_ds_file_group::UP& ds_file_group_b)
 {
-    ctf_fs_ds_file_group * const *ds_file_group_a = (ctf_fs_ds_file_group **) a;
-    ctf_fs_ds_file_group * const *ds_file_group_b = (ctf_fs_ds_file_group **) b;
-
-    BT_ASSERT((*ds_file_group_a)->ds_file_infos->len > 0);
-    BT_ASSERT((*ds_file_group_b)->ds_file_infos->len > 0);
-
-    const ctf_fs_ds_file_info *first_ds_file_info_a =
-        (const ctf_fs_ds_file_info *) (*ds_file_group_a)->ds_file_infos->pdata[0];
-    const ctf_fs_ds_file_info *first_ds_file_info_b =
-        (const ctf_fs_ds_file_info *) (*ds_file_group_b)->ds_file_infos->pdata[0];
+    BT_ASSERT(!ds_file_group_a->ds_file_infos.empty());
+    BT_ASSERT(!ds_file_group_b->ds_file_infos.empty());
 
-    return strcmp(first_ds_file_info_a->path->str, first_ds_file_info_b->path->str);
-}
-
-static gint compare_strings(gconstpointer p_a, gconstpointer p_b)
-{
-    const char *a = *((const char **) p_a);
-    const char *b = *((const char **) p_b);
+    const auto& first_ds_file_info_a = *ds_file_group_a->ds_file_infos[0];
+    const auto& first_ds_file_info_b = *ds_file_group_b->ds_file_infos[0];
 
-    return strcmp(a, b);
+    return first_ds_file_info_a.path < first_ds_file_info_b.path;
 }
 
 int ctf_fs_component_create_ctf_fs_trace(struct ctf_fs_component *ctf_fs,
-                                         const bt_value *paths_value,
-                                         const bt_value *trace_name_value,
-                                         bt_self_component *self_comp,
-                                         bt_self_component_class *self_comp_class)
+                                         const bt2::ConstArrayValue pathsValue,
+                                         const char *traceName, bt_self_component *selfComp)
 {
-    int ret = 0;
-    uint64_t i;
-    bt_logging_level log_level = ctf_fs->log_level;
-    GPtrArray *paths = NULL;
-    GPtrArray *traces;
-    const char *trace_name;
-
-    BT_ASSERT(bt_value_get_type(paths_value) == BT_VALUE_TYPE_ARRAY);
-    BT_ASSERT(!bt_value_array_is_empty(paths_value));
-
-    traces = g_ptr_array_new_with_free_func(ctf_fs_trace_destroy_notifier);
-    if (!traces) {
-        BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
-                                                "Failed to allocate a GPtrArray.");
-        goto error;
-    }
-
-    paths = g_ptr_array_new_with_free_func(g_free);
-    if (!paths) {
-        BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
-                                                "Failed to allocate a GPtrArray.");
-        goto error;
-    }
+    std::vector<std::string> paths;
 
-    trace_name = trace_name_value ? bt_value_string_get(trace_name_value) : NULL;
+    BT_ASSERT(!pathsValue.isEmpty());
 
     /*
      * Create a sorted array of the paths, to make the execution of this
      * component deterministic.
      */
-    for (i = 0; i < bt_value_array_get_length(paths_value); i++) {
-        const bt_value *path_value = bt_value_array_borrow_element_by_index_const(paths_value, i);
-        const char *input = bt_value_string_get(path_value);
-        gchar *input_copy;
-
-        input_copy = g_strdup(input);
-        if (!input_copy) {
-            BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
-                                                    "Failed to copy a string.");
-            goto error;
-        }
-
-        g_ptr_array_add(paths, input_copy);
+    for (const auto pathValue : pathsValue) {
+        BT_ASSERT(pathValue.isString());
+        paths.emplace_back(pathValue.asString().value().str());
     }
 
-    g_ptr_array_sort(paths, compare_strings);
+    std::sort(paths.begin(), paths.end());
 
     /* Create a separate ctf_fs_trace object for each path. */
-    for (i = 0; i < paths->len; i++) {
-        const char *path = (const char *) g_ptr_array_index(paths, i);
-
-        ret = ctf_fs_component_create_ctf_fs_trace_one_path(ctf_fs, path, trace_name, traces,
-                                                            self_comp, self_comp_class);
+    std::vector<ctf_fs_trace::UP> traces;
+    for (const auto& path : paths) {
+        int ret = ctf_fs_component_create_ctf_fs_trace_one_path(ctf_fs, path.c_str(), traceName,
+                                                                traces, selfComp);
         if (ret) {
-            goto end;
+            return ret;
         }
     }
 
-    if (traces->len > 1) {
-        struct ctf_fs_trace *first_trace = (struct ctf_fs_trace *) traces->pdata[0];
+    if (traces.size() > 1) {
+        ctf_fs_trace *first_trace = traces[0].get();
         const uint8_t *first_trace_uuid = first_trace->metadata->tc->uuid;
-        struct ctf_fs_trace *trace;
 
         /*
          * We have more than one trace, they must all share the same
          * UUID, verify that.
          */
-        for (i = 0; i < traces->len; i++) {
-            struct ctf_fs_trace *this_trace = (struct ctf_fs_trace *) traces->pdata[i];
+        for (size_t i = 0; i < traces.size(); i++) {
+            ctf_fs_trace *this_trace = traces[i].get();
             const uint8_t *this_trace_uuid = this_trace->metadata->tc->uuid;
 
             if (!this_trace->metadata->tc->is_uuid_set) {
-                BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                    self_comp, self_comp_class,
-                    "Multiple traces given, but a trace does not have a UUID: path=%s",
-                    this_trace->path->str);
-                goto error;
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(
+                    ctf_fs->logger,
+                    "Multiple traces given, but a trace does not have a UUID: path={}",
+                    this_trace->path);
+                return -1;
             }
 
             if (bt_uuid_compare(first_trace_uuid, this_trace_uuid) != 0) {
@@ -2030,35 +1394,31 @@ int ctf_fs_component_create_ctf_fs_trace(struct ctf_fs_component *ctf_fs,
                 bt_uuid_to_str(first_trace_uuid, first_trace_uuid_str);
                 bt_uuid_to_str(this_trace_uuid, this_trace_uuid_str);
 
-                BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(
-                    self_comp, self_comp_class,
-                    "Multiple traces given, but UUIDs don't match: "
-                    "first-trace-uuid=%s, first-trace-path=%s, "
-                    "trace-uuid=%s, trace-path=%s",
-                    first_trace_uuid_str, first_trace->path->str, this_trace_uuid_str,
-                    this_trace->path->str);
-                goto error;
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(ctf_fs->logger,
+                                             "Multiple traces given, but UUIDs don't match: "
+                                             "first-trace-uuid={}, first-trace-path={}, "
+                                             "trace-uuid={}, trace-path={}",
+                                             first_trace_uuid_str, first_trace->path,
+                                             this_trace_uuid_str, this_trace->path);
+                return -1;
             }
         }
 
-        ret = merge_ctf_fs_traces((struct ctf_fs_trace **) traces->pdata, traces->len, &trace);
+        int ret = merge_ctf_fs_traces(std::move(traces), ctf_fs->trace);
         if (ret) {
-            BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
-                                                    "Failed to merge traces with the same UUID.");
-            goto error;
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(ctf_fs->logger,
+                                         "Failed to merge traces with the same UUID.");
+            return ret;
         }
-
-        ctf_fs->trace = trace;
     } else {
         /* Just one trace, it may or may not have a UUID, both are fine. */
-        ctf_fs->trace = (ctf_fs_trace *) traces->pdata[0];
-        traces->pdata[0] = NULL;
+        ctf_fs->trace = std::move(traces[0]);
     }
 
-    ret = fix_packet_index_tracer_bugs(ctf_fs, self_comp, self_comp_class);
+    int ret = fix_packet_index_tracer_bugs(ctf_fs->trace.get());
     if (ret) {
-        BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
-                                                "Failed to fix packet index tracer bugs.");
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(ctf_fs->logger, "Failed to fix packet index tracer bugs.");
+        return ret;
     }
 
     /*
@@ -2073,116 +1433,56 @@ int ctf_fs_component_create_ctf_fs_trace(struct ctf_fs_component *ctf_fs,
      * Having a deterministic order here can help debugging and
      * testing.
      */
-    g_ptr_array_sort(ctf_fs->trace->ds_file_groups, compare_ds_file_groups_by_first_path);
-    goto end;
-error:
-    ret = -1;
-
-end:
-    if (traces) {
-        g_ptr_array_free(traces, TRUE);
-    }
-
-    if (paths) {
-        g_ptr_array_free(paths, TRUE);
-    }
+    std::sort(ctf_fs->trace->ds_file_groups.begin(), ctf_fs->trace->ds_file_groups.end(),
+              compare_ds_file_groups_by_first_path);
 
-    return ret;
+    return 0;
 }
 
-static GString *get_stream_instance_unique_name(struct ctf_fs_ds_file_group *ds_file_group)
+static const std::string&
+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.
+     * 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 = (ctf_fs_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;
+    BT_ASSERT(!ds_file_group->ds_file_infos.empty());
+    return ds_file_group->ds_file_infos[0]->path;
 }
 
 /* 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;
-    bt_logging_level log_level = ctf_fs_trace->log_level;
-    bt_self_component *self_comp = ctf_fs_trace->self_comp;
-
-    for (i = 0; i < ctf_fs_trace->ds_file_groups->len; i++) {
-        ctf_fs_ds_file_group *ds_file_group =
-            (ctf_fs_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;
-        }
+    for (const auto& ds_file_group : ctf_fs_trace->ds_file_groups) {
+        const std::string& name = get_stream_instance_unique_name(ds_file_group.get());
 
-        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;
-        }
+        BT_ASSERT(ds_file_group->sc->ir_sc);
+        BT_ASSERT(ctf_fs_trace->trace);
+
+        const bt2::StreamClass sc {ds_file_group->sc->ir_sc};
 
-        if (!ds_file_group->stream) {
-            BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                      "Cannot create stream for DS file group: "
-                                      "addr=%p, stream-name=\"%s\"",
-                                      ds_file_group, name->str);
-            goto error;
+        if (ds_file_group->stream_id == UINT64_C(-1)) {
+            /* No stream ID: use 0 */
+            ds_file_group->stream =
+                sc.instantiate(*ctf_fs_trace->trace, ctf_fs_trace->next_stream_id);
+            ctf_fs_trace->next_stream_id++;
+        } else {
+            /* Specific stream ID */
+            ds_file_group->stream = sc.instantiate(*ctf_fs_trace->trace, ds_file_group->stream_id);
         }
 
-        ret = bt_stream_set_name(ds_file_group->stream, name->str);
+        int ret = bt_stream_set_name(ds_file_group->stream->libObjPtr(), name.c_str());
         if (ret) {
-            BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                      "Cannot set stream's name: "
-                                      "addr=%p, stream-name=\"%s\"",
-                                      ds_file_group->stream, name->str);
-            goto error;
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(ctf_fs_trace->logger,
+                                         "Cannot set stream's name: "
+                                         "addr={}, stream-name=\"{}\"",
+                                         fmt::ptr(ds_file_group->stream->libObjPtr()), name);
+            return ret;
         }
-
-        g_string_free(name, TRUE);
-        name = NULL;
     }
 
-    ret = 0;
-    goto end;
-
-error:
-    ret = -1;
-
-end:
-
-    if (name) {
-        g_string_free(name, TRUE);
-    }
-    return ret;
+    return 0;
 }
 
 static const bt_param_validation_value_descr inputs_elem_descr =
@@ -2202,96 +1502,66 @@ static bt_param_validation_map_value_entry_descr fs_params_entries_descr[] = {
      bt_param_validation_value_descr::makeBool()},
     BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_END};
 
-bool read_src_fs_parameters(const bt_value *params, const bt_value **inputs,
-                            const bt_value **trace_name, struct ctf_fs_component *ctf_fs,
-                            bt_self_component *self_comp, bt_self_component_class *self_comp_class)
+ctf::src::fs::Parameters read_src_fs_parameters(const bt2::ConstMapValue params,
+                                                const bt2c::Logger& logger)
 {
-    bool ret;
-    const bt_value *value;
-    bt_logging_level log_level = ctf_fs->log_level;
-    enum bt_param_validation_status validate_value_status;
     gchar *error = NULL;
+    bt_param_validation_status validate_value_status =
+        bt_param_validation_validate(params.libObjPtr(), fs_params_entries_descr, &error);
 
-    validate_value_status = bt_param_validation_validate(params, fs_params_entries_descr, &error);
     if (validate_value_status != BT_PARAM_VALIDATION_STATUS_OK) {
-        BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class, "%s", error);
-        ret = false;
-        goto end;
+        bt2c::GCharUP errorFreer {error};
+        BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(logger, bt2c::Error, "{}", error);
     }
 
-    /* inputs parameter */
-    *inputs = bt_value_map_borrow_entry_value_const(params, "inputs");
+    ctf::src::fs::Parameters parameters {params["inputs"]->asArray()};
 
     /* clock-class-offset-s parameter */
-    value = bt_value_map_borrow_entry_value_const(params, "clock-class-offset-s");
-    if (value) {
-        ctf_fs->metadata_config.clock_class_offset_s = bt_value_integer_signed_get(value);
+    if (const auto clockClassOffsetS = params["clock-class-offset-s"]) {
+        parameters.clkClsCfg.offsetSec = clockClassOffsetS->asSignedInteger().value();
     }
 
     /* clock-class-offset-ns parameter */
-    value = bt_value_map_borrow_entry_value_const(params, "clock-class-offset-ns");
-    if (value) {
-        ctf_fs->metadata_config.clock_class_offset_ns = bt_value_integer_signed_get(value);
+    if (const auto clockClassOffsetNs = params["clock-class-offset-ns"]) {
+        parameters.clkClsCfg.offsetNanoSec = clockClassOffsetNs->asSignedInteger().value();
     }
 
     /* force-clock-class-origin-unix-epoch parameter */
-    value = bt_value_map_borrow_entry_value_const(params, "force-clock-class-origin-unix-epoch");
-    if (value) {
-        ctf_fs->metadata_config.force_clock_class_origin_unix_epoch = bt_value_bool_get(value);
+    if (const auto forceClockClassOriginUnixEpoch = params["force-clock-class-origin-unix-epoch"]) {
+        parameters.clkClsCfg.forceOriginIsUnixEpoch =
+            forceClockClassOriginUnixEpoch->asBool().value();
     }
 
     /* trace-name parameter */
-    *trace_name = bt_value_map_borrow_entry_value_const(params, "trace-name");
-
-    ret = true;
+    if (const auto traceName = params["trace-name"]) {
+        parameters.traceName = traceName->asString().value().str();
+    }
 
-end:
-    g_free(error);
-    return ret;
+    return parameters;
 }
 
-static struct ctf_fs_component *ctf_fs_create(const bt_value *params,
-                                              bt_self_component_source *self_comp_src)
+static ctf_fs_component::UP ctf_fs_create(const bt2::ConstMapValue params,
+                                          bt_self_component_source *self_comp_src)
 {
-    struct ctf_fs_component *ctf_fs = NULL;
-    const bt_value *inputs_value;
-    const bt_value *trace_name_value;
     bt_self_component *self_comp = bt_self_component_source_as_self_component(self_comp_src);
+    const bt2c::Logger logger {bt2::SelfSourceComponent {self_comp_src}, "PLUGIN/SRC.CTF.FS/COMP"};
+    const auto parameters = read_src_fs_parameters(params, logger);
+    auto ctf_fs = bt2s::make_unique<ctf_fs_component>(parameters.clkClsCfg, logger);
 
-    ctf_fs = ctf_fs_component_create(
-        bt_component_get_logging_level(bt_self_component_as_component(self_comp)));
-    if (!ctf_fs) {
-        goto error;
-    }
-
-    if (!read_src_fs_parameters(params, &inputs_value, &trace_name_value, ctf_fs, self_comp,
-                                NULL)) {
-        goto error;
+    if (ctf_fs_component_create_ctf_fs_trace(
+            ctf_fs.get(), parameters.inputs,
+            parameters.traceName ? parameters.traceName->c_str() : nullptr, self_comp)) {
+        return nullptr;
     }
 
-    bt_self_component_set_data(self_comp, ctf_fs);
-
-    if (ctf_fs_component_create_ctf_fs_trace(ctf_fs, inputs_value, trace_name_value, self_comp,
-                                             NULL)) {
-        goto error;
-    }
-
-    if (create_streams_for_trace(ctf_fs->trace)) {
-        goto error;
+    if (create_streams_for_trace(ctf_fs->trace.get())) {
+        return nullptr;
     }
 
-    if (create_ports_for_trace(ctf_fs, ctf_fs->trace, self_comp_src)) {
-        goto error;
+    if (create_ports_for_trace(ctf_fs.get(), ctf_fs->trace.get(), self_comp_src)) {
+        return nullptr;
     }
 
-    goto end;
-
-error:
-    ctf_fs_destroy(ctf_fs);
-    ctf_fs = NULL;
-    bt_self_component_set_data(self_comp, NULL);
-
-end:
     return ctf_fs;
 }
 
@@ -2299,39 +1569,55 @@ bt_component_class_initialize_method_status ctf_fs_init(bt_self_component_source
                                                         bt_self_component_source_configuration *,
                                                         const bt_value *params, void *)
 {
-    struct ctf_fs_component *ctf_fs;
-    bt_component_class_initialize_method_status ret =
-        BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK;
+    try {
+        bt_component_class_initialize_method_status ret =
+            BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK;
 
-    ctf_fs = ctf_fs_create(params, self_comp_src);
-    if (!ctf_fs) {
-        ret = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
-    }
+        ctf_fs_component::UP ctf_fs = ctf_fs_create(bt2::ConstMapValue {params}, self_comp_src);
+        if (!ctf_fs) {
+            ret = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
+        }
 
-    return ret;
+        bt_self_component_set_data(bt_self_component_source_as_self_component(self_comp_src),
+                                   ctf_fs.release());
+        return ret;
+    } catch (const std::bad_alloc&) {
+        return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
+    } catch (const bt2::Error&) {
+        return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
+    }
 }
 
-bt_component_class_query_method_status ctf_fs_query(bt_self_component_class_source *comp_class,
+bt_component_class_query_method_status ctf_fs_query(bt_self_component_class_source *comp_class_src,
                                                     bt_private_query_executor *priv_query_exec,
                                                     const char *object, const bt_value *params,
                                                     __attribute__((unused)) void *method_data,
                                                     const bt_value **result)
 {
-    bt_component_class_query_method_status status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK;
-    bt_logging_level log_level = bt_query_executor_get_logging_level(
-        bt_private_query_executor_as_query_executor_const(priv_query_exec));
-
-    if (strcmp(object, "metadata-info") == 0) {
-        status = metadata_info_query(comp_class, params, log_level, result);
-    } else if (strcmp(object, "babeltrace.trace-infos") == 0) {
-        status = trace_infos_query(comp_class, params, log_level, result);
-    } else if (!strcmp(object, "babeltrace.support-info")) {
-        status = support_info_query(comp_class, params, log_level, result);
-    } else {
-        BT_LOGE("Unknown query object `%s`", object);
-        status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_UNKNOWN_OBJECT;
-        goto end;
+    try {
+        bt2c::Logger logger {bt2::SelfComponentClass {comp_class_src},
+                             bt2::PrivateQueryExecutor {priv_query_exec},
+                             "PLUGIN/SRC.CTF.FS/QUERY"};
+        bt2::ConstMapValue paramsObj(params);
+        bt2::Value::Shared resultObj;
+
+        if (strcmp(object, "metadata-info") == 0) {
+            resultObj = metadata_info_query(paramsObj, logger);
+        } else if (strcmp(object, "babeltrace.trace-infos") == 0) {
+            resultObj = trace_infos_query(paramsObj, logger);
+        } else if (!strcmp(object, "babeltrace.support-info")) {
+            resultObj = support_info_query(paramsObj, logger);
+        } else {
+            BT_CPPLOGE_SPEC(logger, "Unknown query object `{}`", object);
+            return BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_UNKNOWN_OBJECT;
+        }
+
+        *result = resultObj.release().libObjPtr();
+
+        return BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK;
+    } catch (const std::bad_alloc&) {
+        return BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR;
+    } catch (const bt2::Error&) {
+        return BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR;
     }
-end:
-    return status;
 }
index fadef78b78e9c21e44b27297b2107ce6268f6d7d..c9ca2a90be0dd093086a89c6ced1f38d3eaedfa7 100644 (file)
 
 #include <babeltrace2/babeltrace.h>
 
-#include "metadata.hpp"
+#include "cpp-common/bt2c/logging.hpp"
 
-extern bool ctf_fs_debug;
-
-struct ctf_fs_file
-{
-    bt_logging_level log_level;
-
-    /* Weak */
-    bt_self_component *self_comp;
+#include "data-stream-file.hpp"
+#include "plugins/ctf/common/src/metadata/tsdl/decoder.hpp"
 
-    /* Owned by this */
-    GString *path;
-
-    /* Owned by this */
-    FILE *fp;
-
-    off_t size;
-};
+extern bool ctf_fs_debug;
 
 struct ctf_fs_metadata
 {
-    /* Owned by this */
-    struct ctf_metadata_decoder *decoder;
+    using UP = std::unique_ptr<ctf_fs_metadata>;
 
     /* Owned by this */
-    bt_trace_class *trace_class;
+    ctf_metadata_decoder_up decoder;
 
-    /* Weak (owned by `decoder` above) */
-    struct ctf_trace_class *tc;
-
-    /* Owned by this */
-    char *text;
+    bt2::TraceClass::Shared trace_class;
 
-    int bo;
-};
-
-struct ctf_fs_component
-{
-    bt_logging_level log_level;
-
-    /* Array of struct ctf_fs_port_data *, owned by this */
-    GPtrArray *port_data;
-
-    /* Owned by this */
-    struct ctf_fs_trace *trace;
+    /* Weak (owned by `decoder` above) */
+    struct ctf_trace_class *tc = nullptr;
 
-    struct ctf_fs_metadata_config metadata_config;
+    int bo = 0;
 };
 
 struct ctf_fs_trace
 {
-    bt_logging_level log_level;
+    using UP = std::unique_ptr<ctf_fs_trace>;
 
-    /*
-     * Weak. These are mostly used to generate log messages or to append
-     * error causes. They are mutually exclusive, only one of them must be
-     * set.
-     */
-    bt_self_component *self_comp;
-    bt_self_component_class *self_comp_class;
+    explicit ctf_fs_trace(const bt2c::Logger& parentLogger) :
+        logger {parentLogger, "PLUGIN/SRC.CTF.FS/TRACE"}
+    {
+    }
 
-    /* Owned by this */
-    struct ctf_fs_metadata *metadata;
+    bt2c::Logger logger;
 
-    /* Owned by this */
-    bt_trace *trace;
+    ctf_fs_metadata::UP metadata;
 
-    /* Array of struct ctf_fs_ds_file_group *, owned by this */
-    GPtrArray *ds_file_groups;
+    bt2::Trace::Shared trace;
 
-    /* Owned by this */
-    GString *path;
+    std::vector<ctf_fs_ds_file_group::UP> ds_file_groups;
+
+    std::string path;
 
     /* Next automatic stream ID when not provided by packet header */
-    uint64_t next_stream_id;
+    uint64_t next_stream_id = 0;
 };
 
-struct ctf_fs_ds_index_entry
+struct ctf_fs_port_data
 {
-    /* Weak, belongs to ctf_fs_ds_file_info. */
-    const char *path;
-
-    /* Position, in bytes, of the packet from the beginning of the file. */
-    uint64_t offset;
+    using UP = std::unique_ptr<ctf_fs_port_data>;
 
-    /* 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;
-
-    /*
-     * Packet sequence number, or UINT64_MAX if not present in the index.
-     */
-    uint64_t packet_seq_num;
-};
+    /* Weak, belongs to ctf_fs_trace */
+    struct ctf_fs_ds_file_group *ds_file_group = nullptr;
 
-struct ctf_fs_ds_index
-{
-    /* Array of pointer to struct ctf_fs_ds_index_entry. */
-    GPtrArray *entries;
+    /* Weak */
+    struct ctf_fs_component *ctf_fs = nullptr;
 };
 
-struct ctf_fs_ds_file_group
+struct ctf_fs_component
 {
-    /*
-     * 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;
+    using UP = std::unique_ptr<ctf_fs_component>;
 
-    /* Owned by this */
-    struct ctf_stream_class *sc;
+    explicit ctf_fs_component(const ctf::src::ClkClsCfg& clkClsCfgParam,
+                              const bt2c::Logger& parentLogger) noexcept :
+        logger {parentLogger, "PLUGIN/SRC.CTF.FS/COMP"},
+        clkClsCfg {clkClsCfgParam}
+    {
+    }
 
-    /* Owned by this */
-    bt_stream *stream;
+    bt2c::Logger logger;
 
-    /* Stream (instance) ID; -1ULL means none */
-    uint64_t stream_id;
+    std::vector<ctf_fs_port_data::UP> port_data;
 
-    /* Weak, belongs to component */
-    struct ctf_fs_trace *ctf_fs_trace;
-
-    /*
-     * Owned by this.
-     */
-    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;
+    ctf_fs_trace::UP trace;
 
-    /* Weak */
-    struct ctf_fs_component *ctf_fs;
+    ctf::src::ClkClsCfg clkClsCfg;
 };
 
 struct ctf_fs_msg_iter_data
 {
-    bt_logging_level log_level;
+    using UP = std::unique_ptr<ctf_fs_msg_iter_data>;
 
-    /* Weak */
-    bt_self_component *self_comp;
+    explicit ctf_fs_msg_iter_data(bt_self_message_iterator *selfMsgIter) :
+        self_msg_iter {selfMsgIter}, logger {bt2::SelfMessageIterator {self_msg_iter},
+                                             "PLUGIN/SRC.CTF.FS/MSG-ITER"}
+    {
+    }
 
     /* Weak */
-    bt_self_message_iterator *self_msg_iter;
+    bt_self_message_iterator *self_msg_iter = nullptr;
+
+    bt2c::Logger logger;
 
     /* Weak, belongs to ctf_fs_trace */
-    struct ctf_fs_ds_file_group *ds_file_group;
+    struct ctf_fs_ds_file_group *ds_file_group = nullptr;
 
-    /* Owned by this */
-    struct ctf_msg_iter *msg_iter;
+    ctf_msg_iter_up msg_iter;
 
     /*
      * Saved error.  If we hit an error in the _next method, but have some
      * messages ready to return, we save the error here and return it on
      * the next _next call.
      */
-    bt_message_iterator_class_next_method_status next_saved_status;
-    const struct bt_error *next_saved_error;
+    bt_message_iterator_class_next_method_status next_saved_status =
+        BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK;
+    const struct bt_error *next_saved_error = nullptr;
 
-    struct ctf_fs_ds_group_medops_data *msg_iter_medops_data;
+    ctf_fs_ds_group_medops_data_up msg_iter_medops_data;
 };
 
 bt_component_class_initialize_method_status
@@ -219,10 +147,6 @@ ctf_fs_iterator_next(bt_self_message_iterator *iterator, bt_message_array_const
 bt_message_iterator_class_seek_beginning_method_status
 ctf_fs_iterator_seek_beginning(bt_self_message_iterator *message_iterator);
 
-/* Create and initialize a new, empty ctf_fs_component. */
-
-struct ctf_fs_component *ctf_fs_component_create(bt_logging_level log_level);
-
 /*
  * Create one `struct ctf_fs_trace` from one trace, or multiple traces sharing
  * the same UUID.
@@ -236,40 +160,43 @@ struct ctf_fs_component *ctf_fs_component_create(bt_logging_level log_level);
  */
 
 int ctf_fs_component_create_ctf_fs_trace(struct ctf_fs_component *ctf_fs,
-                                         const bt_value *paths_value,
-                                         const bt_value *trace_name_value,
-                                         bt_self_component *self_comp,
-                                         bt_self_component_class *self_comp_class);
+                                         bt2::ConstArrayValue pathsValue, const char *traceName,
+                                         bt_self_component *selfComp);
+
+namespace ctf {
+namespace src {
+namespace fs {
 
-/* Free `ctf_fs` and everything it owns. */
+/* `src.ctf.fs` parameters */
 
-void ctf_fs_destroy(struct ctf_fs_component *ctf_fs);
+struct Parameters
+{
+    explicit Parameters(const bt2::ConstArrayValue inputsParam) noexcept : inputs {inputsParam}
+    {
+    }
+
+    bt2::ConstArrayValue inputs;
+    bt2s::optional<std::string> traceName;
+    ClkClsCfg clkClsCfg;
+};
+
+} /* namespace fs */
+} /* namespace src */
+} /* namespace ctf */
 
 /*
  * 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.
- *  - The optional `trace-name` parameter is returned in `*trace_name` if
- *    present, else `*trace_name` is set to NULL.
- *
- * `self_comp` and `self_comp_class` are used for logging, only one of them
- * should be set.
- *
- * Return true on success, false if any parameter didn't pass validation.
+ * Throw if any parameter doesn't pass validation.
  */
 
-bool read_src_fs_parameters(const bt_value *params, const bt_value **paths,
-                            const bt_value **trace_name, struct ctf_fs_component *ctf_fs,
-                            bt_self_component *self_comp, bt_self_component_class *self_comp_class);
+ctf::src::fs::Parameters read_src_fs_parameters(bt2::ConstMapValue params,
+                                                const bt2c::Logger& logger);
 
 /*
  * 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.
  */
 
-gchar *ctf_fs_make_port_name(struct ctf_fs_ds_file_group *ds_file_group);
+std::string ctf_fs_make_port_name(ctf_fs_ds_file_group *ds_file_group);
 
 #endif /* BABELTRACE_PLUGIN_CTF_FS_H */
index ad215f9fdd216cfbd64c1ee5369ccf5ecefee811..bf905d3ae0975c3c88b29cdb30ca03424996eee9 100644 (file)
@@ -5,26 +5,15 @@
  * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation
  */
 
-#include <glib.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <babeltrace2/babeltrace.h>
-
-#define BT_COMP_LOG_SELF_COMP self_comp
-#define BT_LOG_OUTPUT_LEVEL   log_level
-#define BT_LOG_TAG            "PLUGIN/SRC.CTF.FS/META"
-#include "logging/comp-logging.h"
-
 #include "common/assert.h"
+#include "cpp-common/bt2s/make-unique.hpp"
 
-#include "../common/metadata/decoder.hpp"
+#include "../common/src/metadata/tsdl/decoder.hpp"
 #include "file.hpp"
 #include "fs.hpp"
 #include "metadata.hpp"
 
-FILE *ctf_fs_metadata_open_file(const char *trace_path, bt_logging_level log_level,
-                                bt_self_component_class *comp_class)
+FILE *ctf_fs_metadata_open_file(const char *trace_path, const bt2c::Logger& logger)
 {
     GString *metadata_path;
     FILE *fp = NULL;
@@ -37,8 +26,8 @@ FILE *ctf_fs_metadata_open_file(const char *trace_path, bt_logging_level log_lev
     g_string_append(metadata_path, G_DIR_SEPARATOR_S CTF_FS_METADATA_FILENAME);
     fp = fopen(metadata_path->str, "rb");
     if (!fp) {
-        BT_COMP_CLASS_LOGE_APPEND_CAUSE_ERRNO(comp_class, "Failed to open metadata file",
-                                              ": path=\"%s\"", metadata_path->str);
+        BT_CPPLOGE_ERRNO_APPEND_CAUSE_SPEC(logger, "Failed to open metadata file", ": path=\"{}\"",
+                                           metadata_path->str);
     }
 
     g_string_free(metadata_path, TRUE);
@@ -47,96 +36,68 @@ end:
     return fp;
 }
 
-static struct ctf_fs_file *get_file(const char *trace_path, bt_logging_level log_level,
-                                    bt_self_component *self_comp)
+static ctf_fs_file::UP get_file(const bt2c::CStringView trace_path, const bt2c::Logger& logger)
 {
-    struct ctf_fs_file *file = ctf_fs_file_create(log_level, self_comp);
+    auto file = bt2s::make_unique<ctf_fs_file>(logger);
 
     if (!file) {
         goto error;
     }
 
-    g_string_append(file->path, trace_path);
-    g_string_append(file->path, G_DIR_SEPARATOR_S CTF_FS_METADATA_FILENAME);
+    file->path = fmt::format("{}" G_DIR_SEPARATOR_S CTF_FS_METADATA_FILENAME, trace_path);
 
-    if (ctf_fs_file_open(file, "rb")) {
+    if (ctf_fs_file_open(file.get(), "rb")) {
         goto error;
     }
 
     goto end;
 
 error:
-    if (file) {
-        ctf_fs_file_destroy(file);
-        file = NULL;
-    }
+    file.reset();
 
 end:
     return file;
 }
 
 int ctf_fs_metadata_set_trace_class(bt_self_component *self_comp, struct ctf_fs_trace *ctf_fs_trace,
-                                    struct ctf_fs_metadata_config *config)
+                                    const ctf::src::ClkClsCfg& clkClsCfg)
 {
     int ret = 0;
-    struct ctf_fs_file *file = NULL;
-    bt_logging_level log_level = ctf_fs_trace->log_level;
-
-    ctf_metadata_decoder_config decoder_config {};
-    decoder_config.log_level = ctf_fs_trace->log_level, decoder_config.self_comp = self_comp,
-    decoder_config.clock_class_offset_s = config ? config->clock_class_offset_s : 0,
-    decoder_config.clock_class_offset_ns = config ? config->clock_class_offset_ns : 0,
-    decoder_config.force_clock_class_origin_unix_epoch =
-        config ? config->force_clock_class_origin_unix_epoch : false,
-    decoder_config.create_trace_class = true,
-
-    file = get_file(ctf_fs_trace->path->str, log_level, self_comp);
+    ctf_metadata_decoder_config decoder_config {ctf_fs_trace->logger};
+
+    decoder_config.self_comp = self_comp;
+    decoder_config.clkClsCfg = clkClsCfg;
+    decoder_config.create_trace_class = true;
+
+    const auto file = get_file(ctf_fs_trace->path, ctf_fs_trace->logger);
     if (!file) {
-        BT_COMP_LOGE("Cannot create metadata file object.");
+        BT_CPPLOGE_SPEC(ctf_fs_trace->logger, "Cannot create metadata file object.");
         ret = -1;
         goto end;
     }
 
     ctf_fs_trace->metadata->decoder = ctf_metadata_decoder_create(&decoder_config);
     if (!ctf_fs_trace->metadata->decoder) {
-        BT_COMP_LOGE("Cannot create metadata decoder object.");
+        BT_CPPLOGE_SPEC(ctf_fs_trace->logger, "Cannot create metadata decoder object.");
         ret = -1;
         goto end;
     }
 
-    ret = ctf_metadata_decoder_append_content(ctf_fs_trace->metadata->decoder, file->fp);
+    ret =
+        ctf_metadata_decoder_append_content(ctf_fs_trace->metadata->decoder.get(), file->fp.get());
     if (ret) {
-        BT_COMP_LOGE("Cannot update metadata decoder's content.");
+        BT_CPPLOGE_SPEC(ctf_fs_trace->logger, "Cannot update metadata decoder's content.");
         goto end;
     }
 
     ctf_fs_trace->metadata->trace_class =
-        ctf_metadata_decoder_get_ir_trace_class(ctf_fs_trace->metadata->decoder);
+        ctf_metadata_decoder_get_ir_trace_class(ctf_fs_trace->metadata->decoder.get());
     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);
+        ctf_metadata_decoder_borrow_ctf_trace_class(ctf_fs_trace->metadata->decoder.get());
     BT_ASSERT(ctf_fs_trace->metadata->tc);
 
 end:
-    ctf_fs_file_destroy(file);
     return ret;
 }
-
-int ctf_fs_metadata_init(struct ctf_fs_metadata *)
-{
-    /* Nothing to initialize for the moment. */
-    return 0;
-}
-
-void ctf_fs_metadata_fini(struct ctf_fs_metadata *metadata)
-{
-    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);
-    }
-}
index 60790adac50166a1750e9e07e3abc8d79e6122fb..14d7cc191f19f152df8f0e25921cbb786612957f 100644 (file)
 
 #include <babeltrace2/babeltrace.h>
 
-#define CTF_FS_METADATA_FILENAME "metadata"
+namespace bt2c {
+
+class Logger;
 
-struct ctf_fs_metadata_config
-{
-    bool force_clock_class_origin_unix_epoch;
-    int64_t clock_class_offset_s;
-    int64_t clock_class_offset_ns;
-};
+} /* namespace bt2c */
 
-int ctf_fs_metadata_init(struct ctf_fs_metadata *metadata);
+#include "../common/src/clk-cls-cfg.hpp"
 
-void ctf_fs_metadata_fini(struct ctf_fs_metadata *metadata);
+#define CTF_FS_METADATA_FILENAME "metadata"
 
 int ctf_fs_metadata_set_trace_class(bt_self_component *self_comp, struct ctf_fs_trace *ctf_fs_trace,
-                                    struct ctf_fs_metadata_config *config);
+                                    const ctf::src::ClkClsCfg& clkClsCfg);
 
-FILE *ctf_fs_metadata_open_file(const char *trace_path, bt_logging_level log_level,
-                                bt_self_component_class *comp_class);
+FILE *ctf_fs_metadata_open_file(const char *trace_path, const bt2c::Logger& logger);
 
 bool ctf_metadata_is_packetized(FILE *fp, int *byte_order);
 
index fa73ab19d8bd24bba688fae309f1c70b27687a83..0b700e91250458ba0df0c8d05522b5747356d753 100644 (file)
 
 #include <babeltrace2/babeltrace.h>
 
-#define BT_LOG_OUTPUT_LEVEL ((enum bt_log_level) log_level)
-#define BT_LOG_TAG          "PLUGIN/SRC.CTF.FS/QUERY"
-#include "logging/comp-logging.h"
-#include "logging/log.h"
+#include "cpp-common/bt2/exc.hpp"
+#include "cpp-common/bt2c/glib-up.hpp"
+#include "cpp-common/bt2c/libc-up.hpp"
 
-#include "common/assert.h"
+#include "plugins/common/param-validation/param-validation.h"
 
-#include "../common/metadata/decoder.hpp"
+#include "../common/src/metadata/tsdl/decoder.hpp"
+#include "data-stream-file.hpp"
 #include "fs.hpp"
 #include "metadata.hpp"
 #include "query.hpp"
@@ -33,420 +33,218 @@ struct range
     bool set = false;
 };
 
-bt_component_class_query_method_status
-metadata_info_query(bt_self_component_class_source *self_comp_class_src, const bt_value *params,
-                    bt_logging_level log_level, const bt_value **user_result)
-{
-    bt_component_class_query_method_status status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK;
-    bt_self_component_class *self_comp_class =
-        bt_self_component_class_source_as_self_component_class(self_comp_class_src);
-    bt_value *result = NULL;
-    const bt_value *path_value = NULL;
-    FILE *metadata_fp = NULL;
-    int ret;
-    int bo;
-    const char *path;
-    bool is_packetized;
-    struct ctf_metadata_decoder *decoder = NULL;
-    ctf_metadata_decoder_config decoder_cfg {};
-    enum ctf_metadata_decoder_status decoder_status;
-    GString *g_metadata_text = NULL;
-    const char *plaintext;
-
-    result = bt_value_map_create();
-    if (!result) {
-        status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR;
-        goto error;
-    }
+static bt_param_validation_map_value_entry_descr metadataInfoQueryParamsDesc[] = {
+    {"path", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_MANDATORY,
+     bt_param_validation_value_descr::makeString()},
+    BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_END};
 
-    BT_ASSERT(params);
+bt2::Value::Shared metadata_info_query(const bt2::ConstMapValue params, const bt2c::Logger& logger)
+{
+    gchar *validateError = nullptr;
+    const auto validationStatus = bt_param_validation_validate(
+        params.libObjPtr(), metadataInfoQueryParamsDesc, &validateError);
 
-    if (!bt_value_is_map(params)) {
-        BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class,
-                                        "Query parameters is not a map value object.");
-        status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR;
-        goto error;
-    }
+    if (validationStatus == BT_PARAM_VALIDATION_STATUS_MEMORY_ERROR) {
+        throw bt2::MemoryError {};
+    } else if (validationStatus == BT_PARAM_VALIDATION_STATUS_VALIDATION_ERROR) {
+        const bt2c::GCharUP deleter {validateError};
 
-    path_value = bt_value_map_borrow_entry_value_const(params, "path");
-    if (!path_value) {
-        BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, "Mandatory `path` parameter missing");
-        status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR;
-        goto error;
+        BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(logger, bt2::Error, "{}", validateError);
     }
 
-    if (!bt_value_is_string(path_value)) {
-        BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class,
-                                        "`path` parameter is required to be a string value");
-        status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR;
-        goto error;
+    const auto path = params["path"]->asString().value();
+    bt2c::FileUP metadataFp {ctf_fs_metadata_open_file(path, logger)};
+    if (!metadataFp) {
+        BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(logger, bt2::Error,
+                                               "Cannot open trace metadata: path=\"{}\".", path);
     }
 
-    path = bt_value_string_get(path_value);
-
-    BT_ASSERT(path);
-    metadata_fp = ctf_fs_metadata_open_file(path, log_level, self_comp_class);
-    if (!metadata_fp) {
-        BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, "Cannot open trace metadata: path=\"%s\".",
-                                        path);
-        goto error;
-    }
+    bool is_packetized;
+    int bo;
+    int ret = ctf_metadata_decoder_is_packetized(metadataFp.get(), &is_packetized, &bo, logger);
 
-    ret = ctf_metadata_decoder_is_packetized(metadata_fp, &is_packetized, &bo, log_level, NULL);
     if (ret) {
-        BT_COMP_CLASS_LOGE_APPEND_CAUSE(
-            self_comp_class,
-            "Cannot check whether or not the metadata stream is packetized: path=\"%s\".", path);
-        goto error;
+        BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(
+            logger, bt2::Error,
+            "Cannot check whether or not the metadata stream is packetized: path=\"{}\".", path);
     }
 
-    decoder_cfg.log_level = log_level;
-    decoder_cfg.self_comp_class = self_comp_class;
+    ctf_metadata_decoder_config decoder_cfg {logger};
     decoder_cfg.keep_plain_text = true;
-    decoder = ctf_metadata_decoder_create(&decoder_cfg);
+    ctf_metadata_decoder_up decoder = ctf_metadata_decoder_create(&decoder_cfg);
     if (!decoder) {
-        BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class,
-                                        "Cannot create metadata decoder: path=\"%s\".", path);
-        goto error;
+        BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(
+            logger, bt2::Error, "Cannot create metadata decoder: path=\"{}}\".", path);
     }
 
-    rewind(metadata_fp);
-    decoder_status = ctf_metadata_decoder_append_content(decoder, metadata_fp);
+    rewind(metadataFp.get());
+    ctf_metadata_decoder_status decoder_status =
+        ctf_metadata_decoder_append_content(decoder.get(), metadataFp.get());
     if (decoder_status) {
-        BT_COMP_CLASS_LOGE_APPEND_CAUSE(
-            self_comp_class, "Cannot update metadata decoder's content: path=\"%s\".", path);
-        goto error;
-    }
-
-    plaintext = ctf_metadata_decoder_get_text(decoder);
-    g_metadata_text = g_string_new(NULL);
-
-    if (!g_metadata_text) {
-        goto error;
-    }
-
-    if (strncmp(plaintext, 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, plaintext);
-
-    ret = bt_value_map_insert_string_entry(result, "text", g_metadata_text->str);
-    if (ret) {
-        BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class,
-                                        "Cannot insert metadata text into query result.");
-        goto error;
+        BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(
+            logger, bt2::Error, "Cannot update metadata decoder's content: path=\"{}\".", path);
     }
 
-    ret = bt_value_map_insert_bool_entry(result, "is-packetized", is_packetized);
-    if (ret) {
-        BT_COMP_CLASS_LOGE_APPEND_CAUSE(
-            self_comp_class, "Cannot insert \"is-packetized\" attribute into query result.");
-        goto error;
-    }
-
-    goto end;
+    const char *plain_text = ctf_metadata_decoder_get_text(decoder.get());
+    std::string metadata_text;
 
-error:
-    BT_VALUE_PUT_REF_AND_RESET(result);
-    result = NULL;
-
-    if (status >= 0) {
-        status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR;
+    if (strncmp(plain_text, METADATA_TEXT_SIG, sizeof(METADATA_TEXT_SIG) - 1) != 0) {
+        metadata_text = METADATA_TEXT_SIG;
+        metadata_text += " */\n\n";
     }
 
-end:
-    if (g_metadata_text) {
-        g_string_free(g_metadata_text, TRUE);
-    }
-    ctf_metadata_decoder_destroy(decoder);
+    metadata_text += plain_text;
 
-    if (metadata_fp) {
-        ret = fclose(metadata_fp);
-        if (ret) {
-            BT_LOGE_ERRNO("Cannot close metadata file stream", ": path=\"%s\"", path);
-        }
-    }
+    const auto result = bt2::MapValue::create();
+    result->insert("text", metadata_text);
+    result->insert("is-packetized", is_packetized);
 
-    *user_result = result;
-    return status;
+    return result;
 }
 
-static int add_range(bt_value *info, struct range *range, const char *range_name)
+static void add_range(const bt2::MapValue info, const range& range, const char *range_name)
 {
-    int ret = 0;
-    bt_value_map_insert_entry_status status;
-    bt_value *range_map;
-
-    if (!range->set) {
+    if (!range.set) {
         /* Not an error. */
-        goto end;
-    }
-
-    status = bt_value_map_insert_empty_map_entry(info, range_name, &range_map);
-    if (status != BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK) {
-        ret = -1;
-        goto end;
+        return;
     }
 
-    status = bt_value_map_insert_signed_integer_entry(range_map, "begin", range->begin_ns);
-    if (status != BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK) {
-        ret = -1;
-        goto end;
-    }
-
-    status = bt_value_map_insert_signed_integer_entry(range_map, "end", range->end_ns);
-    if (status != BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK) {
-        ret = -1;
-        goto end;
-    }
-
-end:
-    return ret;
+    const auto rangeMap = info.insertEmptyMap(range_name);
+    rangeMap.insert("begin", range.begin_ns);
+    rangeMap.insert("end", range.end_ns);
 }
 
-static int populate_stream_info(struct ctf_fs_ds_file_group *group, bt_value *group_info,
-                                struct range *stream_range)
+static void populate_stream_info(struct ctf_fs_ds_file_group *group, const bt2::MapValue groupInfo)
 {
-    int ret = 0;
-    bt_value_map_insert_entry_status insert_status;
-    struct ctf_fs_ds_index_entry *first_ds_index_entry, *last_ds_index_entry;
-    gchar *port_name = NULL;
-
     /*
      * 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);
+    BT_ASSERT(!group->index.entries.empty());
 
     /* First entry. */
-    first_ds_index_entry =
-        (struct ctf_fs_ds_index_entry *) g_ptr_array_index(group->index->entries, 0);
+    const auto& first_ds_index_entry = group->index.entries.front();
 
     /* Last entry. */
-    last_ds_index_entry = (struct ctf_fs_ds_index_entry *) g_ptr_array_index(
-        group->index->entries, group->index->entries->len - 1);
+    const auto& last_ds_index_entry = group->index.entries.back();
 
-    stream_range->begin_ns = first_ds_index_entry->timestamp_begin_ns;
-    stream_range->end_ns = last_ds_index_entry->timestamp_end_ns;
+    range stream_range;
+    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;
-    }
-
-    port_name = ctf_fs_make_port_name(group);
-    if (!port_name) {
-        ret = -1;
-        goto end;
-    }
-
-    insert_status = bt_value_map_insert_string_entry(group_info, "port-name", port_name);
-    if (insert_status != BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK) {
-        ret = -1;
-        goto end;
-    }
+    stream_range.set = stream_range.begin_ns != UINT64_C(-1) && stream_range.end_ns != UINT64_C(-1);
 
-end:
-    g_free(port_name);
-    return ret;
+    add_range(groupInfo, stream_range, "range-ns");
+    groupInfo.insert("port-name", ctf_fs_make_port_name(group));
 }
 
-static int populate_trace_info(const struct ctf_fs_trace *trace, bt_value *trace_info,
-                               bt_logging_level log_level, bt_self_component_class *self_comp_class)
+static void populate_trace_info(const struct ctf_fs_trace *trace, const bt2::MapValue traceInfo,
+                                const bt2c::Logger& logger)
 {
-    int ret = 0;
-    size_t group_idx;
-    bt_value_map_insert_entry_status insert_status;
-    bt_value_array_append_element_status append_status;
-    bt_value *file_groups = NULL;
-
-    BT_ASSERT(trace->ds_file_groups);
     /* Add trace range info only if it contains streams. */
-    if (trace->ds_file_groups->len == 0) {
-        ret = -1;
-        BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, "Trace has no streams: trace-path=%s",
-                                        trace->path->str);
-        goto end;
+    if (trace->ds_file_groups.empty()) {
+        BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(logger, bt2::Error,
+                                               "Trace has no streams: trace-path={}", trace->path);
     }
 
-    insert_status = bt_value_map_insert_empty_array_entry(trace_info, "stream-infos", &file_groups);
-    if (insert_status != BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK) {
-        ret = -1;
-        goto end;
-    }
+    const auto fileGroups = traceInfo.insertEmptyArray("stream-infos");
 
     /* 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;
-        range group_range;
-        ctf_fs_ds_file_group *group =
-            (ctf_fs_ds_file_group *) g_ptr_array_index(trace->ds_file_groups, group_idx);
-
-        append_status = bt_value_array_append_empty_map_element(file_groups, &group_info);
-        if (append_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) {
-            ret = -1;
-            goto end;
-        }
-
-        ret = populate_stream_info(group, group_info, &group_range);
-        if (ret) {
-            goto end;
-        }
+    for (const auto& group : trace->ds_file_groups) {
+        const auto groupInfo = fileGroups.appendEmptyMap();
+        populate_stream_info(group.get(), groupInfo);
     }
-
-end:
-    return ret;
 }
 
-bt_component_class_query_method_status
-trace_infos_query(bt_self_component_class_source *self_comp_class_src, const bt_value *params,
-                  bt_logging_level log_level, const bt_value **user_result)
+bt2::Value::Shared trace_infos_query(const bt2::ConstMapValue params, const bt2c::Logger& logger)
 {
-    struct ctf_fs_component *ctf_fs = NULL;
-    bt_component_class_query_method_status status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK;
-    bt_self_component_class *self_comp_class =
-        bt_self_component_class_source_as_self_component_class(self_comp_class_src);
-    bt_value *result = NULL;
-    const bt_value *inputs_value = NULL;
-    const bt_value *trace_name_value;
-    int ret = 0;
-    bt_value *trace_info = NULL;
-    bt_value_array_append_element_status append_status;
-
-    BT_ASSERT(params);
-
-    if (!bt_value_is_map(params)) {
-        BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class,
-                                        "Query parameters is not a map value object.");
-        status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR;
-        goto error;
-    }
+    const auto parameters = read_src_fs_parameters(params, logger);
+    ctf_fs_component ctf_fs {parameters.clkClsCfg, logger};
 
-    ctf_fs = ctf_fs_component_create(log_level);
-    if (!ctf_fs) {
-        goto error;
+    if (ctf_fs_component_create_ctf_fs_trace(
+            &ctf_fs, parameters.inputs,
+            parameters.traceName ? parameters.traceName->c_str() : nullptr, nullptr)) {
+        BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(logger, bt2::Error, "Failed to create trace");
     }
 
-    if (!read_src_fs_parameters(params, &inputs_value, &trace_name_value, ctf_fs, NULL,
-                                self_comp_class)) {
-        status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR;
-        goto error;
-    }
+    const auto result = bt2::ArrayValue::create();
+    const auto traceInfo = result->appendEmptyMap();
+    populate_trace_info(ctf_fs.trace.get(), traceInfo, logger);
 
-    if (ctf_fs_component_create_ctf_fs_trace(ctf_fs, inputs_value, trace_name_value, NULL,
-                                             self_comp_class)) {
-        goto error;
-    }
+    return result;
+}
 
-    result = bt_value_array_create();
-    if (!result) {
-        status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR;
-        goto error;
-    }
+static bt_param_validation_map_value_entry_descr supportInfoQueryParamsDesc[] = {
+    {"type", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_MANDATORY,
+     bt_param_validation_value_descr::makeString()},
+    {"input", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_MANDATORY,
+     bt_param_validation_value_descr::makeString()},
+    BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_END};
 
-    append_status = bt_value_array_append_empty_map_element(result, &trace_info);
-    if (append_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) {
-        BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, "Failed to create trace info map.");
-        goto error;
-    }
+bt2::Value::Shared support_info_query(const bt2::ConstMapValue params, const bt2c::Logger& logger)
+{
+    gchar *validateError = NULL;
+    const auto validationStatus = bt_param_validation_validate(
+        params.libObjPtr(), supportInfoQueryParamsDesc, &validateError);
 
-    ret = populate_trace_info(ctf_fs->trace, trace_info, log_level, self_comp_class);
-    if (ret) {
-        goto error;
-    }
+    if (validationStatus == BT_PARAM_VALIDATION_STATUS_MEMORY_ERROR) {
+        throw bt2::MemoryError {};
+    } else if (validationStatus == BT_PARAM_VALIDATION_STATUS_VALIDATION_ERROR) {
+        const bt2c::GCharUP deleter {validateError};
 
-    goto end;
+        BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(logger, bt2::Error, "{}", validateError);
+    }
 
-error:
-    BT_VALUE_PUT_REF_AND_RESET(result);
+    const auto type = params["type"]->asString().value();
 
-    if (status >= 0) {
-        status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR;
+    if (strcmp(type, "directory") != 0) {
+        /*
+         * The input type is not a directory so we are 100% sure it's not a CTF
+         * 1.8 trace as it would need a directory with at least 1 metadata file
+         * and 1 data stream file.
+         */
+        const auto result = bt2::MapValue::create();
+        result->insert("weight", 0.0f);
+        return result;
     }
 
-end:
-    if (ctf_fs) {
-        ctf_fs_destroy(ctf_fs);
-        ctf_fs = NULL;
-    }
+    const auto input = params["input"]->asString().value();
 
-    *user_result = result;
-    return status;
-}
+    bt2c::GCharUP metadataPath {g_build_filename(input, CTF_FS_METADATA_FILENAME, NULL)};
+    if (!metadataPath) {
+        BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(logger, bt2::Error, "Failed to read parameters");
+    }
 
-bt_component_class_query_method_status
-support_info_query(bt_self_component_class_source *comp_class, const bt_value *params,
-                   bt_logging_level log_level, const bt_value **user_result)
-{
-    const bt_value *input_type_value;
-    const char *input_type;
-    bt_component_class_query_method_status status;
-    bt_value_map_insert_entry_status insert_entry_status;
     double weight = 0;
-    gchar *metadata_path = NULL;
-    bt_value *result = NULL;
-    struct ctf_metadata_decoder *metadata_decoder = NULL;
-    FILE *metadata_file = NULL;
     char uuid_str[BT_UUID_STR_LEN + 1];
     bool has_uuid = false;
-    const bt_value *input_value;
-    const char *input;
-
-    input_type_value = bt_value_map_borrow_entry_value_const(params, "type");
-    BT_ASSERT(input_type_value);
-    BT_ASSERT(bt_value_get_type(input_type_value) == BT_VALUE_TYPE_STRING);
-    input_type = bt_value_string_get(input_type_value);
-
-    if (strcmp(input_type, "directory") != 0) {
-        goto create_result;
-    }
-
-    input_value = bt_value_map_borrow_entry_value_const(params, "input");
-    BT_ASSERT(input_value);
-    BT_ASSERT(bt_value_get_type(input_value) == BT_VALUE_TYPE_STRING);
-    input = bt_value_string_get(input_value);
-
-    metadata_path = g_build_filename(input, CTF_FS_METADATA_FILENAME, NULL);
-    if (!metadata_path) {
-        status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR;
-        goto end;
-    }
-
-    metadata_file = g_fopen(metadata_path, "rb");
-    if (metadata_file) {
-        ctf_metadata_decoder_config metadata_decoder_config {};
+    bt2c::FileUP metadataFile {g_fopen(metadataPath.get(), "rb")};
+    if (metadataFile) {
         enum ctf_metadata_decoder_status decoder_status;
         bt_uuid_t uuid;
 
-        metadata_decoder_config.log_level = log_level;
-        metadata_decoder_config.self_comp_class =
-            bt_self_component_class_source_as_self_component_class(comp_class);
+        ctf_metadata_decoder_config metadata_decoder_config {logger};
 
-        metadata_decoder = ctf_metadata_decoder_create(&metadata_decoder_config);
+        ctf_metadata_decoder_up metadata_decoder =
+            ctf_metadata_decoder_create(&metadata_decoder_config);
         if (!metadata_decoder) {
-            status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR;
-            goto end;
+            BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(logger, bt2::Error,
+                                                   "Failed to create metadata decoder");
         }
 
-        decoder_status = ctf_metadata_decoder_append_content(metadata_decoder, metadata_file);
+        decoder_status =
+            ctf_metadata_decoder_append_content(metadata_decoder.get(), metadataFile.get());
         if (decoder_status != CTF_METADATA_DECODER_STATUS_OK) {
-            BT_LOGW("cannot append metadata content: metadata-decoder-status=%d", decoder_status);
-            status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR;
-            goto end;
+            BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(
+                logger, bt2::Error, "Failed to append metadata content: metadata-decoder-status={}",
+                decoder_status);
         }
 
         /*
@@ -456,44 +254,21 @@ support_info_query(bt_self_component_class_source *comp_class, const bt_value *p
         weight = 0.75;
 
         /* If the trace has a UUID, return the stringified UUID as the group. */
-        if (ctf_metadata_decoder_get_trace_class_uuid(metadata_decoder, uuid) == 0) {
+        if (ctf_metadata_decoder_get_trace_class_uuid(metadata_decoder.get(), uuid) == 0) {
             bt_uuid_to_str(uuid, uuid_str);
             has_uuid = true;
         }
     }
 
-create_result:
-    result = bt_value_map_create();
-    if (!result) {
-        status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR;
-        goto end;
-    }
-
-    insert_entry_status = bt_value_map_insert_real_entry(result, "weight", weight);
-    if (insert_entry_status != BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK) {
-        status = (bt_component_class_query_method_status) insert_entry_status;
-        goto end;
-    }
+    const auto result = bt2::MapValue::create();
+    result->insert("weight", weight);
 
     /* We are not supposed to have weight == 0 and a UUID. */
     BT_ASSERT(weight > 0 || !has_uuid);
 
     if (weight > 0 && has_uuid) {
-        insert_entry_status = bt_value_map_insert_string_entry(result, "group", uuid_str);
-        if (insert_entry_status != BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK) {
-            status = (bt_component_class_query_method_status) insert_entry_status;
-            goto end;
-        }
+        result->insert("group", uuid_str);
     }
 
-    *user_result = result;
-    result = NULL;
-    status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK;
-
-end:
-    g_free(metadata_path);
-    bt_value_put_ref(result);
-    ctf_metadata_decoder_destroy(metadata_decoder);
-
-    return status;
+    return result;
 }
index 053540fffa00c2ab8b6e7f3f1813207a6c5f25d4..2c7aca09ecc5d07f207e434c70d9645ee4d07467 100644 (file)
@@ -9,19 +9,18 @@
 #ifndef BABELTRACE_PLUGIN_CTF_FS_QUERY_H
 #define BABELTRACE_PLUGIN_CTF_FS_QUERY_H
 
-#include <babeltrace2/babeltrace.h>
+#include "cpp-common/bt2/value.hpp"
 
-bt_component_class_query_method_status
-metadata_info_query(bt_self_component_class_source *comp_class, const bt_value *params,
-                    bt_logging_level log_level, const bt_value **result);
+namespace bt2c {
 
-bt_component_class_query_method_status trace_infos_query(bt_self_component_class_source *comp_class,
-                                                         const bt_value *params,
-                                                         bt_logging_level log_level,
-                                                         const bt_value **result);
+class Logger;
 
-bt_component_class_query_method_status
-support_info_query(bt_self_component_class_source *comp_class, const bt_value *params,
-                   bt_logging_level log_level, const bt_value **result);
+} /* namespace bt2c */
+
+bt2::Value::Shared metadata_info_query(bt2::ConstMapValue params, const bt2c::Logger& logger);
+
+bt2::Value::Shared trace_infos_query(bt2::ConstMapValue params, const bt2c::Logger& logger);
+
+bt2::Value::Shared support_info_query(bt2::ConstMapValue params, const bt2c::Logger& logger);
 
 #endif /* BABELTRACE_PLUGIN_CTF_FS_QUERY_H */
index 4bba7ddb326ad9dfbb5108bdfaeb24838f6ff96d..8f4ae873d234d7415b8c737c081d88209898dc5b 100644 (file)
@@ -7,23 +7,20 @@
  * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation
  */
 
+#include <sstream>
+
 #include <glib.h>
-#include <inttypes.h>
 #include <stdio.h>
+#include <stdlib.h>
 
 #include <babeltrace2/babeltrace.h>
 
-#include "plugins/ctf/common/metadata/decoder.hpp"
-
-#define BT_COMP_LOG_SELF_COMP self_comp
-#define BT_LOG_OUTPUT_LEVEL   log_level
-#define BT_LOG_TAG            "PLUGIN/SRC.CTF.LTTNG-LIVE/DS"
-#include "logging/comp-logging.h"
-
 #include "common/assert.h"
 #include "compat/mman.h" /* IWYU pragma: keep  */
+#include "cpp-common/bt2s/make-unique.hpp"
+#include "cpp-common/vendor/fmt/format.h"
 
-#include "../common/msg-iter/msg-iter.hpp"
+#include "../common/src/msg-iter/msg-iter.hpp"
 #include "data-stream.hpp"
 
 #define STREAM_NAME_PREFIX "stream-"
@@ -31,7 +28,6 @@
 static enum ctf_msg_iter_medium_status medop_request_bytes(size_t request_sz, uint8_t **buffer_addr,
                                                            size_t *buffer_sz, void *data)
 {
-    enum ctf_msg_iter_medium_status status = CTF_MSG_ITER_MEDIUM_STATUS_OK;
     lttng_live_stream_iterator *stream = (lttng_live_stream_iterator *) data;
     struct lttng_live_trace *trace = stream->trace;
     struct lttng_live_session *session = trace->session;
@@ -43,40 +39,44 @@ static enum ctf_msg_iter_medium_status medop_request_bytes(size_t request_sz, ui
     BT_ASSERT(request_sz);
 
     if (stream->has_stream_hung_up) {
-        status = CTF_MSG_ITER_MEDIUM_STATUS_EOF;
-        goto end;
+        return CTF_MSG_ITER_MEDIUM_STATUS_EOF;
     }
 
     len_left = stream->base_offset + stream->len - stream->offset;
     if (!len_left) {
         lttng_live_stream_iterator_set_state(stream, LTTNG_LIVE_STREAM_ACTIVE_NO_DATA);
-        status = CTF_MSG_ITER_MEDIUM_STATUS_AGAIN;
-        goto end;
+        return CTF_MSG_ITER_MEDIUM_STATUS_AGAIN;
     }
 
-    read_len = MIN(request_sz, stream->buflen);
+    read_len = MIN(request_sz, stream->buf.size());
     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;
+
+    const auto status = lttng_live_get_stream_bytes(live_msg_iter, stream, stream->buf.data(),
+                                                    stream->offset, read_len, &recv_len);
+
+    if (status != CTF_MSG_ITER_MEDIUM_STATUS_OK) {
+        return status;
+    }
+
+    *buffer_addr = stream->buf.data();
     *buffer_sz = recv_len;
     stream->offset += recv_len;
-end:
-    return status;
+
+    return CTF_MSG_ITER_MEDIUM_STATUS_OK;
 }
 
 static bt_stream *medop_borrow_stream(bt_stream_class *stream_class, int64_t stream_id, void *data)
 {
     lttng_live_stream_iterator *lttng_live_stream = (lttng_live_stream_iterator *) data;
-    bt_logging_level log_level = lttng_live_stream->log_level;
-    bt_self_component *self_comp = lttng_live_stream->self_comp;
 
     if (!lttng_live_stream->stream) {
         uint64_t stream_class_id = bt_stream_class_get_id(stream_class);
 
-        BT_COMP_LOGI("Creating stream %s (ID: %" PRIu64 ") out of stream "
-                     "class %" PRId64,
-                     lttng_live_stream->name->str, stream_id, stream_class_id);
+        BT_CPPLOGI_SPEC(lttng_live_stream->logger,
+                        "Creating stream {} (ID: {}) out of stream class {}",
+                        lttng_live_stream->name, stream_id, stream_class_id);
+
+        bt_stream *stream;
 
         if (stream_id < 0) {
             /*
@@ -85,26 +85,28 @@ static bt_stream *medop_borrow_stream(bt_stream_class *stream_class, int64_t str
              * 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);
+            stream =
+                bt_stream_create_with_id(stream_class, lttng_live_stream->trace->trace->libObjPtr(),
+                                         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);
+            stream = bt_stream_create_with_id(
+                stream_class, lttng_live_stream->trace->trace->libObjPtr(), (uint64_t) stream_id);
         }
 
-        if (!lttng_live_stream->stream) {
-            BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                      "Cannot create stream %s (stream class ID "
-                                      "%" PRId64 ", stream ID %" PRIu64 ")",
-                                      lttng_live_stream->name->str, stream_class_id, stream_id);
-            goto end;
+        if (!stream) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(
+                lttng_live_stream->logger,
+                "Cannot create stream {} (stream class ID {}, stream ID {})",
+                lttng_live_stream->name, stream_class_id, stream_id);
+            return nullptr;
         }
 
-        bt_stream_set_name(lttng_live_stream->stream, lttng_live_stream->name->str);
+        lttng_live_stream->stream = bt2::Stream::Shared::createWithoutRef(stream);
+
+        lttng_live_stream->stream->name(lttng_live_stream->name);
     }
 
-end:
-    return lttng_live_stream->stream;
+    return lttng_live_stream->stream->libObjPtr();
 }
 
 static struct ctf_msg_iter_medium_ops medops = {
@@ -118,43 +120,37 @@ enum lttng_live_iterator_status lttng_live_lazy_msg_init(struct lttng_live_sessi
                                                          bt_self_message_iterator *self_msg_iter)
 {
     struct lttng_live_component *lttng_live = session->lttng_live_msg_iter->lttng_live_comp;
-    uint64_t trace_idx, stream_iter_idx;
-    bt_logging_level log_level = session->log_level;
-    bt_self_component *self_comp = session->self_comp;
 
     if (!session->lazy_stream_msg_init) {
         return LTTNG_LIVE_ITERATOR_STATUS_OK;
     }
 
-    BT_COMP_LOGD("Lazily initializing self message iterator for live session: "
-                 "session-id=%" PRIu64 ", self-msg-iter-addr=%p",
-                 session->id, self_msg_iter);
-
-    for (trace_idx = 0; trace_idx < session->traces->len; trace_idx++) {
-        struct lttng_live_trace *trace =
-            (lttng_live_trace *) g_ptr_array_index(session->traces, trace_idx);
+    BT_CPPLOGD_SPEC(session->logger,
+                    "Lazily initializing self message iterator for live session: "
+                    "session-id={}, self-msg-iter-addr={}",
+                    session->id, fmt::ptr(self_msg_iter));
 
-        for (stream_iter_idx = 0; stream_iter_idx < trace->stream_iterators->len;
-             stream_iter_idx++) {
+    for (lttng_live_trace::UP& trace : session->traces) {
+        for (lttng_live_stream_iterator::UP& stream_iter : trace->stream_iterators) {
             struct ctf_trace_class *ctf_tc;
-            struct lttng_live_stream_iterator *stream_iter =
-                (lttng_live_stream_iterator *) 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);
-            BT_COMP_LOGD("Creating CTF message iterator: "
-                         "session-id=%" PRIu64 ", ctf-tc-addr=%p, "
-                         "stream-iter-name=%s, self-msg-iter-addr=%p",
-                         session->id, ctf_tc, stream_iter->name->str, self_msg_iter);
+
+            ctf_tc = ctf_metadata_decoder_borrow_ctf_trace_class(trace->metadata->decoder.get());
+            BT_CPPLOGD_SPEC(stream_iter->logger,
+                            "Creating CTF message iterator: session-id={}, ctf-tc-addr={}, "
+                            "stream-iter-name={}, self-msg-iter-addr={}",
+                            session->id, fmt::ptr(ctf_tc), stream_iter->name,
+                            fmt::ptr(self_msg_iter));
             stream_iter->msg_iter =
-                ctf_msg_iter_create(ctf_tc, lttng_live->max_query_size, medops, stream_iter,
-                                    log_level, self_comp, self_msg_iter);
+                ctf_msg_iter_create(ctf_tc, lttng_live->max_query_size, medops, stream_iter.get(),
+                                    self_msg_iter, stream_iter->logger);
             if (!stream_iter->msg_iter) {
-                BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to create CTF message iterator");
-                goto error;
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(stream_iter->logger,
+                                             "Failed to create CTF message iterator");
+                return LTTNG_LIVE_ITERATOR_STATUS_ERROR;
             }
         }
     }
@@ -162,44 +158,28 @@ enum lttng_live_iterator_status lttng_live_lazy_msg_init(struct lttng_live_sessi
     session->lazy_stream_msg_init = false;
 
     return LTTNG_LIVE_ITERATOR_STATUS_OK;
-
-error:
-    return LTTNG_LIVE_ITERATOR_STATUS_ERROR;
 }
 
 struct lttng_live_stream_iterator *
 lttng_live_stream_iterator_create(struct lttng_live_session *session, uint64_t ctf_trace_id,
                                   uint64_t stream_id, bt_self_message_iterator *self_msg_iter)
 {
-    struct lttng_live_stream_iterator *stream_iter;
-    struct lttng_live_component *lttng_live;
-    struct lttng_live_trace *trace;
-    bt_logging_level log_level;
-    bt_self_component *self_comp;
+    std::stringstream nameSs;
 
     BT_ASSERT(session);
     BT_ASSERT(session->lttng_live_msg_iter);
     BT_ASSERT(session->lttng_live_msg_iter->lttng_live_comp);
-    log_level = session->log_level;
-    self_comp = session->self_comp;
-
-    lttng_live = session->lttng_live_msg_iter->lttng_live_comp;
 
-    stream_iter = g_new0(struct lttng_live_stream_iterator, 1);
-    if (!stream_iter) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "Failed to allocate struct lttng_live_stream_iterator");
-        goto error;
-    }
-
-    stream_iter->log_level = log_level;
-    stream_iter->self_comp = self_comp;
-    trace = lttng_live_session_borrow_or_create_trace_by_id(session, ctf_trace_id);
+    lttng_live_component *lttng_live = session->lttng_live_msg_iter->lttng_live_comp;
+    lttng_live_trace *trace =
+        lttng_live_session_borrow_or_create_trace_by_id(session, ctf_trace_id);
     if (!trace) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to borrow CTF trace.");
-        goto error;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(session->logger, "Failed to borrow CTF trace.");
+        return nullptr;
     }
 
+    auto stream_iter = bt2s::make_unique<lttng_live_stream_iterator>(session->logger);
+
     stream_iter->trace = trace;
     stream_iter->state = LTTNG_LIVE_STREAM_ACTIVE_NO_DATA;
     stream_iter->viewer_stream_id = stream_id;
@@ -212,66 +192,33 @@ lttng_live_stream_iterator_create(struct lttng_live_session *session, uint64_t c
 
     if (trace->trace) {
         struct ctf_trace_class *ctf_tc =
-            ctf_metadata_decoder_borrow_ctf_trace_class(trace->metadata->decoder);
+            ctf_metadata_decoder_borrow_ctf_trace_class(trace->metadata->decoder.get());
         BT_ASSERT(!stream_iter->msg_iter);
         stream_iter->msg_iter =
-            ctf_msg_iter_create(ctf_tc, lttng_live->max_query_size, medops, stream_iter, log_level,
-                                self_comp, self_msg_iter);
+            ctf_msg_iter_create(ctf_tc, lttng_live->max_query_size, medops, stream_iter.get(),
+                                self_msg_iter, stream_iter->logger);
         if (!stream_iter->msg_iter) {
-            BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to create CTF message iterator");
-            goto error;
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(stream_iter->logger,
+                                         "Failed to create CTF message iterator");
+            return nullptr;
         }
     }
-    stream_iter->buf = g_new0(uint8_t, lttng_live->max_query_size);
-    if (!stream_iter->buf) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to allocate live stream iterator buffer");
-        goto error;
-    }
+    stream_iter->buf.resize(lttng_live->max_query_size);
 
-    stream_iter->buflen = lttng_live->max_query_size;
-    stream_iter->name = g_string_new(NULL);
-    if (!stream_iter->name) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to allocate live stream iterator name buffer");
-        goto error;
-    }
+    nameSs << STREAM_NAME_PREFIX << stream_iter->viewer_stream_id;
+    stream_iter->name = nameSs.str();
 
-    g_string_printf(stream_iter->name, STREAM_NAME_PREFIX "%" PRIu64,
-                    stream_iter->viewer_stream_id);
-    g_ptr_array_add(trace->stream_iterators, stream_iter);
+    const auto ret = stream_iter.get();
+    trace->stream_iterators.emplace_back(std::move(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;
+    return ret;
 }
 
-void lttng_live_stream_iterator_destroy(struct lttng_live_stream_iterator *stream_iter)
+lttng_live_stream_iterator::~lttng_live_stream_iterator()
 {
-    if (!stream_iter) {
-        return;
-    }
-
-    if (stream_iter->stream) {
-        BT_STREAM_PUT_REF_AND_RESET(stream_iter->stream);
-    }
-
-    if (stream_iter->msg_iter) {
-        ctf_msg_iter_destroy(stream_iter->msg_iter);
-    }
-    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--;
-
-    g_free(stream_iter);
+    this->trace->session->lttng_live_msg_iter->active_stream_iter--;
 }
index d49a9506c5eed8fce809a165cab7ea4b663fc9d6..675bbdbbaae51e7cf36c535999a7d6744d60878e 100644 (file)
@@ -18,6 +18,4 @@ struct lttng_live_stream_iterator *
 lttng_live_stream_iterator_create(struct lttng_live_session *session, uint64_t ctf_trace_id,
                                   uint64_t stream_id, bt_self_message_iterator *self_msg_iter);
 
-void lttng_live_stream_iterator_destroy(struct lttng_live_stream_iterator *stream);
-
 #endif /* LTTNG_LIVE_DATA_STREAM_H */
index 35cbff95eb713d66a9f67be072d6472bee751b84..6368181000f641718cb9c192cda053ba131b2341 100644 (file)
@@ -9,17 +9,14 @@
  */
 
 #include <glib.h>
-#include <inttypes.h>
 #include <unistd.h>
 
-#include <babeltrace2/babeltrace.h>
-
-#define BT_COMP_LOG_SELF_COMP self_comp
-#define BT_LOG_OUTPUT_LEVEL   log_level
-#define BT_LOG_TAG            "PLUGIN/SRC.CTF.LTTNG-LIVE"
-#include "logging/comp-logging.h"
-
 #include "common/assert.h"
+#include "cpp-common/bt2c/fmt.hpp"
+#include "cpp-common/bt2c/glib-up.hpp"
+#include "cpp-common/bt2c/vector.hpp"
+#include "cpp-common/bt2s/make-unique.hpp"
+#include "cpp-common/vendor/fmt/format.h"
 
 #include "plugins/common/muxing/muxing.h"
 #include "plugins/common/param-validation/param-validation.h"
 #define SESS_NOT_FOUND_ACTION_FAIL_STR     "fail"
 #define SESS_NOT_FOUND_ACTION_END_STR      "end"
 
-#define print_dbg(fmt, ...) BT_COMP_LOGD(fmt, ##__VA_ARGS__)
-
-static const char *lttng_live_iterator_status_string(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:
-        bt_common_abort();
-    }
-}
-
-static const char *lttng_live_stream_state_string(enum lttng_live_stream_state state)
-{
-    switch (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";
-    }
-}
-
 void lttng_live_stream_iterator_set_state(struct lttng_live_stream_iterator *stream_iter,
                                           enum lttng_live_stream_state new_state)
 {
-    bt_self_component *self_comp = stream_iter->self_comp;
-    bt_logging_level log_level = stream_iter->log_level;
-
-    BT_COMP_LOGD("Setting live stream iterator state: viewer-stream-id=%" PRIu64
-                 ", old-state=%s, new-state=%s",
-                 stream_iter->viewer_stream_id, lttng_live_stream_state_string(stream_iter->state),
-                 lttng_live_stream_state_string(new_state));
+    BT_CPPLOGD_SPEC(stream_iter->logger,
+                    "Setting live stream iterator state: viewer-stream-id={}, "
+                    "old-state={}, new-state={}",
+                    stream_iter->viewer_stream_id, stream_iter->state, new_state);
 
     stream_iter->state = new_state;
 }
 
 #define LTTNG_LIVE_LOGD_STREAM_ITER(live_stream_iter)                                              \
     do {                                                                                           \
-        BT_COMP_LOGD("Live stream iterator state=%s, "                                             \
-                     "last-inact-ts-is-set=%d, last-inact-ts-value=%" PRId64 ", "                  \
-                     "curr-inact-ts=%" PRId64,                                                     \
-                     lttng_live_stream_state_string(live_stream_iter->state),                      \
-                     live_stream_iter->last_inactivity_ts.is_set,                                  \
-                     live_stream_iter->last_inactivity_ts.value,                                   \
-                     live_stream_iter->current_inactivity_ts);                                     \
+        BT_CPPLOGD_SPEC((live_stream_iter)->logger,                                                \
+                        "Live stream iterator state={}, "                                          \
+                        "last-inact-ts-is-set={}, last-inact-ts-value={}, "                        \
+                        "curr-inact-ts={}",                                                        \
+                        (live_stream_iter)->state, (live_stream_iter)->last_inactivity_ts.is_set,  \
+                        (live_stream_iter)->last_inactivity_ts.value,                              \
+                        (live_stream_iter)->current_inactivity_ts);                                \
     } while (0);
 
 bool lttng_live_graph_is_canceled(struct lttng_live_msg_iter *msg_iter)
 {
-    bool ret;
-
     if (!msg_iter) {
-        ret = false;
-        goto end;
+        return false;
     }
 
-    ret = bt_self_message_iterator_is_interrupted(msg_iter->self_msg_iter);
-
-end:
-    return ret;
+    return bt_self_message_iterator_is_interrupted(msg_iter->self_msg_iter);
 }
 
 static struct lttng_live_trace *
 lttng_live_session_borrow_trace_by_id(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 =
-            (lttng_live_trace *) g_ptr_array_index(session->traces, trace_idx);
+    for (lttng_live_trace::UP& trace : session->traces) {
         if (trace->id == trace_id) {
-            ret_trace = trace;
-            goto end;
+            return trace.get();
         }
     }
 
-end:
-    return ret_trace;
-}
-
-static void lttng_live_destroy_trace(struct lttng_live_trace *trace)
-{
-    bt_logging_level log_level = trace->log_level;
-    bt_self_component *self_comp = trace->self_comp;
-
-    BT_COMP_LOGD("Destroying live trace: trace-id=%" PRIu64, trace->id);
-
-    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);
+    return nullptr;
 }
 
 static struct lttng_live_trace *lttng_live_create_trace(struct lttng_live_session *session,
                                                         uint64_t trace_id)
 {
-    struct lttng_live_trace *trace = NULL;
-    bt_logging_level log_level = session->log_level;
-    bt_self_component *self_comp = session->self_comp;
-
-    BT_COMP_LOGD("Creating live trace: "
-                 "session-id=%" PRIu64 ", trace-id=%" PRIu64,
-                 session->id, trace_id);
-    trace = g_new0(struct lttng_live_trace, 1);
-    if (!trace) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to allocate live trace");
-        goto error;
-    }
-    trace->log_level = session->log_level;
-    trace->self_comp = session->self_comp;
+    BT_CPPLOGD_SPEC(session->logger, "Creating live trace: session-id={}, trace-id={}", session->id,
+                    trace_id);
+
+    auto trace = bt2s::make_unique<lttng_live_trace>(session->logger);
+
     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->metadata_stream_state = LTTNG_LIVE_METADATA_STREAM_STATE_NEEDED;
-    g_ptr_array_add(session->traces, trace);
 
-    goto end;
-error:
-    g_free(trace);
-    trace = NULL;
-end:
-    return trace;
+    const auto ret = trace.get();
+    session->traces.emplace_back(std::move(trace));
+    return ret;
 }
 
 struct lttng_live_trace *
 lttng_live_session_borrow_or_create_trace_by_id(struct lttng_live_session *session,
                                                 uint64_t trace_id)
 {
-    struct lttng_live_trace *trace;
-
-    trace = lttng_live_session_borrow_trace_by_id(session, trace_id);
-    if (trace) {
-        goto end;
+    if (lttng_live_trace *trace = lttng_live_session_borrow_trace_by_id(session, trace_id)) {
+        return trace;
     }
 
     /* The session is the owner of the newly created trace. */
-    trace = lttng_live_create_trace(session, trace_id);
-
-end:
-    return trace;
+    return lttng_live_create_trace(session, trace_id);
 }
 
 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;
-    bt_logging_level log_level = lttng_live_msg_iter->log_level;
-    bt_self_component *self_comp = lttng_live_msg_iter->self_comp;
-
-    BT_COMP_LOGD("Adding live session: "
-                 "session-id=%" PRIu64 ", hostname=\"%s\" session-name=\"%s\"",
-                 session_id, hostname, session_name);
+    BT_CPPLOGD_SPEC(lttng_live_msg_iter->logger,
+                    "Adding live session: "
+                    "session-id={}, hostname=\"{}\", session-name=\"{}\"",
+                    session_id, hostname, session_name);
 
-    session = g_new0(struct lttng_live_session, 1);
-    if (!session) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to allocate live session");
-        goto error;
-    }
+    auto session = bt2s::make_unique<lttng_live_session>(lttng_live_msg_iter->logger);
 
-    session->log_level = lttng_live_msg_iter->log_level;
     session->self_comp = lttng_live_msg_iter->self_comp;
     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->hostname = hostname;
+    session->session_name = session_name;
 
-    session->session_name = g_string_new(session_name);
-    BT_ASSERT(session->session_name);
+    lttng_live_msg_iter->sessions.emplace_back(std::move(session));
 
-    g_ptr_array_add(lttng_live_msg_iter->sessions, session);
-    goto end;
-error:
-    g_free(session);
-    ret = -1;
-end:
-    return ret;
+    return 0;
 }
 
-static void lttng_live_destroy_session(struct lttng_live_session *session)
+lttng_live_session::~lttng_live_session()
 {
-    bt_logging_level log_level;
-    bt_self_component *self_comp;
+    BT_CPPLOGD_SPEC(this->logger, "Destroying live session: session-id={}, session-name=\"{}\"",
+                    this->id, this->session_name);
 
-    if (!session) {
-        goto end;
-    }
-
-    log_level = session->log_level;
-    self_comp = session->self_comp;
-    BT_COMP_LOGD("Destroying live session: "
-                 "session-id=%" PRIu64 ", session-name=\"%s\"",
-                 session->id, session->session_name->str);
-    if (session->id != -1ULL) {
-        if (lttng_live_session_detach(session)) {
-            if (!lttng_live_graph_is_canceled(session->lttng_live_msg_iter)) {
+    if (this->id != -1ULL) {
+        if (lttng_live_session_detach(this)) {
+            if (!lttng_live_graph_is_canceled(this->lttng_live_msg_iter)) {
                 /* Old relayd cannot detach sessions. */
-                BT_COMP_LOGD("Unable to detach lttng live session %" PRIu64, session->id);
+                BT_CPPLOGD_SPEC(this->logger, "Unable to detach lttng live session {}", this->id);
             }
         }
-        session->id = -1ULL;
-    }
-
-    if (session->traces) {
-        g_ptr_array_free(session->traces, TRUE);
-    }
 
-    if (session->hostname) {
-        g_string_free(session->hostname, TRUE);
+        this->id = -1ULL;
     }
-    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)
+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);
-    }
-
-    if (lttng_live_msg_iter->viewer_connection) {
-        live_viewer_connection_destroy(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);
+    BT_ASSERT(this->lttng_live_comp);
+    BT_ASSERT(this->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_ASSERT(this->active_stream_iter == 0);
+    this->lttng_live_comp->has_msg_iter = false;
 }
 
 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 =
-        (struct 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);
+    lttng_live_msg_iter::UP {
+        static_cast<lttng_live_msg_iter *>(bt_self_message_iterator_get_data(self_msg_iter))};
 }
 
 static enum lttng_live_iterator_status
 lttng_live_iterator_next_check_stream_state(struct lttng_live_stream_iterator *lttng_live_stream)
 {
-    bt_logging_level log_level = lttng_live_stream->log_level;
-    bt_self_component *self_comp = lttng_live_stream->self_comp;
-
     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_COMP_LOGF("Unexpected stream state \"ACTIVE_NO_DATA\"");
+        BT_CPPLOGF_SPEC(lttng_live_stream->logger, "Unexpected stream state \"ACTIVE_NO_DATA\"");
         bt_common_abort();
     case LTTNG_LIVE_STREAM_QUIESCENT_NO_DATA:
         /* Invalid state. */
-        BT_COMP_LOGF("Unexpected stream state \"QUIESCENT_NO_DATA\"");
+        BT_CPPLOGF_SPEC(lttng_live_stream->logger, "Unexpected stream state \"QUIESCENT_NO_DATA\"");
         bt_common_abort();
     case LTTNG_LIVE_STREAM_EOF:
         break;
@@ -363,27 +193,25 @@ static enum lttng_live_iterator_status lttng_live_iterator_next_handle_one_no_da
     struct lttng_live_msg_iter *lttng_live_msg_iter,
     struct lttng_live_stream_iterator *lttng_live_stream)
 {
-    bt_logging_level log_level = lttng_live_msg_iter->log_level;
-    bt_self_component *self_comp = lttng_live_msg_iter->self_comp;
     enum lttng_live_iterator_status ret = LTTNG_LIVE_ITERATOR_STATUS_OK;
     enum lttng_live_stream_state orig_state = lttng_live_stream->state;
     struct packet_index index;
 
     if (lttng_live_stream->trace->metadata_stream_state ==
         LTTNG_LIVE_METADATA_STREAM_STATE_NEEDED) {
-        BT_COMP_LOGD(
-            "Need to get an update for the metadata stream before proceeding further with this stream: "
-            "stream-name=\"%s\"",
-            lttng_live_stream->name->str);
+        BT_CPPLOGD_SPEC(lttng_live_msg_iter->logger,
+                        "Need to get an update for the metadata stream before proceeding "
+                        "further with this stream: stream-name=\"{}\"",
+                        lttng_live_stream->name);
         ret = LTTNG_LIVE_ITERATOR_STATUS_CONTINUE;
         goto end;
     }
 
     if (lttng_live_stream->trace->session->new_streams_needed) {
-        BT_COMP_LOGD(
-            "Need to get an update of all streams before proceeding further with this stream: "
-            "stream-name=\"%s\"",
-            lttng_live_stream->name->str);
+        BT_CPPLOGD_SPEC(lttng_live_msg_iter->logger,
+                        "Need to get an update of all streams before proceeding further "
+                        "with this stream: stream-name=\"{}\"",
+                        lttng_live_stream->name);
         ret = LTTNG_LIVE_ITERATOR_STATUS_CONTINUE;
         goto end;
     }
@@ -423,11 +251,12 @@ static enum lttng_live_iterator_status lttng_live_iterator_next_handle_one_no_da
     lttng_live_stream->offset = index.offset;
     lttng_live_stream->len = index.packet_size / CHAR_BIT;
 
-    BT_COMP_LOGD("Setting live stream reading info: stream-name=\"%s\", "
-                 "viewer-stream-id=%" PRIu64 ", stream-base-offset=%" PRIu64
-                 ", stream-offset=%" PRIu64 ", stream-len=%" PRIu64,
-                 lttng_live_stream->name->str, lttng_live_stream->viewer_stream_id,
-                 lttng_live_stream->base_offset, lttng_live_stream->offset, lttng_live_stream->len);
+    BT_CPPLOGD_SPEC(lttng_live_msg_iter->logger,
+                    "Setting live stream reading info: stream-name=\"{}\", "
+                    "viewer-stream-id={}, stream-base-offset={}, stream-offset={}, stream-len={}",
+                    lttng_live_stream->name, lttng_live_stream->viewer_stream_id,
+                    lttng_live_stream->base_offset, lttng_live_stream->offset,
+                    lttng_live_stream->len);
 
 end:
     if (ret == LTTNG_LIVE_ITERATOR_STATUS_OK) {
@@ -447,13 +276,11 @@ static enum lttng_live_iterator_status
 lttng_live_get_session(struct lttng_live_msg_iter *lttng_live_msg_iter,
                        struct lttng_live_session *session)
 {
-    bt_logging_level log_level = lttng_live_msg_iter->log_level;
-    bt_self_component *self_comp = lttng_live_msg_iter->self_comp;
     enum lttng_live_iterator_status status;
-    uint64_t trace_idx;
 
     if (!session->attached) {
-        BT_COMP_LOGD("Attach to session: session-id=%" PRIu64, session->id);
+        BT_CPPLOGD_SPEC(lttng_live_msg_iter->logger, "Attach to session: session-id={}",
+                        session->id);
         enum lttng_live_viewer_status attach_status =
             lttng_live_session_attach(session, lttng_live_msg_iter->self_msg_iter);
         if (attach_status != LTTNG_LIVE_VIEWER_STATUS_OK) {
@@ -465,18 +292,18 @@ lttng_live_get_session(struct lttng_live_msg_iter *lttng_live_msg_iter,
                  * cancelled.
                  */
                 bt_current_thread_clear_error();
-                status = LTTNG_LIVE_ITERATOR_STATUS_AGAIN;
+                return LTTNG_LIVE_ITERATOR_STATUS_AGAIN;
             } else {
-                status = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
-                BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Error attaching to LTTng live session");
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(lttng_live_msg_iter->logger,
+                                             "Error attaching to LTTng live session");
+                return LTTNG_LIVE_ITERATOR_STATUS_ERROR;
             }
-            goto end;
         }
     }
 
-    BT_COMP_LOGD("Updating all data streams: "
-                 "session-id=%" PRIu64 ", session-name=\"%s\"",
-                 session->id, session->session_name->str);
+    BT_CPPLOGD_SPEC(lttng_live_msg_iter->logger,
+                    "Updating all data streams: session-id={}, session-name=\"{}\"", session->id,
+                    session->session_name);
 
     status = lttng_live_session_get_new_streams(session, lttng_live_msg_iter->self_msg_iter);
     switch (status) {
@@ -484,52 +311,47 @@ lttng_live_get_session(struct lttng_live_msg_iter *lttng_live_msg_iter,
         break;
     case LTTNG_LIVE_ITERATOR_STATUS_END:
         /*
-                * We received a `_END` from the `_get_new_streams()` function,
-                * which means no more data will ever be received from the data
-                * streams of this session. But it's possible that the metadata
-                * is incomplete.
-                * The live protocol guarantees that we receive all the
-                * metadata needed before we receive data streams needing it.
-                * But it's possible to receive metadata NOT needed by
-                * data streams after the session was closed. For example, this
-                * could happen if a new event is registered and the session is
-                * stopped before any tracepoint for that event is actually
-                * fired.
-                */
-        BT_COMP_LOGD(
+         * We received a `_END` from the `_get_new_streams()` function,
+         * which means no more data will ever be received from the data
+         * streams of this session. But it's possible that the metadata
+         * is incomplete.
+         * The live protocol guarantees that we receive all the
+         * metadata needed before we receive data streams needing it.
+         * But it's possible to receive metadata NOT needed by
+         * data streams after the session was closed. For example, this
+         * could happen if a new event is registered and the session is
+         * stopped before any tracepoint for that event is actually
+         * fired.
+         */
+        BT_CPPLOGD_SPEC(
+            lttng_live_msg_iter->logger,
             "Updating streams returned _END status. Override status to _OK in order fetch any remaining metadata:"
-            "session-id=%" PRIu64 ", session-name=\"%s\"",
-            session->id, session->session_name->str);
-        status = LTTNG_LIVE_ITERATOR_STATUS_OK;
-        break;
+            "session-id={}, session-name=\"{}\"",
+            session->id, session->session_name);
+        return LTTNG_LIVE_ITERATOR_STATUS_OK;
     default:
-        goto end;
+        return status;
     }
 
-    BT_COMP_LOGD("Updating metadata stream for session: "
-                 "session-id=%" PRIu64 ", session-name=\"%s\"",
-                 session->id, session->session_name->str);
-
-    trace_idx = 0;
-    while (trace_idx < session->traces->len) {
-        struct lttng_live_trace *trace =
-            (lttng_live_trace *) g_ptr_array_index(session->traces, trace_idx);
+    BT_CPPLOGD_SPEC(lttng_live_msg_iter->logger,
+                    "Updating metadata stream for session: session-id={}, session-name=\"{}\"",
+                    session->id, session->session_name);
 
-        status = lttng_live_metadata_update(trace);
+    for (lttng_live_trace::UP& trace : session->traces) {
+        status = lttng_live_metadata_update(trace.get());
         switch (status) {
         case LTTNG_LIVE_ITERATOR_STATUS_END:
         case LTTNG_LIVE_ITERATOR_STATUS_OK:
-            trace_idx++;
             break;
         case LTTNG_LIVE_ITERATOR_STATUS_CONTINUE:
         case LTTNG_LIVE_ITERATOR_STATUS_AGAIN:
-            goto end;
+            return status;
         default:
-            BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                      "Error updating trace metadata: "
-                                      "stream-iter-status=%s, trace-id=%" PRIu64,
-                                      lttng_live_iterator_status_string(status), trace->id);
-            goto end;
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(
+                lttng_live_msg_iter->logger,
+                "Error updating trace metadata: stream-iter-status={}, trace-id={}", status,
+                trace->id);
+            return status;
         }
     }
 
@@ -537,32 +359,23 @@ lttng_live_get_session(struct lttng_live_msg_iter *lttng_live_msg_iter,
      * Now that we have the metadata we can initialize the downstream
      * iterator.
      */
-    status = lttng_live_lazy_msg_init(session, lttng_live_msg_iter->self_msg_iter);
-
-end:
-    return status;
+    return lttng_live_lazy_msg_init(session, lttng_live_msg_iter->self_msg_iter);
 }
 
 static void
 lttng_live_force_new_streams_and_metadata(struct lttng_live_msg_iter *lttng_live_msg_iter)
 {
-    uint64_t session_idx, trace_idx;
-    bt_logging_level log_level = lttng_live_msg_iter->log_level;
-    bt_self_component *self_comp = lttng_live_msg_iter->self_comp;
-
-    for (session_idx = 0; session_idx < lttng_live_msg_iter->sessions->len; session_idx++) {
-        struct lttng_live_session *session =
-            (lttng_live_session *) g_ptr_array_index(lttng_live_msg_iter->sessions, session_idx);
-        BT_COMP_LOGD("Force marking session as needing new streams: "
-                     "session-id=%" PRIu64,
-                     session->id);
+    for (const auto& session : lttng_live_msg_iter->sessions) {
+        BT_CPPLOGD_SPEC(lttng_live_msg_iter->logger,
+                        "Force marking session as needing new streams: "
+                        "session-id={}",
+                        session->id);
         session->new_streams_needed = true;
-        for (trace_idx = 0; trace_idx < session->traces->len; trace_idx++) {
-            struct lttng_live_trace *trace =
-                (lttng_live_trace *) g_ptr_array_index(session->traces, trace_idx);
-            BT_COMP_LOGD("Force marking trace metadata state as needing an update: "
-                         "session-id=%" PRIu64 ", trace-id=%" PRIu64,
-                         session->id, trace->id);
+        for (lttng_live_trace::UP& trace : session->traces) {
+            BT_CPPLOGD_SPEC(lttng_live_msg_iter->logger,
+                            "Force marking trace metadata state as needing an update: "
+                            "session-id={}, trace-id={}",
+                            session->id, trace->id);
 
             BT_ASSERT(trace->metadata_stream_state != LTTNG_LIVE_METADATA_STREAM_STATE_CLOSED);
 
@@ -574,32 +387,30 @@ lttng_live_force_new_streams_and_metadata(struct lttng_live_msg_iter *lttng_live
 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 status;
     enum lttng_live_viewer_status viewer_status;
-    bt_logging_level log_level = lttng_live_msg_iter->log_level;
-    bt_self_component *self_comp = lttng_live_msg_iter->self_comp;
-    uint64_t session_idx = 0, nr_sessions_opened = 0;
-    struct lttng_live_session *session;
+    uint64_t nr_sessions_opened = 0;
     enum session_not_found_action sess_not_found_act =
         lttng_live_msg_iter->lttng_live_comp->params.sess_not_found_act;
 
-    BT_COMP_LOGD("Update data and metadata of all sessions: "
-                 "live-msg-iter-addr=%p",
-                 lttng_live_msg_iter);
+    BT_CPPLOGD_SPEC(lttng_live_msg_iter->logger,
+                    "Update data and metadata of all sessions: "
+                    "live-msg-iter-addr={}",
+                    fmt::ptr(lttng_live_msg_iter));
     /*
      * 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 (lttng_live_msg_iter->sessions.empty()) {
         if (sess_not_found_act != SESSION_NOT_FOUND_ACTION_CONTINUE) {
-            BT_COMP_LOGD(
+            BT_CPPLOGD_SPEC(
+                lttng_live_msg_iter->logger,
                 "No session found. Exiting in accordance with the `session-not-found-action` parameter");
-            status = LTTNG_LIVE_ITERATOR_STATUS_END;
-            goto end;
+            return LTTNG_LIVE_ITERATOR_STATUS_END;
         } else {
-            BT_COMP_LOGD(
+            BT_CPPLOGD_SPEC(
+                lttng_live_msg_iter->logger,
                 "No session found. Try creating a new one in accordance with the `session-not-found-action` parameter");
             /*
              * Retry to create a viewer session for the requested
@@ -608,23 +419,20 @@ lttng_live_iterator_handle_new_streams_and_metadata(struct lttng_live_msg_iter *
             viewer_status = lttng_live_create_viewer_session(lttng_live_msg_iter);
             if (viewer_status != LTTNG_LIVE_VIEWER_STATUS_OK) {
                 if (viewer_status == LTTNG_LIVE_VIEWER_STATUS_ERROR) {
-                    status = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
-                    BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                              "Error creating LTTng live viewer session");
+                    BT_CPPLOGE_APPEND_CAUSE_SPEC(lttng_live_msg_iter->logger,
+                                                 "Error creating LTTng live viewer session");
+                    return LTTNG_LIVE_ITERATOR_STATUS_ERROR;
                 } else if (viewer_status == LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED) {
-                    status = LTTNG_LIVE_ITERATOR_STATUS_AGAIN;
+                    return LTTNG_LIVE_ITERATOR_STATUS_AGAIN;
                 } else {
                     bt_common_abort();
                 }
-                goto end;
             }
         }
     }
 
-    for (session_idx = 0; session_idx < lttng_live_msg_iter->sessions->len; session_idx++) {
-        session =
-            (lttng_live_session *) g_ptr_array_index(lttng_live_msg_iter->sessions, session_idx);
-        status = lttng_live_get_session(lttng_live_msg_iter, session);
+    for (const auto& session : lttng_live_msg_iter->sessions) {
+        const auto status = lttng_live_get_session(lttng_live_msg_iter, session.get());
         switch (status) {
         case LTTNG_LIVE_ITERATOR_STATUS_OK:
         case LTTNG_LIVE_ITERATOR_STATUS_END:
@@ -635,7 +443,7 @@ lttng_live_iterator_handle_new_streams_and_metadata(struct lttng_live_msg_iter *
              */
             break;
         default:
-            goto end;
+            return status;
         }
         if (!session->closed) {
             nr_sessions_opened++;
@@ -643,54 +451,41 @@ lttng_live_iterator_handle_new_streams_and_metadata(struct lttng_live_msg_iter *
     }
 
     if (sess_not_found_act != SESSION_NOT_FOUND_ACTION_CONTINUE && nr_sessions_opened == 0) {
-        status = LTTNG_LIVE_ITERATOR_STATUS_END;
+        return LTTNG_LIVE_ITERATOR_STATUS_END;
     } else {
-        status = LTTNG_LIVE_ITERATOR_STATUS_OK;
+        return LTTNG_LIVE_ITERATOR_STATUS_OK;
     }
-
-end:
-    return status;
 }
 
 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, const bt_message **message,
-                        uint64_t timestamp)
+                        struct lttng_live_stream_iterator *stream_iter,
+                        bt2::ConstMessage::Shared& message, uint64_t timestamp)
 {
-    enum lttng_live_iterator_status ret = LTTNG_LIVE_ITERATOR_STATUS_OK;
-    bt_logging_level log_level = lttng_live_msg_iter->log_level;
-    bt_self_component *self_comp = lttng_live_msg_iter->self_comp;
-    bt_message *msg = NULL;
-
     BT_ASSERT(stream_iter->trace->clock_class);
+    BT_CPPLOGD_SPEC(lttng_live_msg_iter->logger,
+                    "Emitting inactivity message for stream: ctf-stream-id={}, "
+                    "viewer-stream-id={}, timestamp={}",
+                    stream_iter->ctf_stream_class_id.value, stream_iter->viewer_stream_id,
+                    timestamp);
 
-    BT_COMP_LOGD("Emitting inactivity message for stream: ctf-stream-id=%" PRIu64
-                 ", viewer-stream-id=%" PRIu64 ", timestamp=%" PRIu64,
-                 stream_iter->ctf_stream_class_id.value, stream_iter->viewer_stream_id, timestamp);
+    const auto msg = bt_message_message_iterator_inactivity_create(
+        lttng_live_msg_iter->self_msg_iter, stream_iter->trace->clock_class, timestamp);
 
-    msg = bt_message_message_iterator_inactivity_create(lttng_live_msg_iter->self_msg_iter,
-                                                        stream_iter->trace->clock_class, timestamp);
     if (!msg) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Error emitting message iterator inactivity message");
-        goto error;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(lttng_live_msg_iter->logger,
+                                     "Error emitting message iterator inactivity message");
+        return LTTNG_LIVE_ITERATOR_STATUS_ERROR;
     }
 
-    *message = msg;
-end:
-    return ret;
-
-error:
-    ret = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
-    bt_message_put_ref(msg);
-    goto end;
+    message = bt2::ConstMessage::Shared::createWithoutRef(msg);
+    return LTTNG_LIVE_ITERATOR_STATUS_OK;
 }
 
 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, const bt_message **message)
+    struct lttng_live_stream_iterator *lttng_live_stream, bt2::ConstMessage::Shared& 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;
     }
@@ -704,17 +499,20 @@ static enum lttng_live_iterator_status lttng_live_iterator_next_handle_one_quies
         lttng_live_stream_iterator_set_state(lttng_live_stream,
                                              LTTNG_LIVE_STREAM_QUIESCENT_NO_DATA);
 
-        ret = LTTNG_LIVE_ITERATOR_STATUS_CONTINUE;
-        goto end;
+        return LTTNG_LIVE_ITERATOR_STATUS_CONTINUE;
     }
 
-    ret = emit_inactivity_message(lttng_live_msg_iter, lttng_live_stream, message,
-                                  lttng_live_stream->current_inactivity_ts);
+    const auto status = emit_inactivity_message(lttng_live_msg_iter, lttng_live_stream, message,
+                                                lttng_live_stream->current_inactivity_ts);
+
+    if (status != LTTNG_LIVE_ITERATOR_STATUS_OK) {
+        return status;
+    }
 
     lttng_live_stream->last_inactivity_ts.value = lttng_live_stream->current_inactivity_ts;
     lttng_live_stream->last_inactivity_ts.is_set = true;
-end:
-    return ret;
+
+    return LTTNG_LIVE_ITERATOR_STATUS_OK;
 }
 
 static int live_get_msg_ts_ns(struct lttng_live_msg_iter *lttng_live_msg_iter,
@@ -722,15 +520,14 @@ static int live_get_msg_ts_ns(struct lttng_live_msg_iter *lttng_live_msg_iter,
 {
     const bt_clock_snapshot *clock_snapshot = NULL;
     int ret = 0;
-    bt_logging_level log_level = lttng_live_msg_iter->log_level;
-    bt_self_component *self_comp = lttng_live_msg_iter->self_comp;
 
     BT_ASSERT_DBG(msg);
     BT_ASSERT_DBG(ts_ns);
 
-    BT_COMP_LOGD("Getting message's timestamp: iter-data-addr=%p, msg-addr=%p, "
-                 "last-msg-ts=%" PRId64,
-                 lttng_live_msg_iter, msg, last_msg_ts_ns);
+    BT_CPPLOGD_SPEC(lttng_live_msg_iter->logger,
+                    "Getting message's timestamp: iter-data-addr={}, msg-addr={}, "
+                    "last-msg-ts={}",
+                    fmt::ptr(lttng_live_msg_iter), fmt::ptr(msg), last_msg_ts_ns);
 
     switch (bt_message_get_type(msg)) {
     case BT_MESSAGE_TYPE_EVENT:
@@ -755,145 +552,119 @@ static int live_get_msg_ts_ns(struct lttng_live_msg_iter *lttng_live_msg_iter,
         break;
     default:
         /* All the other messages have a higher priority */
-        BT_COMP_LOGD_STR("Message has no timestamp: using the last message timestamp.");
+        BT_CPPLOGD_SPEC(lttng_live_msg_iter->logger,
+                        "Message has no timestamp, using the last message timestamp: "
+                        "iter-data-addr={}, msg-addr={}, last-msg-ts={}, ts={}",
+                        fmt::ptr(lttng_live_msg_iter), fmt::ptr(msg), last_msg_ts_ns, *ts_ns);
         *ts_ns = last_msg_ts_ns;
-        goto end;
+        return 0;
     }
 
     ret = bt_clock_snapshot_get_ns_from_origin(clock_snapshot, ts_ns);
     if (ret) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "Cannot get nanoseconds from Epoch of clock snapshot: "
-                                  "clock-snapshot-addr=%p",
-                                  clock_snapshot);
-        goto error;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(lttng_live_msg_iter->logger,
+                                     "Cannot get nanoseconds from Epoch of clock snapshot: "
+                                     "clock-snapshot-addr={}",
+                                     fmt::ptr(clock_snapshot));
+        return -1;
     }
 
-    goto end;
+    BT_CPPLOGD_SPEC(
+        lttng_live_msg_iter->logger,
+        "Found message's timestamp: iter-data-addr={}, msg-addr={}, last-msg-ts={}, ts={}",
+        fmt::ptr(lttng_live_msg_iter), fmt::ptr(msg), last_msg_ts_ns, *ts_ns);
 
-error:
-    ret = -1;
-
-end:
-    if (ret == 0) {
-        BT_COMP_LOGD("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;
+    return 0;
 }
 
 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, const bt_message **message)
+    struct lttng_live_stream_iterator *lttng_live_stream, bt2::ConstMessage::Shared& message)
 {
-    enum lttng_live_iterator_status ret = LTTNG_LIVE_ITERATOR_STATUS_OK;
-    bt_logging_level log_level = lttng_live_msg_iter->log_level;
-    bt_self_component *self_comp = lttng_live_msg_iter->self_comp;
     enum ctf_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 =
-            (lttng_live_session *) g_ptr_array_index(lttng_live_msg_iter->sessions, session_idx);
 
+    for (const auto& session : lttng_live_msg_iter->sessions) {
         if (session->new_streams_needed) {
-            BT_COMP_LOGD("Need an update for streams: "
-                         "session-id=%" PRIu64,
-                         session->id);
-            ret = LTTNG_LIVE_ITERATOR_STATUS_CONTINUE;
-            goto end;
+            BT_CPPLOGD_SPEC(lttng_live_msg_iter->logger,
+                            "Need an update for streams: session-id={}", session->id);
+            return LTTNG_LIVE_ITERATOR_STATUS_CONTINUE;
         }
-        for (trace_idx = 0; trace_idx < session->traces->len; trace_idx++) {
-            struct lttng_live_trace *trace =
-                (lttng_live_trace *) g_ptr_array_index(session->traces, trace_idx);
+        for (lttng_live_trace::UP& trace : session->traces) {
             if (trace->metadata_stream_state == LTTNG_LIVE_METADATA_STREAM_STATE_NEEDED) {
-                BT_COMP_LOGD("Need an update for metadata stream: "
-                             "session-id=%" PRIu64 ", trace-id=%" PRIu64,
-                             session->id, trace->id);
-                ret = LTTNG_LIVE_ITERATOR_STATUS_CONTINUE;
-                goto end;
+                BT_CPPLOGD_SPEC(lttng_live_msg_iter->logger,
+                                "Need an update for metadata stream: session-id={}, trace-id={}",
+                                session->id, trace->id);
+                return LTTNG_LIVE_ITERATOR_STATUS_CONTINUE;
             }
         }
     }
 
     if (lttng_live_stream->state != LTTNG_LIVE_STREAM_ACTIVE_DATA) {
-        ret = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "Invalid state of live stream iterator"
-                                  "stream-iter-status=%s",
-                                  lttng_live_stream_state_string(lttng_live_stream->state));
-        goto end;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(lttng_live_msg_iter->logger,
+                                     "Invalid state of live stream iterator: stream-iter-status={}",
+                                     lttng_live_stream->state);
+        return LTTNG_LIVE_ITERATOR_STATUS_ERROR;
     }
 
-    status = ctf_msg_iter_get_next_message(lttng_live_stream->msg_iter, message);
+    const bt_message *msg;
+    status = ctf_msg_iter_get_next_message(lttng_live_stream->msg_iter.get(), &msg);
     switch (status) {
     case CTF_MSG_ITER_STATUS_EOF:
-        ret = LTTNG_LIVE_ITERATOR_STATUS_END;
-        break;
+        return LTTNG_LIVE_ITERATOR_STATUS_END;
     case CTF_MSG_ITER_STATUS_OK:
-        ret = LTTNG_LIVE_ITERATOR_STATUS_OK;
-        break;
+        message = bt2::ConstMessage::Shared::createWithoutRef(msg);
+        return LTTNG_LIVE_ITERATOR_STATUS_OK;
     case CTF_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;
+        return LTTNG_LIVE_ITERATOR_STATUS_CONTINUE;
     case CTF_MSG_ITER_STATUS_ERROR:
     default:
-        ret = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "CTF message iterator failed to get next message: "
-                                  "msg-iter=%p, msg-iter-status=%s",
-                                  lttng_live_stream->msg_iter, ctf_msg_iter_status_string(status));
-        break;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(
+            lttng_live_msg_iter->logger,
+            "CTF message iterator failed to get next message: msg-iter={}, msg-iter-status={}",
+            fmt::ptr(lttng_live_stream->msg_iter), status);
+        return LTTNG_LIVE_ITERATOR_STATUS_ERROR;
     }
-
-end:
-    return ret;
 }
 
 static enum lttng_live_iterator_status
 lttng_live_iterator_close_stream(struct lttng_live_msg_iter *lttng_live_msg_iter,
                                  struct lttng_live_stream_iterator *stream_iter,
-                                 const bt_message **curr_msg)
+                                 bt2::ConstMessage::Shared& curr_msg)
 {
-    enum lttng_live_iterator_status live_status = LTTNG_LIVE_ITERATOR_STATUS_OK;
-    bt_logging_level log_level = lttng_live_msg_iter->log_level;
-    bt_self_component *self_comp = lttng_live_msg_iter->self_comp;
-
-    BT_COMP_LOGD("Closing live stream iterator: stream-name=\"%s\", "
-                 "viewer-stream-id=%" PRIu64,
-                 stream_iter->name->str, stream_iter->viewer_stream_id);
+    BT_CPPLOGD_SPEC(lttng_live_msg_iter->logger,
+                    "Closing live stream iterator: stream-name=\"{}\", "
+                    "viewer-stream-id={}",
+                    stream_iter->name, stream_iter->viewer_stream_id);
 
     /*
      * The viewer has hung up on us so we are closing the stream. The
      * `ctf_msg_iter` should simply realize that it needs to close the
      * stream properly by emitting the necessary stream end message.
      */
+    const bt_message *msg;
     enum ctf_msg_iter_status status =
-        ctf_msg_iter_get_next_message(stream_iter->msg_iter, curr_msg);
+        ctf_msg_iter_get_next_message(stream_iter->msg_iter.get(), &msg);
 
     if (status == CTF_MSG_ITER_STATUS_ERROR) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "Error getting the next message from CTF message iterator");
-        live_status = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
-        goto end;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(lttng_live_msg_iter->logger,
+                                     "Error getting the next message from CTF message iterator");
+        return LTTNG_LIVE_ITERATOR_STATUS_ERROR;
     } else if (status == CTF_MSG_ITER_STATUS_EOF) {
-        BT_COMP_LOGI("Reached the end of the live stream iterator.");
-        live_status = LTTNG_LIVE_ITERATOR_STATUS_END;
-        goto end;
+        BT_CPPLOGI_SPEC(lttng_live_msg_iter->logger,
+                        "Reached the end of the live stream iterator.");
+        return LTTNG_LIVE_ITERATOR_STATUS_END;
     }
 
     BT_ASSERT(status == CTF_MSG_ITER_STATUS_OK);
 
-end:
-    return live_status;
+    curr_msg = bt2::ConstMessage::Shared::createWithoutRef(msg);
+
+    return LTTNG_LIVE_ITERATOR_STATUS_OK;
 }
 
 /*
@@ -947,15 +718,14 @@ end:
 static enum lttng_live_iterator_status
 lttng_live_iterator_next_msg_on_stream(struct lttng_live_msg_iter *lttng_live_msg_iter,
                                        struct lttng_live_stream_iterator *stream_iter,
-                                       const bt_message **curr_msg)
+                                       bt2::ConstMessage::Shared& curr_msg)
 {
-    bt_logging_level log_level = lttng_live_msg_iter->log_level;
-    bt_self_component *self_comp = lttng_live_msg_iter->self_comp;
     enum lttng_live_iterator_status live_status;
 
-    BT_COMP_LOGD("Advancing live stream iterator until next message if possible: "
-                 "stream-name=\"%s\", viewer-stream-id=%" PRIu64,
-                 stream_iter->name->str, stream_iter->viewer_stream_id);
+    BT_CPPLOGD_SPEC(lttng_live_msg_iter->logger,
+                    "Advancing live stream iterator until next message if possible: "
+                    "stream-name=\"{}\", viewer-stream-id={}",
+                    stream_iter->name, stream_iter->viewer_stream_id);
 
     if (stream_iter->has_stream_hung_up) {
         /*
@@ -997,46 +767,45 @@ retry:
     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);
+        BT_ASSERT(!curr_msg);
         goto end;
     }
-    if (*curr_msg) {
+    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);
+        BT_ASSERT(!curr_msg);
     }
 
 end:
     if (live_status == LTTNG_LIVE_ITERATOR_STATUS_CONTINUE) {
-        BT_COMP_LOGD("Ask the relay daemon for an updated view of the data and metadata streams");
+        BT_CPPLOGD_SPEC(
+            lttng_live_msg_iter->logger,
+            "Ask the relay daemon for an updated view of the data and metadata streams");
         goto retry;
     }
 
-    BT_COMP_LOGD("Returning from advancing live stream iterator: status=%s, "
-                 "stream-name=\"%s\", viewer-stream-id=%" PRIu64,
-                 lttng_live_iterator_status_string(live_status), stream_iter->name->str,
-                 stream_iter->viewer_stream_id);
+    BT_CPPLOGD_SPEC(lttng_live_msg_iter->logger,
+                    "Returning from advancing live stream iterator: status={}, "
+                    "stream-name=\"{}\", viewer-stream-id={}",
+                    live_status, stream_iter->name, stream_iter->viewer_stream_id);
 
     return live_status;
 }
 
-static bool is_discarded_packet_or_event_message(const bt_message *msg)
+static bool is_discarded_packet_or_event_message(const bt2::ConstMessage msg)
 {
-    const enum bt_message_type msg_type = bt_message_get_type(msg);
-
-    return msg_type == BT_MESSAGE_TYPE_DISCARDED_EVENTS ||
-           msg_type == BT_MESSAGE_TYPE_DISCARDED_PACKETS;
+    return msg.type() == bt2::MessageType::DiscardedEvents ||
+           msg.type() == bt2::MessageType::DiscardedPackets;
 }
 
 static enum lttng_live_iterator_status
 adjust_discarded_packets_message(bt_self_message_iterator *iter, const bt_stream *stream,
-                                 const bt_message *msg_in, bt_message **msg_out,
+                                 const bt_message *msg_in, bt2::ConstMessage::Shared& msg_out,
                                  uint64_t new_begin_ts)
 {
-    enum lttng_live_iterator_status status = LTTNG_LIVE_ITERATOR_STATUS_OK;
     enum bt_property_availability availability;
     const bt_clock_snapshot *clock_snapshot;
     uint64_t end_ts;
@@ -1048,24 +817,23 @@ adjust_discarded_packets_message(bt_self_message_iterator *iter, const bt_stream
     availability = bt_message_discarded_packets_get_count(msg_in, &count);
     BT_ASSERT_DBG(availability == BT_PROPERTY_AVAILABILITY_AVAILABLE);
 
-    *msg_out = bt_message_discarded_packets_create_with_default_clock_snapshots(
+    const auto msg = bt_message_discarded_packets_create_with_default_clock_snapshots(
         iter, stream, new_begin_ts, end_ts);
-    if (!*msg_out) {
-        status = LTTNG_LIVE_ITERATOR_STATUS_NOMEM;
-        goto end;
+
+    if (!msg) {
+        return LTTNG_LIVE_ITERATOR_STATUS_NOMEM;
     }
 
-    bt_message_discarded_packets_set_count(*msg_out, count);
-end:
-    return status;
+    bt_message_discarded_packets_set_count(msg, count);
+    msg_out = bt2::ConstMessage::Shared::createWithoutRef(msg);
+    return LTTNG_LIVE_ITERATOR_STATUS_OK;
 }
 
 static enum lttng_live_iterator_status
 adjust_discarded_events_message(bt_self_message_iterator *iter, const bt_stream *stream,
-                                const bt_message *msg_in, bt_message **msg_out,
+                                const bt_message *msg_in, bt2::ConstMessage::Shared& msg_out,
                                 uint64_t new_begin_ts)
 {
-    enum lttng_live_iterator_status status = LTTNG_LIVE_ITERATOR_STATUS_OK;
     enum bt_property_availability availability;
     const bt_clock_snapshot *clock_snapshot;
     uint64_t end_ts;
@@ -1077,32 +845,29 @@ adjust_discarded_events_message(bt_self_message_iterator *iter, const bt_stream
     availability = bt_message_discarded_events_get_count(msg_in, &count);
     BT_ASSERT_DBG(availability == BT_PROPERTY_AVAILABILITY_AVAILABLE);
 
-    *msg_out = bt_message_discarded_events_create_with_default_clock_snapshots(
+    const auto msg = bt_message_discarded_events_create_with_default_clock_snapshots(
         iter, stream, new_begin_ts, end_ts);
-    if (!*msg_out) {
-        status = LTTNG_LIVE_ITERATOR_STATUS_NOMEM;
-        goto end;
+
+    if (!msg) {
+        return LTTNG_LIVE_ITERATOR_STATUS_NOMEM;
     }
 
-    bt_message_discarded_events_set_count(*msg_out, count);
-end:
-    return status;
+    bt_message_discarded_events_set_count(msg, count);
+    msg_out = bt2::ConstMessage::Shared::createWithoutRef(msg);
+    return LTTNG_LIVE_ITERATOR_STATUS_OK;
 }
 
 static enum lttng_live_iterator_status
 handle_late_message(struct lttng_live_msg_iter *lttng_live_msg_iter,
                     struct lttng_live_stream_iterator *stream_iter, int64_t late_msg_ts_ns,
-                    const bt_message *late_msg)
+                    const bt2::ConstMessage& late_msg)
 {
-    bt_self_component *self_comp = lttng_live_msg_iter->self_comp;
-    bt_logging_level log_level = lttng_live_msg_iter->log_level;
     const bt_clock_class *clock_class;
     const bt_stream_class *stream_class;
     enum bt_clock_class_cycles_to_ns_from_origin_status ts_ns_status;
     int64_t last_inactivity_ts_ns;
-    enum lttng_live_iterator_status stream_iter_status = LTTNG_LIVE_ITERATOR_STATUS_OK;
     enum lttng_live_iterator_status adjust_status;
-    bt_message *adjusted_message;
+    bt2::ConstMessage::Shared adjusted_message;
 
     /*
      * The timestamp of the current message is before the last message sent
@@ -1127,92 +892,88 @@ handle_late_message(struct lttng_live_msg_iter *lttng_live_msg_iter,
      * In short, the only scenario in which it's okay and fixable to
      * received a late message is when:
      *  1. the late message is a discarded packets or discarded events
-     * message,
+     *     message,
      *  2. this stream produced an inactivity message downstream, and
      *  3. the timestamp of the late message is within the inactivity
-     * timespan we sent downstream through the inactivity message.
+     *     timespan we sent downstream through the inactivity message.
      */
 
-    BT_COMP_LOGD("Handling late message on live stream iterator: "
-                 "stream-name=\"%s\", viewer-stream-id=%" PRIu64,
-                 stream_iter->name->str, stream_iter->viewer_stream_id);
+    BT_CPPLOGD_SPEC(lttng_live_msg_iter->logger,
+                    "Handling late message on live stream iterator: "
+                    "stream-name=\"{}\", viewer-stream-id={}",
+                    stream_iter->name, stream_iter->viewer_stream_id);
 
     if (!stream_iter->last_inactivity_ts.is_set) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Invalid live stream state: "
-                                             "have a late message when no inactivity message "
-                                             "was ever sent for that stream.");
-        stream_iter_status = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
-        goto end;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(lttng_live_msg_iter->logger,
+                                     "Invalid live stream state: "
+                                     "have a late message when no inactivity message "
+                                     "was ever sent for that stream.");
+        return LTTNG_LIVE_ITERATOR_STATUS_ERROR;
     }
 
     if (!is_discarded_packet_or_event_message(late_msg)) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "Invalid live stream state: "
-                                  "have a late message that is not a packet discarded or "
-                                  "event discarded message: late-msg-type=%s",
-                                  bt_common_message_type_string(bt_message_get_type(late_msg)));
-        stream_iter_status = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
-        goto end;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(lttng_live_msg_iter->logger,
+                                     "Invalid live stream state: "
+                                     "have a late message that is not a packet discarded or "
+                                     "event discarded message: late-msg-type={}",
+                                     late_msg.type());
+        return LTTNG_LIVE_ITERATOR_STATUS_ERROR;
     }
 
-    stream_class = bt_stream_borrow_class_const(stream_iter->stream);
+    stream_class = bt_stream_borrow_class_const(stream_iter->stream->libObjPtr());
     clock_class = bt_stream_class_borrow_default_clock_class_const(stream_class);
 
     ts_ns_status = bt_clock_class_cycles_to_ns_from_origin(
         clock_class, stream_iter->last_inactivity_ts.value, &last_inactivity_ts_ns);
     if (ts_ns_status != BT_CLOCK_CLASS_CYCLES_TO_NS_FROM_ORIGIN_STATUS_OK) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Error converting last "
-                                             "inactivity message timestamp to nanoseconds");
-        stream_iter_status = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
-        goto end;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(lttng_live_msg_iter->logger,
+                                     "Error converting last "
+                                     "inactivity message timestamp to nanoseconds");
+        return LTTNG_LIVE_ITERATOR_STATUS_ERROR;
     }
 
     if (last_inactivity_ts_ns <= late_msg_ts_ns) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "Invalid live stream state: "
-                                  "have a late message that is none included in a stream "
-                                  "inactivity timespan: last-inactivity-ts-ns=%" PRIu64
-                                  "late-msg-ts-ns=%" PRIu64,
-                                  last_inactivity_ts_ns, late_msg_ts_ns);
-        stream_iter_status = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
-        goto end;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(lttng_live_msg_iter->logger,
+                                     "Invalid live stream state: "
+                                     "have a late message that is none included in a stream "
+                                     "inactivity timespan: last-inactivity-ts-ns={}, "
+                                     "late-msg-ts-ns={}",
+                                     last_inactivity_ts_ns, late_msg_ts_ns);
+        return LTTNG_LIVE_ITERATOR_STATUS_ERROR;
     }
 
     /*
      * We now know that it's okay for this message to be late, we can now
      * adjust its timestamp to ensure monotonicity.
      */
-    BT_COMP_LOGD("Adjusting the timestamp of late message: late-msg-type=%s, "
-                 "msg-new-ts-ns=%" PRIu64,
-                 bt_common_message_type_string(bt_message_get_type(late_msg)),
-                 stream_iter->last_inactivity_ts.value);
-    switch (bt_message_get_type(late_msg)) {
-    case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
+    BT_CPPLOGD_SPEC(lttng_live_msg_iter->logger,
+                    "Adjusting the timestamp of late message: late-msg-type={}, "
+                    "msg-new-ts-ns={}",
+                    late_msg.type(), stream_iter->last_inactivity_ts.value);
+    switch (late_msg.type()) {
+    case bt2::MessageType::DiscardedEvents:
         adjust_status = adjust_discarded_events_message(
-            lttng_live_msg_iter->self_msg_iter, stream_iter->stream, late_msg, &adjusted_message,
-            stream_iter->last_inactivity_ts.value);
+            lttng_live_msg_iter->self_msg_iter, stream_iter->stream->libObjPtr(),
+            late_msg.libObjPtr(), adjusted_message, stream_iter->last_inactivity_ts.value);
         break;
-    case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
+    case bt2::MessageType::DiscardedPackets:
         adjust_status = adjust_discarded_packets_message(
-            lttng_live_msg_iter->self_msg_iter, stream_iter->stream, late_msg, &adjusted_message,
-            stream_iter->last_inactivity_ts.value);
+            lttng_live_msg_iter->self_msg_iter, stream_iter->stream->libObjPtr(),
+            late_msg.libObjPtr(), adjusted_message, stream_iter->last_inactivity_ts.value);
         break;
     default:
         bt_common_abort();
     }
 
     if (adjust_status != LTTNG_LIVE_ITERATOR_STATUS_OK) {
-        stream_iter_status = adjust_status;
-        goto end;
+        return adjust_status;
     }
 
     BT_ASSERT_DBG(adjusted_message);
     stream_iter->current_msg = adjusted_message;
     stream_iter->current_msg_ts_ns = last_inactivity_ts_ns;
-    bt_message_put_ref(late_msg);
 
-end:
-    return stream_iter_status;
+    return LTTNG_LIVE_ITERATOR_STATUS_OK;
 }
 
 static enum lttng_live_iterator_status
@@ -1221,19 +982,15 @@ next_stream_iterator_for_trace(struct lttng_live_msg_iter *lttng_live_msg_iter,
                                struct lttng_live_stream_iterator **youngest_trace_stream_iter)
 {
     struct lttng_live_stream_iterator *youngest_candidate_stream_iter = NULL;
-    bt_logging_level log_level = lttng_live_msg_iter->log_level;
-    bt_self_component *self_comp = lttng_live_msg_iter->self_comp;
-    enum lttng_live_iterator_status stream_iter_status;
-    ;
     int64_t youngest_candidate_msg_ts = INT64_MAX;
     uint64_t stream_iter_idx;
 
     BT_ASSERT_DBG(live_trace);
-    BT_ASSERT_DBG(live_trace->stream_iterators);
 
-    BT_COMP_LOGD("Finding the next stream iterator for trace: "
-                 "trace-id=%" PRIu64,
-                 live_trace->id);
+    BT_CPPLOGD_SPEC(lttng_live_msg_iter->logger,
+                    "Finding the next stream iterator for trace: "
+                    "trace-id={}",
+                    live_trace->id);
     /*
      * Update the current message of every stream iterators of this trace.
      * The current msg of every stream must have a timestamp equal or
@@ -1241,22 +998,21 @@ next_stream_iterator_for_trace(struct lttng_live_msg_iter *lttng_live_msg_iter,
      * ensure monotonicity.
      */
     stream_iter_idx = 0;
-    while (stream_iter_idx < live_trace->stream_iterators->len) {
+    while (stream_iter_idx < live_trace->stream_iterators.size()) {
         bool stream_iter_is_ended = false;
-        struct lttng_live_stream_iterator *stream_iter =
-            (lttng_live_stream_iterator *) g_ptr_array_index(live_trace->stream_iterators,
-                                                             stream_iter_idx);
+        lttng_live_stream_iterator *stream_iter =
+            live_trace->stream_iterators[stream_iter_idx].get();
 
         /*
          * If there is no current message for this stream, go fetch
          * one.
          */
         while (!stream_iter->current_msg) {
-            const bt_message *msg = NULL;
+            bt2::ConstMessage::Shared msg;
             int64_t curr_msg_ts_ns = INT64_MAX;
 
-            stream_iter_status =
-                lttng_live_iterator_next_msg_on_stream(lttng_live_msg_iter, stream_iter, &msg);
+            const auto stream_iter_status =
+                lttng_live_iterator_next_msg_on_stream(lttng_live_msg_iter, stream_iter, msg);
 
             if (stream_iter_status == LTTNG_LIVE_ITERATOR_STATUS_END) {
                 stream_iter_is_ended = true;
@@ -1264,22 +1020,22 @@ next_stream_iterator_for_trace(struct lttng_live_msg_iter *lttng_live_msg_iter,
             }
 
             if (stream_iter_status != LTTNG_LIVE_ITERATOR_STATUS_OK) {
-                goto end;
+                return stream_iter_status;
             }
 
             BT_ASSERT_DBG(msg);
 
-            BT_COMP_LOGD("Live stream iterator returned message: msg-type=%s, "
-                         "stream-name=\"%s\", viewer-stream-id=%" PRIu64,
-                         bt_common_message_type_string(bt_message_get_type(msg)),
-                         stream_iter->name->str, stream_iter->viewer_stream_id);
+            BT_CPPLOGD_SPEC(lttng_live_msg_iter->logger,
+                            "Live stream iterator returned message: msg-type={}, "
+                            "stream-name=\"{}\", viewer-stream-id={}",
+                            msg->type(), stream_iter->name, stream_iter->viewer_stream_id);
 
             /*
              * Get the timestamp in nanoseconds from origin of this
              * message.
              */
-            live_get_msg_ts_ns(lttng_live_msg_iter, msg, lttng_live_msg_iter->last_msg_ts_ns,
-                               &curr_msg_ts_ns);
+            live_get_msg_ts_ns(lttng_live_msg_iter, msg->libObjPtr(),
+                               lttng_live_msg_iter->last_msg_ts_ns, &curr_msg_ts_ns);
 
             /*
              * Check if the message of the current live stream
@@ -1288,25 +1044,24 @@ next_stream_iterator_for_trace(struct lttng_live_msg_iter *lttng_live_msg_iter,
              * iterator. If not, we need to handle it with care.
              */
             if (curr_msg_ts_ns >= lttng_live_msg_iter->last_msg_ts_ns) {
-                stream_iter->current_msg = msg;
+                stream_iter->current_msg = std::move(msg);
                 stream_iter->current_msg_ts_ns = curr_msg_ts_ns;
             } else {
                 /*
                  * We received a message from the past. This
                  * may be fixable but it can also be an error.
                  */
-                stream_iter_status =
-                    handle_late_message(lttng_live_msg_iter, stream_iter, curr_msg_ts_ns, msg);
-                if (stream_iter_status != LTTNG_LIVE_ITERATOR_STATUS_OK) {
-                    BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                              "Late message could not be handled correctly: "
-                                              "lttng-live-msg-iter-addr=%p, "
-                                              "stream-name=\"%s\", "
-                                              "curr-msg-ts=%" PRId64 ", last-msg-ts=%" PRId64,
-                                              lttng_live_msg_iter, stream_iter->name->str,
-                                              curr_msg_ts_ns, lttng_live_msg_iter->last_msg_ts_ns);
-                    stream_iter_status = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
-                    goto end;
+                if (handle_late_message(lttng_live_msg_iter, stream_iter, curr_msg_ts_ns, *msg) !=
+                    LTTNG_LIVE_ITERATOR_STATUS_OK) {
+                    BT_CPPLOGE_APPEND_CAUSE_SPEC(lttng_live_msg_iter->logger,
+                                                 "Late message could not be handled correctly: "
+                                                 "lttng-live-msg-iter-addr={}, "
+                                                 "stream-name=\"{}\", "
+                                                 "curr-msg-ts={}, last-msg-ts={}",
+                                                 fmt::ptr(lttng_live_msg_iter), stream_iter->name,
+                                                 curr_msg_ts_ns,
+                                                 lttng_live_msg_iter->last_msg_ts_ns);
+                    return LTTNG_LIVE_ITERATOR_STATUS_ERROR;
                 }
             }
         }
@@ -1330,7 +1085,8 @@ next_stream_iterator_for_trace(struct lttng_live_msg_iter *lttng_live_msg_iter,
                  */
                 BT_ASSERT_DBG(stream_iter != youngest_candidate_stream_iter);
                 int ret = common_muxing_compare_messages(
-                    stream_iter->current_msg, youngest_candidate_stream_iter->current_msg);
+                    stream_iter->current_msg->libObjPtr(),
+                    youngest_candidate_stream_iter->current_msg->libObjPtr());
                 if (ret < 0) {
                     /*
                      * The `youngest_candidate_stream_iter->current_msg`
@@ -1344,11 +1100,12 @@ next_stream_iterator_for_trace(struct lttng_live_msg_iter *lttng_live_msg_iter,
                      * Unable to pick which one should go
                      * first.
                      */
-                    BT_COMP_LOGW(
+                    BT_CPPLOGW_SPEC(
+                        lttng_live_msg_iter->logger,
                         "Cannot deterministically pick next live stream message iterator because they have identical next messages: "
-                        "stream-iter-addr=%p"
-                        "stream-iter-addr=%p",
-                        stream_iter, youngest_candidate_stream_iter);
+                        "stream-iter-addr={}"
+                        "stream-iter-addr={}",
+                        fmt::ptr(stream_iter), fmt::ptr(youngest_candidate_stream_iter));
                 }
             }
 
@@ -1363,24 +1120,21 @@ next_stream_iterator_for_trace(struct lttng_live_msg_iter *lttng_live_msg_iter,
              * removed element with the array's last
              * element.
              */
-            g_ptr_array_remove_index_fast(live_trace->stream_iterators, stream_iter_idx);
+            bt2c::vectorFastRemove(live_trace->stream_iterators, stream_iter_idx);
         }
     }
 
     if (youngest_candidate_stream_iter) {
         *youngest_trace_stream_iter = youngest_candidate_stream_iter;
-        stream_iter_status = LTTNG_LIVE_ITERATOR_STATUS_OK;
+        return 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;
+        BT_ASSERT(live_trace->stream_iterators.empty());
+        return LTTNG_LIVE_ITERATOR_STATUS_END;
     }
-
-end:
-    return stream_iter_status;
 }
 
 static enum lttng_live_iterator_status
@@ -1388,16 +1142,15 @@ next_stream_iterator_for_session(struct lttng_live_msg_iter *lttng_live_msg_iter
                                  struct lttng_live_session *session,
                                  struct lttng_live_stream_iterator **youngest_session_stream_iter)
 {
-    bt_self_component *self_comp = lttng_live_msg_iter->self_comp;
-    bt_logging_level log_level = lttng_live_msg_iter->log_level;
     enum lttng_live_iterator_status stream_iter_status;
     uint64_t trace_idx = 0;
     int64_t youngest_candidate_msg_ts = INT64_MAX;
     struct lttng_live_stream_iterator *youngest_candidate_stream_iter = NULL;
 
-    BT_COMP_LOGD("Finding the next stream iterator for session: "
-                 "session-id=%" PRIu64,
-                 session->id);
+    BT_CPPLOGD_SPEC(lttng_live_msg_iter->logger,
+                    "Finding the next stream iterator for session: "
+                    "session-id={}",
+                    session->id);
     /*
      * Make sure we are attached to the session and look for new streams
      * and metadata.
@@ -1406,16 +1159,13 @@ next_stream_iterator_for_session(struct lttng_live_msg_iter *lttng_live_msg_iter
     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;
+        return stream_iter_status;
     }
 
-    BT_ASSERT_DBG(session->traces);
-
-    while (trace_idx < session->traces->len) {
+    while (trace_idx < session->traces.size()) {
         bool trace_is_ended = false;
         struct lttng_live_stream_iterator *stream_iter;
-        struct lttng_live_trace *trace =
-            (lttng_live_trace *) g_ptr_array_index(session->traces, trace_idx);
+        lttng_live_trace *trace = session->traces[trace_idx].get();
 
         stream_iter_status =
             next_stream_iterator_for_trace(lttng_live_msg_iter, trace, &stream_iter);
@@ -1426,7 +1176,7 @@ next_stream_iterator_for_session(struct lttng_live_msg_iter *lttng_live_msg_iter
              */
             trace_is_ended = true;
         } else if (stream_iter_status != LTTNG_LIVE_ITERATOR_STATUS_OK) {
-            goto end;
+            return stream_iter_status;
         }
 
         if (!trace_is_ended) {
@@ -1442,7 +1192,8 @@ next_stream_iterator_for_session(struct lttng_live_msg_iter *lttng_live_msg_iter
                  * deterministic way.
                  */
                 int ret = common_muxing_compare_messages(
-                    stream_iter->current_msg, youngest_candidate_stream_iter->current_msg);
+                    stream_iter->current_msg->libObjPtr(),
+                    youngest_candidate_stream_iter->current_msg->libObjPtr());
                 if (ret < 0) {
                     /*
                      * The `youngest_candidate_stream_iter->current_msg`
@@ -1453,26 +1204,27 @@ next_stream_iterator_for_session(struct lttng_live_msg_iter *lttng_live_msg_iter
                     youngest_candidate_stream_iter = stream_iter;
                 } else if (ret == 0) {
                     /* Unable to pick which one should go first. */
-                    BT_COMP_LOGW(
+                    BT_CPPLOGW_SPEC(
+                        lttng_live_msg_iter->logger,
                         "Cannot deterministically pick next live stream message iterator because they have identical next messages: "
-                        "stream-iter-addr=%p"
-                        "stream-iter-addr=%p",
-                        stream_iter, youngest_candidate_stream_iter);
+                        "stream-iter-addr={}"
+                        "youngest-candidate-stream-iter-addr={}",
+                        fmt::ptr(stream_iter), fmt::ptr(youngest_candidate_stream_iter));
                 }
             }
             trace_idx++;
         } else {
             /*
              * trace_idx is not incremented since
-             * g_ptr_array_remove_index_fast replaces the
+             * vectorFastRemove replaces the
              * element at trace_idx with the array's last element.
              */
-            g_ptr_array_remove_index_fast(session->traces, trace_idx);
+            bt2c::vectorFastRemove(session->traces, trace_idx);
         }
     }
     if (youngest_candidate_stream_iter) {
         *youngest_session_stream_iter = youngest_candidate_stream_iter;
-        stream_iter_status = LTTNG_LIVE_ITERATOR_STATUS_OK;
+        return LTTNG_LIVE_ITERATOR_STATUS_OK;
     } else {
         /*
          * The only cases where we don't have a candidate for this
@@ -1483,11 +1235,9 @@ next_stream_iterator_for_session(struct lttng_live_msg_iter *lttng_live_msg_iter
          *
          * In either cases, we return END.
          */
-        BT_ASSERT(session->traces->len == 0);
-        stream_iter_status = LTTNG_LIVE_ITERATOR_STATUS_END;
+        BT_ASSERT(session->traces.empty());
+        return LTTNG_LIVE_ITERATOR_STATUS_END;
     }
-end:
-    return stream_iter_status;
 }
 
 static inline void put_messages(bt_message_array_const msgs, uint64_t count)
@@ -1503,377 +1253,362 @@ bt_message_iterator_class_next_method_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_message_iterator_class_next_method_status status;
-    enum lttng_live_viewer_status viewer_status;
-    struct lttng_live_msg_iter *lttng_live_msg_iter =
-        (struct 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;
-    bt_self_component *self_comp = lttng_live_msg_iter->self_comp;
-    bt_logging_level log_level = lttng_live_msg_iter->log_level;
-    enum lttng_live_iterator_status stream_iter_status;
-    uint64_t session_idx;
+    try {
+        bt_message_iterator_class_next_method_status status;
+        enum lttng_live_viewer_status viewer_status;
+        struct lttng_live_msg_iter *lttng_live_msg_iter =
+            (struct 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;
 
-    *count = 0;
+        *count = 0;
 
-    BT_ASSERT_DBG(lttng_live_msg_iter);
+        BT_ASSERT_DBG(lttng_live_msg_iter);
+
+        if (G_UNLIKELY(lttng_live_msg_iter->was_interrupted)) {
+            /*
+             * The iterator was interrupted in a previous call to the
+             * `_next()` method. We currently do not support generating
+             * messages after such event. The babeltrace2 CLI should never
+             * be running the graph after being interrupted. So this check
+             * is to prevent other graph users from using this live
+             * iterator in an messed up internal state.
+             */
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(
+                lttng_live_msg_iter->logger,
+                "Message iterator was interrupted during a previous call to the `next()` and currently does not support continuing after such event.");
+            return BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_ERROR;
+        }
 
-    if (G_UNLIKELY(lttng_live_msg_iter->was_interrupted)) {
         /*
-         * The iterator was interrupted in a previous call to the
-         * `_next()` method. We currently do not support generating
-         * messages after such event. The babeltrace2 CLI should never
-         * be running the graph after being interrupted. So this check
-         * is to prevent other graph users from using this live
-         * iterator in an messed up internal state.
+         * Clear all the invalid message reference that might be left over in
+         * the output array.
          */
-        status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_ERROR;
-        BT_COMP_LOGE_APPEND_CAUSE(
-            self_comp,
-            "Message iterator was interrupted during a previous call to the `next()` and currently does not support continuing after such event.");
-        goto end;
-    }
-
-    /*
-     * Clear all the invalid message reference that might be left over in
-     * the output array.
-     */
-    memset(msgs, 0, capacity * sizeof(*msgs));
+        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_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_END;
-            goto end;
-        } else {
-            /*
-             * The are no more active session for this session
-             * name. Retry to create a viewer session for the
-             * requested session name.
-             */
-            viewer_status = lttng_live_create_viewer_session(lttng_live_msg_iter);
-            if (viewer_status != LTTNG_LIVE_VIEWER_STATUS_OK) {
-                if (viewer_status == LTTNG_LIVE_VIEWER_STATUS_ERROR) {
-                    status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_ERROR;
-                    BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                              "Error creating LTTng live viewer session");
-                } else if (viewer_status == LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED) {
-                    status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_AGAIN;
-                } else {
-                    bt_common_abort();
+        /*
+         * 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.empty()) {
+            if (lttng_live->params.sess_not_found_act != SESSION_NOT_FOUND_ACTION_CONTINUE) {
+                return BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_END;
+            } else {
+                /*
+                 * The are no more active session for this session
+                 * name. Retry to create a viewer session for the
+                 * requested session name.
+                 */
+                viewer_status = lttng_live_create_viewer_session(lttng_live_msg_iter);
+                if (viewer_status != LTTNG_LIVE_VIEWER_STATUS_OK) {
+                    if (viewer_status == LTTNG_LIVE_VIEWER_STATUS_ERROR) {
+                        BT_CPPLOGE_APPEND_CAUSE_SPEC(lttng_live_msg_iter->logger,
+                                                     "Error creating LTTng live viewer session");
+                        return BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_ERROR;
+                    } else if (viewer_status == LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED) {
+                        return BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_AGAIN;
+                    } else {
+                        bt_common_abort();
+                    }
                 }
-                goto end;
             }
         }
-    }
 
-    if (lttng_live_msg_iter->active_stream_iter == 0) {
-        lttng_live_force_new_streams_and_metadata(lttng_live_msg_iter);
-    }
+        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 *youngest_stream_iter = NULL,
-                                          *candidate_stream_iter = NULL;
-        int64_t youngest_msg_ts_ns = INT64_MAX;
-
-        BT_ASSERT_DBG(lttng_live_msg_iter->sessions);
-        session_idx = 0;
-        while (session_idx < lttng_live_msg_iter->sessions->len) {
-            struct lttng_live_session *session = (lttng_live_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.
-                     * session_idx is not modified since
-                     * g_ptr_array_remove_index_fast
-                     * replaces the the removed element with
-                     * the array's last element.
-                     */
-                    g_ptr_array_remove_index_fast(lttng_live_msg_iter->sessions, session_idx);
-                } else {
-                    session_idx++;
+        /*
+         * 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 *youngest_stream_iter = NULL,
+                                              *candidate_stream_iter = NULL;
+            int64_t youngest_msg_ts_ns = INT64_MAX;
+
+            uint64_t session_idx = 0;
+            while (session_idx < lttng_live_msg_iter->sessions.size()) {
+                lttng_live_session *session = lttng_live_msg_iter->sessions[session_idx].get();
+
+                /* 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.empty()) {
+                        /*
+                         * Remove the session from the list.
+                         * session_idx is not modified since
+                         * g_ptr_array_remove_index_fast
+                         * replaces the the removed element with
+                         * the array's last element.
+                         */
+                        bt2c::vectorFastRemove(lttng_live_msg_iter->sessions, session_idx);
+                    } else {
+                        session_idx++;
+                    }
+                    continue;
                 }
-                continue;
-            }
 
-            if (stream_iter_status != LTTNG_LIVE_ITERATOR_STATUS_OK) {
-                goto return_status;
-            }
+                if (stream_iter_status != LTTNG_LIVE_ITERATOR_STATUS_OK) {
+                    goto return_status;
+                }
 
-            if (G_UNLIKELY(youngest_stream_iter == NULL) ||
-                candidate_stream_iter->current_msg_ts_ns < youngest_msg_ts_ns) {
-                youngest_msg_ts_ns = candidate_stream_iter->current_msg_ts_ns;
-                youngest_stream_iter = candidate_stream_iter;
-            } else if (candidate_stream_iter->current_msg_ts_ns == youngest_msg_ts_ns) {
-                /*
-                 * The currently selected message to be sent
-                 * downstream next has the exact same timestamp
-                 * that of the current candidate message. We
-                 * must break the tie in a predictable manner.
-                 */
-                BT_COMP_LOGD_STR(
-                    "Two of the next message candidates have the same timestamps, pick one deterministically.");
-                /*
-                 * Order the messages in an arbitrary but
-                 * deterministic way.
-                 */
-                int ret = common_muxing_compare_messages(candidate_stream_iter->current_msg,
-                                                         youngest_stream_iter->current_msg);
-                if (ret < 0) {
-                    /*
-                     * The `candidate_stream_iter->current_msg`
-                     * should go first. Update the next
-                     * iterator and the current timestamp.
-                     */
+                if (G_UNLIKELY(youngest_stream_iter == NULL) ||
+                    candidate_stream_iter->current_msg_ts_ns < youngest_msg_ts_ns) {
                     youngest_msg_ts_ns = candidate_stream_iter->current_msg_ts_ns;
                     youngest_stream_iter = candidate_stream_iter;
-                } else if (ret == 0) {
-                    /* Unable to pick which one should go first. */
-                    BT_COMP_LOGW(
-                        "Cannot deterministically pick next live stream message iterator because they have identical next messages: "
-                        "next-stream-iter-addr=%p"
-                        "candidate-stream-iter-addr=%p",
-                        youngest_stream_iter, candidate_stream_iter);
+                } else if (candidate_stream_iter->current_msg_ts_ns == youngest_msg_ts_ns) {
+                    /*
+                     * The currently selected message to be sent
+                     * downstream next has the exact same timestamp
+                     * that of the current candidate message. We
+                     * must break the tie in a predictable manner.
+                     */
+                    BT_CPPLOGD_SPEC(
+                        lttng_live_msg_iter->logger,
+                        "Two of the next message candidates have the same timestamps, pick one deterministically.");
+                    /*
+                     * Order the messages in an arbitrary but
+                     * deterministic way.
+                     */
+                    int ret = common_muxing_compare_messages(
+                        candidate_stream_iter->current_msg->libObjPtr(),
+                        youngest_stream_iter->current_msg->libObjPtr());
+                    if (ret < 0) {
+                        /*
+                         * The `candidate_stream_iter->current_msg`
+                         * should go first. Update the next
+                         * iterator and the current timestamp.
+                         */
+                        youngest_msg_ts_ns = candidate_stream_iter->current_msg_ts_ns;
+                        youngest_stream_iter = candidate_stream_iter;
+                    } else if (ret == 0) {
+                        /* Unable to pick which one should go first. */
+                        BT_CPPLOGW_SPEC(
+                            lttng_live_msg_iter->logger,
+                            "Cannot deterministically pick next live stream message iterator because they have identical next messages: "
+                            "next-stream-iter-addr={}"
+                            "candidate-stream-iter-addr={}",
+                            fmt::ptr(youngest_stream_iter), fmt::ptr(candidate_stream_iter));
+                    }
                 }
-            }
 
-            session_idx++;
-        }
+                session_idx++;
+            }
 
-        if (!youngest_stream_iter) {
-            stream_iter_status = LTTNG_LIVE_ITERATOR_STATUS_AGAIN;
-            goto return_status;
-        }
+            if (!youngest_stream_iter) {
+                stream_iter_status = LTTNG_LIVE_ITERATOR_STATUS_AGAIN;
+                goto return_status;
+            }
 
-        BT_ASSERT_DBG(youngest_stream_iter->current_msg);
-        /* Ensure monotonicity. */
-        BT_ASSERT_DBG(lttng_live_msg_iter->last_msg_ts_ns <=
-                      youngest_stream_iter->current_msg_ts_ns);
+            BT_ASSERT_DBG(youngest_stream_iter->current_msg);
+            /* Ensure monotonicity. */
+            BT_ASSERT_DBG(lttng_live_msg_iter->last_msg_ts_ns <=
+                          youngest_stream_iter->current_msg_ts_ns);
 
-        /*
-         * Insert the next message to the message batch. This will set
-         * stream iterator current message to NULL so that next time
-         * we fetch the next message of that stream iterator
-         */
-        BT_MESSAGE_MOVE_REF(msgs[*count], youngest_stream_iter->current_msg);
-        (*count)++;
+            /*
+             * Insert the next message to the message batch. This will set
+             * stream iterator current message to NULL so that next time
+             * we fetch the next message of that stream iterator
+             */
+            msgs[*count] = youngest_stream_iter->current_msg.release().libObjPtr();
+            (*count)++;
 
-        /* Update the last timestamp in nanoseconds sent downstream. */
-        lttng_live_msg_iter->last_msg_ts_ns = youngest_msg_ts_ns;
-        youngest_stream_iter->current_msg_ts_ns = INT64_MAX;
+            /* Update the last timestamp in nanoseconds sent downstream. */
+            lttng_live_msg_iter->last_msg_ts_ns = youngest_msg_ts_ns;
+            youngest_stream_iter->current_msg_ts_ns = INT64_MAX;
 
-        stream_iter_status = LTTNG_LIVE_ITERATOR_STATUS_OK;
-    }
+            stream_iter_status = LTTNG_LIVE_ITERATOR_STATUS_OK;
+        }
 
 return_status:
-    switch (stream_iter_status) {
-    case LTTNG_LIVE_ITERATOR_STATUS_OK:
-    case LTTNG_LIVE_ITERATOR_STATUS_AGAIN:
-        /*
-         * If we gathered messages, return _OK even if the graph was
-         * interrupted. This allows for the components downstream to at
-         * least get the those messages. If the graph was indeed
-         * interrupted there should not be another _next() call as the
-         * application will tear down the graph. This component class
-         * doesn't support restarting after an interruption.
-         */
-        if (*count > 0) {
-            status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK;
-        } else {
-            status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_AGAIN;
+        switch (stream_iter_status) {
+        case LTTNG_LIVE_ITERATOR_STATUS_OK:
+        case LTTNG_LIVE_ITERATOR_STATUS_AGAIN:
+            /*
+             * If we gathered messages, return _OK even if the graph was
+             * interrupted. This allows for the components downstream to at
+             * least get the those messages. If the graph was indeed
+             * interrupted there should not be another _next() call as the
+             * application will tear down the graph. This component class
+             * doesn't support restarting after an interruption.
+             */
+            if (*count > 0) {
+                status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK;
+            } else {
+                status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_AGAIN;
+            }
+            break;
+        case LTTNG_LIVE_ITERATOR_STATUS_END:
+            status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_END;
+            break;
+        case LTTNG_LIVE_ITERATOR_STATUS_NOMEM:
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(lttng_live_msg_iter->logger,
+                                         "Memory error preparing the next batch of messages: "
+                                         "live-iter-status={}",
+                                         stream_iter_status);
+            status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_MEMORY_ERROR;
+            break;
+        case LTTNG_LIVE_ITERATOR_STATUS_ERROR:
+        case LTTNG_LIVE_ITERATOR_STATUS_INVAL:
+        case LTTNG_LIVE_ITERATOR_STATUS_UNSUPPORTED:
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(lttng_live_msg_iter->logger,
+                                         "Error preparing the next batch of messages: "
+                                         "live-iter-status={}",
+                                         stream_iter_status);
+
+            status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_ERROR;
+            /* Put all existing messages on error. */
+            put_messages(msgs, *count);
+            break;
+        default:
+            bt_common_abort();
         }
-        break;
-    case LTTNG_LIVE_ITERATOR_STATUS_END:
-        status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_END;
-        break;
-    case LTTNG_LIVE_ITERATOR_STATUS_NOMEM:
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "Memory error preparing the next batch of messages: "
-                                  "live-iter-status=%s",
-                                  lttng_live_iterator_status_string(stream_iter_status));
-        status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_MEMORY_ERROR;
-        break;
-    case LTTNG_LIVE_ITERATOR_STATUS_ERROR:
-    case LTTNG_LIVE_ITERATOR_STATUS_INVAL:
-    case LTTNG_LIVE_ITERATOR_STATUS_UNSUPPORTED:
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "Error preparing the next batch of messages: "
-                                  "live-iter-status=%s",
-                                  lttng_live_iterator_status_string(stream_iter_status));
-
-        status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_ERROR;
-        /* Put all existing messages on error. */
-        put_messages(msgs, *count);
-        break;
-    default:
-        bt_common_abort();
-    }
 
-end:
-    return status;
+        return status;
+    } catch (const std::bad_alloc&) {
+        return BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_MEMORY_ERROR;
+    } catch (const bt2::Error&) {
+        return BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_ERROR;
+    }
 }
 
-static struct lttng_live_msg_iter *
+static lttng_live_msg_iter::UP
 lttng_live_msg_iter_create(struct lttng_live_component *lttng_live_comp,
                            bt_self_message_iterator *self_msg_it)
 {
-    bt_self_component *self_comp = lttng_live_comp->self_comp;
-    bt_logging_level log_level = lttng_live_comp->log_level;
-
-    struct lttng_live_msg_iter *lttng_live_msg_iter = g_new0(struct lttng_live_msg_iter, 1);
-    if (!lttng_live_msg_iter) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to allocate lttng_live_msg_iter");
-        goto end;
-    }
-
-    lttng_live_msg_iter->log_level = lttng_live_comp->log_level;
-    lttng_live_msg_iter->self_comp = lttng_live_comp->self_comp;
-    lttng_live_msg_iter->lttng_live_comp = lttng_live_comp;
-    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->was_interrupted = false;
+    auto msg_iter = bt2s::make_unique<struct lttng_live_msg_iter>(lttng_live_comp->logger);
 
-    lttng_live_msg_iter->sessions =
-        g_ptr_array_new_with_free_func((GDestroyNotify) lttng_live_destroy_session);
-    BT_ASSERT(lttng_live_msg_iter->sessions);
+    msg_iter->self_comp = lttng_live_comp->self_comp;
+    msg_iter->lttng_live_comp = lttng_live_comp;
+    msg_iter->self_msg_iter = self_msg_it;
+    msg_iter->active_stream_iter = 0;
+    msg_iter->last_msg_ts_ns = INT64_MIN;
+    msg_iter->was_interrupted = false;
 
-end:
-    return lttng_live_msg_iter;
+    return msg_iter;
 }
 
 bt_message_iterator_class_initialize_method_status
 lttng_live_msg_iter_init(bt_self_message_iterator *self_msg_it,
                          bt_self_message_iterator_configuration *, bt_self_component_port_output *)
 {
-    bt_message_iterator_class_initialize_method_status status;
-    struct lttng_live_component *lttng_live;
-    struct lttng_live_msg_iter *lttng_live_msg_iter;
-    enum lttng_live_viewer_status viewer_status;
-    bt_logging_level log_level;
-    bt_self_component *self_comp = bt_self_message_iterator_borrow_component(self_msg_it);
-
-    lttng_live = (lttng_live_component *) bt_self_component_get_data(self_comp);
-    log_level = lttng_live->log_level;
-    self_comp = lttng_live->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 = lttng_live_msg_iter_create(lttng_live, self_msg_it);
-    if (!lttng_live_msg_iter) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to create lttng_live_msg_iter");
-        status = BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
-        goto error;
-    }
-
-    viewer_status = live_viewer_connection_create(
-        self_comp, NULL, log_level, lttng_live->params.url->str, false, lttng_live_msg_iter,
-        &lttng_live_msg_iter->viewer_connection);
-    if (viewer_status != LTTNG_LIVE_VIEWER_STATUS_OK) {
-        if (viewer_status == LTTNG_LIVE_VIEWER_STATUS_ERROR) {
-            BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to create viewer connection");
-        } else if (viewer_status == LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED) {
-            /*
-             * Interruption in the _iter_init() method is not
-             * supported. Return an error.
-             */
-            BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Interrupted while creating viewer connection");
+    try {
+        struct lttng_live_component *lttng_live;
+        enum lttng_live_viewer_status viewer_status;
+        bt_self_component *self_comp = bt_self_message_iterator_borrow_component(self_msg_it);
+
+        lttng_live = (lttng_live_component *) 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;
+
+        auto lttng_live_msg_iter = lttng_live_msg_iter_create(lttng_live, self_msg_it);
+        if (!lttng_live_msg_iter) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(lttng_live->logger,
+                                         "Failed to create lttng_live_msg_iter");
+            return BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
         }
 
-        status = BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
-        goto error;
-    }
+        viewer_status = live_viewer_connection_create(
+            lttng_live->params.url.c_str(), false, lttng_live_msg_iter.get(),
+            lttng_live_msg_iter->logger, lttng_live_msg_iter->viewer_connection);
+        if (viewer_status != LTTNG_LIVE_VIEWER_STATUS_OK) {
+            if (viewer_status == LTTNG_LIVE_VIEWER_STATUS_ERROR) {
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(lttng_live_msg_iter->logger,
+                                             "Failed to create viewer connection");
+            } else if (viewer_status == LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED) {
+                /*
+                 * Interruption in the _iter_init() method is not
+                 * supported. Return an error.
+                 */
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(lttng_live_msg_iter->logger,
+                                             "Interrupted while creating viewer connection");
+            }
 
-    viewer_status = lttng_live_create_viewer_session(lttng_live_msg_iter);
-    if (viewer_status != LTTNG_LIVE_VIEWER_STATUS_OK) {
-        if (viewer_status == LTTNG_LIVE_VIEWER_STATUS_ERROR) {
-            BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to create viewer session");
-        } else if (viewer_status == LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED) {
-            /*
-             * Interruption in the _iter_init() method is not
-             * supported. Return an error.
-             */
-            BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Interrupted when creating viewer session");
+            return BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
         }
 
-        status = BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
-        goto error;
-    }
+        viewer_status = lttng_live_create_viewer_session(lttng_live_msg_iter.get());
+        if (viewer_status != LTTNG_LIVE_VIEWER_STATUS_OK) {
+            if (viewer_status == LTTNG_LIVE_VIEWER_STATUS_ERROR) {
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(lttng_live_msg_iter->logger,
+                                             "Failed to create viewer session");
+            } else if (viewer_status == LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED) {
+                /*
+                 * Interruption in the _iter_init() method is not
+                 * supported. Return an error.
+                 */
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(lttng_live_msg_iter->logger,
+                                             "Interrupted when creating viewer session");
+            }
 
-    if (lttng_live_msg_iter->sessions->len == 0) {
-        switch (lttng_live->params.sess_not_found_act) {
-        case SESSION_NOT_FOUND_ACTION_CONTINUE:
-            BT_COMP_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_COMP_LOGE_APPEND_CAUSE(
-                self_comp,
-                "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);
-            status = BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
-            goto error;
-        case SESSION_NOT_FOUND_ACTION_END:
-            BT_COMP_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;
-        default:
-            bt_common_abort();
+            return BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
         }
-    }
 
-    bt_self_message_iterator_set_data(self_msg_it, lttng_live_msg_iter);
-    status = BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_OK;
-    goto end;
+        if (lttng_live_msg_iter->sessions.empty()) {
+            switch (lttng_live->params.sess_not_found_act) {
+            case SESSION_NOT_FOUND_ACTION_CONTINUE:
+                BT_CPPLOGI_SPEC(
+                    lttng_live_msg_iter->logger,
+                    "Unable to connect to the requested live viewer session. "
+                    "Keep trying to connect because of {}=\"{}\" component parameter: url=\"{}\"",
+                    SESS_NOT_FOUND_ACTION_PARAM, SESS_NOT_FOUND_ACTION_CONTINUE_STR,
+                    lttng_live->params.url);
+                break;
+            case SESSION_NOT_FOUND_ACTION_FAIL:
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(
+                    lttng_live_msg_iter->logger,
+                    "Unable to connect to the requested live viewer session. "
+                    "Fail the message iterator initialization because of {}=\"{}\" "
+                    "component parameter: url =\"{}\"",
+                    SESS_NOT_FOUND_ACTION_PARAM, SESS_NOT_FOUND_ACTION_FAIL_STR,
+                    lttng_live->params.url);
+                return BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
+            case SESSION_NOT_FOUND_ACTION_END:
+                BT_CPPLOGI_SPEC(lttng_live_msg_iter->logger,
+                                "Unable to connect to the requested live viewer session. "
+                                "End gracefully at the first _next() call because of {}=\"{}\""
+                                " component parameter: url=\"{}\"",
+                                SESS_NOT_FOUND_ACTION_PARAM, SESS_NOT_FOUND_ACTION_END_STR,
+                                lttng_live->params.url);
+                break;
+            default:
+                bt_common_abort();
+            }
+        }
 
-error:
-    lttng_live_msg_iter_destroy(lttng_live_msg_iter);
-end:
-    return status;
+        bt_self_message_iterator_set_data(self_msg_it, lttng_live_msg_iter.release());
+        return BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_OK;
+    } catch (const std::bad_alloc&) {
+        return BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
+    } catch (const bt2::Error&) {
+        return BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
+    }
 }
 
 static struct bt_param_validation_map_value_entry_descr list_sessions_params[] = {
@@ -1881,140 +1616,88 @@ static struct bt_param_validation_map_value_entry_descr list_sessions_params[] =
      bt_param_validation_value_descr::makeString()},
     BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_END};
 
-static bt_component_class_query_method_status
-lttng_live_query_list_sessions(const bt_value *params, const bt_value **result,
-                               bt_self_component_class *self_comp_class, bt_logging_level log_level)
+static bt2::Value::Shared lttng_live_query_list_sessions(const bt2::ConstMapValue params,
+                                                         const bt2c::Logger& logger)
 {
-    bt_component_class_query_method_status status;
-    const bt_value *url_value = NULL;
     const char *url;
-    struct live_viewer_connection *viewer_connection = NULL;
+    live_viewer_connection::UP viewer_connection;
     enum lttng_live_viewer_status viewer_status;
     enum bt_param_validation_status validation_status;
     gchar *validate_error = NULL;
 
-    validation_status = bt_param_validation_validate(params, list_sessions_params, &validate_error);
+    validation_status =
+        bt_param_validation_validate(params.libObjPtr(), list_sessions_params, &validate_error);
     if (validation_status == BT_PARAM_VALIDATION_STATUS_MEMORY_ERROR) {
-        status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR;
-        goto error;
+        throw bt2c::MemoryError {};
     } else if (validation_status == BT_PARAM_VALIDATION_STATUS_VALIDATION_ERROR) {
-        status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR;
-        BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, "%s", validate_error);
-        goto error;
+        bt2c::GCharUP errorFreer {validate_error};
+
+        BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(logger, bt2::Error, "{}", validate_error);
     }
 
-    url_value = bt_value_map_borrow_entry_value_const(params, URL_PARAM);
-    url = bt_value_string_get(url_value);
+    url = params[URL_PARAM]->asString().value();
 
-    viewer_status = live_viewer_connection_create(NULL, self_comp_class, log_level, url, true, NULL,
-                                                  &viewer_connection);
+    viewer_status = live_viewer_connection_create(url, true, NULL, logger, viewer_connection);
     if (viewer_status != LTTNG_LIVE_VIEWER_STATUS_OK) {
         if (viewer_status == LTTNG_LIVE_VIEWER_STATUS_ERROR) {
-            BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, "Failed to create viewer connection");
-            status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR;
+            BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(logger, bt2::Error,
+                                                   "Failed to create viewer connection");
         } else if (viewer_status == LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED) {
-            status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_AGAIN;
+            throw bt2c::TryAgain {};
         } else {
             bt_common_abort();
         }
-        goto error;
-    }
-
-    status = live_viewer_connection_list_sessions(viewer_connection, result);
-    if (status != BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK) {
-        BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, "Failed to list viewer sessions");
-        goto error;
-    }
-
-    goto end;
-
-error:
-    BT_VALUE_PUT_REF_AND_RESET(*result);
-
-    if (status >= 0) {
-        status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR;
     }
 
-end:
-    if (viewer_connection) {
-        live_viewer_connection_destroy(viewer_connection);
-    }
-
-    g_free(validate_error);
-
-    return status;
+    return live_viewer_connection_list_sessions(viewer_connection.get());
 }
 
-static bt_component_class_query_method_status
-lttng_live_query_support_info(const bt_value *params, const bt_value **result,
-                              bt_self_component_class *self_comp_class, bt_logging_level log_level)
+static bt2::Value::Shared lttng_live_query_support_info(const bt2::ConstMapValue params,
+                                                        const bt2c::Logger& logger)
 {
-    bt_component_class_query_method_status status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK;
-    const bt_value *input_type_value;
-    const bt_value *input_value;
-    double weight = 0;
     struct bt_common_lttng_live_url_parts parts = {};
+    bt_common_lttng_live_url_parts_deleter partsDeleter {parts};
 
     /* Used by the logging macros */
     __attribute__((unused)) bt_self_component *self_comp = NULL;
 
-    *result = NULL;
-    input_type_value = bt_value_map_borrow_entry_value_const(params, "type");
-    if (!input_type_value) {
-        BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, "Missing expected `type` parameter.");
-        goto error;
+    const auto typeValue = params["type"];
+    if (!typeValue) {
+        BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(logger, bt2::Error,
+                                               "Missing expected `type` parameter.");
     }
 
-    if (!bt_value_is_string(input_type_value)) {
-        BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, "`type` parameter is not a string value.");
-        goto error;
+    if (!typeValue->isString()) {
+        BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(logger, bt2::Error,
+                                               "`type` parameter is not a string value.");
     }
 
-    if (strcmp(bt_value_string_get(input_type_value), "string") != 0) {
+    if (strcmp(typeValue->asString().value(), "string") != 0) {
         /* We don't handle file system paths */
-        goto create_result;
+        return bt2::RealValue::create();
     }
 
-    input_value = bt_value_map_borrow_entry_value_const(params, "input");
-    if (!input_value) {
-        BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, "Missing expected `input` parameter.");
-        goto error;
+    const auto inputValue = params["input"];
+    if (!inputValue) {
+        BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(logger, bt2::Error,
+                                               "Missing expected `input` parameter.");
     }
 
-    if (!bt_value_is_string(input_value)) {
-        BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class,
-                                        "`input` parameter is not a string value.");
-        goto error;
+    if (!inputValue->isString()) {
+        BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(logger, bt2::Error,
+                                               "`input` parameter is not a string value.");
     }
 
-    parts = bt_common_parse_lttng_live_url(bt_value_string_get(input_value), NULL, 0);
+    parts = bt_common_parse_lttng_live_url(inputValue->asString().value(), NULL, 0);
     if (parts.session_name) {
         /*
          * Looks pretty much like an LTTng live URL: we got the
          * session name part, which forms a complete URL.
          */
-        weight = .75;
-    }
-
-create_result:
-    *result = bt_value_real_create_init(weight);
-    if (!*result) {
-        status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR;
-        goto error;
+        return bt2::RealValue::create(.75);
     }
 
-    goto end;
-
-error:
-    if (status >= 0) {
-        status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR;
-    }
-
-    BT_ASSERT(!*result);
-
-end:
-    bt_common_destroy_lttng_live_url_parts(&parts);
-    return status;
+    return bt2::RealValue::create();
 }
 
 bt_component_class_query_method_status lttng_live_query(bt_self_component_class_source *comp_class,
@@ -2023,47 +1706,38 @@ bt_component_class_query_method_status lttng_live_query(bt_self_component_class_
                                                         __attribute__((unused)) void *method_data,
                                                         const bt_value **result)
 {
-    bt_component_class_query_method_status status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK;
-    bt_self_component *self_comp = NULL;
-    bt_self_component_class *self_comp_class =
-        bt_self_component_class_source_as_self_component_class(comp_class);
-    bt_logging_level log_level = bt_query_executor_get_logging_level(
-        bt_private_query_executor_as_query_executor_const(priv_query_exec));
-
-    if (strcmp(object, "sessions") == 0) {
-        status = lttng_live_query_list_sessions(params, result, self_comp_class, log_level);
-    } else if (strcmp(object, "babeltrace.support-info") == 0) {
-        status = lttng_live_query_support_info(params, result, self_comp_class, log_level);
-    } else {
-        BT_COMP_LOGI("Unknown query object `%s`", object);
-        status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_UNKNOWN_OBJECT;
-        goto end;
-    }
+    try {
+        bt2c::Logger logger {bt2::SelfComponentClass {comp_class},
+                             bt2::PrivateQueryExecutor {priv_query_exec},
+                             "PLUGIN/SRC.CTF.LTTNG-LIVE/QUERY"};
+        const bt2::ConstMapValue paramsObj(params);
+        bt2::Value::Shared resultObj;
+
+        if (strcmp(object, "sessions") == 0) {
+            resultObj = lttng_live_query_list_sessions(paramsObj, logger);
+        } else if (strcmp(object, "babeltrace.support-info") == 0) {
+            resultObj = lttng_live_query_support_info(paramsObj, logger);
+        } else {
+            BT_CPPLOGI_SPEC(logger, "Unknown query object `{}`", object);
+            return BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_UNKNOWN_OBJECT;
+        }
 
-end:
-    return status;
-}
+        *result = resultObj.release().libObjPtr();
 
-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);
+        return BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK;
+    } catch (const bt2c::TryAgain&) {
+        return BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR;
+    } catch (const std::bad_alloc&) {
+        return BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR;
+    } catch (const bt2::Error&) {
+        return BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR;
     }
-    g_free(lttng_live);
 }
 
 void lttng_live_component_finalize(bt_self_component_source *component)
 {
-    lttng_live_component *data = (lttng_live_component *) bt_self_component_get_data(
-        bt_self_component_source_as_self_component(component));
-
-    if (!data) {
-        return;
-    }
-    lttng_live_component_destroy_data(data);
+    lttng_live_component::UP {static_cast<lttng_live_component *>(
+        bt_self_component_get_data(bt_self_component_source_as_self_component(component)))};
 }
 
 static enum session_not_found_action
@@ -2101,99 +1775,76 @@ static struct bt_param_validation_map_value_entry_descr params_descr[] = {
     BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_END};
 
 static bt_component_class_initialize_method_status
-lttng_live_component_create(const bt_value *params, bt_logging_level log_level,
-                            bt_self_component *self_comp, struct lttng_live_component **component)
+lttng_live_component_create(const bt_value *params, bt_self_component_source *self_comp,
+                            lttng_live_component::UP& component)
 {
-    struct lttng_live_component *lttng_live = NULL;
     const bt_value *inputs_value;
     const bt_value *url_value;
     const bt_value *value;
-    const char *url;
     enum bt_param_validation_status validation_status;
     gchar *validation_error = NULL;
-    bt_component_class_initialize_method_status status;
+    bt2c::Logger logger {bt2::SelfSourceComponent {self_comp}, "PLUGIN/SRC.CTF.LTTNG-LIVE/COMP"};
 
     validation_status = bt_param_validation_validate(params, params_descr, &validation_error);
     if (validation_status == BT_PARAM_VALIDATION_STATUS_MEMORY_ERROR) {
-        status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
-        goto error;
+        return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
     } else if (validation_status == BT_PARAM_VALIDATION_STATUS_VALIDATION_ERROR) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "%s", validation_error);
-        status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
-        goto error;
+        bt2c::GCharUP errorFreer {validation_error};
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(logger, "{}", validation_error);
+        return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
     }
 
-    lttng_live = g_new0(struct lttng_live_component, 1);
-    if (!lttng_live) {
-        status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
-        goto end;
-    }
-    lttng_live->log_level = log_level;
-    lttng_live->self_comp = self_comp;
+    auto lttng_live = bt2s::make_unique<lttng_live_component>(std::move(logger));
+    lttng_live->self_comp = bt_self_component_source_as_self_component(self_comp);
     lttng_live->max_query_size = MAX_QUERY_SIZE;
     lttng_live->has_msg_iter = false;
 
     inputs_value = bt_value_map_borrow_entry_value_const(params, INPUTS_PARAM);
     url_value = bt_value_array_borrow_element_by_index_const(inputs_value, 0);
-    url = bt_value_string_get(url_value);
-
-    lttng_live->params.url = g_string_new(url);
-    if (!lttng_live->params.url) {
-        status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
-        goto error;
-    }
+    lttng_live->params.url = bt_value_string_get(url_value);
 
     value = bt_value_map_borrow_entry_value_const(params, SESS_NOT_FOUND_ACTION_PARAM);
     if (value) {
         lttng_live->params.sess_not_found_act = parse_session_not_found_action_param(value);
     } else {
-        BT_COMP_LOGI("Optional `%s` parameter is missing: "
-                     "defaulting to `%s`.",
-                     SESS_NOT_FOUND_ACTION_PARAM, SESS_NOT_FOUND_ACTION_CONTINUE_STR);
+        BT_CPPLOGI_SPEC(lttng_live->logger,
+                        "Optional `{}` parameter is missing: defaulting to `{}`.",
+                        SESS_NOT_FOUND_ACTION_PARAM, SESS_NOT_FOUND_ACTION_CONTINUE_STR);
         lttng_live->params.sess_not_found_act = SESSION_NOT_FOUND_ACTION_CONTINUE;
     }
 
-    status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK;
-    goto end;
-
-error:
-    lttng_live_component_destroy_data(lttng_live);
-    lttng_live = NULL;
-end:
-    g_free(validation_error);
-
-    *component = lttng_live;
-    return status;
+    component = std::move(lttng_live);
+    return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK;
 }
 
 bt_component_class_initialize_method_status
 lttng_live_component_init(bt_self_component_source *self_comp_src,
                           bt_self_component_source_configuration *, const bt_value *params, void *)
 {
-    struct lttng_live_component *lttng_live;
-    bt_component_class_initialize_method_status ret;
-    bt_self_component *self_comp = bt_self_component_source_as_self_component(self_comp_src);
-    bt_logging_level log_level =
-        bt_component_get_logging_level(bt_self_component_as_component(self_comp));
-    bt_self_component_add_port_status add_port_status;
-
-    ret = lttng_live_component_create(params, log_level, self_comp, &lttng_live);
-    if (ret != BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK) {
-        goto error;
-    }
+    try {
+        lttng_live_component::UP lttng_live;
+        bt_component_class_initialize_method_status ret;
+        bt_self_component *self_comp = bt_self_component_source_as_self_component(self_comp_src);
+        bt_self_component_add_port_status add_port_status;
+
+        ret = lttng_live_component_create(params, self_comp_src, lttng_live);
+        if (ret != BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK) {
+            return ret;
+        }
 
-    add_port_status = bt_self_component_source_add_output_port(self_comp_src, "out", NULL, NULL);
-    if (add_port_status != BT_SELF_COMPONENT_ADD_PORT_STATUS_OK) {
-        ret = (bt_component_class_initialize_method_status) add_port_status;
-        goto end;
-    }
+        add_port_status =
+            bt_self_component_source_add_output_port(self_comp_src, "out", NULL, NULL);
+        if (add_port_status != BT_SELF_COMPONENT_ADD_PORT_STATUS_OK) {
+            ret = (bt_component_class_initialize_method_status) add_port_status;
+            return ret;
+        }
 
-    bt_self_component_set_data(self_comp, lttng_live);
-    goto end;
+        bt_self_component_set_data(self_comp, lttng_live.release());
 
-error:
-    lttng_live_component_destroy_data(lttng_live);
-    lttng_live = NULL;
-end:
-    return ret;
+        return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK;
+    } catch (const std::bad_alloc&) {
+        return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
+    } catch (const bt2::Error&) {
+        return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
+    }
 }
index 9ca87401b70005947a0548d62a6bed262dce1312..9dbc432abf3f527abc3ef64017b474aab2ddbc3d 100644 (file)
 
 #include <babeltrace2/babeltrace.h>
 
-#include "../common/msg-iter/msg-iter.hpp"
+#include "cpp-common/bt2/message.hpp"
+#include "cpp-common/vendor/fmt/format.h" /* IWYU pragma: keep */
+
+#include "../common/src/metadata/tsdl/decoder.hpp"
+#include "../common/src/msg-iter/msg-iter.hpp"
 #include "viewer-connection.hpp"
 
+/*
+ * bt_common_lttng_live_url_parts is defined in common code, and is also used
+ * by C code, so it can't be C++-ified yet.  Use this separate deleter object
+ * in the mean time.
+ */
+struct bt_common_lttng_live_url_parts_deleter
+{
+    explicit bt_common_lttng_live_url_parts_deleter(bt_common_lttng_live_url_parts& obj) noexcept :
+        _mObj {&obj}
+    {
+    }
+
+    bt_common_lttng_live_url_parts_deleter(const bt_common_lttng_live_url_parts_deleter&) = delete;
+    bt_common_lttng_live_url_parts&
+    operator=(const bt_common_lttng_live_url_parts_deleter&) = delete;
+
+    ~bt_common_lttng_live_url_parts_deleter()
+    {
+        bt_common_destroy_lttng_live_url_parts(_mObj);
+    }
+
+private:
+    bt_common_lttng_live_url_parts *_mObj;
+};
+
 enum lttng_live_stream_state
 {
     /* This stream won't have data until some known time in the future. */
@@ -39,38 +68,67 @@ enum lttng_live_stream_state
     LTTNG_LIVE_STREAM_EOF,
 };
 
+inline const char *format_as(const lttng_live_stream_state state) noexcept
+{
+    switch (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";
+    }
+
+    bt_common_abort();
+}
+
 /* Iterator over a live stream. */
 struct lttng_live_stream_iterator
 {
-    bt_logging_level log_level;
-    bt_self_component *self_comp;
+    using UP = std::unique_ptr<lttng_live_stream_iterator>;
+
+    explicit lttng_live_stream_iterator(const bt2c::Logger& parentLogger) :
+        logger {parentLogger, "PLUGIN/SRC.CTF.LTTNG-LIVE/STREAM-ITER"}
+    {
+    }
+
+    ~lttng_live_stream_iterator();
 
-    /* Owned by this. */
-    bt_stream *stream;
+    bt2c::Logger logger;
+
+    bt2::Stream::Shared stream;
 
     /* Weak reference. */
-    struct lttng_live_trace *trace;
+    struct lttng_live_trace *trace = nullptr;
 
     /*
      * Since only a single iterator per viewer connection, we have
      * only a single message iterator per stream.
      */
-    struct ctf_msg_iter *msg_iter;
+    ctf_msg_iter_up msg_iter;
 
-    uint64_t viewer_stream_id;
+    uint64_t viewer_stream_id = 0;
 
     struct
     {
-        bool is_set;
-        uint64_t value;
+        bool is_set = false;
+        uint64_t value = 0;
     } ctf_stream_class_id;
 
     /* base offset in current index. */
-    uint64_t base_offset;
+    uint64_t base_offset = 0;
     /* len to read in current index. */
-    uint64_t len;
+    uint64_t len = 0;
     /* offset in current index. */
-    uint64_t offset;
+    uint64_t offset = 0;
 
     /*
      * Clock Snapshot value of the last message iterator inactivity message
@@ -78,45 +136,46 @@ struct lttng_live_stream_iterator
      */
     struct
     {
-        bool is_set;
-        uint64_t value;
+        bool is_set = false;
+        uint64_t value = 0;
     } last_inactivity_ts;
 
     /*
      * Clock Snapshot value of the current message iterator inactivity
      * message we might want to send downstream.
      */
-    uint64_t current_inactivity_ts;
+    uint64_t current_inactivity_ts = 0;
 
-    enum lttng_live_stream_state state;
+    enum lttng_live_stream_state state = LTTNG_LIVE_STREAM_QUIESCENT;
 
-    /*
-     * The current message produced by this live stream iterator. Owned by
-     * this.
-     */
-    const bt_message *current_msg;
+    /* The current message produced by this live stream iterator. */
+    bt2::ConstMessage::Shared current_msg;
 
     /* Timestamp in nanoseconds of the current message (current_msg). */
-    int64_t current_msg_ts_ns;
+    int64_t current_msg_ts_ns = 0;
 
-    /* Owned by this. */
-    uint8_t *buf;
-    size_t buflen;
+    std::vector<uint8_t> buf;
 
-    /* Owned by this. */
-    GString *name;
+    std::string name;
 
-    bool has_stream_hung_up;
+    bool has_stream_hung_up = false;
 };
 
 struct lttng_live_metadata
 {
-    bt_logging_level log_level;
-    bt_self_component *self_comp;
+    using UP = std::unique_ptr<lttng_live_metadata>;
+
+    explicit lttng_live_metadata(const bt2c::Logger& parentLogger) :
+        logger {parentLogger, "PLUGIN/SRC.CTF.LTTNG-LIVE/METADATA"}
+    {
+    }
+
+    bt2c::Logger logger;
+
+    uint64_t stream_id = 0;
 
-    uint64_t stream_id;
     /* Weak reference. */
-    struct ctf_metadata_decoder *decoder;
+    ctf_metadata_decoder_up decoder;
 };
 
 enum lttng_live_metadata_stream_state
@@ -143,55 +202,65 @@ enum lttng_live_metadata_stream_state
 
 struct lttng_live_trace
 {
-    bt_logging_level log_level;
-    bt_self_component *self_comp;
+    using UP = std::unique_ptr<lttng_live_trace>;
+
+    explicit lttng_live_trace(const bt2c::Logger& parentLogger) :
+        logger {parentLogger, "PLUGIN/SRC.CTF.LTTNG-LIVE/TRACE"}
+    {
+    }
+
+    bt2c::Logger logger;
 
     /* Back reference to session. */
-    struct lttng_live_session *session;
+    struct lttng_live_session *session = nullptr;
 
     /* ctf trace ID within the session. */
-    uint64_t id;
+    uint64_t id = 0;
 
-    /* Owned by this. */
-    bt_trace *trace;
+    bt2::Trace::Shared trace;
 
-    /* Weak reference. */
-    bt_trace_class *trace_class;
+    bt2::TraceClass::Shared trace_class;
 
-    struct lttng_live_metadata *metadata;
+    lttng_live_metadata::UP metadata;
 
-    const bt_clock_class *clock_class;
+    const bt_clock_class *clock_class = nullptr;
 
-    /* Array of pointers to struct lttng_live_stream_iterator. */
-    /* Owned by this. */
-    GPtrArray *stream_iterators;
+    std::vector<lttng_live_stream_iterator::UP> stream_iterators;
 
-    enum lttng_live_metadata_stream_state metadata_stream_state;
+    enum lttng_live_metadata_stream_state metadata_stream_state =
+        LTTNG_LIVE_METADATA_STREAM_STATE_NEEDED;
 };
 
 struct lttng_live_session
 {
-    bt_logging_level log_level;
-    bt_self_component *self_comp;
+    using UP = std::unique_ptr<lttng_live_session>;
+
+    explicit lttng_live_session(const bt2c::Logger& parentLogger) :
+        logger {parentLogger, "PLUGIN/SRC.CTF.LTTNG-LIVE/SESSION"}
+    {
+    }
+
+    ~lttng_live_session();
+
+    bt2c::Logger logger;
+
+    bt_self_component *self_comp = nullptr;
 
     /* Weak reference. */
-    struct lttng_live_msg_iter *lttng_live_msg_iter;
+    struct lttng_live_msg_iter *lttng_live_msg_iter = nullptr;
 
-    /* Owned by this. */
-    GString *hostname;
+    std::string hostname;
 
-    /* Owned by this. */
-    GString *session_name;
+    std::string session_name;
 
-    uint64_t id;
+    uint64_t id = 0;
 
-    /* Array of pointers to struct lttng_live_trace. */
-    GPtrArray *traces;
+    std::vector<lttng_live_trace::UP> traces;
 
-    bool attached;
-    bool new_streams_needed;
-    bool lazy_stream_msg_init;
-    bool closed;
+    bool attached = false;
+    bool new_streams_needed = false;
+    bool lazy_stream_msg_init = false;
+    bool closed = false;
 };
 
 enum session_not_found_action
@@ -206,51 +275,66 @@ enum session_not_found_action
  */
 struct lttng_live_component
 {
-    bt_logging_level log_level;
+    using UP = std::unique_ptr<lttng_live_component>;
+
+    explicit lttng_live_component(bt2c::Logger loggerParam) noexcept :
+        logger {std::move(loggerParam)}
+    {
+    }
+
+    bt2c::Logger logger;
 
     /* Weak reference. */
-    bt_self_component *self_comp;
+    bt_self_component *self_comp = nullptr;
 
     struct
     {
-        GString *url;
-        enum session_not_found_action sess_not_found_act;
+        std::string url;
+        enum session_not_found_action sess_not_found_act = SESSION_NOT_FOUND_ACTION_CONTINUE;
     } params;
 
-    size_t max_query_size;
+    size_t max_query_size = 0;
 
     /*
      * Keeps track of whether the downstream component already has a
      * message iterator on this component.
      */
-    bool has_msg_iter;
+    bool has_msg_iter = false;
 };
 
 struct lttng_live_msg_iter
 {
-    bt_logging_level log_level;
-    bt_self_component *self_comp;
+    using UP = std::unique_ptr<lttng_live_msg_iter>;
+
+    explicit lttng_live_msg_iter(const bt2c::Logger& parentLogger) :
+        logger {parentLogger, "PLUGIN/SRC.CTF.LTTNG-LIVE/MSG-ITER"}
+    {
+    }
+
+    ~lttng_live_msg_iter();
+
+    bt2c::Logger logger;
+
+    bt_self_component *self_comp = nullptr;
 
     /* Weak reference. */
-    struct lttng_live_component *lttng_live_comp;
+    struct lttng_live_component *lttng_live_comp = nullptr;
 
     /* Weak reference. */
-    bt_self_message_iterator *self_msg_iter;
+    bt_self_message_iterator *self_msg_iter = nullptr;
 
-    /* Owned by this. */
-    struct live_viewer_connection *viewer_connection;
+    live_viewer_connection::UP viewer_connection;
 
-    /* Array of pointers to struct lttng_live_session. */
-    GPtrArray *sessions;
+    std::vector<lttng_live_session::UP> sessions;
 
     /* Number of live stream iterator this message iterator has.*/
-    uint64_t active_stream_iter;
+    uint64_t active_stream_iter = 0;
 
     /* Timestamp in nanosecond of the last message sent downstream. */
-    int64_t last_msg_ts_ns;
+    int64_t last_msg_ts_ns = 0;
 
     /* True if the iterator was interrupted. */
-    bool was_interrupted;
+    bool was_interrupted = false;
 };
 
 enum lttng_live_iterator_status
@@ -273,6 +357,37 @@ enum lttng_live_iterator_status
     LTTNG_LIVE_ITERATOR_STATUS_UNSUPPORTED = -4,
 };
 
+inline const char *format_as(const lttng_live_iterator_status status) noexcept
+{
+    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";
+    }
+
+    bt_common_abort();
+}
+
 bt_component_class_initialize_method_status
 lttng_live_component_init(bt_self_component_source *self_comp,
                           bt_self_component_source_configuration *config, const bt_value *params,
@@ -320,7 +435,7 @@ int lttng_live_add_session(struct lttng_live_msg_iter *lttng_live_msg_iter, uint
  * written to the file.
  */
 enum lttng_live_get_one_metadata_status
-lttng_live_get_one_metadata_packet(struct lttng_live_trace *trace, FILE *fp, size_t *reply_len);
+lttng_live_get_one_metadata_packet(struct lttng_live_trace *trace, std::vector<char>& buf);
 
 enum lttng_live_iterator_status
 lttng_live_get_next_index(struct lttng_live_msg_iter *lttng_live_msg_iter,
index bf9abae4297fc0549f3a0fd7b8211a7a5d20d6d0..926ace11ee35cc6ee7178c71b255c5804a99de86 100644 (file)
@@ -11,7 +11,9 @@
 
 #include <stdint.h>
 
-#include "compat/limits.h" /* IWYU pragma: keep  */
+#include "common/common.h"
+#include "compat/limits.h"                /* IWYU pragma: keep  */
+#include "cpp-common/vendor/fmt/format.h" /* IWYU pragma: keep */
 
 #define LTTNG_VIEWER_PATH_MAX      4096
 #define LTTNG_VIEWER_NAME_MAX      255
@@ -39,6 +41,40 @@ enum lttng_viewer_command
     LTTNG_VIEWER_DETACH_SESSION = 9,
 };
 
+inline const char *format_as(const lttng_viewer_command cmd) noexcept
+{
+    switch (cmd) {
+    case LTTNG_VIEWER_CONNECT:
+        return "CONNECT";
+
+    case LTTNG_VIEWER_LIST_SESSIONS:
+        return "LIST_SESSIONS";
+
+    case LTTNG_VIEWER_ATTACH_SESSION:
+        return "ATTACH_SESSION";
+
+    case LTTNG_VIEWER_GET_NEXT_INDEX:
+        return "GET_NEXT_INDEX";
+
+    case LTTNG_VIEWER_GET_PACKET:
+        return "GET_PACKET";
+
+    case LTTNG_VIEWER_GET_METADATA:
+        return "GET_METADATA";
+
+    case LTTNG_VIEWER_GET_NEW_STREAMS:
+        return "GET_NEW_STREAMS";
+
+    case LTTNG_VIEWER_CREATE_SESSION:
+        return "CREATE_SESSION";
+
+    case LTTNG_VIEWER_DETACH_SESSION:
+        return "DETACH_SESSION";
+    }
+
+    bt_common_abort();
+}
+
 enum lttng_viewer_attach_return_code
 {
     LTTNG_VIEWER_ATTACH_OK = 1,         /* The attach command succeeded. */
@@ -66,6 +102,31 @@ enum lttng_viewer_next_index_return_code
     LTTNG_VIEWER_INDEX_EOF = 6,      /* End of index file. */
 };
 
+inline const char *format_as(const lttng_viewer_next_index_return_code code) noexcept
+{
+    switch (code) {
+    case LTTNG_VIEWER_INDEX_OK:
+        return "INDEX_OK";
+
+    case LTTNG_VIEWER_INDEX_RETRY:
+        return "INDEX_RETRY";
+
+    case LTTNG_VIEWER_INDEX_HUP:
+        return "INDEX_HUP";
+
+    case LTTNG_VIEWER_INDEX_ERR:
+        return "INDEX_ERR";
+
+    case LTTNG_VIEWER_INDEX_INACTIVE:
+        return "INDEX_INACTIVE";
+
+    case LTTNG_VIEWER_INDEX_EOF:
+        return "INDEX_EOF";
+    }
+
+    bt_common_abort();
+}
+
 enum lttng_viewer_get_packet_return_code
 {
     LTTNG_VIEWER_GET_PACKET_OK = 1,
@@ -74,6 +135,25 @@ enum lttng_viewer_get_packet_return_code
     LTTNG_VIEWER_GET_PACKET_EOF = 4,
 };
 
+inline const char *format_as(const lttng_viewer_get_packet_return_code code) noexcept
+{
+    switch (code) {
+    case LTTNG_VIEWER_GET_PACKET_OK:
+        return "GET_PACKET_OK";
+
+    case LTTNG_VIEWER_GET_PACKET_RETRY:
+        return "GET_PACKET_RETRY";
+
+    case LTTNG_VIEWER_GET_PACKET_ERR:
+        return "GET_PACKET_ERR";
+
+    case LTTNG_VIEWER_GET_PACKET_EOF:
+        return "GET_PACKET_EOF";
+    }
+
+    bt_common_abort();
+};
+
 enum lttng_viewer_get_metadata_return_code
 {
     LTTNG_VIEWER_METADATA_OK = 1,
@@ -95,6 +175,19 @@ enum lttng_viewer_seek
     LTTNG_VIEWER_SEEK_LAST = 2,
 };
 
+inline const char *format_as(const lttng_viewer_seek seek) noexcept
+{
+    switch (seek) {
+    case LTTNG_VIEWER_SEEK_BEGINNING:
+        return "SEEK_BEGINNING";
+
+    case LTTNG_VIEWER_SEEK_LAST:
+        return "SEEK_LAST";
+    }
+
+    bt_common_abort();
+}
+
 enum lttng_viewer_new_streams_return_code
 {
     LTTNG_VIEWER_NEW_STREAMS_OK = 1,     /* If new streams are being sent. */
index b081d6395bf4342e9029396e19d1f5c2b60fef25..693042d7bf228be5acae70c22b82f85887c238f6 100644 (file)
@@ -6,22 +6,13 @@
  * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation
  */
 
-#include <glib.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <babeltrace2/babeltrace.h>
-
-#define BT_COMP_LOG_SELF_COMP self_comp
-#define BT_LOG_OUTPUT_LEVEL   log_level
-#define BT_LOG_TAG            "PLUGIN/SRC.CTF.LTTNG-LIVE/META"
-#include "logging/comp-logging.h"
-
 #include "compat/memstream.h"
+#include "cpp-common/bt2c/libc-up.hpp"
+#include "cpp-common/bt2s/make-unique.hpp"
 
-#include "../common/metadata/ctf-meta-configure-ir-trace.hpp"
-#include "../common/metadata/decoder.hpp"
+#include "../common/src/metadata/tsdl/ctf-meta-configure-ir-trace.hpp"
+#include "../common/src/metadata/tsdl/decoder.hpp"
+#include "lttng-live.hpp"
 #include "metadata.hpp"
 
 #define TSDL_MAGIC 0x75d11d57
@@ -41,13 +32,11 @@ struct packet_header
 } __attribute__((__packed__));
 
 static bool stream_classes_all_have_default_clock_class(bt_trace_class *tc,
-                                                        bt_logging_level log_level,
-                                                        bt_self_component *self_comp)
+                                                        const bt2c::Logger& logger)
 {
     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++) {
@@ -57,17 +46,15 @@ static bool stream_classes_all_have_default_clock_class(bt_trace_class *tc,
 
         cc = bt_stream_class_borrow_default_clock_class_const(sc);
         if (!cc) {
-            ret = false;
-            BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                      "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;
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(logger,
+                                         "Stream class doesn't have a default clock class: "
+                                         "sc-id={}, sc-name=\"{}\"",
+                                         bt_stream_class_get_id(sc), bt_stream_class_get_name(sc));
+            return false;
         }
     }
 
-end:
-    return ret;
+    return true;
 }
 /*
  * Iterate over the stream classes and returns the first clock class
@@ -87,30 +74,25 @@ static const bt_clock_class *borrow_any_clock_class(bt_trace_class *tc)
 
         cc = bt_stream_class_borrow_default_clock_class_const(sc);
         if (cc) {
-            goto end;
+            return cc;
         }
     }
-end:
-    BT_ASSERT_DBG(cc);
-    return cc;
+
+    bt_common_abort();
 }
 
 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;
-    size_t size, len_read = 0;
-    char *metadata_buf = NULL;
+    struct lttng_live_metadata *metadata = trace->metadata.get();
+    std::vector<char> metadataBuf;
     bool keep_receiving;
-    FILE *fp = NULL;
+    bt2c::FileUP fp;
     enum ctf_metadata_decoder_status decoder_status;
-    enum lttng_live_iterator_status status = LTTNG_LIVE_ITERATOR_STATUS_OK;
-    bt_logging_level log_level = trace->log_level;
-    bt_self_component *self_comp = trace->self_comp;
     enum lttng_live_get_one_metadata_status metadata_status;
 
-    BT_COMP_LOGD("Updating metadata for trace: session-id=%" PRIu64 ", trace-id=%" PRIu64,
-                 session->id, trace->id);
+    BT_CPPLOGD_SPEC(metadata->logger, "Updating metadata for trace: session-id={}, trace-id={}",
+                    session->id, trace->id);
 
     /* No metadata stream yet. */
     if (!metadata) {
@@ -120,40 +102,22 @@ enum lttng_live_iterator_status lttng_live_metadata_update(struct lttng_live_tra
              * metadata this indicates that we will never receive
              * any metadata.
              */
-            status = LTTNG_LIVE_ITERATOR_STATUS_END;
+            return LTTNG_LIVE_ITERATOR_STATUS_END;
         } else if (session->new_streams_needed) {
-            status = LTTNG_LIVE_ITERATOR_STATUS_AGAIN;
+            return LTTNG_LIVE_ITERATOR_STATUS_AGAIN;
         } else {
             session->new_streams_needed = true;
-            status = LTTNG_LIVE_ITERATOR_STATUS_CONTINUE;
+            return LTTNG_LIVE_ITERATOR_STATUS_CONTINUE;
         }
-        goto end;
     }
 
     if (trace->metadata_stream_state != LTTNG_LIVE_METADATA_STREAM_STATE_NEEDED) {
-        goto end;
-    }
-
-    /*
-     * Open a new write only file handle to populate the `metadata_buf`
-     * memory buffer so we can write in loop in it easily.
-     */
-    fp = bt_open_memstream(&metadata_buf, &size);
-    if (!fp) {
-        if (errno == EINTR && lttng_live_graph_is_canceled(session->lttng_live_msg_iter)) {
-            session->lttng_live_msg_iter->was_interrupted = true;
-            status = LTTNG_LIVE_ITERATOR_STATUS_AGAIN;
-        } else {
-            BT_COMP_LOGE_APPEND_CAUSE_ERRNO(self_comp, "Metadata open_memstream", ".");
-            status = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
-        }
-        goto end;
+        return LTTNG_LIVE_ITERATOR_STATUS_OK;
     }
 
     keep_receiving = true;
     /* Grab all available metadata. */
     while (keep_receiving) {
-        size_t reply_len = 0;
         /*
          * lttng_live_get_one_metadata_packet() asks the Relay Daemon
          * for new metadata. If new metadata is received, the function
@@ -166,19 +130,20 @@ enum lttng_live_iterator_status lttng_live_metadata_update(struct lttng_live_tra
          * If we receive an _ERROR status, it means there was a
          * networking, allocating, or some other unrecoverable error.
          */
-        metadata_status = lttng_live_get_one_metadata_packet(trace, fp, &reply_len);
+        metadata_status = lttng_live_get_one_metadata_packet(trace, metadataBuf);
 
         switch (metadata_status) {
         case LTTNG_LIVE_GET_ONE_METADATA_STATUS_OK:
-            len_read += reply_len;
             break;
         case LTTNG_LIVE_GET_ONE_METADATA_STATUS_END:
             keep_receiving = false;
             break;
         case LTTNG_LIVE_GET_ONE_METADATA_STATUS_CLOSED:
-            BT_COMP_LOGD("Metadata stream was closed by the Relay, the trace is no longer active: "
-                         "trace-id=%" PRIu64 ", metadata-stream-id=%" PRIu64,
-                         trace->id, metadata->stream_id);
+            BT_CPPLOGD_SPEC(
+                metadata->logger,
+                "Metadata stream was closed by the Relay, the trace is no longer active: "
+                "trace-id={}, metadata-stream-id={}",
+                trace->id, metadata->stream_id);
             /*
              * The stream was closed and we received everything
              * there was to receive for this metadata stream.
@@ -189,155 +154,103 @@ enum lttng_live_iterator_status lttng_live_metadata_update(struct lttng_live_tra
             trace->metadata_stream_state = LTTNG_LIVE_METADATA_STREAM_STATE_CLOSED;
             break;
         case LTTNG_LIVE_GET_ONE_METADATA_STATUS_ERROR:
-            BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                      "Error getting one trace metadata packet: "
-                                      "trace-id=%" PRIu64,
-                                      trace->id);
-            goto error;
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(metadata->logger,
+                                         "Error getting one trace metadata packet: trace-id={}",
+                                         trace->id);
+            return LTTNG_LIVE_ITERATOR_STATUS_ERROR;
         default:
             bt_common_abort();
         }
     }
 
-    /* The memory buffer `metadata_buf` contains all the metadata. */
-    if (bt_close_memstream(&metadata_buf, &size, fp)) {
-        BT_COMP_LOGW_ERRNO("Metadata bt_close_memstream", ".");
-    }
-
-    fp = NULL;
-
-    if (len_read == 0) {
+    if (metadataBuf.empty()) {
         if (!trace->trace) {
-            status = LTTNG_LIVE_ITERATOR_STATUS_AGAIN;
-            goto end;
+            return LTTNG_LIVE_ITERATOR_STATUS_AGAIN;
         }
 
         /* The relay sent zero bytes of metadata. */
         trace->metadata_stream_state = LTTNG_LIVE_METADATA_STREAM_STATE_NOT_NEEDED;
-        goto end;
+        return LTTNG_LIVE_ITERATOR_STATUS_OK;
     }
 
     /*
      * Open a new reading file handle on the `metadata_buf` and pass it to
      * the metadata decoder.
      */
-    fp = bt_fmemopen(metadata_buf, len_read, "rb");
+    fp.reset(bt_fmemopen(metadataBuf.data(), metadataBuf.size(), "rb"));
     if (!fp) {
         if (errno == EINTR && lttng_live_graph_is_canceled(session->lttng_live_msg_iter)) {
             session->lttng_live_msg_iter->was_interrupted = true;
-            status = LTTNG_LIVE_ITERATOR_STATUS_AGAIN;
+            return LTTNG_LIVE_ITERATOR_STATUS_AGAIN;
         } else {
-            BT_COMP_LOGE_APPEND_CAUSE_ERRNO(self_comp, "Cannot memory-open metadata buffer", ".");
-            status = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
+            BT_CPPLOGE_ERRNO_APPEND_CAUSE_SPEC(metadata->logger,
+                                               "Cannot memory-open metadata buffer", ".");
+            return LTTNG_LIVE_ITERATOR_STATUS_ERROR;
         }
-        goto end;
     }
 
     /*
      * The call to ctf_metadata_decoder_append_content() will append
      * new metadata to our current trace class.
      */
-    BT_COMP_LOGD("Appending new metadata to the ctf_trace class");
-    decoder_status = ctf_metadata_decoder_append_content(metadata->decoder, fp);
+    BT_CPPLOGD_SPEC(metadata->logger, "Appending new metadata to the ctf_trace class");
+    decoder_status = ctf_metadata_decoder_append_content(metadata->decoder.get(), fp.get());
     switch (decoder_status) {
     case CTF_METADATA_DECODER_STATUS_OK:
         if (!trace->trace_class) {
             struct ctf_trace_class *tc =
-                ctf_metadata_decoder_borrow_ctf_trace_class(metadata->decoder);
+                ctf_metadata_decoder_borrow_ctf_trace_class(metadata->decoder.get());
 
-            trace->trace_class = ctf_metadata_decoder_get_ir_trace_class(metadata->decoder);
-            trace->trace = bt_trace_create(trace->trace_class);
+            trace->trace_class = ctf_metadata_decoder_get_ir_trace_class(metadata->decoder.get());
+            trace->trace = trace->trace_class->instantiate();
             if (!trace->trace) {
-                BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to create bt_trace");
-                goto error;
-            }
-            if (ctf_trace_class_configure_ir_trace(tc, trace->trace)) {
-                BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to configure ctf trace class");
-                goto error;
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(metadata->logger, "Failed to create bt_trace");
+                return LTTNG_LIVE_ITERATOR_STATUS_ERROR;
             }
-            if (!stream_classes_all_have_default_clock_class(trace->trace_class, log_level,
-                                                             self_comp)) {
+
+            ctf_trace_class_configure_ir_trace(tc, *trace->trace);
+
+            if (!stream_classes_all_have_default_clock_class(trace->trace_class->libObjPtr(),
+                                                             metadata->logger)) {
                 /* Error logged in function. */
-                goto error;
+                return LTTNG_LIVE_ITERATOR_STATUS_ERROR;
             }
-            trace->clock_class = borrow_any_clock_class(trace->trace_class);
+            trace->clock_class = borrow_any_clock_class(trace->trace_class->libObjPtr());
         }
 
         /* The metadata was updated successfully. */
         trace->metadata_stream_state = LTTNG_LIVE_METADATA_STREAM_STATE_NOT_NEEDED;
 
-        break;
+        return LTTNG_LIVE_ITERATOR_STATUS_OK;
     default:
-        goto error;
+        return LTTNG_LIVE_ITERATOR_STATUS_ERROR;
     }
-
-    goto end;
-
-error:
-    status = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
-end:
-    if (fp) {
-        int closeret;
-
-        closeret = fclose(fp);
-        if (closeret) {
-            BT_COMP_LOGW_ERRNO("Error on fclose", ".");
-        }
-    }
-    free(metadata_buf);
-    return status;
 }
 
 int lttng_live_metadata_create_stream(struct lttng_live_session *session, uint64_t ctf_trace_id,
                                       uint64_t stream_id)
 {
-    bt_self_component *self_comp = session->self_comp;
-    bt_logging_level log_level = session->log_level;
-    struct lttng_live_metadata *metadata = NULL;
     struct lttng_live_trace *trace;
 
-    ctf_metadata_decoder_config cfg {};
-    cfg.log_level = session->log_level;
+    ctf_metadata_decoder_config cfg {session->logger};
     cfg.self_comp = session->self_comp;
-    cfg.clock_class_offset_s = 0;
-    cfg.clock_class_offset_ns = 0;
     cfg.create_trace_class = true;
 
-    metadata = g_new0(struct lttng_live_metadata, 1);
-    if (!metadata) {
-        return -1;
-    }
-    metadata->log_level = session->log_level;
-    metadata->self_comp = session->self_comp;
+    auto metadata = bt2s::make_unique<lttng_live_metadata>(session->logger);
     metadata->stream_id = stream_id;
 
     metadata->decoder = ctf_metadata_decoder_create(&cfg);
     if (!metadata->decoder) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to create CTF metadata decoder");
-        goto error;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(session->logger, "Failed to create CTF metadata decoder");
+        return -1;
     }
+
     trace = lttng_live_session_borrow_or_create_trace_by_id(session, ctf_trace_id);
     if (!trace) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to borrow trace");
-        goto error;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(session->logger, "Failed to borrow trace");
+        return -1;
     }
-    trace->metadata = metadata;
-    return 0;
 
-error:
-    ctf_metadata_decoder_destroy(metadata->decoder);
-    g_free(metadata);
-    return -1;
-}
-
-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);
+    trace->metadata = std::move(metadata);
+    return 0;
 }
index 49596c3b51234f2acd63ea7636125461fcf91eec..7c2d7659d023724ee388e603cee1dc7feb78aabf 100644 (file)
@@ -16,6 +16,4 @@ int lttng_live_metadata_create_stream(struct lttng_live_session *session, uint64
 
 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 */
index 5ea98cdda21d4c62a1116dac32cc9e29218f06f8..46cfd2c4378a21298f697e1eb695d1d93b5a1de7 100644 (file)
 
 #include <babeltrace2/babeltrace.h>
 
-#define BT_COMP_LOG_SELF_COMP (viewer_connection->self_comp)
-#define BT_LOG_OUTPUT_LEVEL   ((enum bt_log_level) viewer_connection->log_level)
-#define BT_LOG_TAG            "PLUGIN/SRC.CTF.LTTNG-LIVE/VIEWER"
-#include "logging/comp-logging.h"
-
 #include "common/common.h"
 #include "compat/endian.h" /* IWYU pragma: keep  */
+#include "cpp-common/bt2s/make-unique.hpp"
 
 #include "data-stream.hpp"
 #include "lttng-live.hpp"
 #include "metadata.hpp"
 #include "viewer-connection.hpp"
 
-#define viewer_handle_send_recv_status(_self_comp, _self_comp_class, _status, _action, _msg_str)   \
+#define viewer_handle_send_recv_status(_status, _action, _msg_str)                                 \
     do {                                                                                           \
         switch (_status) {                                                                         \
         case LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED:                                                 \
             break;                                                                                 \
         case LTTNG_LIVE_VIEWER_STATUS_ERROR:                                                       \
-            BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(_self_comp, _self_comp_class,                  \
-                                                    "Error " _action " " _msg_str);                \
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger,                                \
+                                         "Error " _action " " _msg_str);                           \
             break;                                                                                 \
         default:                                                                                   \
             bt_common_abort();                                                                     \
         }                                                                                          \
     } while (0)
 
-#define viewer_handle_send_status(_self_comp, _self_comp_class, _status, _msg_str)                 \
-    viewer_handle_send_recv_status(_self_comp, _self_comp_class, _status, "sending", _msg_str)
+#define viewer_handle_send_status(_status, _msg_str)                                               \
+    viewer_handle_send_recv_status(_status, "sending", _msg_str)
 
-#define viewer_handle_recv_status(_self_comp, _self_comp_class, _status, _msg_str)                 \
-    viewer_handle_send_recv_status(_self_comp, _self_comp_class, _status, "receiving", _msg_str)
+#define viewer_handle_recv_status(_status, _msg_str)                                               \
+    viewer_handle_send_recv_status(_status, "receiving", _msg_str)
 
-#define LTTNG_LIVE_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE_ERRNO(_self_comp, _self_comp_class, _msg,  \
-                                                              _fmt, ...)                           \
+#define LTTNG_LIVE_CPPLOGE_APPEND_CAUSE_ERRNO(_msg, _fmt, ...)                                     \
     do {                                                                                           \
-        BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(_self_comp, _self_comp_class, _msg ": %s" _fmt,    \
-                                                bt_socket_errormsg(), ##__VA_ARGS__);              \
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger, _msg ": {}" _fmt,                  \
+                                     bt_socket_errormsg(), ##__VA_ARGS__);                         \
     } while (0)
 
-static const char *lttng_viewer_command_string(enum lttng_viewer_command cmd)
-{
-    switch (cmd) {
-    case LTTNG_VIEWER_CONNECT:
-        return "CONNECT";
-    case LTTNG_VIEWER_LIST_SESSIONS:
-        return "LIST_SESSIONS";
-    case LTTNG_VIEWER_ATTACH_SESSION:
-        return "ATTACH_SESSION";
-    case LTTNG_VIEWER_GET_NEXT_INDEX:
-        return "GET_NEXT_INDEX";
-    case LTTNG_VIEWER_GET_PACKET:
-        return "GET_PACKET";
-    case LTTNG_VIEWER_GET_METADATA:
-        return "GET_METADATA";
-    case LTTNG_VIEWER_GET_NEW_STREAMS:
-        return "GET_NEW_STREAMS";
-    case LTTNG_VIEWER_CREATE_SESSION:
-        return "CREATE_SESSION";
-    case LTTNG_VIEWER_DETACH_SESSION:
-        return "DETACH_SESSION";
-    }
-
-    bt_common_abort();
-}
-
-static const char *
-lttng_viewer_next_index_return_code_string(enum lttng_viewer_next_index_return_code code)
-{
-    switch (code) {
-    case LTTNG_VIEWER_INDEX_OK:
-        return "INDEX_OK";
-    case LTTNG_VIEWER_INDEX_RETRY:
-        return "INDEX_RETRY";
-    case LTTNG_VIEWER_INDEX_HUP:
-        return "INDEX_HUP";
-    case LTTNG_VIEWER_INDEX_ERR:
-        return "INDEX_ERR";
-    case LTTNG_VIEWER_INDEX_INACTIVE:
-        return "INDEX_INACTIVE";
-    case LTTNG_VIEWER_INDEX_EOF:
-        return "INDEX_EOF";
-    }
-
-    bt_common_abort();
-}
-
-static const char *lttng_viewer_next_index_return_code_string(uint32_t code)
-{
-    return lttng_viewer_next_index_return_code_string((lttng_viewer_next_index_return_code) code);
-}
-
-static const char *
-lttng_viewer_get_packet_return_code_string(enum lttng_viewer_get_packet_return_code code)
-{
-    switch (code) {
-    case LTTNG_VIEWER_GET_PACKET_OK:
-        return "GET_PACKET_OK";
-    case LTTNG_VIEWER_GET_PACKET_RETRY:
-        return "GET_PACKET_RETRY";
-    case LTTNG_VIEWER_GET_PACKET_ERR:
-        return "GET_PACKET_ERR";
-    case LTTNG_VIEWER_GET_PACKET_EOF:
-        return "GET_PACKET_EOF";
-    }
-
-    bt_common_abort();
-};
-
-static const char *lttng_viewer_get_packet_return_code_string(uint32_t code)
-{
-    return lttng_viewer_get_packet_return_code_string((lttng_viewer_get_packet_return_code) code);
-}
-
-static const char *lttng_viewer_seek_string(enum lttng_viewer_seek seek)
-{
-    switch (seek) {
-    case LTTNG_VIEWER_SEEK_BEGINNING:
-        return "SEEK_BEGINNING";
-    case LTTNG_VIEWER_SEEK_LAST:
-        return "SEEK_LAST";
-    }
-
-    bt_common_abort();
-}
-
 static inline enum lttng_live_iterator_status
 viewer_status_to_live_iterator_status(enum lttng_live_viewer_status viewer_status)
 {
@@ -170,12 +79,14 @@ viewer_status_to_ctf_msg_iter_medium_status(enum lttng_live_viewer_status viewer
 
 static inline void viewer_connection_close_socket(struct live_viewer_connection *viewer_connection)
 {
-    bt_self_component_class *self_comp_class = viewer_connection->self_comp_class;
-    bt_self_component *self_comp = viewer_connection->self_comp;
+    if (viewer_connection->control_sock == BT_INVALID_SOCKET) {
+        return;
+    }
+
     int ret = bt_socket_close(viewer_connection->control_sock);
     if (ret == -1) {
-        BT_COMP_OR_COMP_CLASS_LOGW_ERRNO(self_comp, self_comp_class,
-                                         "Error closing viewer connection socket: ", ".");
+        BT_CPPLOGW_ERRNO_SPEC(viewer_connection->logger,
+                              "Error closing viewer connection socket: ", ".");
     }
 
     viewer_connection->control_sock = BT_INVALID_SOCKET;
@@ -191,11 +102,8 @@ static enum lttng_live_viewer_status
 lttng_live_recv(struct live_viewer_connection *viewer_connection, void *buf, size_t len)
 {
     ssize_t received;
-    bt_self_component_class *self_comp_class = viewer_connection->self_comp_class;
-    bt_self_component *self_comp = viewer_connection->self_comp;
     size_t total_received = 0, to_receive = len;
     struct lttng_live_msg_iter *lttng_live_msg_iter = viewer_connection->lttng_live_msg_iter;
-    enum lttng_live_viewer_status status;
     BT_SOCKET sock = viewer_connection->control_sock;
 
     /*
@@ -211,9 +119,8 @@ lttng_live_recv(struct live_viewer_connection *viewer_connection, void *buf, siz
                      * SIGINT and the graph is being torn
                      * down.
                      */
-                    status = LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED;
                     lttng_live_msg_iter->was_interrupted = true;
-                    goto end;
+                    return LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED;
                 } else {
                     /*
                      * A signal was received, but the graph
@@ -226,12 +133,10 @@ lttng_live_recv(struct live_viewer_connection *viewer_connection, void *buf, siz
                  * For any other types of socket error, close
                  * the socket and return an error.
                  */
-                LTTNG_LIVE_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE_ERRNO(
-                    self_comp, self_comp_class, "Error receiving from Relay", ".");
+                LTTNG_LIVE_CPPLOGE_APPEND_CAUSE_ERRNO("Error receiving from Relay", ".");
 
                 viewer_connection_close_socket(viewer_connection);
-                status = LTTNG_LIVE_VIEWER_STATUS_ERROR;
-                goto end;
+                return LTTNG_LIVE_VIEWER_STATUS_ERROR;
             }
         } else if (received == 0) {
             /*
@@ -241,11 +146,10 @@ lttng_live_recv(struct live_viewer_connection *viewer_connection, void *buf, siz
              * a message from it, it means something when wrong.
              * Close the socket and return an error.
              */
-            BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
-                                                    "Remote side has closed connection");
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger,
+                                         "Remote side has closed connection");
             viewer_connection_close_socket(viewer_connection);
-            status = LTTNG_LIVE_VIEWER_STATUS_ERROR;
-            goto end;
+            return LTTNG_LIVE_VIEWER_STATUS_ERROR;
         }
 
         BT_ASSERT(received <= to_receive);
@@ -255,10 +159,7 @@ lttng_live_recv(struct live_viewer_connection *viewer_connection, void *buf, siz
     } while (to_receive > 0);
 
     BT_ASSERT(total_received == len);
-    status = LTTNG_LIVE_VIEWER_STATUS_OK;
-
-end:
-    return status;
+    return LTTNG_LIVE_VIEWER_STATUS_OK;
 }
 
 /*
@@ -270,9 +171,6 @@ end:
 static enum lttng_live_viewer_status
 lttng_live_send(struct live_viewer_connection *viewer_connection, const void *buf, size_t len)
 {
-    enum lttng_live_viewer_status status;
-    bt_self_component_class *self_comp_class = viewer_connection->self_comp_class;
-    bt_self_component *self_comp = viewer_connection->self_comp;
     struct lttng_live_msg_iter *lttng_live_msg_iter = viewer_connection->lttng_live_msg_iter;
     BT_SOCKET sock = viewer_connection->control_sock;
     size_t to_send = len;
@@ -287,9 +185,8 @@ lttng_live_send(struct live_viewer_connection *viewer_connection, const void *bu
                      * This interruption was a SIGINT and
                      * the graph is being teared down.
                      */
-                    status = LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED;
                     lttng_live_msg_iter->was_interrupted = true;
-                    goto end;
+                    return LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED;
                 } else {
                     /*
                      * A signal was received, but the graph
@@ -302,12 +199,10 @@ lttng_live_send(struct live_viewer_connection *viewer_connection, const void *bu
                  * For any other types of socket error, close
                  * the socket and return an error.
                  */
-                LTTNG_LIVE_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE_ERRNO(
-                    self_comp, self_comp_class, "Error sending to Relay", ".");
+                LTTNG_LIVE_CPPLOGE_APPEND_CAUSE_ERRNO("Error sending to Relay", ".");
 
                 viewer_connection_close_socket(viewer_connection);
-                status = LTTNG_LIVE_VIEWER_STATUS_ERROR;
-                goto end;
+                return LTTNG_LIVE_VIEWER_STATUS_ERROR;
             }
         }
 
@@ -318,35 +213,30 @@ lttng_live_send(struct live_viewer_connection *viewer_connection, const void *bu
     } while (to_send > 0);
 
     BT_ASSERT(total_sent == len);
-    status = LTTNG_LIVE_VIEWER_STATUS_OK;
-
-end:
-    return status;
+    return LTTNG_LIVE_VIEWER_STATUS_OK;
 }
 
 static int parse_url(struct live_viewer_connection *viewer_connection)
 {
     char error_buf[256] = {0};
-    bt_self_component *self_comp = viewer_connection->self_comp;
-    bt_self_component_class *self_comp_class = viewer_connection->self_comp_class;
     struct bt_common_lttng_live_url_parts lttng_live_url_parts = {};
-    int ret = -1;
-    const char *path = viewer_connection->url->str;
+    bt_common_lttng_live_url_parts_deleter partsDeleter {lttng_live_url_parts};
 
-    if (!path) {
-        goto end;
+    if (viewer_connection->url.empty()) {
+        return -1;
     }
 
-    lttng_live_url_parts = bt_common_parse_lttng_live_url(path, error_buf, sizeof(error_buf));
+    lttng_live_url_parts = bt_common_parse_lttng_live_url(viewer_connection->url.c_str(), error_buf,
+                                                          sizeof(error_buf));
     if (!lttng_live_url_parts.proto) {
-        BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
-                                                "Invalid LTTng live URL format: %s", error_buf);
-        goto end;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger, "Invalid LTTng live URL format: {}",
+                                     error_buf);
+        return -1;
     }
-    viewer_connection->proto = lttng_live_url_parts.proto;
+    viewer_connection->proto.reset(lttng_live_url_parts.proto);
     lttng_live_url_parts.proto = NULL;
 
-    viewer_connection->relay_hostname = lttng_live_url_parts.hostname;
+    viewer_connection->relay_hostname.reset(lttng_live_url_parts.hostname);
     lttng_live_url_parts.hostname = NULL;
 
     if (lttng_live_url_parts.port >= 0) {
@@ -355,19 +245,15 @@ static int parse_url(struct live_viewer_connection *viewer_connection)
         viewer_connection->port = LTTNG_DEFAULT_NETWORK_VIEWER_PORT;
     }
 
-    viewer_connection->target_hostname = lttng_live_url_parts.target_hostname;
+    viewer_connection->target_hostname.reset(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;
+        viewer_connection->session_name.reset(lttng_live_url_parts.session_name);
         lttng_live_url_parts.session_name = NULL;
     }
 
-    ret = 0;
-
-end:
-    bt_common_destroy_lttng_live_url_parts(&lttng_live_url_parts);
-    return ret;
+    return 0;
 }
 
 static enum lttng_live_viewer_status
@@ -376,15 +262,12 @@ lttng_live_handshake(struct live_viewer_connection *viewer_connection)
     struct lttng_viewer_cmd cmd;
     struct lttng_viewer_connect connect;
     enum lttng_live_viewer_status status;
-    bt_self_component_class *self_comp_class = viewer_connection->self_comp_class;
-    bt_self_component *self_comp = viewer_connection->self_comp;
     const size_t cmd_buf_len = sizeof(cmd) + sizeof(connect);
     char cmd_buf[cmd_buf_len];
 
-    BT_COMP_OR_COMP_CLASS_LOGD(
-        self_comp, self_comp_class,
-        "Handshaking with the relay daemon: cmd=%s, major-version=%u, minor-version=%u",
-        lttng_viewer_command_string(LTTNG_VIEWER_CONNECT), LTTNG_LIVE_MAJOR, LTTNG_LIVE_MINOR);
+    BT_CPPLOGD_SPEC(viewer_connection->logger,
+                    "Handshaking with the relay daemon: cmd={}, major-version={}, minor-version={}",
+                    LTTNG_VIEWER_CONNECT, LTTNG_LIVE_MAJOR, LTTNG_LIVE_MINOR);
 
     cmd.cmd = htobe32(LTTNG_VIEWER_CONNECT);
     cmd.data_size = htobe64((uint64_t) sizeof(connect));
@@ -405,26 +288,25 @@ lttng_live_handshake(struct live_viewer_connection *viewer_connection)
 
     status = lttng_live_send(viewer_connection, &cmd_buf, cmd_buf_len);
     if (status != LTTNG_LIVE_VIEWER_STATUS_OK) {
-        viewer_handle_send_status(self_comp, self_comp_class, status, "viewer connect command");
-        goto end;
+        viewer_handle_send_status(status, "viewer connect command");
+        return status;
     }
 
     status = lttng_live_recv(viewer_connection, &connect, sizeof(connect));
     if (status != LTTNG_LIVE_VIEWER_STATUS_OK) {
-        viewer_handle_recv_status(self_comp, self_comp_class, status, "viewer connect reply");
-        goto end;
+        viewer_handle_recv_status(status, "viewer connect reply");
+        return status;
     }
 
-    BT_COMP_OR_COMP_CLASS_LOGI(self_comp, self_comp_class, "Received viewer session ID : %" PRIu64,
-                               (uint64_t) be64toh(connect.viewer_session_id));
-    BT_COMP_OR_COMP_CLASS_LOGI(self_comp, self_comp_class, "Relayd version : %u.%u",
-                               be32toh(connect.major), be32toh(connect.minor));
+    BT_CPPLOGI_SPEC(viewer_connection->logger, "Received viewer session ID : {}",
+                    (uint64_t) be64toh(connect.viewer_session_id));
+    BT_CPPLOGI_SPEC(viewer_connection->logger, "Relayd version : {}.{}", be32toh(connect.major),
+                    be32toh(connect.minor));
 
     if (LTTNG_LIVE_MAJOR != be32toh(connect.major)) {
-        BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
-                                                "Incompatible lttng-relayd protocol");
-        status = LTTNG_LIVE_VIEWER_STATUS_ERROR;
-        goto end;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger,
+                                     "Incompatible lttng-relayd protocol");
+        return LTTNG_LIVE_VIEWER_STATUS_ERROR;
     }
     /* Use the smallest protocol version implemented. */
     if (LTTNG_LIVE_MINOR > be32toh(connect.minor)) {
@@ -434,12 +316,7 @@ lttng_live_handshake(struct live_viewer_connection *viewer_connection)
     }
     viewer_connection->major = LTTNG_LIVE_MAJOR;
 
-    status = LTTNG_LIVE_VIEWER_STATUS_OK;
-
-    goto end;
-
-end:
-    return status;
+    return LTTNG_LIVE_VIEWER_STATUS_OK;
 }
 
 static enum lttng_live_viewer_status
@@ -448,19 +325,15 @@ lttng_live_connect_viewer(struct live_viewer_connection *viewer_connection)
     struct hostent *host;
     struct sockaddr_in server_addr;
     enum lttng_live_viewer_status status;
-    bt_self_component_class *self_comp_class = viewer_connection->self_comp_class;
-    bt_self_component *self_comp = viewer_connection->self_comp;
 
     if (parse_url(viewer_connection)) {
-        BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class, "Failed to parse URL");
-        status = LTTNG_LIVE_VIEWER_STATUS_ERROR;
-        goto error;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger, "Failed to parse URL");
+        return LTTNG_LIVE_VIEWER_STATUS_ERROR;
     }
 
-    BT_COMP_OR_COMP_CLASS_LOGD(
-        self_comp, self_comp_class,
-        "Connecting to hostname : %s, port : %d, "
-        "target hostname : %s, session name : %s, proto : %s",
+    BT_CPPLOGD_SPEC(
+        viewer_connection->logger,
+        "Connecting to hostname : {}, port : {}, target hostname : {}, session name : {}, proto : {}",
         viewer_connection->relay_hostname->str, viewer_connection->port,
         !viewer_connection->target_hostname ? "<none>" : viewer_connection->target_hostname->str,
         !viewer_connection->session_name ? "<none>" : viewer_connection->session_name->str,
@@ -468,18 +341,16 @@ lttng_live_connect_viewer(struct live_viewer_connection *viewer_connection)
 
     host = gethostbyname(viewer_connection->relay_hostname->str);
     if (!host) {
-        BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
-                                                "Cannot lookup hostname: hostname=\"%s\"",
-                                                viewer_connection->relay_hostname->str);
-        status = LTTNG_LIVE_VIEWER_STATUS_ERROR;
-        goto error;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger,
+                                     "Cannot lookup hostname: hostname=\"{}\"",
+                                     viewer_connection->relay_hostname->str);
+        return LTTNG_LIVE_VIEWER_STATUS_ERROR;
     }
 
     if ((viewer_connection->control_sock = socket(AF_INET, SOCK_STREAM, 0)) == BT_INVALID_SOCKET) {
-        BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
-                                                "Socket creation failed: %s", bt_socket_errormsg());
-        status = LTTNG_LIVE_VIEWER_STATUS_ERROR;
-        goto error;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger, "Socket creation failed: {}",
+                                     bt_socket_errormsg());
+        return LTTNG_LIVE_VIEWER_STATUS_ERROR;
     }
 
     server_addr.sin_family = AF_INET;
@@ -489,10 +360,10 @@ lttng_live_connect_viewer(struct live_viewer_connection *viewer_connection)
 
     if (connect(viewer_connection->control_sock, (struct sockaddr *) &server_addr,
                 sizeof(struct sockaddr)) == BT_SOCKET_ERROR) {
-        BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class, "Connection failed: %s",
-                                                bt_socket_errormsg());
-        status = LTTNG_LIVE_VIEWER_STATUS_ERROR;
-        goto error;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger, "Connection failed: {}",
+                                     bt_socket_errormsg());
+        viewer_connection_close_socket(viewer_connection);
+        return LTTNG_LIVE_VIEWER_STATUS_ERROR;
     }
 
     status = lttng_live_handshake(viewer_connection);
@@ -502,130 +373,93 @@ lttng_live_connect_viewer(struct live_viewer_connection *viewer_connection)
      * interruption.
      */
     if (status == LTTNG_LIVE_VIEWER_STATUS_ERROR) {
-        BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
-                                                "Viewer handshake failed");
-        goto error;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger, "Viewer handshake failed");
+        viewer_connection_close_socket(viewer_connection);
+        return LTTNG_LIVE_VIEWER_STATUS_ERROR;
     } else if (status == LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED) {
-        goto end;
-    }
-
-    goto end;
-
-error:
-    if (viewer_connection->control_sock != BT_INVALID_SOCKET) {
-        if (bt_socket_close(viewer_connection->control_sock) == BT_SOCKET_ERROR) {
-            BT_COMP_OR_COMP_CLASS_LOGW(self_comp, self_comp_class, "Error closing socket: %s.",
-                                       bt_socket_errormsg());
-        }
+        return LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED;
     }
-    viewer_connection->control_sock = BT_INVALID_SOCKET;
-end:
-    return status;
-}
 
-static void lttng_live_disconnect_viewer(struct live_viewer_connection *viewer_connection)
-{
-    bt_self_component_class *self_comp_class = viewer_connection->self_comp_class;
-    bt_self_component *self_comp = viewer_connection->self_comp;
-
-    if (viewer_connection->control_sock == BT_INVALID_SOCKET) {
-        return;
-    }
-    if (bt_socket_close(viewer_connection->control_sock) == BT_SOCKET_ERROR) {
-        BT_COMP_OR_COMP_CLASS_LOGW(self_comp, self_comp_class, "Error closing socket: %s",
-                                   bt_socket_errormsg());
-        viewer_connection->control_sock = BT_INVALID_SOCKET;
-    }
+    return LTTNG_LIVE_VIEWER_STATUS_OK;
 }
 
-static int list_update_session(bt_value *results, const struct lttng_viewer_session *session,
-                               bool *_found, struct live_viewer_connection *viewer_connection)
+static int list_update_session(const bt2::ArrayValue results,
+                               const struct lttng_viewer_session *session, bool *_found,
+                               struct live_viewer_connection *viewer_connection)
 {
-    bt_self_component_class *self_comp_class = viewer_connection->self_comp_class;
-    bt_self_component *self_comp = viewer_connection->self_comp;
-    int ret = 0;
-    uint64_t i, len;
-    bt_value *map = NULL;
-    bt_value *hostname = NULL;
-    bt_value *session_name = NULL;
-    bt_value *btval = NULL;
     bool found = false;
 
-    len = bt_value_array_get_length(results);
-    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, i);
-        hostname = bt_value_map_borrow_entry_value(map, "target-hostname");
-        if (!hostname) {
-            BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
-                                                    "Error borrowing \"target-hostname\" entry.");
-            ret = -1;
-            goto end;
+    for (const auto value : results) {
+        const auto map = value.asMap();
+        const auto hostnameVal = map["target-hostname"];
+
+        if (!hostnameVal) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger,
+                                         "Error borrowing \"target-hostname\" entry.");
+            return -1;
         }
-        session_name = bt_value_map_borrow_entry_value(map, "session-name");
-        if (!session_name) {
-            BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
-                                                    "Error borrowing \"session-name\" entry.");
-            ret = -1;
-            goto end;
+
+        const auto sessionNameVal = map["session-name"];
+
+        if (!sessionNameVal) {
+            BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger,
+                                         "Error borrowing \"session-name\" entry.");
+            return -1;
         }
-        hostname_str = bt_value_string_get(hostname);
-        session_name_str = bt_value_string_get(session_name);
+
+        const auto hostname_str = hostnameVal->asString().value();
+        const auto session_name_str = sessionNameVal->asString().value();
 
         if (strcmp(session->hostname, hostname_str) == 0 &&
             strcmp(session->session_name, session_name_str) == 0) {
-            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_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
-                                                        "Error borrowing \"stream-count\" entry.");
-                ret = -1;
-                goto end;
+            const auto streamCountVal = map["stream-count"];
+
+            if (!streamCountVal) {
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger,
+                                             "Error borrowing \"stream-count\" entry.");
+                return -1;
             }
-            val = bt_value_integer_unsigned_get(btval);
+
+            auto val = streamCountVal->asUnsignedInteger().value();
+
             /* sum */
             val += streams;
-            bt_value_integer_unsigned_set(btval, val);
-
-            btval = bt_value_map_borrow_entry_value(map, "client-count");
-            if (!btval) {
-                BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
-                                                        "Error borrowing \"client-count\" entry.");
-                ret = -1;
-                goto end;
+            streamCountVal->asUnsignedInteger().value(val);
+
+            const auto clientCountVal = map["client-count"];
+
+            if (!clientCountVal) {
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger,
+                                             "Error borrowing \"client-count\" entry.");
+                return -1;
             }
-            val = bt_value_integer_unsigned_get(btval);
+
+            val = clientCountVal->asUnsignedInteger().value();
+
             /* max */
-            val = bt_max_t(int64_t, clients, val);
-            bt_value_integer_unsigned_set(btval, val);
+            val = std::max<uint64_t>(clients, val);
+            clientCountVal->asUnsignedInteger().value(val);
         }
 
         if (found) {
             break;
         }
     }
-end:
+
     *_found = found;
-    return ret;
+    return 0;
 }
 
-static int list_append_session(bt_value *results, GString *base_url,
+static int list_append_session(const bt2::ArrayValue results, const std::string& base_url,
                                const struct lttng_viewer_session *session,
                                struct live_viewer_connection *viewer_connection)
 {
     int ret = 0;
-    bt_self_component_class *self_comp_class = viewer_connection->self_comp_class;
-    bt_value_map_insert_entry_status insert_status;
-    bt_value_array_append_element_status append_status;
-    bt_value *map = NULL;
-    GString *url = NULL;
     bool found = false;
 
     /*
@@ -634,60 +468,34 @@ static int list_append_session(bt_value *results, GString *base_url,
      */
     ret = list_update_session(results, session, &found, viewer_connection);
     if (ret || found) {
-        goto end;
+        return ret;
     }
 
-    map = bt_value_map_create();
-    if (!map) {
-        BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, "Error creating map value.");
-        ret = -1;
-        goto end;
-    }
+    const auto map = bt2::MapValue::create();
 
-    if (base_url->len < 1) {
-        BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, "Error: base_url length smaller than 1.");
-        ret = -1;
-        goto end;
+    if (base_url.empty()) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger, "Error: base_url empty.");
+        return -1;
     }
+
     /*
      * 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);
-
-    insert_status = bt_value_map_insert_string_entry(map, "url", url->str);
-    if (insert_status != BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK) {
-        BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, "Error inserting \"url\" entry.");
-        ret = -1;
-        goto end;
-    }
+    map->insert("url",
+                fmt::format("{}/host/{}/{}", base_url, session->hostname, session->session_name));
 
     /*
      * key = "target-hostname",
      * value = <string>,
      */
-    insert_status = bt_value_map_insert_string_entry(map, "target-hostname", session->hostname);
-    if (insert_status != BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK) {
-        BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class,
-                                        "Error inserting \"target-hostname\" entry.");
-        ret = -1;
-        goto end;
-    }
+    map->insert("target-hostname", session->hostname);
 
     /*
      * key = "session-name",
      * value = <string>,
      */
-    insert_status = bt_value_map_insert_string_entry(map, "session-name", session->session_name);
-    if (insert_status != BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK) {
-        BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, "Error inserting \"session-name\" entry.");
-        ret = -1;
-        goto end;
-    }
+    map->insert("session-name", session->session_name);
 
     /*
      * key = "timer-us",
@@ -696,12 +504,7 @@ static int list_append_session(bt_value *results, GString *base_url,
     {
         uint32_t live_timer = be32toh(session->live_timer);
 
-        insert_status = bt_value_map_insert_unsigned_integer_entry(map, "timer-us", live_timer);
-        if (insert_status != BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK) {
-            BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, "Error inserting \"timer-us\" entry.");
-            ret = -1;
-            goto end;
-        }
+        map->insert("timer-us", (uint64_t) live_timer);
     }
 
     /*
@@ -711,13 +514,7 @@ static int list_append_session(bt_value *results, GString *base_url,
     {
         uint32_t streams = be32toh(session->streams);
 
-        insert_status = bt_value_map_insert_unsigned_integer_entry(map, "stream-count", streams);
-        if (insert_status != BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK) {
-            BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class,
-                                            "Error inserting \"stream-count\" entry.");
-            ret = -1;
-            goto end;
-        }
+        map->insert("stream-count", (uint64_t) streams);
     }
 
     /*
@@ -727,27 +524,11 @@ static int list_append_session(bt_value *results, GString *base_url,
     {
         uint32_t clients = be32toh(session->clients);
 
-        insert_status = bt_value_map_insert_unsigned_integer_entry(map, "client-count", clients);
-        if (insert_status != BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK) {
-            BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class,
-                                            "Error inserting \"client-count\" entry.");
-            ret = -1;
-            goto end;
-        }
-    }
-
-    append_status = bt_value_array_append_element(results, map);
-    if (append_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) {
-        BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, "Error appending map to results.");
-        ret = -1;
+        map->insert("client-count", (uint64_t) clients);
     }
 
-end:
-    if (url) {
-        g_string_free(url, true);
-    }
-    BT_VALUE_PUT_REF_AND_RESET(map);
-    return ret;
+    results.append(*map);
+    return 0;
 }
 
 /*
@@ -786,27 +567,17 @@ end:
  *   }
  */
 
-bt_component_class_query_method_status
-live_viewer_connection_list_sessions(struct live_viewer_connection *viewer_connection,
-                                     const bt_value **user_result)
+bt2::Value::Shared
+live_viewer_connection_list_sessions(struct live_viewer_connection *viewer_connection)
 {
-    bt_self_component_class *self_comp_class = viewer_connection->self_comp_class;
-    bt_component_class_query_method_status status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK;
-    bt_value *result = NULL;
     enum lttng_live_viewer_status viewer_status;
     struct lttng_viewer_cmd cmd;
     struct lttng_viewer_list_sessions list;
     uint32_t i, sessions_count;
+    auto result = bt2::ArrayValue::create();
 
-    result = bt_value_array_create();
-    if (!result) {
-        BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, "Error creating array");
-        status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR;
-        goto error;
-    }
-
-    BT_LOGD("Requesting list of sessions: cmd=%s",
-            lttng_viewer_command_string(LTTNG_VIEWER_LIST_SESSIONS));
+    BT_CPPLOGD_SPEC(viewer_connection->logger, "Requesting list of sessions: cmd={}",
+                    LTTNG_VIEWER_LIST_SESSIONS);
 
     cmd.cmd = htobe32(LTTNG_VIEWER_LIST_SESSIONS);
     cmd.data_size = htobe64((uint64_t) 0);
@@ -814,22 +585,18 @@ live_viewer_connection_list_sessions(struct live_viewer_connection *viewer_conne
 
     viewer_status = lttng_live_send(viewer_connection, &cmd, sizeof(cmd));
     if (viewer_status == LTTNG_LIVE_VIEWER_STATUS_ERROR) {
-        BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, "Error sending list sessions command");
-        status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR;
-        goto error;
+        BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(viewer_connection->logger, bt2::Error,
+                                               "Error sending list sessions command");
     } else if (viewer_status == LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED) {
-        status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_AGAIN;
-        goto error;
+        throw bt2c::TryAgain {};
     }
 
     viewer_status = lttng_live_recv(viewer_connection, &list, sizeof(list));
     if (viewer_status == LTTNG_LIVE_VIEWER_STATUS_ERROR) {
-        BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, "Error receiving session list");
-        status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR;
-        goto error;
+        BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(viewer_connection->logger, bt2::Error,
+                                               "Error receiving session list");
     } else if (viewer_status == LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED) {
-        status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_AGAIN;
-        goto error;
+        throw bt2c::TryAgain {};
     }
 
     sessions_count = be32toh(list.sessions_count);
@@ -838,29 +605,21 @@ live_viewer_connection_list_sessions(struct live_viewer_connection *viewer_conne
 
         viewer_status = lttng_live_recv(viewer_connection, &lsession, sizeof(lsession));
         if (viewer_status == LTTNG_LIVE_VIEWER_STATUS_ERROR) {
-            BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, "Error receiving session:");
-            status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR;
-            goto error;
+            BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(viewer_connection->logger, bt2::Error,
+                                                   "Error receiving session:");
         } else if (viewer_status == LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED) {
-            status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_AGAIN;
-            goto error;
+            throw bt2c::TryAgain {};
         }
 
         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, viewer_connection)) {
-            BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class, "Error appending session");
-            status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR;
-            goto error;
+        if (list_append_session(*result, viewer_connection->url, &lsession, viewer_connection)) {
+            BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(viewer_connection->logger, bt2::Error,
+                                                   "Error appending session");
         }
     }
 
-    *user_result = result;
-    goto end;
-error:
-    BT_VALUE_PUT_REF_AND_RESET(result);
-end:
-    return status;
+    return result;
 }
 
 static enum lttng_live_viewer_status
@@ -872,12 +631,11 @@ lttng_live_query_session_ids(struct lttng_live_msg_iter *lttng_live_msg_iter)
     uint32_t i, sessions_count;
     uint64_t session_id;
     enum lttng_live_viewer_status status;
-    struct live_viewer_connection *viewer_connection = lttng_live_msg_iter->viewer_connection;
-    bt_self_component *self_comp = viewer_connection->self_comp;
-    bt_self_component_class *self_comp_class = viewer_connection->self_comp_class;
+    live_viewer_connection *viewer_connection = lttng_live_msg_iter->viewer_connection.get();
 
-    BT_COMP_LOGD("Asking the relay daemon for the list of sessions: cmd=%s",
-                 lttng_viewer_command_string(LTTNG_VIEWER_LIST_SESSIONS));
+    BT_CPPLOGD_SPEC(viewer_connection->logger,
+                    "Asking the relay daemon for the list of sessions: cmd={}",
+                    LTTNG_VIEWER_LIST_SESSIONS);
 
     cmd.cmd = htobe32(LTTNG_VIEWER_LIST_SESSIONS);
     cmd.data_size = htobe64((uint64_t) 0);
@@ -885,30 +643,31 @@ lttng_live_query_session_ids(struct lttng_live_msg_iter *lttng_live_msg_iter)
 
     status = lttng_live_send(viewer_connection, &cmd, sizeof(cmd));
     if (status != LTTNG_LIVE_VIEWER_STATUS_OK) {
-        viewer_handle_send_status(self_comp, self_comp_class, status, "list sessions command");
-        goto end;
+        viewer_handle_send_status(status, "list sessions command");
+        return status;
     }
 
     status = lttng_live_recv(viewer_connection, &list, sizeof(list));
     if (status != LTTNG_LIVE_VIEWER_STATUS_OK) {
-        viewer_handle_recv_status(self_comp, self_comp_class, status, "session list reply");
-        goto end;
+        viewer_handle_recv_status(status, "session list reply");
+        return status;
     }
 
     sessions_count = be32toh(list.sessions_count);
     for (i = 0; i < sessions_count; i++) {
         status = lttng_live_recv(viewer_connection, &lsession, sizeof(lsession));
         if (status != LTTNG_LIVE_VIEWER_STATUS_OK) {
-            viewer_handle_recv_status(self_comp, self_comp_class, status, "session reply");
-            goto end;
+            viewer_handle_recv_status(status, "session reply");
+            return status;
         }
         lsession.hostname[LTTNG_VIEWER_HOST_NAME_MAX - 1] = '\0';
         lsession.session_name[LTTNG_VIEWER_NAME_MAX - 1] = '\0';
         session_id = be64toh(lsession.id);
 
-        BT_COMP_LOGI("Adding session to internal list: "
-                     "session-id=%" PRIu64 ", hostname=\"%s\", session-name=\"%s\"",
-                     session_id, lsession.hostname, lsession.session_name);
+        BT_CPPLOGI_SPEC(viewer_connection->logger,
+                        "Adding session to internal list: "
+                        "session-id={}, hostname=\"{}\", session-name=\"{}\"",
+                        session_id, lsession.hostname, lsession.session_name);
 
         if ((strncmp(lsession.session_name, viewer_connection->session_name->str,
                      LTTNG_VIEWER_NAME_MAX) == 0) &&
@@ -916,17 +675,14 @@ lttng_live_query_session_ids(struct lttng_live_msg_iter *lttng_live_msg_iter)
                      LTTNG_VIEWER_HOST_NAME_MAX) == 0)) {
             if (lttng_live_add_session(lttng_live_msg_iter, session_id, lsession.hostname,
                                        lsession.session_name)) {
-                BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to add live session");
-                status = LTTNG_LIVE_VIEWER_STATUS_ERROR;
-                goto end;
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger,
+                                             "Failed to add live session");
+                return LTTNG_LIVE_VIEWER_STATUS_ERROR;
             }
         }
     }
 
-    status = LTTNG_LIVE_VIEWER_STATUS_OK;
-
-end:
-    return status;
+    return LTTNG_LIVE_VIEWER_STATUS_OK;
 }
 
 enum lttng_live_viewer_status
@@ -935,12 +691,10 @@ 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;
     enum lttng_live_viewer_status status;
-    struct live_viewer_connection *viewer_connection = lttng_live_msg_iter->viewer_connection;
-    bt_self_component *self_comp = viewer_connection->self_comp;
-    bt_self_component_class *self_comp_class = viewer_connection->self_comp_class;
+    live_viewer_connection *viewer_connection = lttng_live_msg_iter->viewer_connection.get();
 
-    BT_COMP_OR_COMP_CLASS_LOGD(self_comp, self_comp_class, "Creating a viewer session: cmd=%s",
-                               lttng_viewer_command_string(LTTNG_VIEWER_CREATE_SESSION));
+    BT_CPPLOGD_SPEC(viewer_connection->logger, "Creating a viewer session: cmd={}",
+                    LTTNG_VIEWER_CREATE_SESSION);
 
     cmd.cmd = htobe32(LTTNG_VIEWER_CREATE_SESSION);
     cmd.data_size = htobe64((uint64_t) 0);
@@ -948,32 +702,31 @@ lttng_live_create_viewer_session(struct lttng_live_msg_iter *lttng_live_msg_iter
 
     status = lttng_live_send(viewer_connection, &cmd, sizeof(cmd));
     if (status != LTTNG_LIVE_VIEWER_STATUS_OK) {
-        viewer_handle_send_status(self_comp, self_comp_class, status, "create session command");
-        goto end;
+        viewer_handle_send_status(status, "create session command");
+        return status;
     }
 
     status = lttng_live_recv(viewer_connection, &resp, sizeof(resp));
     if (status != LTTNG_LIVE_VIEWER_STATUS_OK) {
-        viewer_handle_recv_status(self_comp, self_comp_class, status, "create session reply");
-        goto end;
+        viewer_handle_recv_status(status, "create session reply");
+        return status;
     }
 
     if (be32toh(resp.status) != LTTNG_VIEWER_CREATE_SESSION_OK) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Error creating viewer session");
-        status = LTTNG_LIVE_VIEWER_STATUS_ERROR;
-        goto end;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger, "Error creating viewer session");
+        return LTTNG_LIVE_VIEWER_STATUS_ERROR;
     }
 
     status = lttng_live_query_session_ids(lttng_live_msg_iter);
     if (status == LTTNG_LIVE_VIEWER_STATUS_ERROR) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to query live viewer session ids");
-        goto end;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger,
+                                     "Failed to query live viewer session ids");
+        return LTTNG_LIVE_VIEWER_STATUS_ERROR;
     } else if (status == LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED) {
-        goto end;
+        return LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED;
     }
 
-end:
-    return status;
+    return LTTNG_LIVE_VIEWER_STATUS_OK;
 }
 
 static enum lttng_live_viewer_status receive_streams(struct lttng_live_session *session,
@@ -983,10 +736,9 @@ static enum lttng_live_viewer_status receive_streams(struct lttng_live_session *
     uint32_t i;
     struct lttng_live_msg_iter *lttng_live_msg_iter = session->lttng_live_msg_iter;
     enum lttng_live_viewer_status status;
-    struct live_viewer_connection *viewer_connection = lttng_live_msg_iter->viewer_connection;
-    bt_self_component *self_comp = viewer_connection->self_comp;
+    live_viewer_connection *viewer_connection = lttng_live_msg_iter->viewer_connection.get();
 
-    BT_COMP_LOGI("Getting %" PRIu32 " new streams", stream_count);
+    BT_CPPLOGI_SPEC(viewer_connection->logger, "Getting {} new streams", stream_count);
     for (i = 0; i < stream_count; i++) {
         struct lttng_viewer_stream stream;
         struct lttng_live_stream_iterator *live_stream;
@@ -995,8 +747,8 @@ static enum lttng_live_viewer_status receive_streams(struct lttng_live_session *
 
         status = lttng_live_recv(viewer_connection, &stream, sizeof(stream));
         if (status != LTTNG_LIVE_VIEWER_STATUS_OK) {
-            viewer_handle_recv_status(self_comp, NULL, status, "stream reply");
-            goto end;
+            viewer_handle_recv_status(status, "stream reply");
+            return status;
         }
         stream.path_name[LTTNG_VIEWER_PATH_MAX - 1] = '\0';
         stream.channel_name[LTTNG_VIEWER_NAME_MAX - 1] = '\0';
@@ -1004,30 +756,27 @@ static enum lttng_live_viewer_status receive_streams(struct lttng_live_session *
         ctf_trace_id = be64toh(stream.ctf_trace_id);
 
         if (stream.metadata_flag) {
-            BT_COMP_LOGI("    metadata stream %" PRIu64 " : %s/%s", stream_id, stream.path_name,
-                         stream.channel_name);
+            BT_CPPLOGI_SPEC(viewer_connection->logger, "    metadata stream {} : {}/{}", stream_id,
+                            stream.path_name, stream.channel_name);
             if (lttng_live_metadata_create_stream(session, ctf_trace_id, stream_id)) {
-                BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Error creating metadata stream");
-                status = LTTNG_LIVE_VIEWER_STATUS_ERROR;
-                goto end;
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger,
+                                             "Error creating metadata stream");
+                return LTTNG_LIVE_VIEWER_STATUS_ERROR;
             }
             session->lazy_stream_msg_init = true;
         } else {
-            BT_COMP_LOGI("    stream %" PRIu64 " : %s/%s", stream_id, stream.path_name,
-                         stream.channel_name);
+            BT_CPPLOGI_SPEC(viewer_connection->logger, "    stream {} : {}/{}", stream_id,
+                            stream.path_name, stream.channel_name);
             live_stream =
                 lttng_live_stream_iterator_create(session, ctf_trace_id, stream_id, self_msg_iter);
             if (!live_stream) {
-                BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Error creating stream");
-                status = LTTNG_LIVE_VIEWER_STATUS_ERROR;
-                goto end;
+                BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger, "Error creating stream");
+                return LTTNG_LIVE_VIEWER_STATUS_ERROR;
             }
         }
     }
-    status = LTTNG_LIVE_VIEWER_STATUS_OK;
 
-end:
-    return status;
+    return LTTNG_LIVE_VIEWER_STATUS_OK;
 }
 
 enum lttng_live_viewer_status lttng_live_session_attach(struct lttng_live_session *session,
@@ -1038,16 +787,15 @@ enum lttng_live_viewer_status lttng_live_session_attach(struct lttng_live_sessio
     struct lttng_viewer_attach_session_request rq;
     struct lttng_viewer_attach_session_response rp;
     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_self_component *self_comp = viewer_connection->self_comp;
+    live_viewer_connection *viewer_connection = lttng_live_msg_iter->viewer_connection.get();
     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];
 
-    BT_COMP_LOGD("Attaching to session: cmd=%s, session-id=%" PRIu64 ", seek=%s",
-                 lttng_viewer_command_string(LTTNG_VIEWER_ATTACH_SESSION), session_id,
-                 lttng_viewer_seek_string(LTTNG_VIEWER_SEEK_LAST));
+    BT_CPPLOGD_SPEC(viewer_connection->logger,
+                    "Attaching to session: cmd={}, session-id={}, seek={}",
+                    LTTNG_VIEWER_ATTACH_SESSION, session_id, LTTNG_VIEWER_SEEK_LAST);
 
     cmd.cmd = htobe32(LTTNG_VIEWER_ATTACH_SESSION);
     cmd.data_size = htobe64((uint64_t) sizeof(rq));
@@ -1068,14 +816,14 @@ enum lttng_live_viewer_status lttng_live_session_attach(struct lttng_live_sessio
     memcpy(cmd_buf + sizeof(cmd), &rq, sizeof(rq));
     status = lttng_live_send(viewer_connection, &cmd_buf, cmd_buf_len);
     if (status != LTTNG_LIVE_VIEWER_STATUS_OK) {
-        viewer_handle_send_status(self_comp, NULL, status, "attach session command");
-        goto end;
+        viewer_handle_send_status(status, "attach session command");
+        return status;
     }
 
     status = lttng_live_recv(viewer_connection, &rp, sizeof(rp));
     if (status != LTTNG_LIVE_VIEWER_STATUS_OK) {
-        viewer_handle_recv_status(self_comp, NULL, status, "attach session reply");
-        goto end;
+        viewer_handle_recv_status(status, "attach session reply");
+        return status;
     }
 
     streams_count = be32toh(rp.streams_count);
@@ -1083,25 +831,23 @@ enum lttng_live_viewer_status lttng_live_session_attach(struct lttng_live_sessio
     case LTTNG_VIEWER_ATTACH_OK:
         break;
     case LTTNG_VIEWER_ATTACH_UNK:
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Session id %" PRIu64 " is unknown", session_id);
-        status = LTTNG_LIVE_VIEWER_STATUS_ERROR;
-        goto end;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger, "Session id {} is unknown",
+                                     session_id);
+        return LTTNG_LIVE_VIEWER_STATUS_ERROR;
     case LTTNG_VIEWER_ATTACH_ALREADY:
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "There is already a viewer attached to this session");
-        status = LTTNG_LIVE_VIEWER_STATUS_ERROR;
-        goto end;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger,
+                                     "There is already a viewer attached to this session");
+        return LTTNG_LIVE_VIEWER_STATUS_ERROR;
     case LTTNG_VIEWER_ATTACH_NOT_LIVE:
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Not a live session");
-        status = LTTNG_LIVE_VIEWER_STATUS_ERROR;
-        goto end;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger, "Not a live session");
+        return LTTNG_LIVE_VIEWER_STATUS_ERROR;
     case LTTNG_VIEWER_ATTACH_SEEK_ERR:
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Wrong seek parameter");
-        status = LTTNG_LIVE_VIEWER_STATUS_ERROR;
-        goto end;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger, "Wrong seek parameter");
+        return LTTNG_LIVE_VIEWER_STATUS_ERROR;
     default:
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Unknown attach return code %u", be32toh(rp.status));
-        status = LTTNG_LIVE_VIEWER_STATUS_ERROR;
-        goto end;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger, "Unknown attach return code {}",
+                                     be32toh(rp.status));
+        return LTTNG_LIVE_VIEWER_STATUS_ERROR;
     }
 
     /* We receive the initial list of streams. */
@@ -1110,10 +856,10 @@ enum lttng_live_viewer_status lttng_live_session_attach(struct lttng_live_sessio
     case LTTNG_LIVE_VIEWER_STATUS_OK:
         break;
     case LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED:
-        goto end;
+        return status;
     case LTTNG_LIVE_VIEWER_STATUS_ERROR:
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Error receiving streams");
-        goto end;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger, "Error receiving streams");
+        return status;
     default:
         bt_common_abort();
     }
@@ -1121,8 +867,7 @@ enum lttng_live_viewer_status lttng_live_session_attach(struct lttng_live_sessio
     session->attached = true;
     session->new_streams_needed = false;
 
-end:
-    return status;
+    return LTTNG_LIVE_VIEWER_STATUS_OK;
 }
 
 enum lttng_live_viewer_status lttng_live_session_detach(struct lttng_live_session *session)
@@ -1132,8 +877,7 @@ enum lttng_live_viewer_status lttng_live_session_detach(struct lttng_live_sessio
     struct lttng_viewer_detach_session_request rq;
     struct lttng_viewer_detach_session_response rp;
     struct lttng_live_msg_iter *lttng_live_msg_iter = session->lttng_live_msg_iter;
-    bt_self_component *self_comp = session->self_comp;
-    struct live_viewer_connection *viewer_connection = lttng_live_msg_iter->viewer_connection;
+    live_viewer_connection *viewer_connection = lttng_live_msg_iter->viewer_connection.get();
     uint64_t session_id = session->id;
     const size_t cmd_buf_len = sizeof(cmd) + sizeof(rq);
     char cmd_buf[cmd_buf_len];
@@ -1147,8 +891,8 @@ enum lttng_live_viewer_status lttng_live_session_detach(struct lttng_live_sessio
         return LTTNG_LIVE_VIEWER_STATUS_OK;
     }
 
-    BT_COMP_LOGD("Detaching from session: cmd=%s, session-id=%" PRIu64,
-                 lttng_viewer_command_string(LTTNG_VIEWER_DETACH_SESSION), session_id);
+    BT_CPPLOGD_SPEC(viewer_connection->logger, "Detaching from session: cmd={}, session-id={}",
+                    LTTNG_VIEWER_DETACH_SESSION, session_id);
 
     cmd.cmd = htobe32(LTTNG_VIEWER_DETACH_SESSION);
     cmd.data_size = htobe64((uint64_t) sizeof(rq));
@@ -1166,64 +910,56 @@ enum lttng_live_viewer_status lttng_live_session_detach(struct lttng_live_sessio
     memcpy(cmd_buf + sizeof(cmd), &rq, sizeof(rq));
     status = lttng_live_send(viewer_connection, &cmd_buf, cmd_buf_len);
     if (status != LTTNG_LIVE_VIEWER_STATUS_OK) {
-        viewer_handle_send_status(self_comp, NULL, status, "detach session command");
-        goto end;
+        viewer_handle_send_status(status, "detach session command");
+        return status;
     }
 
     status = lttng_live_recv(viewer_connection, &rp, sizeof(rp));
     if (status != LTTNG_LIVE_VIEWER_STATUS_OK) {
-        viewer_handle_recv_status(self_comp, NULL, status, "detach session reply");
-        goto end;
+        viewer_handle_recv_status(status, "detach session reply");
+        return status;
     }
 
     switch (be32toh(rp.status)) {
     case LTTNG_VIEWER_DETACH_SESSION_OK:
         break;
     case LTTNG_VIEWER_DETACH_SESSION_UNK:
-        BT_COMP_LOGW("Session id %" PRIu64 " is unknown", session_id);
-        status = LTTNG_LIVE_VIEWER_STATUS_ERROR;
-        goto end;
+        BT_CPPLOGW_SPEC(viewer_connection->logger, "Session id {} is unknown", session_id);
+        return LTTNG_LIVE_VIEWER_STATUS_ERROR;
     case LTTNG_VIEWER_DETACH_SESSION_ERR:
-        BT_COMP_LOGW("Error detaching session id %" PRIu64 "", session_id);
-        status = LTTNG_LIVE_VIEWER_STATUS_ERROR;
-        goto end;
+        BT_CPPLOGW_SPEC(viewer_connection->logger, "Error detaching session id {}", session_id);
+        return LTTNG_LIVE_VIEWER_STATUS_ERROR;
     default:
-        BT_COMP_LOGE("Unknown detach return code %u", be32toh(rp.status));
-        status = LTTNG_LIVE_VIEWER_STATUS_ERROR;
-        goto end;
+        BT_CPPLOGE_SPEC(viewer_connection->logger, "Unknown detach return code {}",
+                        be32toh(rp.status));
+        return LTTNG_LIVE_VIEWER_STATUS_ERROR;
     }
 
     session->attached = false;
 
-    status = LTTNG_LIVE_VIEWER_STATUS_OK;
-
-end:
-    return status;
+    return LTTNG_LIVE_VIEWER_STATUS_OK;
 }
 
 enum lttng_live_get_one_metadata_status
-lttng_live_get_one_metadata_packet(struct lttng_live_trace *trace, FILE *fp, size_t *reply_len)
+lttng_live_get_one_metadata_packet(struct lttng_live_trace *trace, std::vector<char>& buf)
 {
     uint64_t len = 0;
-    enum lttng_live_get_one_metadata_status status;
     enum lttng_live_viewer_status viewer_status;
     struct lttng_viewer_cmd cmd;
     struct lttng_viewer_get_metadata rq;
     struct lttng_viewer_metadata_packet rp;
-    gchar *data = NULL;
-    ssize_t writelen;
+    std::vector<char> data;
     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;
-    bt_self_component *self_comp = viewer_connection->self_comp;
+    struct lttng_live_metadata *metadata = trace->metadata.get();
+    live_viewer_connection *viewer_connection = lttng_live_msg_iter->viewer_connection.get();
     const size_t cmd_buf_len = sizeof(cmd) + sizeof(rq);
     char cmd_buf[cmd_buf_len];
 
-    BT_COMP_LOGD("Requesting new metadata for trace:"
-                 "cmd=%s, trace-id=%" PRIu64 ", metadata-stream-id=%" PRIu64,
-                 lttng_viewer_command_string(LTTNG_VIEWER_GET_METADATA), trace->id,
-                 metadata->stream_id);
+    BT_CPPLOGD_SPEC(viewer_connection->logger,
+                    "Requesting new metadata for trace:"
+                    "cmd={}, trace-id={}, metadata-stream-id={}",
+                    LTTNG_VIEWER_GET_METADATA, trace->id, metadata->stream_id);
 
     rq.stream_id = htobe64(metadata->stream_id);
     cmd.cmd = htobe32(LTTNG_VIEWER_GET_METADATA);
@@ -1239,39 +975,35 @@ lttng_live_get_one_metadata_packet(struct lttng_live_trace *trace, FILE *fp, siz
     memcpy(cmd_buf + sizeof(cmd), &rq, sizeof(rq));
     viewer_status = lttng_live_send(viewer_connection, &cmd_buf, cmd_buf_len);
     if (viewer_status != LTTNG_LIVE_VIEWER_STATUS_OK) {
-        viewer_handle_send_status(self_comp, NULL, viewer_status, "get metadata command");
-        status = (enum lttng_live_get_one_metadata_status) viewer_status;
-        goto end;
+        viewer_handle_send_status(viewer_status, "get metadata command");
+        return (lttng_live_get_one_metadata_status) viewer_status;
     }
 
     viewer_status = lttng_live_recv(viewer_connection, &rp, sizeof(rp));
     if (viewer_status != LTTNG_LIVE_VIEWER_STATUS_OK) {
-        viewer_handle_recv_status(self_comp, NULL, viewer_status, "get metadata reply");
-        status = (enum lttng_live_get_one_metadata_status) viewer_status;
-        goto end;
+        viewer_handle_recv_status(viewer_status, "get metadata reply");
+        return (lttng_live_get_one_metadata_status) viewer_status;
     }
 
     switch (be32toh(rp.status)) {
     case LTTNG_VIEWER_METADATA_OK:
-        BT_COMP_LOGD("Received get_metadata response: ok");
+        BT_CPPLOGD_SPEC(viewer_connection->logger, "Received get_metadata response: ok");
         break;
     case LTTNG_VIEWER_NO_NEW_METADATA:
-        BT_COMP_LOGD("Received get_metadata response: no new");
-        status = LTTNG_LIVE_GET_ONE_METADATA_STATUS_END;
-        goto end;
+        BT_CPPLOGD_SPEC(viewer_connection->logger, "Received get_metadata response: no new");
+        return LTTNG_LIVE_GET_ONE_METADATA_STATUS_END;
     case LTTNG_VIEWER_METADATA_ERR:
         /*
              * The Relayd cannot find this stream id. Maybe its
              * gone already. This can happen in short lived UST app
              * in a per-pid session.
              */
-        BT_COMP_LOGD("Received get_metadata response: error");
-        status = LTTNG_LIVE_GET_ONE_METADATA_STATUS_CLOSED;
-        goto end;
+        BT_CPPLOGD_SPEC(viewer_connection->logger, "Received get_metadata response: error");
+        return LTTNG_LIVE_GET_ONE_METADATA_STATUS_CLOSED;
     default:
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Received get_metadata response: unknown");
-        status = LTTNG_LIVE_GET_ONE_METADATA_STATUS_ERROR;
-        goto end;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger,
+                                     "Received get_metadata response: unknown");
+        return LTTNG_LIVE_GET_ONE_METADATA_STATUS_ERROR;
     }
 
     len = be64toh(rp.len);
@@ -1281,49 +1013,32 @@ lttng_live_get_one_metadata_packet(struct lttng_live_trace *trace, FILE *fp, siz
          * length of 0. This means we must try again. This scenario
          * arises when a clear command is performed on an lttng session.
          */
-        BT_COMP_LOGD(
+        BT_CPPLOGD_SPEC(
+            viewer_connection->logger,
             "Expecting a metadata packet of size 0. Retry to get a packet from the relay.");
-        goto empty_metadata_packet_retry;
+        return LTTNG_LIVE_GET_ONE_METADATA_STATUS_OK;
     }
 
-    BT_COMP_LOGD("Writing %" PRIu64 " bytes to metadata", len);
+    BT_CPPLOGD_SPEC(viewer_connection->logger, "Writing {} bytes to metadata", len);
     if (len <= 0) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Erroneous response length");
-        status = LTTNG_LIVE_GET_ONE_METADATA_STATUS_ERROR;
-        goto end;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger, "Erroneous response length");
+        return LTTNG_LIVE_GET_ONE_METADATA_STATUS_ERROR;
     }
 
-    data = g_new0(gchar, len);
-    if (!data) {
-        BT_COMP_LOGE_APPEND_CAUSE_ERRNO(self_comp, "Failed to allocate data buffer", ".");
-        status = LTTNG_LIVE_GET_ONE_METADATA_STATUS_ERROR;
-        goto end;
-    }
+    data.resize(len);
 
-    viewer_status = lttng_live_recv(viewer_connection, data, len);
+    viewer_status = lttng_live_recv(viewer_connection, data.data(), len);
     if (viewer_status != LTTNG_LIVE_VIEWER_STATUS_OK) {
-        viewer_handle_recv_status(self_comp, NULL, viewer_status, "get metadata packet");
-        status = (enum lttng_live_get_one_metadata_status) viewer_status;
-        goto end;
+        viewer_handle_recv_status(viewer_status, "get metadata packet");
+        return (lttng_live_get_one_metadata_status) viewer_status;
     }
 
     /*
      * Write the metadata to the file handle.
      */
-    writelen = fwrite(data, sizeof(uint8_t), len, fp);
-    if (writelen != len) {
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Writing in the metadata file stream");
-        status = LTTNG_LIVE_GET_ONE_METADATA_STATUS_ERROR;
-        goto end;
-    }
-
-empty_metadata_packet_retry:
-    *reply_len = len;
-    status = LTTNG_LIVE_GET_ONE_METADATA_STATUS_OK;
+    buf.insert(buf.end(), data.begin(), data.end());
 
-end:
-    g_free(data);
-    return status;
+    return LTTNG_LIVE_GET_ONE_METADATA_STATUS_OK;
 }
 
 /*
@@ -1345,15 +1060,11 @@ static void lttng_index_to_packet_index(struct lttng_viewer_index *lindex,
 
 static void lttng_live_need_new_streams(struct lttng_live_msg_iter *lttng_live_msg_iter)
 {
-    uint64_t session_idx;
-    struct live_viewer_connection *viewer_connection = lttng_live_msg_iter->viewer_connection;
-
-    for (session_idx = 0; session_idx < lttng_live_msg_iter->sessions->len; session_idx++) {
-        struct lttng_live_session *session =
-            (lttng_live_session *) g_ptr_array_index(lttng_live_msg_iter->sessions, session_idx);
-        BT_COMP_LOGD("Marking session as needing new streams: "
-                     "session-id=%" PRIu64,
-                     session->id);
+    for (const auto& session : lttng_live_msg_iter->sessions) {
+        BT_CPPLOGD_SPEC(lttng_live_msg_iter->logger,
+                        "Marking session as needing new streams: "
+                        "session-id={}",
+                        session->id);
         session->new_streams_needed = true;
     }
 }
@@ -1366,18 +1077,16 @@ lttng_live_get_next_index(struct lttng_live_msg_iter *lttng_live_msg_iter,
     struct lttng_viewer_get_next_index rq;
     enum lttng_live_viewer_status viewer_status;
     struct lttng_viewer_index rp;
-    enum lttng_live_iterator_status status;
-    struct live_viewer_connection *viewer_connection = lttng_live_msg_iter->viewer_connection;
-    bt_self_component *self_comp = viewer_connection->self_comp;
+    live_viewer_connection *viewer_connection = lttng_live_msg_iter->viewer_connection.get();
     struct lttng_live_trace *trace = stream->trace;
     const size_t cmd_buf_len = sizeof(cmd) + sizeof(rq);
     char cmd_buf[cmd_buf_len];
     uint32_t flags, rp_status;
 
-    BT_COMP_LOGD("Requesting next index for stream: cmd=%s, "
-                 "viewer-stream-id=%" PRIu64,
-                 lttng_viewer_command_string(LTTNG_VIEWER_GET_NEXT_INDEX),
-                 stream->viewer_stream_id);
+    BT_CPPLOGD_SPEC(viewer_connection->logger,
+                    "Requesting next index for stream: cmd={}, "
+                    "viewer-stream-id={}",
+                    LTTNG_VIEWER_GET_NEXT_INDEX, stream->viewer_stream_id);
     cmd.cmd = htobe32(LTTNG_VIEWER_GET_NEXT_INDEX);
     cmd.data_size = htobe64((uint64_t) sizeof(rq));
     cmd.cmd_version = htobe32(0);
@@ -1395,27 +1104,28 @@ lttng_live_get_next_index(struct lttng_live_msg_iter *lttng_live_msg_iter,
 
     viewer_status = lttng_live_send(viewer_connection, &cmd_buf, cmd_buf_len);
     if (viewer_status != LTTNG_LIVE_VIEWER_STATUS_OK) {
-        viewer_handle_send_status(self_comp, NULL, viewer_status, "get next index command");
-        goto error;
+        viewer_handle_send_status(viewer_status, "get next index command");
+        return viewer_status_to_live_iterator_status(viewer_status);
     }
 
     viewer_status = lttng_live_recv(viewer_connection, &rp, sizeof(rp));
     if (viewer_status != LTTNG_LIVE_VIEWER_STATUS_OK) {
-        viewer_handle_recv_status(self_comp, NULL, viewer_status, "get next index reply");
-        goto error;
+        viewer_handle_recv_status(viewer_status, "get next index reply");
+        return viewer_status_to_live_iterator_status(viewer_status);
     }
 
     flags = be32toh(rp.flags);
     rp_status = be32toh(rp.status);
 
-    BT_COMP_LOGD("Received response from relay daemon: cmd=%s, response=%s",
-                 lttng_viewer_command_string(LTTNG_VIEWER_GET_NEXT_INDEX),
-                 lttng_viewer_next_index_return_code_string(rp_status));
+    BT_CPPLOGD_SPEC(
+        viewer_connection->logger, "Received response from relay daemon: cmd=%s, response={}",
+        LTTNG_VIEWER_GET_NEXT_INDEX, static_cast<lttng_viewer_next_index_return_code>(rp_status));
 
     if (flags & LTTNG_VIEWER_FLAG_NEW_STREAM) {
-        BT_COMP_LOGD("Marking all sessions as possibly needing new streams: "
-                     "response=%s, response-flag=NEW_STREAM",
-                     lttng_viewer_next_index_return_code_string(rp_status));
+        BT_CPPLOGD_SPEC(viewer_connection->logger,
+                        "Marking all sessions as possibly needing new streams: "
+                        "response={}, response-flag=NEW_STREAM",
+                        static_cast<lttng_viewer_next_index_return_code>(rp_status));
         lttng_live_need_new_streams(lttng_live_msg_iter);
     }
 
@@ -1435,8 +1145,7 @@ lttng_live_get_next_index(struct lttng_live_msg_iter *lttng_live_msg_iter,
             stream->ctf_stream_class_id.is_set = true;
         }
         lttng_live_stream_iterator_set_state(stream, LTTNG_LIVE_STREAM_QUIESCENT);
-        status = LTTNG_LIVE_ITERATOR_STATUS_OK;
-        break;
+        return LTTNG_LIVE_ITERATOR_STATUS_OK;
     }
     case LTTNG_VIEWER_INDEX_OK:
     {
@@ -1453,45 +1162,36 @@ lttng_live_get_next_index(struct lttng_live_msg_iter *lttng_live_msg_iter,
         lttng_live_stream_iterator_set_state(stream, LTTNG_LIVE_STREAM_ACTIVE_DATA);
 
         if (flags & LTTNG_VIEWER_FLAG_NEW_METADATA) {
-            BT_COMP_LOGD("Marking trace as needing new metadata: "
-                         "response=%s, response-flag=NEW_METADATA, trace-id=%" PRIu64,
-                         lttng_viewer_next_index_return_code_string(rp_status), trace->id);
+            BT_CPPLOGD_SPEC(viewer_connection->logger,
+                            "Marking trace as needing new metadata: "
+                            "response={}, response-flag=NEW_METADATA, trace-id={}",
+                            static_cast<lttng_viewer_next_index_return_code>(rp_status), trace->id);
             trace->metadata_stream_state = LTTNG_LIVE_METADATA_STREAM_STATE_NEEDED;
         }
-        status = LTTNG_LIVE_ITERATOR_STATUS_OK;
+        return LTTNG_LIVE_ITERATOR_STATUS_OK;
         break;
     }
     case LTTNG_VIEWER_INDEX_RETRY:
         memset(index, 0, sizeof(struct packet_index));
         lttng_live_stream_iterator_set_state(stream, LTTNG_LIVE_STREAM_ACTIVE_NO_DATA);
-        status = LTTNG_LIVE_ITERATOR_STATUS_AGAIN;
-        goto end;
+        return LTTNG_LIVE_ITERATOR_STATUS_AGAIN;
     case LTTNG_VIEWER_INDEX_HUP:
         memset(index, 0, sizeof(struct packet_index));
         index->offset = EOF;
         lttng_live_stream_iterator_set_state(stream, LTTNG_LIVE_STREAM_EOF);
         stream->has_stream_hung_up = true;
-        status = LTTNG_LIVE_ITERATOR_STATUS_END;
-        break;
+        return LTTNG_LIVE_ITERATOR_STATUS_END;
     case LTTNG_VIEWER_INDEX_ERR:
         memset(index, 0, sizeof(struct packet_index));
         lttng_live_stream_iterator_set_state(stream, LTTNG_LIVE_STREAM_ACTIVE_NO_DATA);
-        status = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
-        goto end;
+        return LTTNG_LIVE_ITERATOR_STATUS_ERROR;
     default:
-        BT_COMP_LOGD("Received get_next_index response: unknown value");
+        BT_CPPLOGD_SPEC(viewer_connection->logger,
+                        "Received get_next_index response: unknown value");
         memset(index, 0, sizeof(struct packet_index));
         lttng_live_stream_iterator_set_state(stream, LTTNG_LIVE_STREAM_ACTIVE_NO_DATA);
-        status = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
-        goto end;
+        return LTTNG_LIVE_ITERATOR_STATUS_ERROR;
     }
-
-    goto end;
-
-error:
-    status = viewer_status_to_live_iterator_status(viewer_status);
-end:
-    return status;
 }
 
 enum ctf_msg_iter_medium_status
@@ -1499,21 +1199,20 @@ 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 ctf_msg_iter_medium_status status;
     enum lttng_live_viewer_status viewer_status;
     struct lttng_viewer_trace_packet rp;
     struct lttng_viewer_cmd cmd;
     struct lttng_viewer_get_packet rq;
-    struct live_viewer_connection *viewer_connection = lttng_live_msg_iter->viewer_connection;
-    bt_self_component *self_comp = viewer_connection->self_comp;
+    live_viewer_connection *viewer_connection = lttng_live_msg_iter->viewer_connection.get();
     struct lttng_live_trace *trace = stream->trace;
     const size_t cmd_buf_len = sizeof(cmd) + sizeof(rq);
     char cmd_buf[cmd_buf_len];
     uint32_t flags, rp_status;
 
-    BT_COMP_LOGD("Requesting data from stream: cmd=%s, "
-                 "offset=%" PRIu64 ", request-len=%" PRIu64,
-                 lttng_viewer_command_string(LTTNG_VIEWER_GET_PACKET), offset, req_len);
+    BT_CPPLOGD_SPEC(viewer_connection->logger,
+                    "Requesting data from stream: cmd={}, "
+                    "offset={}, request-len={}",
+                    LTTNG_VIEWER_GET_PACKET, offset, req_len);
 
     cmd.cmd = htobe32(LTTNG_VIEWER_GET_PACKET);
     cmd.data_size = htobe64((uint64_t) sizeof(rq));
@@ -1534,83 +1233,76 @@ lttng_live_get_stream_bytes(struct lttng_live_msg_iter *lttng_live_msg_iter,
 
     viewer_status = lttng_live_send(viewer_connection, &cmd_buf, cmd_buf_len);
     if (viewer_status != LTTNG_LIVE_VIEWER_STATUS_OK) {
-        viewer_handle_send_status(self_comp, NULL, viewer_status, "get data packet command");
-        goto error_convert_status;
+        viewer_handle_send_status(viewer_status, "get data packet command");
+        return viewer_status_to_ctf_msg_iter_medium_status(viewer_status);
     }
 
     viewer_status = lttng_live_recv(viewer_connection, &rp, sizeof(rp));
     if (viewer_status != LTTNG_LIVE_VIEWER_STATUS_OK) {
-        viewer_handle_recv_status(self_comp, NULL, viewer_status, "get data packet reply");
-        goto error_convert_status;
+        viewer_handle_recv_status(viewer_status, "get data packet reply");
+        return viewer_status_to_ctf_msg_iter_medium_status(viewer_status);
     }
 
     flags = be32toh(rp.flags);
     rp_status = be32toh(rp.status);
 
-    BT_COMP_LOGD("Received response from relay daemon: cmd=%s, response=%s",
-                 lttng_viewer_command_string(LTTNG_VIEWER_GET_PACKET),
-                 lttng_viewer_get_packet_return_code_string(rp_status));
+    BT_CPPLOGD_SPEC(
+        viewer_connection->logger, "Received response from relay daemon: cmd={}, response={}",
+        LTTNG_VIEWER_GET_PACKET, static_cast<lttng_viewer_get_packet_return_code>(rp_status));
     switch (rp_status) {
     case LTTNG_VIEWER_GET_PACKET_OK:
         req_len = be32toh(rp.len);
-        BT_COMP_LOGD("Got packet from relay daemon: response=%s, packet-len=%" PRIu64 "",
-                     lttng_viewer_get_packet_return_code_string(rp_status), req_len);
+        BT_CPPLOGD_SPEC(viewer_connection->logger,
+                        "Got packet from relay daemon: response={}, packet-len={}",
+                        static_cast<lttng_viewer_get_packet_return_code>(rp_status), req_len);
         break;
     case LTTNG_VIEWER_GET_PACKET_RETRY:
         /* Unimplemented by relay daemon */
-        status = CTF_MSG_ITER_MEDIUM_STATUS_AGAIN;
-        goto end;
+        return CTF_MSG_ITER_MEDIUM_STATUS_AGAIN;
     case LTTNG_VIEWER_GET_PACKET_ERR:
         if (flags & LTTNG_VIEWER_FLAG_NEW_METADATA) {
-            BT_COMP_LOGD("Marking trace as needing new metadata: "
-                         "response=%s, response-flag=NEW_METADATA, trace-id=%" PRIu64,
-                         lttng_viewer_next_index_return_code_string(rp_status), trace->id);
+            BT_CPPLOGD_SPEC(viewer_connection->logger,
+                            "Marking trace as needing new metadata: "
+                            "response={}, response-flag=NEW_METADATA, trace-id={}",
+                            static_cast<lttng_viewer_get_packet_return_code>(rp_status), trace->id);
             trace->metadata_stream_state = LTTNG_LIVE_METADATA_STREAM_STATE_NEEDED;
         }
         if (flags & LTTNG_VIEWER_FLAG_NEW_STREAM) {
-            BT_COMP_LOGD("Marking all sessions as possibly needing new streams: "
-                         "response=%s, response-flag=NEW_STREAM",
-                         lttng_viewer_next_index_return_code_string(rp_status));
+            BT_CPPLOGD_SPEC(viewer_connection->logger,
+                            "Marking all sessions as possibly needing new streams: "
+                            "response={}, response-flag=NEW_STREAM",
+                            static_cast<lttng_viewer_get_packet_return_code>(rp_status));
             lttng_live_need_new_streams(lttng_live_msg_iter);
         }
         if (flags & (LTTNG_VIEWER_FLAG_NEW_METADATA | LTTNG_VIEWER_FLAG_NEW_STREAM)) {
-            status = CTF_MSG_ITER_MEDIUM_STATUS_AGAIN;
-            BT_COMP_LOGD("Reply with any one flags set means we should retry: response=%s",
-                         lttng_viewer_get_packet_return_code_string(rp_status));
-            goto end;
+            BT_CPPLOGD_SPEC(viewer_connection->logger,
+                            "Reply with any one flags set means we should retry: response={}",
+                            static_cast<lttng_viewer_get_packet_return_code>(rp_status));
+            return CTF_MSG_ITER_MEDIUM_STATUS_AGAIN;
         }
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Received get_data_packet response: error");
-        status = CTF_MSG_ITER_MEDIUM_STATUS_ERROR;
-        goto end;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger,
+                                     "Received get_data_packet response: error");
+        return CTF_MSG_ITER_MEDIUM_STATUS_ERROR;
     case LTTNG_VIEWER_GET_PACKET_EOF:
-        status = CTF_MSG_ITER_MEDIUM_STATUS_EOF;
-        goto end;
+        return CTF_MSG_ITER_MEDIUM_STATUS_EOF;
     default:
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Received get_data_packet response: unknown (%d)",
-                                  rp_status);
-        status = CTF_MSG_ITER_MEDIUM_STATUS_ERROR;
-        goto end;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger,
+                                     "Received get_data_packet response: unknown ({})", rp_status);
+        return CTF_MSG_ITER_MEDIUM_STATUS_ERROR;
     }
 
     if (req_len == 0) {
-        status = CTF_MSG_ITER_MEDIUM_STATUS_ERROR;
-        goto end;
+        return CTF_MSG_ITER_MEDIUM_STATUS_ERROR;
     }
 
     viewer_status = lttng_live_recv(viewer_connection, buf, req_len);
     if (viewer_status != LTTNG_LIVE_VIEWER_STATUS_OK) {
-        viewer_handle_recv_status(self_comp, NULL, viewer_status, "get data packet");
-        goto error_convert_status;
+        viewer_handle_recv_status(viewer_status, "get data packet");
+        return viewer_status_to_ctf_msg_iter_medium_status(viewer_status);
     }
     *recv_len = req_len;
 
-    status = CTF_MSG_ITER_MEDIUM_STATUS_OK;
-    goto end;
-
-error_convert_status:
-    status = viewer_status_to_ctf_msg_iter_medium_status(viewer_status);
-end:
-    return status;
+    return CTF_MSG_ITER_MEDIUM_STATUS_OK;
 }
 
 /*
@@ -1620,26 +1312,23 @@ enum lttng_live_iterator_status
 lttng_live_session_get_new_streams(struct lttng_live_session *session,
                                    bt_self_message_iterator *self_msg_iter)
 {
-    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;
     struct lttng_live_msg_iter *lttng_live_msg_iter = session->lttng_live_msg_iter;
     enum lttng_live_viewer_status viewer_status;
-    struct live_viewer_connection *viewer_connection = lttng_live_msg_iter->viewer_connection;
-    bt_self_component *self_comp = viewer_connection->self_comp;
+    live_viewer_connection *viewer_connection = lttng_live_msg_iter->viewer_connection.get();
     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) {
-        status = LTTNG_LIVE_ITERATOR_STATUS_OK;
-        goto end;
+        return LTTNG_LIVE_ITERATOR_STATUS_OK;
     }
 
-    BT_COMP_LOGD("Requesting new streams for session: cmd=%s, "
-                 "session-id=%" PRIu64,
-                 lttng_viewer_command_string(LTTNG_VIEWER_GET_NEW_STREAMS), session->id);
+    BT_CPPLOGD_SPEC(viewer_connection->logger,
+                    "Requesting new streams for session: cmd={}, session-id={}",
+                    LTTNG_VIEWER_GET_NEW_STREAMS, session->id);
 
     cmd.cmd = htobe32(LTTNG_VIEWER_GET_NEW_STREAMS);
     cmd.data_size = htobe64((uint64_t) sizeof(rq));
@@ -1658,16 +1347,14 @@ lttng_live_session_get_new_streams(struct lttng_live_session *session,
 
     viewer_status = lttng_live_send(viewer_connection, &cmd_buf, cmd_buf_len);
     if (viewer_status != LTTNG_LIVE_VIEWER_STATUS_OK) {
-        viewer_handle_send_status(self_comp, NULL, viewer_status, "get new streams command");
-        status = viewer_status_to_live_iterator_status(viewer_status);
-        goto end;
+        viewer_handle_send_status(viewer_status, "get new streams command");
+        return viewer_status_to_live_iterator_status(viewer_status);
     }
 
     viewer_status = lttng_live_recv(viewer_connection, &rp, sizeof(rp));
     if (viewer_status != LTTNG_LIVE_VIEWER_STATUS_OK) {
-        viewer_handle_recv_status(self_comp, NULL, viewer_status, "get new streams reply");
-        status = viewer_status_to_live_iterator_status(viewer_status);
-        goto end;
+        viewer_handle_recv_status(viewer_status, "get new streams reply");
+        return viewer_status_to_live_iterator_status(viewer_status);
     }
 
     streams_count = be32toh(rp.streams_count);
@@ -1678,142 +1365,75 @@ lttng_live_session_get_new_streams(struct lttng_live_session *session,
         break;
     case LTTNG_VIEWER_NEW_STREAMS_NO_NEW:
         session->new_streams_needed = false;
-        goto end;
+        return LTTNG_LIVE_ITERATOR_STATUS_OK;
     case LTTNG_VIEWER_NEW_STREAMS_HUP:
         session->new_streams_needed = false;
         session->closed = true;
-        status = LTTNG_LIVE_ITERATOR_STATUS_END;
-        goto end;
+        return LTTNG_LIVE_ITERATOR_STATUS_END;
     case LTTNG_VIEWER_NEW_STREAMS_ERR:
-        BT_COMP_LOGD("Received get_new_streams response: error");
-        status = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
-        goto end;
+        BT_CPPLOGD_SPEC(viewer_connection->logger, "Received get_new_streams response: error");
+        return LTTNG_LIVE_ITERATOR_STATUS_ERROR;
     default:
-        BT_COMP_LOGE_APPEND_CAUSE(self_comp,
-                                  "Received get_new_streams response: Unknown:"
-                                  "return code %u",
-                                  be32toh(rp.status));
-        status = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
-        goto end;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger,
+                                     "Received get_new_streams response: Unknown return code {}",
+                                     be32toh(rp.status));
+        return LTTNG_LIVE_ITERATOR_STATUS_ERROR;
     }
 
     viewer_status = receive_streams(session, streams_count, self_msg_iter);
     if (viewer_status != LTTNG_LIVE_VIEWER_STATUS_OK) {
-        viewer_handle_recv_status(self_comp, NULL, viewer_status, "new streams");
-        status = viewer_status_to_live_iterator_status(viewer_status);
-        goto end;
+        viewer_handle_recv_status(viewer_status, "new streams");
+        return viewer_status_to_live_iterator_status(viewer_status);
     }
 
-    status = LTTNG_LIVE_ITERATOR_STATUS_OK;
-end:
-    return status;
+    return LTTNG_LIVE_ITERATOR_STATUS_OK;
 }
 
-enum lttng_live_viewer_status live_viewer_connection_create(
-    bt_self_component *self_comp, bt_self_component_class *self_comp_class,
-    bt_logging_level log_level, const char *url, bool in_query,
-    struct lttng_live_msg_iter *lttng_live_msg_iter, struct live_viewer_connection **viewer)
+enum lttng_live_viewer_status
+live_viewer_connection_create(const char *url, bool in_query,
+                              struct lttng_live_msg_iter *lttng_live_msg_iter,
+                              const bt2c::Logger& parentLogger, live_viewer_connection::UP& viewer)
 {
-    struct live_viewer_connection *viewer_connection;
-    enum lttng_live_viewer_status status;
-
-    viewer_connection = g_new0(struct live_viewer_connection, 1);
+    auto viewer_connection = bt2s::make_unique<live_viewer_connection>(parentLogger);
 
-    if (bt_socket_init(log_level) != 0) {
-        BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
-                                                "Failed to init socket");
-        status = LTTNG_LIVE_VIEWER_STATUS_ERROR;
-        goto error;
+    if (bt_socket_init(viewer_connection->logger) != 0) {
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger, "Failed to init socket");
+        return LTTNG_LIVE_VIEWER_STATUS_ERROR;
     }
 
-    viewer_connection->log_level = log_level;
-
-    viewer_connection->self_comp = self_comp;
-    viewer_connection->self_comp_class = self_comp_class;
-
     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) {
-        BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
-                                                "Failed to allocate URL buffer");
-        status = LTTNG_LIVE_VIEWER_STATUS_ERROR;
-        goto error;
-    }
+    viewer_connection->url = url;
+
+    BT_CPPLOGD_SPEC(viewer_connection->logger, "Establishing connection to url \"{}\"...", url);
+    const auto status = lttng_live_connect_viewer(viewer_connection.get());
 
-    BT_COMP_OR_COMP_CLASS_LOGD(self_comp, self_comp_class,
-                               "Establishing connection to url \"%s\"...", url);
-    status = lttng_live_connect_viewer(viewer_connection);
     /*
      * Only print error and append cause in case of error. not in case of
      * interruption.
      */
     if (status == LTTNG_LIVE_VIEWER_STATUS_ERROR) {
-        BT_COMP_OR_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp, self_comp_class,
-                                                "Failed to establish connection: "
-                                                "url=\"%s\"",
-                                                url);
-        goto error;
+        BT_CPPLOGE_APPEND_CAUSE_SPEC(viewer_connection->logger,
+                                     "Failed to establish connection: "
+                                     "url=\"{}\"",
+                                     url);
+        return status;
     } else if (status == LTTNG_LIVE_VIEWER_STATUS_INTERRUPTED) {
-        goto error;
+        return status;
     }
-    BT_COMP_OR_COMP_CLASS_LOGD(self_comp, self_comp_class,
-                               "Connection to url \"%s\" is established", url);
+    BT_CPPLOGD_SPEC(viewer_connection->logger, "Connection to url \"{}\" is established", url);
 
-    *viewer = viewer_connection;
-    status = LTTNG_LIVE_VIEWER_STATUS_OK;
-    goto end;
-
-error:
-    if (viewer_connection) {
-        live_viewer_connection_destroy(viewer_connection);
-    }
-end:
-    return status;
+    viewer = std::move(viewer_connection);
+    return LTTNG_LIVE_VIEWER_STATUS_OK;
 }
 
-void live_viewer_connection_destroy(struct live_viewer_connection *viewer_connection)
+live_viewer_connection::~live_viewer_connection()
 {
-    bt_self_component *self_comp = viewer_connection->self_comp;
-    bt_self_component_class *self_comp_class = viewer_connection->self_comp_class;
-
-    if (!viewer_connection) {
-        goto end;
-    }
-
-    BT_COMP_OR_COMP_CLASS_LOGD(self_comp, self_comp_class,
-                               "Closing connection to relay:"
-                               "relay-url=\"%s\"",
-                               viewer_connection->url->str);
+    BT_CPPLOGD_SPEC(this->logger, "Closing connection to relay: relay-url=\"{}\"", this->url);
 
-    lttng_live_disconnect_viewer(viewer_connection);
-
-    if (viewer_connection->url) {
-        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);
-    }
-
-    if (viewer_connection->proto) {
-        g_string_free(viewer_connection->proto, true);
-    }
-
-    g_free(viewer_connection);
+    viewer_connection_close_socket(this);
 
     bt_socket_fini();
-
-end:
-    return;
 }
index 67e71e0c3770cb925fffa13e6f399c3afd8fbe27..0f284581e1de33328f631544906d4c89be823adc 100644 (file)
@@ -7,12 +7,17 @@
 #ifndef LTTNG_LIVE_VIEWER_CONNECTION_H
 #define LTTNG_LIVE_VIEWER_CONNECTION_H
 
+#include <string>
+
 #include <glib.h>
 #include <stdint.h>
 
 #include <babeltrace2/babeltrace.h>
 
-#include "compat/socket.h"
+#include "compat/socket.hpp"
+#include "cpp-common/bt2/value.hpp"
+#include "cpp-common/bt2c/glib-up.hpp"
+#include "cpp-common/bt2c/logging.hpp"
 
 #define LTTNG_DEFAULT_NETWORK_VIEWER_PORT 5344
 
@@ -46,25 +51,32 @@ enum lttng_live_get_one_metadata_status
 
 struct live_viewer_connection
 {
-    bt_logging_level log_level;
-    bt_self_component *self_comp;
-    bt_self_component_class *self_comp_class;
+    using UP = std::unique_ptr<live_viewer_connection>;
+
+    explicit live_viewer_connection(const bt2c::Logger& parentLogger) :
+        logger {parentLogger, "PLUGIN/SRC.CTF.LTTNG-LIVE/VIEWER"}
+    {
+    }
+
+    ~live_viewer_connection();
 
-    GString *url;
+    bt2c::Logger logger;
 
-    GString *relay_hostname;
-    GString *target_hostname;
-    GString *session_name;
-    GString *proto;
+    std::string url;
 
-    BT_SOCKET control_sock;
-    int port;
+    bt2c::GStringUP relay_hostname;
+    bt2c::GStringUP target_hostname;
+    bt2c::GStringUP session_name;
+    bt2c::GStringUP proto;
 
-    int32_t major;
-    int32_t minor;
+    BT_SOCKET control_sock {};
+    int port = 0;
 
-    bool in_query;
-    struct lttng_live_msg_iter *lttng_live_msg_iter;
+    int32_t major = 0;
+    int32_t minor = 0;
+
+    bool in_query = false;
+    struct lttng_live_msg_iter *lttng_live_msg_iter = nullptr;
 };
 
 struct packet_index_time
@@ -89,19 +101,14 @@ struct packet_index
 };
 
 enum lttng_live_viewer_status
-live_viewer_connection_create(bt_self_component *self_comp,
-                              bt_self_component_class *self_comp_class, bt_logging_level log_level,
-                              const char *url, bool in_query,
+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);
-
-void live_viewer_connection_destroy(struct live_viewer_connection *conn);
+                              const bt2c::Logger& parentLogger, live_viewer_connection::UP& viewer);
 
 enum lttng_live_viewer_status
 lttng_live_create_viewer_session(struct lttng_live_msg_iter *lttng_live_msg_iter);
 
-bt_component_class_query_method_status
-live_viewer_connection_list_sessions(struct live_viewer_connection *viewer_connection,
-                                     const bt_value **user_result);
+bt2::Value::Shared
+live_viewer_connection_list_sessions(struct live_viewer_connection *viewer_connection);
 
 #endif /* LTTNG_LIVE_VIEWER_CONNECTION_H */
index 1962f5dfe3506a775c754370e2a7b1cfd96c9326..5c9f9e75591a6039a8ccd438ecf674aea8806004 100644 (file)
@@ -413,8 +413,11 @@ void write_value(struct details_write_ctx *ctx, const bt_value *value,
                write_float_prop_value(ctx, bt_value_real_get(value));
                break;
        case BT_VALUE_TYPE_STRING:
-               write_sp(ctx);
-               write_str_prop_value(ctx, bt_value_string_get(value));
+               if (strlen(bt_value_string_get(value)) > 0) {
+                       write_sp(ctx);
+                       write_str_prop_value(ctx, bt_value_string_get(value));
+               }
+
                break;
        case BT_VALUE_TYPE_ARRAY:
        {
@@ -2122,16 +2125,19 @@ void write_trace(struct details_write_ctx *ctx, const bt_trace *trace)
 
                        BT_ASSERT_DBG(value);
                        write_compound_member_name(ctx, name);
-                       write_sp(ctx);
 
                        if (bt_value_get_type(value) ==
                                        BT_VALUE_TYPE_SIGNED_INTEGER) {
+                               write_sp(ctx);
                                write_int_prop_value(ctx,
                                        bt_value_integer_signed_get(value));
                        } else if (bt_value_get_type(value) ==
                                        BT_VALUE_TYPE_STRING) {
-                               write_str_prop_value(ctx,
-                                       bt_value_string_get(value));
+                               if (strlen(bt_value_string_get(value)) > 0) {
+                                       write_sp(ctx);
+                                       write_str_prop_value(ctx,
+                                               bt_value_string_get(value));
+                               }
                        } else {
                                bt_common_abort();
                        }
index a08235e80cb4219786717fb4bbeb837c43c3070a..4c7e18337b5e459787ad2233080f1b4c8d1eea6a 100644 (file)
@@ -1311,11 +1311,9 @@ int print_field(struct pretty_component *pretty,
        } else if (bt_field_class_type_is(class_id,
                        BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY)) {
                return print_sequence(pretty, field, print_names);
-       } else {
-               // TODO: log instead
-               fprintf(pretty->err, "[error] Unknown type id: %d\n", (int) class_id);
-               return -1;
        }
+
+       bt_common_abort();
 }
 
 static
index ea2df4d03136316bd8df66ee8e034ab5547d26f8..fb2a111936a1213594de541447862cdbb4de85e0 100644 (file)
@@ -13,7 +13,7 @@ namespace bt2mux {
 Comp::Comp(const bt2::SelfFilterComponent selfComp, const bt2::ConstMapValue params, void *) :
     bt2::UserFilterComponent<Comp, MsgIter> {selfComp, "PLUGIN/FLT.UTILS.MUXER"}
 {
-    BT_CPPLOGI_STR("Initializing component.");
+    BT_CPPLOGI("Initializing component.");
 
     /* No parameters expected */
     if (!params.isEmpty()) {
@@ -28,10 +28,10 @@ Comp::Comp(const bt2::SelfFilterComponent selfComp, const bt2::ConstMapValue par
     try {
         this->_addOutputPort("out");
     } catch (const bt2c::Error&) {
-        BT_CPPLOGE_STR_APPEND_CAUSE_AND_RETHROW("Failed to add a single output port.");
+        BT_CPPLOGE_APPEND_CAUSE_AND_RETHROW("Failed to add a single output port.");
     }
 
-    BT_CPPLOGI_STR("Initialized component.");
+    BT_CPPLOGI("Initialized component.");
 }
 
 void Comp::_inputPortConnected(const bt2::SelfComponentInputPort, const bt2::ConstOutputPort)
@@ -44,7 +44,7 @@ void Comp::_addAvailInputPort()
     try {
         this->_addInputPort(fmt::format("in{}", this->_inputPorts().length()));
     } catch (const bt2c::Error&) {
-        BT_CPPLOGE_STR_APPEND_CAUSE_AND_RETHROW("Failed to add an available input port.");
+        BT_CPPLOGE_APPEND_CAUSE_AND_RETHROW("Failed to add an available input port.");
     }
 
     BT_CPPLOGI("Added one available input port: name={}", this->_inputPorts().back().name());
index b1d869458e95b589d89088db52c9e08710d309b0..2754bb1143c61bc597fc59bbda2c13569039add3 100644 (file)
@@ -125,7 +125,7 @@ void MsgIter::_next(bt2::ConstMessageArray& msgs)
             oldestUpstreamMsgIter.portName());
 
         try {
-            if (G_LIKELY(oldestUpstreamMsgIter.reload() == UpstreamMsgIter::ReloadStatus::MORE)) {
+            if (G_LIKELY(oldestUpstreamMsgIter.reload() == UpstreamMsgIter::ReloadStatus::More)) {
                 /* New current message: update heap */
                 _mHeap.replaceTop(&oldestUpstreamMsgIter);
                 BT_CPPLOGD("More messages available; updated heap: port-name={}, heap-len={}",
@@ -166,7 +166,7 @@ void MsgIter::_ensureFullHeap()
                    "port-name={}, heap-len={}, to-reload-len={}",
                    upstreamMsgIter.portName(), _mHeap.len(), _mUpstreamMsgItersToReload.size());
 
-        if (G_LIKELY(upstreamMsgIter.reload() == UpstreamMsgIter::ReloadStatus::MORE)) {
+        if (G_LIKELY(upstreamMsgIter.reload() == UpstreamMsgIter::ReloadStatus::More)) {
             /* New current message: move to heap */
             _mHeap.insert(&upstreamMsgIter);
             BT_CPPLOGD("More messages available; "
@@ -253,16 +253,16 @@ void MsgIter::_validateMsgClkCls(const bt2::ConstMessage msg)
         const auto actualClockCls = error.actualClockCls();
 
         switch (error.type()) {
-        case Type::EXPECTING_NO_CLOCK_CLASS_GOT_ONE:
+        case Type::ExpectingNoClockClassGotOne:
             BT_CPPLOGE_APPEND_CAUSE_AND_THROW(bt2::Error,
                                               "Expecting no clock class, but got one: "
                                               "clock-class-addr={}, clock-class-name={}",
                                               fmt::ptr(actualClockCls->libObjPtr()),
                                               actualClockCls->name());
 
-        case Type::EXPECTING_ORIGIN_UNIX_GOT_NONE:
-        case Type::EXPECTING_ORIGIN_UUID_GOT_NONE:
-        case Type::EXPECTING_ORIGIN_NO_UUID_GOT_NONE:
+        case Type::ExpectingOriginUnixGotNone:
+        case Type::ExpectingOriginUuidGotNone:
+        case Type::ExpectingOriginNoUuidGotNone:
         {
             const auto streamCls = *error.streamCls();
 
@@ -274,7 +274,7 @@ void MsgIter::_validateMsgClkCls(const bt2::ConstMessage msg)
                                               streamCls.id());
         }
 
-        case Type::EXPECTING_ORIGIN_UNIX_GOT_OTHER:
+        case Type::ExpectingOriginUnixGotOther:
             BT_CPPLOGE_APPEND_CAUSE_AND_THROW(bt2::Error,
                                               "Expecting a clock class having a Unix epoch origin, "
                                               "but got one not having a Unix epoch origin: "
@@ -282,7 +282,7 @@ void MsgIter::_validateMsgClkCls(const bt2::ConstMessage msg)
                                               fmt::ptr(actualClockCls->libObjPtr()),
                                               actualClockCls->name());
 
-        case Type::EXPECTING_ORIGIN_UUID_GOT_UNIX:
+        case Type::ExpectingOriginUuidGotUnix:
             BT_CPPLOGE_APPEND_CAUSE_AND_THROW(
                 bt2::Error,
                 "Expecting a clock class not having a Unix epoch origin, "
@@ -290,14 +290,14 @@ void MsgIter::_validateMsgClkCls(const bt2::ConstMessage msg)
                 "clock-class-addr={}, clock-class-name={}",
                 fmt::ptr(actualClockCls->libObjPtr()), actualClockCls->name());
 
-        case Type::EXPECTING_ORIGIN_UUID_GOT_NO_UUID:
+        case Type::ExpectingOriginUuidGotNoUuid:
             BT_CPPLOGE_APPEND_CAUSE_AND_THROW(
                 bt2::Error,
                 "Expecting a clock class with a UUID, but got one without a UUID: "
                 "clock-class-addr={}, clock-class-name={}",
                 fmt::ptr(actualClockCls->libObjPtr()), actualClockCls->name());
 
-        case Type::EXPECTING_ORIGIN_UUID_GOT_OTHER_UUID:
+        case Type::ExpectingOriginUuidGotOtherUuid:
             BT_CPPLOGE_APPEND_CAUSE_AND_THROW(bt2::Error,
                                               "Expecting a clock class with a specific UUID, "
                                               "but got one with a different UUID: "
@@ -307,7 +307,7 @@ void MsgIter::_validateMsgClkCls(const bt2::ConstMessage msg)
                                               actualClockCls->name(), *error.expectedUuid(),
                                               *actualClockCls->uuid());
 
-        case Type::EXPECTING_ORIGIN_NO_UUID_GOT_OTHER:
+        case Type::ExpectingOriginNoUuidGotOther:
         {
             const auto expectedClockCls = error.expectedClockCls();
 
@@ -367,18 +367,17 @@ bool MsgIter::_HeapComparator::operator()(
              * the oldest one, that is, the one having the smallest
              * timestamp.
              */
-            BT_CPPLOGT_STR("Timestamp of message A is less than timestamp of message B: oldest=A");
+            BT_CPPLOGT("Timestamp of message A is less than timestamp of message B: oldest=A");
             return true;
         } else if (*msgTsA > *msgTsB) {
-            BT_CPPLOGT_STR(
-                "Timestamp of message A is greater than timestamp of message B: oldest=B");
+            BT_CPPLOGT("Timestamp of message A is greater than timestamp of message B: oldest=B");
             return false;
         }
     } else if (msgTsA && !msgTsB) {
-        BT_CPPLOGT_STR("Message A has a timestamp, but message B has none: oldest=B");
+        BT_CPPLOGT("Message A has a timestamp, but message B has none: oldest=B");
         return false;
     } else if (!msgTsA && msgTsB) {
-        BT_CPPLOGT_STR("Message B has a timestamp, but message A has none: oldest=A");
+        BT_CPPLOGT("Message B has a timestamp, but message A has none: oldest=A");
         return true;
     }
 
index 28f5be4741b92b5f04805d35787e94a248cfbd53..ea597da228fd9fde4febd56f550e91353ade6c08 100644 (file)
@@ -33,45 +33,45 @@ namespace {
 bt2::OptionalBorrowedObject<bt2::ConstClockSnapshot> msgCs(const bt2::ConstMessage msg) noexcept
 {
     switch (msg.type()) {
-    case bt2::MessageType::EVENT:
+    case bt2::MessageType::Event:
         if (msg.asEvent().streamClassDefaultClockClass()) {
             return msg.asEvent().defaultClockSnapshot();
         }
 
         break;
-    case bt2::MessageType::PACKET_BEGINNING:
+    case bt2::MessageType::PacketBeginning:
         if (msg.asPacketBeginning().packet().stream().cls().packetsHaveBeginningClockSnapshot()) {
             return msg.asPacketBeginning().defaultClockSnapshot();
         }
 
         break;
-    case bt2::MessageType::PACKET_END:
+    case bt2::MessageType::PacketEnd:
         if (msg.asPacketEnd().packet().stream().cls().packetsHaveEndClockSnapshot()) {
             return msg.asPacketEnd().defaultClockSnapshot();
         }
 
         break;
-    case bt2::MessageType::DISCARDED_EVENTS:
+    case bt2::MessageType::DiscardedEvents:
         if (msg.asDiscardedEvents().stream().cls().discardedEventsHaveDefaultClockSnapshots()) {
             return msg.asDiscardedEvents().beginningDefaultClockSnapshot();
         }
 
         break;
-    case bt2::MessageType::DISCARDED_PACKETS:
+    case bt2::MessageType::DiscardedPackets:
         if (msg.asDiscardedPackets().stream().cls().discardedPacketsHaveDefaultClockSnapshots()) {
             return msg.asDiscardedPackets().beginningDefaultClockSnapshot();
         }
 
         break;
-    case bt2::MessageType::MESSAGE_ITERATOR_INACTIVITY:
+    case bt2::MessageType::MessageIteratorInactivity:
         return msg.asMessageIteratorInactivity().clockSnapshot();
-    case bt2::MessageType::STREAM_BEGINNING:
+    case bt2::MessageType::StreamBeginning:
         if (msg.asStreamBeginning().streamClassDefaultClockClass()) {
             return msg.asStreamBeginning().defaultClockSnapshot();
         }
 
         break;
-    case bt2::MessageType::STREAM_END:
+    case bt2::MessageType::StreamEnd:
         if (msg.asStreamEnd().streamClassDefaultClockClass()) {
             return msg.asStreamEnd().defaultClockSnapshot();
         }
@@ -108,7 +108,7 @@ UpstreamMsgIter::ReloadStatus UpstreamMsgIter::reload()
     if (G_UNLIKELY(!_mMsgs.msgs)) {
         /* Still none: no more */
         _mMsgTs.reset();
-        return ReloadStatus::NO_MORE;
+        return ReloadStatus::NoMore;
     } else {
         if (const auto cs = msgCs(this->msg())) {
             _mMsgTs = cs->nsFromOrigin();
@@ -120,7 +120,7 @@ UpstreamMsgIter::ReloadStatus UpstreamMsgIter::reload()
         }
 
         _mDiscardRequired = true;
-        return ReloadStatus::MORE;
+        return ReloadStatus::More;
     }
 }
 
index 2ae663f8bca9406b02fea5a002a31b6891f3db36..4d89da390f051e1c7293ed02b83b48f015af3b3a 100644 (file)
@@ -33,8 +33,8 @@ public:
     /* Return type of reload() */
     enum class ReloadStatus
     {
-        MORE,
-        NO_MORE,
+        More,
+        NoMore,
     };
 
     /*
diff --git a/tests/bindings/python/bt2/.gitignore b/tests/bindings/python/bt2/.gitignore
deleted file mode 100644 (file)
index 7446a35..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-htmlcov
-.coverage
index 9c7db7cf55128335e99d264e4bf8d0736006c07c..5c534621a86ab058263a00a0136911b5cf59db2f 100644 (file)
@@ -237,8 +237,8 @@ Stream beginning:
       kernel_version: #46-Ubuntu SMP Thu Dec 6 14:45:28 UTC 2018
       sysname: Linux
       trace_buffering_scheme: global
-      trace_creation_datetime: 
-      trace_name: 
+      trace_creation_datetime:
+      trace_name:
       tracer_major: 2
       tracer_minor: 11
       tracer_name: lttng-modules
@@ -261,8 +261,8 @@ Stream beginning:
       kernel_version: #46-Ubuntu SMP Thu Dec 6 14:45:28 UTC 2018
       sysname: Linux
       trace_buffering_scheme: global
-      trace_creation_datetime: 
-      trace_name: 
+      trace_creation_datetime:
+      trace_name:
       tracer_major: 2
       tracer_minor: 11
       tracer_name: lttng-modules
@@ -285,8 +285,8 @@ Stream beginning:
       kernel_version: #46-Ubuntu SMP Thu Dec 6 14:45:28 UTC 2018
       sysname: Linux
       trace_buffering_scheme: global
-      trace_creation_datetime: 
-      trace_name: 
+      trace_creation_datetime:
+      trace_name:
       tracer_major: 2
       tracer_minor: 11
       tracer_name: lttng-modules
@@ -309,8 +309,8 @@ Stream beginning:
       kernel_version: #46-Ubuntu SMP Thu Dec 6 14:45:28 UTC 2018
       sysname: Linux
       trace_buffering_scheme: global
-      trace_creation_datetime: 
-      trace_name: 
+      trace_creation_datetime:
+      trace_name:
       tracer_major: 2
       tracer_minor: 11
       tracer_name: lttng-modules
index a8a4d626b7f0d0ac0fd07ef3142825d0b6f68b4d..aa7e68768390aaa4b4e1fb0692fbbbe6ed2b4de2 100644 (file)
@@ -21,8 +21,8 @@ class ClockClsCompatRunIn final : public RunIn
 public:
     enum class MsgType
     {
-        STREAM_BEG,
-        MSG_ITER_INACTIVITY,
+        StreamBeg,
+        MsgIterInactivity,
     };
 
     using CreateClockCls = bt2::ClockClass::Shared (*)(bt2::SelfComponent);
@@ -58,7 +58,7 @@ private:
         const auto clockCls = createClockCls(self.component());
 
         switch (msgType) {
-        case MsgType::STREAM_BEG:
+        case MsgType::StreamBeg:
         {
             const auto streamCls = trace.cls().createStreamClass();
 
@@ -69,7 +69,7 @@ private:
             return self.createStreamBeginningMessage(*streamCls->instantiate(trace));
         }
 
-        case MsgType::MSG_ITER_INACTIVITY:
+        case MsgType::MsgIterInactivity:
             BT_ASSERT(clockCls);
             return self.createMessageIteratorInactivityMessage(*clockCls, 12);
         };
@@ -85,10 +85,10 @@ private:
 __attribute__((used)) const char *format_as(const ClockClsCompatRunIn::MsgType msgType)
 {
     switch (msgType) {
-    case ClockClsCompatRunIn::MsgType::STREAM_BEG:
+    case ClockClsCompatRunIn::MsgType::StreamBeg:
         return "sb";
 
-    case ClockClsCompatRunIn::MsgType::MSG_ITER_INACTIVITY:
+    case ClockClsCompatRunIn::MsgType::MsgIterInactivity:
         return "mii";
     }
 
@@ -124,13 +124,13 @@ void addClkClsCompatTriggers(CondTriggers& triggers)
          * without a clock class.
          */
         static constexpr std::array<ClockClsCompatRunIn::MsgType, 2> msgTypes {
-            ClockClsCompatRunIn::MsgType::STREAM_BEG,
-            ClockClsCompatRunIn::MsgType::MSG_ITER_INACTIVITY,
+            ClockClsCompatRunIn::MsgType::StreamBeg,
+            ClockClsCompatRunIn::MsgType::MsgIterInactivity,
         };
 
         const auto isInvalidCase = [](const ClockClsCompatRunIn::MsgType msgType,
                                       const ClockClsCompatRunIn::CreateClockCls createClockCls) {
-            return msgType == ClockClsCompatRunIn::MsgType::MSG_ITER_INACTIVITY &&
+            return msgType == ClockClsCompatRunIn::MsgType::MsgIterInactivity &&
                    createClockCls == noClockClass;
         };
 
@@ -146,7 +146,7 @@ void addClkClsCompatTriggers(CondTriggers& triggers)
 
                 triggers.emplace_back(bt2s::make_unique<RunInCondTrigger<ClockClsCompatRunIn>>(
                     ClockClsCompatRunIn {msgType1, createClockCls1, msgType2, createClockCls2},
-                    CondTrigger::Type::POST, condId, fmt::format("{}-{}", msgType1, msgType2)));
+                    CondTrigger::Type::Post, condId, fmt::format("{}-{}", msgType1, msgType2)));
             }
         }
     };
index 3e1cfe864140ee0afe0fee53ba262a913ade2cab..02fe33cee929a8797a7659aaee497307ad0492cf 100644 (file)
@@ -10,7 +10,7 @@
 
 #include "cpp-common/bt2/graph.hpp"
 #include "cpp-common/bt2c/c-string-view.hpp"
-#include "cpp-common/bt2c/span.hpp"
+#include "cpp-common/bt2c/make-span.hpp"
 #include "cpp-common/bt2s/make-unique.hpp"
 
 #include "clk-cls-compat-postconds-triggers.hpp"
@@ -88,25 +88,25 @@ int main(const int argc, const char ** const argv)
         [] {
             bt2::Graph::create(292);
         },
-        CondTrigger::Type::PRE, "graph-create:valid-mip-version"));
+        CondTrigger::Type::Pre, "graph-create:valid-mip-version"));
 
     triggers.emplace_back(makeRunInCompInitTrigger(
         [](const bt2::SelfComponent self) {
             createUIntFc(self)->fieldValueRange(0);
         },
-        CondTrigger::Type::PRE, "field-class-integer-set-field-value-range:valid-n", "0"));
+        CondTrigger::Type::Pre, "field-class-integer-set-field-value-range:valid-n", "0"));
 
     triggers.emplace_back(makeRunInCompInitTrigger(
         [](const bt2::SelfComponent self) {
             createUIntFc(self)->fieldValueRange(65);
         },
-        CondTrigger::Type::PRE, "field-class-integer-set-field-value-range:valid-n", "gt-64"));
+        CondTrigger::Type::Pre, "field-class-integer-set-field-value-range:valid-n", "gt-64"));
 
     triggers.emplace_back(makeSimpleTrigger(
         [] {
             bt_field_class_integer_set_field_value_range(nullptr, 23);
         },
-        CondTrigger::Type::PRE, "field-class-integer-set-field-value-range:not-null:field-class"));
+        CondTrigger::Type::Pre, "field-class-integer-set-field-value-range:not-null:field-class"));
 
     addClkClsCompatTriggers(triggers);
     condMain(bt2c::makeSpan(argv, argc), triggers);
index b7d2c487e03504eac70ed44f47f8ebb826154b55..4d4e3b1dd14454248f787722922605e45ded7279 100644 (file)
@@ -19,7 +19,7 @@
 CondTrigger::CondTrigger(const Type type, const std::string& condId,
                          const bt2c::CStringView nameSuffix) noexcept :
     _mType {type},
-    _mCondId {fmt::format("{}:{}", type == Type::PRE ? "pre" : "post", condId)},
+    _mCondId {fmt::format("{}:{}", type == Type::Pre ? "pre" : "post", condId)},
     _mName {fmt::format("{}{}{}", condId, nameSuffix ? "-" : "", nameSuffix ? nameSuffix : "")}
 {
 }
index d8abfafe11ac2ad2c2861146bbd80423c86dd58b..2ea53bc4e8d7739f488df13decac8f8d8f514986 100644 (file)
@@ -37,8 +37,8 @@ public:
      */
     enum class Type
     {
-        PRE,
-        POST,
+        Pre,
+        Post,
     };
 
 protected:
index b74eabf4e2708b75756a9fa38e736f2bb6857841..e50d1c44981f227cd573e96bea4badee173ff56f 100644 (file)
@@ -63,7 +63,7 @@ void test_bt_no_dwarf(const char *data_dir)
 static
 void test_bt_dwarf(const char *data_dir)
 {
-       int fd, ret, tag;
+       int fd, ret, tag = -1;
        char *path;
        char *die_name = NULL;
        struct bt_dwarf_cu *cu = NULL;
index c922d8ccbfd2bb9a0e8842a5855e7e6a3a5278ff..ef05d1d590d518f37598ab4a8b088a0a0bcac0ad 100644 (file)
@@ -20,19 +20,19 @@ namespace {
 enum class MsgType
 {
     /* Send stream beginning and stream end messages. */
-    STREAM,
+    Stream,
 
     /* Send a message iterator inactivity message. */
-    MSG_ITER_INACTIVITY,
+    MsgIterInactivity,
 };
 
 __attribute__((used)) const char *format_as(MsgType msgType) noexcept
 {
     switch (msgType) {
-    case MsgType::STREAM:
+    case MsgType::Stream:
         return "stream beginning/end";
 
-    case MsgType::MSG_ITER_INACTIVITY:
+    case MsgType::MsgIterInactivity:
         return "message iterator inactivity";
     }
 
@@ -78,7 +78,7 @@ private:
         const auto clockCls = _mData->createClockClass(_mSelf.component());
 
         switch (_mData->msgType) {
-        case MsgType::STREAM:
+        case MsgType::Stream:
         {
             const auto traceCls = _mSelf.component().createTraceClass();
             const auto streamCls = traceCls->createStreamClass();
@@ -113,7 +113,7 @@ private:
             break;
         }
 
-        case MsgType::MSG_ITER_INACTIVITY:
+        case MsgType::MsgIterInactivity:
             msgs.append(
                 this->_createMessageIteratorInactivityMessage(*clockCls, *_mData->clockSnapshot));
             break;
@@ -180,8 +180,8 @@ bt2::ClockClass::Shared noClockClass(bt2::SelfComponent) noexcept
 void ErrorTestCase::run() const noexcept
 {
     static constexpr std::array<MsgType, 2> msgTypes {
-        MsgType::STREAM,
-        MsgType::MSG_ITER_INACTIVITY,
+        MsgType::Stream,
+        MsgType::MsgIterInactivity,
     };
 
     for (const auto msgType1 : msgTypes) {
@@ -190,8 +190,8 @@ void ErrorTestCase::run() const noexcept
              * It's not possible to create message iterator inactivity
              * messages without a clock class. Skip those cases.
              */
-            if ((msgType1 == MsgType::MSG_ITER_INACTIVITY && _mCreateClockClass1 == noClockClass) ||
-                (msgType2 == MsgType::MSG_ITER_INACTIVITY && _mCreateClockClass2 == noClockClass)) {
+            if ((msgType1 == MsgType::MsgIterInactivity && _mCreateClockClass1 == noClockClass) ||
+                (msgType2 == MsgType::MsgIterInactivity && _mCreateClockClass2 == noClockClass)) {
                 continue;
             }
 
@@ -219,7 +219,7 @@ void ErrorTestCase::run() const noexcept
              *
              * Skip those cases.
              */
-            if (msgType1 == MsgType::MSG_ITER_INACTIVITY && _mCreateClockClass2 == noClockClass) {
+            if (msgType1 == MsgType::MsgIterInactivity && _mCreateClockClass2 == noClockClass) {
                 continue;
             }
 
@@ -255,7 +255,7 @@ void ErrorTestCase::_runOne(const MsgType msgType1, const MsgType msgType2) cons
         const auto srcComp1 =
             graph->addComponent(*srcCompCls, "source-1",
                                 TestSourceData {_mCreateClockClass1, msgType1,
-                                                msgType1 == MsgType::MSG_ITER_INACTIVITY ?
+                                                msgType1 == MsgType::MsgIterInactivity ?
                                                     bt2s::optional<std::uint64_t> {10} :
                                                     bt2s::nullopt});
         const auto srcComp2 =
diff --git a/tests/python-plugin-provider/.gitignore b/tests/python-plugin-provider/.gitignore
deleted file mode 100644 (file)
index 7446a35..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-htmlcov
-.coverage
index 9081a88e2e871324448adfc0620bae33db4cc4fb..692def5d7656d58e7b68e39b99481b038dbdf401 100644 (file)
@@ -430,7 +430,8 @@ bt_run_in_py_env() {
        if [[ ${BT_TESTS_ENABLE_ASAN:-} == 1 ]]; then
                if $BT_TESTS_CC_BIN --version | head -n 1 | bt_grep -q '^gcc'; then
                        local -r lib_asan=$($BT_TESTS_CC_BIN -print-file-name=libasan.so)
-                       local -x LD_PRELOAD=$lib_asan${LD_PRELOAD:+:}${LD_PRELOAD:-}
+                       local -r lib_stdcxx=$($BT_TESTS_CC_BIN -print-file-name=libstdc++.so)
+                       local -x LD_PRELOAD=$lib_asan:$lib_stdcxx${LD_PRELOAD:+:}${LD_PRELOAD:-}
                fi
 
                local -x ASAN_OPTIONS=${ASAN_OPTIONS:-}${ASAN_OPTIONS:+,}detect_leaks=0
This page took 0.695904 seconds and 4 git commands to generate.