From: Philippe Proulx Date: Thu, 9 May 2024 04:48:35 +0000 (-0400) Subject: test-field.sh: make sure bt_run_in_py_env() and bt_cli() succeed X-Git-Url: http://git.efficios.com/?p=babeltrace.git;a=commitdiff_plain;h=HEAD;hp=4b9e2e3d5986e17f1594c24dea430cb51a529360 test-field.sh: make sure bt_run_in_py_env() and bt_cli() succeed Signed-off-by: Philippe Proulx Change-Id: I26c033a56d2c214087db058bdc19d20312a6f0e1 Reviewed-on: https://review.lttng.org/c/babeltrace/+/12535 Reviewed-by: Simon Marchi Tested-by: jenkins --- diff --git a/.clang-tidy b/.clang-tidy index acbb1421..a9d4ceb8 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -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, diff --git a/.gitignore b/.gitignore index c63fcaf0..904372ce 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/.reuse/dep5 b/.reuse/dep5 index f880aacc..2f272d84 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -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 diff --git a/CONTRIBUTING.adoc b/CONTRIBUTING.adoc index 431a1669..171fcb14 100644 --- a/CONTRIBUTING.adoc +++ b/CONTRIBUTING.adoc @@ -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; diff --git a/README.adoc b/README.adoc index b47dd1d8..5c7c48e4 100644 --- a/README.adoc +++ b/README.adoc @@ -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] ==== diff --git a/configure.ac b/configure.ac index fa21a881..799df2f7 100644 --- a/configure.ac +++ b/configure.ac @@ -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 index 15523a73..00000000 --- a/doc/api/libbabeltrace2/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -output -Doxyfile -README.html diff --git a/doc/man/.gitignore b/doc/man/.gitignore deleted file mode 100644 index f54189ac..00000000 --- a/doc/man/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -*.1 -*.7 -*.xml -*.html -asciidoc-attrs.conf diff --git a/include/babeltrace2/value.h b/include/babeltrace2/value.h index f6bdbee4..10638bd6 100644 --- a/include/babeltrace2/value.h +++ b/include/babeltrace2/value.h @@ -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() — diff --git a/src/Makefile.am b/src/Makefile.am index 2d18268c..72a71463 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 index fc7a23f1..00000000 --- a/src/bindings/python/bt2/.gitignore +++ /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 diff --git a/src/bindings/python/bt2/setup.py.in b/src/bindings/python/bt2/setup.py.in index 0d1ca724..3c81447e 100644 --- a/src/bindings/python/bt2/setup.py.in +++ b/src/bindings/python/bt2/setup.py.in @@ -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", diff --git a/src/clock-correlation-validator/clock-correlation-validator.cpp b/src/clock-correlation-validator/clock-correlation-validator.cpp index a116c364..4bb1a725 100644 --- a/src/clock-correlation-validator/clock-correlation-validator.cpp +++ b/src/clock-correlation-validator/clock-correlation-validator.cpp @@ -19,12 +19,12 @@ void ClockCorrelationValidator::_validate(const bt2::ConstMessage msg) bt2::OptionalBorrowedObject 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; diff --git a/src/clock-correlation-validator/clock-correlation-validator.hpp b/src/clock-correlation-validator/clock-correlation-validator.hpp index 773c97cb..314551c3 100644 --- a/src/clock-correlation-validator/clock-correlation-validator.hpp +++ b/src/clock-correlation-validator/clock-correlation-validator.hpp @@ -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 diff --git a/src/common/macros.h b/src/common/macros.h index 13ba2d36..0f2bc8fb 100644 --- a/src/common/macros.h +++ b/src/common/macros.h @@ -45,29 +45,6 @@ extern "C" { #define BT_IF_DEV_MODE(txt) #endif -/* - * Yield `ref`'s value while setting `ref` to NULL. - * - * This can be used to give a strong reference to a callee: - * - * add_foo_to_list(list, BT_MOVE_REF(foo)); - * - * or in a simple assignment: - * - * my_struct->foo = BT_MOVE_REF(foo); - * - * When moving a reference in a function call, the reference is given to the - * callee even if that function call fails, so make sure the called function - * is written accordingly. - */ - -#define BT_MOVE_REF(ref) \ - ({ \ - __typeof__(ref) _ref = ref; \ - ref = NULL; \ - _ref; \ - }) - /* Wrapper for g_array_index that adds bound checking. */ #define bt_g_array_index(a, t, i) \ g_array_index((a), t, ({ BT_ASSERT_DBG((i) < (a)->len); (i); })) @@ -99,6 +76,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/common/prio-heap.c b/src/common/prio-heap.c deleted file mode 100644 index 55ed5e81..00000000 --- a/src/common/prio-heap.c +++ /dev/null @@ -1,220 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2011 Mathieu Desnoyers - * - * Static-sized priority heap containing pointers. Based on CLRS, - * chapter 6. - */ - -#include "common/macros.h" -#include "common/assert.h" -#include -#include -#include - -#include "common/prio-heap.h" - -#ifdef DEBUG_HEAP -void check_heap(const struct ptr_heap *heap) -{ - size_t i; - - if (!heap->len) - return; - - for (i = 1; i < heap->len; i++) - BT_ASSERT_DBG(!heap->gt(heap->ptrs[i], heap->ptrs[0])); -} -#endif - -static -size_t parent(size_t i) -{ - return (i - 1) >> 1; -} - -static -size_t left(size_t i) -{ - return (i << 1) + 1; -} - -static -size_t right(size_t i) -{ - return (i << 1) + 2; -} - -/* - * Copy of heap->ptrs pointer is invalid after heap_grow. - */ -static -int heap_grow(struct ptr_heap *heap, size_t new_len) -{ - void **new_ptrs; - - if (G_LIKELY(heap->alloc_len >= new_len)) - return 0; - - heap->alloc_len = bt_max_t(size_t, new_len, heap->alloc_len << 1); - new_ptrs = calloc(heap->alloc_len, sizeof(void *)); - if (G_UNLIKELY(!new_ptrs)) - return -ENOMEM; - if (G_LIKELY(heap->ptrs)) - memcpy(new_ptrs, heap->ptrs, heap->len * sizeof(void *)); - free(heap->ptrs); - heap->ptrs = new_ptrs; - return 0; -} - -static -int heap_set_len(struct ptr_heap *heap, size_t new_len) -{ - int ret; - - ret = heap_grow(heap, new_len); - if (G_UNLIKELY(ret)) - return ret; - heap->len = new_len; - return 0; -} - -int bt_heap_init(struct ptr_heap *heap, size_t alloc_len, - int gt(void *a, void *b)) -{ - heap->ptrs = NULL; - heap->len = 0; - heap->alloc_len = 0; - heap->gt = gt; - /* - * Minimum size allocated is 1 entry to ensure memory allocation - * never fails within bt_heap_replace_max. - */ - return heap_grow(heap, bt_max_t(size_t, 1, alloc_len)); -} - -void bt_heap_free(struct ptr_heap *heap) -{ - free(heap->ptrs); -} - -static void heapify(struct ptr_heap *heap, size_t i) -{ - void **ptrs = heap->ptrs; - size_t l, r, largest; - - for (;;) { - void *tmp; - - l = left(i); - r = right(i); - if (l < heap->len && heap->gt(ptrs[l], ptrs[i])) - largest = l; - else - largest = i; - if (r < heap->len && heap->gt(ptrs[r], ptrs[largest])) - largest = r; - if (G_UNLIKELY(largest == i)) - break; - tmp = ptrs[i]; - ptrs[i] = ptrs[largest]; - ptrs[largest] = tmp; - i = largest; - } - check_heap(heap); -} - -void *bt_heap_replace_max(struct ptr_heap *heap, void *p) -{ - void *res; - - if (G_UNLIKELY(!heap->len)) { - (void) heap_set_len(heap, 1); - heap->ptrs[0] = p; - check_heap(heap); - return NULL; - } - - /* Replace the current max and heapify */ - res = heap->ptrs[0]; - heap->ptrs[0] = p; - heapify(heap, 0); - return res; -} - -int bt_heap_insert(struct ptr_heap *heap, void *p) -{ - void **ptrs; - size_t pos; - int ret; - - ret = heap_set_len(heap, heap->len + 1); - if (G_UNLIKELY(ret)) - return ret; - ptrs = heap->ptrs; - pos = heap->len - 1; - while (pos > 0 && heap->gt(p, ptrs[parent(pos)])) { - /* Move parent down until we find the right spot */ - ptrs[pos] = ptrs[parent(pos)]; - pos = parent(pos); - } - ptrs[pos] = p; - check_heap(heap); - return 0; -} - -void *bt_heap_remove(struct ptr_heap *heap) -{ - switch (heap->len) { - case 0: - return NULL; - case 1: - (void) heap_set_len(heap, 0); - return heap->ptrs[0]; - } - /* Shrink, replace the current max by previous last entry and heapify */ - heap_set_len(heap, heap->len - 1); - /* len changed. previous last entry is at heap->len */ - return bt_heap_replace_max(heap, heap->ptrs[heap->len]); -} - -void *bt_heap_cherrypick(struct ptr_heap *heap, void *p) -{ - size_t pos, len = heap->len; - - for (pos = 0; pos < len; pos++) - if (G_UNLIKELY(heap->ptrs[pos] == p)) - goto found; - return NULL; -found: - if (G_UNLIKELY(heap->len == 1)) { - (void) heap_set_len(heap, 0); - check_heap(heap); - return heap->ptrs[0]; - } - /* Replace p with previous last entry and heapify. */ - heap_set_len(heap, heap->len - 1); - /* len changed. previous last entry is at heap->len */ - heap->ptrs[pos] = heap->ptrs[heap->len]; - heapify(heap, pos); - return p; -} - -int bt_heap_copy(struct ptr_heap *dst, struct ptr_heap *src) -{ - int ret; - - ret = bt_heap_init(dst, src->alloc_len, src->gt); - if (ret < 0) - goto end; - - ret = heap_set_len(dst, src->len); - if (ret < 0) - goto end; - - memcpy(dst->ptrs, src->ptrs, src->len * sizeof(void *)); - -end: - return ret; -} diff --git a/src/common/prio-heap.h b/src/common/prio-heap.h deleted file mode 100644 index 7e56521b..00000000 --- a/src/common/prio-heap.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2011 Mathieu Desnoyers - * - * Static-sized priority heap containing pointers. Based on CLRS, - * chapter 6. - */ - -#ifndef BABELTRACE_COMMON_PRIO_HEAP_H -#define BABELTRACE_COMMON_PRIO_HEAP_H - -#include -#include "common/macros.h" - -struct ptr_heap { - size_t len, alloc_len; - void **ptrs; - int (*gt)(void *a, void *b); -}; - -#ifdef DEBUG_HEAP -void check_heap(const struct ptr_heap *heap); -#else -static inline -void check_heap(const struct ptr_heap *heap __attribute__((unused))) -{ -} -#endif - -/** - * bt_heap_maximum - return the largest element in the heap - * @heap: the heap to be operated on - * - * Returns the largest element in the heap, without performing any modification - * to the heap structure. Returns NULL if the heap is empty. - */ -static inline void *bt_heap_maximum(const struct ptr_heap *heap) -{ - check_heap(heap); - return G_LIKELY(heap->len) ? heap->ptrs[0] : NULL; -} - -/** - * bt_heap_init - initialize the heap - * @heap: the heap to initialize - * @alloc_len: number of elements initially allocated - * @gt: function to compare the elements - * - * Returns -ENOMEM if out of memory. - */ -extern int bt_heap_init(struct ptr_heap *heap, - size_t alloc_len, - int gt(void *a, void *b)); - -/** - * bt_heap_free - free the heap - * @heap: the heap to free - */ -extern void bt_heap_free(struct ptr_heap *heap); - -/** - * bt_heap_insert - insert an element into the heap - * @heap: the heap to be operated on - * @p: the element to add - * - * Insert an element into the heap. - * - * Returns -ENOMEM if out of memory. - */ -extern int bt_heap_insert(struct ptr_heap *heap, void *p); - -/** - * bt_heap_remove - remove the largest element from the heap - * @heap: the heap to be operated on - * - * Returns the largest element in the heap. It removes this element from the - * heap. Returns NULL if the heap is empty. - */ -extern void *bt_heap_remove(struct ptr_heap *heap); - -/** - * bt_heap_cherrypick - remove a given element from the heap - * @heap: the heap to be operated on - * @p: the element - * - * Remove the given element from the heap. Return the element if present, else - * return NULL. This algorithm has a complexity of O(n), which is higher than - * O(log(n)) provided by the rest of this API. - */ -extern void *bt_heap_cherrypick(struct ptr_heap *heap, void *p); - -/** - * bt_heap_replace_max - replace the the largest element from the heap - * @heap: the heap to be operated on - * @p: the pointer to be inserted as topmost element replacement - * - * Returns the largest element in the heap. It removes this element from the - * heap. The heap is rebalanced only once after the insertion. Returns NULL if - * the heap is empty. - * - * This is the equivalent of calling bt_heap_remove() and then bt_heap_insert(), but - * it only rebalances the heap once. It never allocates memory. - */ -extern void *bt_heap_replace_max(struct ptr_heap *heap, void *p); - -/** - * bt_heap_copy - copy a heap - * @dst: the destination heap (must be allocated) - * @src: the source heap - * - * Returns -ENOMEM if out of memory. - */ -extern int bt_heap_copy(struct ptr_heap *dst, struct ptr_heap *src); - -#endif /* BABELTRACE_COMMON_PRIO_HEAP_H */ diff --git a/src/compat/socket.h b/src/compat/socket.h deleted file mode 100644 index 4715677e..00000000 --- a/src/compat/socket.h +++ /dev/null @@ -1,416 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright (C) 2015-2017 Michael Jeanson - * Copyright (C) 2015 Mathieu Desnoyers - */ - -#ifndef _BABELTRACE_COMPAT_SOCKET_H -#define _BABELTRACE_COMPAT_SOCKET_H - -#include - -#ifdef __MINGW32__ - -#include - -#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 -#include -#include -#include -#include - -#include - -#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 - -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 index 00000000..972f6929 --- /dev/null +++ b/src/compat/socket.hpp @@ -0,0 +1,386 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright (C) 2015-2017 Michael Jeanson + * Copyright (C) 2015 Mathieu Desnoyers + */ + +#ifndef BABELTRACE_COMPAT_SOCKET_HPP +#define BABELTRACE_COMPAT_SOCKET_HPP + +#include + +#include "cpp-common/bt2c/logging.hpp" + +#ifdef __MINGW32__ + +# include + +# 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 +# include +# include +# include +# include +# include + +# 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 + +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 */ diff --git a/src/cpp-common/bt2/component-class-dev.hpp b/src/cpp-common/bt2/component-class-dev.hpp index b89ac6b2..e0d45d6b 100644 --- a/src/cpp-common/bt2/component-class-dev.hpp +++ b/src/cpp-common/bt2/component-class-dev.hpp @@ -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 { diff --git a/src/cpp-common/bt2/component-class.hpp b/src/cpp-common/bt2/component-class.hpp index e32ba34a..2933d74f 100644 --- a/src/cpp-common/bt2/component-class.hpp +++ b/src/cpp-common/bt2/component-class.hpp @@ -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 class CommonSourceComponentClass; @@ -52,13 +59,6 @@ public: using typename _ThisBorrowedObject::LibObjPtr; using Shared = SharedObject; - 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} { diff --git a/src/cpp-common/bt2/error.hpp b/src/cpp-common/bt2/error.hpp index 7daaaf6b..d4dfeaac 100644 --- a/src/cpp-common/bt2/error.hpp +++ b/src/cpp-common/bt2/error.hpp @@ -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 { 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(bt_error_cause_get_actor_type(this->libObjPtr())); + return static_cast(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( + return static_cast( 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( + return static_cast( 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( + return static_cast( 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 diff --git a/src/cpp-common/bt2/field-class.hpp b/src/cpp-common/bt2/field-class.hpp index 411cf669..71e32e41 100644 --- a/src/cpp-common/bt2/field-class.hpp +++ b/src/cpp-common/bt2/field-class.hpp @@ -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 : 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 @@ -865,6 +864,9 @@ public: CommonEnumerationFieldClass addMapping(const bt2c::CStringView label, const typename Mapping::RangeSet ranges) const { + static_assert(!std::is_const::value, + "Not available with `bt2::Const*EnumerationFieldClass`."); + const auto status = internal::CommonEnumerationFieldClassSpec::addMapping( this->libObjPtr(), label, ranges.libObjPtr()); diff --git a/src/cpp-common/bt2/field-path.hpp b/src/cpp-common/bt2/field-path.hpp index fc087593..ed44ad4b 100644 --- a/src/cpp-common/bt2/field-path.hpp +++ b/src/cpp-common/bt2/field-path.hpp @@ -12,6 +12,7 @@ #include #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 @@ -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 { public: using Shared = SharedObject; using Iterator = BorrowedObjectIterator; - 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(bt_field_path_get_root_scope(this->libObjPtr())); + return static_cast(bt_field_path_get_root_scope(this->libObjPtr())); } std::uint64_t length() const noexcept diff --git a/src/cpp-common/bt2/graph.hpp b/src/cpp-common/bt2/graph.hpp index 0927cd30..e2bcf77c 100644 --- a/src/cpp-common/bt2/graph.hpp +++ b/src/cpp-common/bt2/graph.hpp @@ -57,7 +57,7 @@ public: ConstSourceComponent addComponent(const ConstSourceComponentClass componentClass, const bt2c::CStringView name, const OptionalBorrowedObject params = {}, - const LoggingLevel loggingLevel = LoggingLevel::NONE) const + const LoggingLevel loggingLevel = LoggingLevel::None) const { return this->_addComponent( componentClass, name, params, static_cast(nullptr), loggingLevel, @@ -68,7 +68,7 @@ public: ConstSourceComponent addComponent(const ConstSourceComponentClass componentClass, const bt2c::CStringView name, InitDataT&& initData, const OptionalBorrowedObject params = {}, - const LoggingLevel loggingLevel = LoggingLevel::NONE) const + const LoggingLevel loggingLevel = LoggingLevel::None) const { return this->_addComponent( componentClass, name, params, &initData, loggingLevel, @@ -78,7 +78,7 @@ public: ConstFilterComponent addComponent(const ConstFilterComponentClass componentClass, const bt2c::CStringView name, const OptionalBorrowedObject params = {}, - const LoggingLevel loggingLevel = LoggingLevel::NONE) const + const LoggingLevel loggingLevel = LoggingLevel::None) const { return this->_addComponent( componentClass, name, params, static_cast(nullptr), loggingLevel, @@ -89,7 +89,7 @@ public: ConstFilterComponent addComponent(const ConstFilterComponentClass componentClass, const bt2c::CStringView name, InitDataT&& initData, const OptionalBorrowedObject params = {}, - const LoggingLevel loggingLevel = LoggingLevel::NONE) const + const LoggingLevel loggingLevel = LoggingLevel::None) const { return this->_addComponent( componentClass, name, params, &initData, loggingLevel, @@ -99,7 +99,7 @@ public: ConstSinkComponent addComponent(const ConstSinkComponentClass componentClass, const bt2c::CStringView name, const OptionalBorrowedObject params = {}, - const LoggingLevel loggingLevel = LoggingLevel::NONE) const + const LoggingLevel loggingLevel = LoggingLevel::None) const { return this->_addComponent( componentClass, name, params, static_cast(nullptr), loggingLevel, @@ -110,7 +110,7 @@ public: ConstSinkComponent addComponent(const ConstSinkComponentClass componentClass, const bt2c::CStringView name, InitDataT&& initData, const OptionalBorrowedObject params = {}, - const LoggingLevel loggingLevel = LoggingLevel::NONE) const + const LoggingLevel loggingLevel = LoggingLevel::None) const { return this->_addComponent( componentClass, name, params, &initData, loggingLevel, diff --git a/src/cpp-common/bt2/logging.hpp b/src/cpp-common/bt2/logging.hpp index 10e1ee3a..d8c8a480 100644 --- a/src/cpp-common/bt2/logging.hpp +++ b/src/cpp-common/bt2/logging.hpp @@ -9,19 +9,27 @@ #include +#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 */ diff --git a/src/cpp-common/bt2/message.hpp b/src/cpp-common/bt2/message.hpp index be9be118..77321778 100644 --- a/src/cpp-common/bt2/message.hpp +++ b/src/cpp-common/bt2/message.hpp @@ -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 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 class CommonMessage : public BorrowedObject @@ -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 diff --git a/src/cpp-common/bt2/trace-ir.hpp b/src/cpp-common/bt2/trace-ir.hpp index f2678f89..07c65924 100644 --- a/src/cpp-common/bt2/trace-ir.hpp +++ b/src/cpp-common/bt2/trace-ir.hpp @@ -12,6 +12,7 @@ #include +#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 class CommonEventClass final : public BorrowedObject { @@ -870,25 +896,6 @@ public: using Shared = SharedObject; using UserAttributes = internal::DepUserAttrs; - 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::value, "Not available with `bt2::ConstEventClass`."); @@ -945,12 +952,12 @@ public: return *this; } - bt2s::optional logLevel() const noexcept + bt2s::optional logLevel() const noexcept { bt_event_class_log_level libLogLevel; if (bt_event_class_get_log_level(this->libObjPtr(), &libLogLevel)) { - return static_cast(libLogLevel); + return static_cast(libLogLevel); } return bt2s::nullopt; diff --git a/src/cpp-common/bt2/value.hpp b/src/cpp-common/bt2/value.hpp index 80e17dea..9f7fdff5 100644 --- a/src/cpp-common/bt2/value.hpp +++ b/src/cpp-common/bt2/value.hpp @@ -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 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 class CommonValueRawValueProxy final diff --git a/src/cpp-common/bt2c/c-string-view.hpp b/src/cpp-common/bt2c/c-string-view.hpp index 0437cd65..771954c1 100644 --- a/src/cpp-common/bt2c/c-string-view.hpp +++ b/src/cpp-common/bt2c/c-string-view.hpp @@ -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 index 00000000..55760f49 --- /dev/null +++ b/src/cpp-common/bt2c/data-len.hpp @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2022 Philippe Proulx + * + * 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 index e69de29b..00000000 diff --git a/src/cpp-common/bt2c/exc.hpp b/src/cpp-common/bt2c/exc.hpp index 3138fdbc..3400dfaf 100644 --- a/src/cpp-common/bt2c/exc.hpp +++ b/src/cpp-common/bt2c/exc.hpp @@ -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 index 00000000..93520182 --- /dev/null +++ b/src/cpp-common/bt2c/file-utils.cpp @@ -0,0 +1,38 @@ + +/* + * Copyright (c) 2022 Francis Deslauriers + * + * SPDX-License-Identifier: MIT + */ +#include + +#include "exc.hpp" +#include "file-utils.hpp" + +namespace bt2c { + +std::vector 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 buffer(static_cast(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(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 index 00000000..9890f0a8 --- /dev/null +++ b/src/cpp-common/bt2c/file-utils.hpp @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2022 Francis Deslauriers + * + * SPDX-License-Identifier: MIT + */ + +#ifndef BABELTRACE_CPP_COMMON_FILE_UTILS_HPP +#define BABELTRACE_CPP_COMMON_FILE_UTILS_HPP + +#include +#include + +namespace bt2c { + +/* + * Returns a vector of all the bytes contained in `path`. + */ +std::vector dataFromFile(const char *path); + +} /* namespace bt2c */ + +#endif /* BABELTRACE_CPP_COMMON_FILE_UTILS_HPP */ diff --git a/src/cpp-common/bt2c/fmt.hpp b/src/cpp-common/bt2c/fmt.hpp index 8af3d71e..ab3d6bc8 100644 --- a/src/cpp-common/bt2c/fmt.hpp +++ b/src/cpp-common/bt2c/fmt.hpp @@ -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 +using EnableIfIsWiseEnum = + typename std::enable_if::value, wise_enum::string_type>::type; + +} /* namespace internal */ namespace bt2 { -inline const char *format_as(const MessageType type) +template +::internal::EnableIfIsWiseEnum format_as(const T val) noexcept { - return bt_common_message_type_string(static_cast(type)); + return wise_enum::to_string(val); } } /* namespace bt2 */ namespace bt2c { +template +::internal::EnableIfIsWiseEnum format_as(const T val) noexcept +{ + return wise_enum::to_string(val); +} + inline std::string format_as(const UuidView uuid) { return uuid.str(); diff --git a/src/cpp-common/bt2c/logging.hpp b/src/cpp-common/bt2c/logging.hpp index 159e909b..2aa22040 100644 --- a/src/cpp-common/bt2c/logging.hpp +++ b/src/cpp-common/bt2c/logging.hpp @@ -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; + + /* 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(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(_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(level), tag, msg); @@ -277,77 +274,37 @@ public: * the error of the current thread using the same message. */ template - void logNoThrow(const char * const fileName, const char * const funcName, - const unsigned int lineNo, const char * const fmt, ArgTs&&...args) const + void log(const char * const fileName, const char * const funcName, const unsigned int lineNo, + fmt::format_string fmt, ArgTs&&...args) const { - this->_logNoThrow<_StdLogWriter, LevelV, AppendCauseV>( - fileName, funcName, lineNo, nullptr, 0, "", fmt, std::forward(args)...); + this->_log<_StdLogWriter, LevelV, AppendCauseV>( + fileName, funcName, lineNo, {}, "", std::move(fmt), std::forward(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 - void logStrNoThrow(const char * const fileName, const char * const funcName, - const unsigned int lineNo, const char * const msg) const - { - this->_logStrNoThrow<_StdLogWriter, LevelV, AppendCauseV>(fileName, funcName, lineNo, - nullptr, 0, "", msg); - } - - /* - * 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 [[noreturn]] void logErrorAndThrow(const char * const fileName, const char * const funcName, - const unsigned int lineNo, const char * const fmt, + const unsigned int lineNo, fmt::format_string fmt, ArgTs&&...args) const { - this->logNoThrow(fileName, funcName, lineNo, fmt, - std::forward(args)...); - throw ExcT {}; - } - - /* - * Like logStrAndNoThrow() with the `Level::ERROR` level, but also - * throws a default-constructed instance of `ExcT`. - */ - template - [[noreturn]] void logErrorStrAndThrow(const char * const fileName, const char * const funcName, - const unsigned int lineNo, const char * const msg) const - { - this->logStrNoThrow(fileName, funcName, lineNo, msg); + this->log(fileName, funcName, lineNo, std::move(fmt), + std::forward(args)...); throw ExcT {}; } /* - * Like logAndNoThrow() with the `Level::ERROR` level, but also - * rethrows. + * Like log() with the `Level::Error` level, but also rethrows. */ template [[noreturn]] void logErrorAndRethrow(const char * const fileName, const char * const funcName, - const unsigned int lineNo, const char * const fmt, - ArgTs&&...args) const + const unsigned int lineNo, + fmt::format_string fmt, ArgTs&&...args) const { - this->logNoThrow(fileName, funcName, lineNo, fmt, - std::forward(args)...); - throw; - } - - /* - * Like logStrAndNoThrow() with the `Level::ERROR` level, but also - * rethrows. - */ - template - [[noreturn]] void logErrorStrAndRethrow(const char * const fileName, - const char * const funcName, const unsigned int lineNo, - const char * const msg) const - { - this->logStrNoThrow(fileName, funcName, lineNo, msg); + this->log(fileName, funcName, lineNo, std::move(fmt), + std::forward(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(level), tag, "%s%s", initMsg, msg); @@ -376,90 +332,41 @@ public: * the error of the current thread using the same message. */ template - 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 + void logErrno(const char * const fileName, const char * const funcName, + const unsigned int lineNo, const char * const initMsg, + fmt::format_string fmt, ArgTs&&...args) const { - this->_logNoThrow<_InitMsgLogWriter, LevelV, AppendCauseV>( - fileName, funcName, lineNo, nullptr, 0, this->_errnoIntroStr(initMsg).c_str(), fmt, + this->_log<_InitMsgLogWriter, LevelV, AppendCauseV>( + fileName, funcName, lineNo, {}, this->_errnoIntroStr(initMsg).c_str(), std::move(fmt), std::forward(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 - void logErrnoStrNoThrow(const char * const fileName, const char * const funcName, - const unsigned int lineNo, const char * const initMsg, - const char * const msg) const - { - this->_logStrNoThrow<_InitMsgLogWriter, LevelV, AppendCauseV>( - fileName, funcName, lineNo, nullptr, 0, this->_errnoIntroStr(initMsg).c_str(), msg); - } - - /* - * 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 [[noreturn]] void logErrorErrnoAndThrow(const char * const fileName, const char * const funcName, const unsigned int lineNo, - const char * const initMsg, const char * const fmt, - ArgTs&&...args) const + const char * const initMsg, + fmt::format_string fmt, ArgTs&&...args) const { - this->logErrnoNoThrow(fileName, funcName, lineNo, initMsg, fmt, - std::forward(args)...); + this->logErrno(fileName, funcName, lineNo, initMsg, + std::move(fmt), std::forward(args)...); throw ExcT {}; } /* - * Like logErrnoStrNoThrow() with the `Level::ERROR` level, but also - * throws a default-constructed instance of `ExcT`. - */ - template - [[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(fileName, funcName, lineNo, initMsg, - msg); - throw ExcT {}; - } - - /* - * Like logErrnoNoThrow() with the `Level::ERROR` level, but also - * rethrows. + * Like logErrno() with the `Level::Error` level, but also rethrows. */ template - [[noreturn]] void logErrorErrnoAndRethrow(const char * const fileName, - const char * const funcName, - const unsigned int lineNo, const char * const initMsg, - const char * const fmt, ArgTs&&...args) const - { - this->logErrnoNoThrow(fileName, funcName, lineNo, initMsg, fmt, - std::forward(args)...); - throw; - } - - /* - * Like logErrnoStrNoThrow() with the `Level::ERROR` level, but also - * rethrows. - */ - template [[noreturn]] void - logErrorErrnoStrAndRethrow(const char * const fileName, const char * const funcName, - const unsigned int lineNo, const char * const initMsg, - const char * const msg) const + logErrorErrnoAndRethrow(const char * const fileName, const char * const funcName, + const unsigned int lineNo, const char * const initMsg, + fmt::format_string fmt, ArgTs&&...args) const { - this->logErrnoStrNoThrow(fileName, funcName, lineNo, initMsg, - msg); + this->logErrno(fileName, funcName, lineNo, initMsg, + std::move(fmt), std::forward(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(level), tag, - memData, memLen, msg); + memData.data(), memData.size(), msg); } }; @@ -484,92 +390,67 @@ public: * the log message. */ template - 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(args)...); - } - - /* - * Logs memory data using the level `LevelV`, starting with the - * message `msg`. - */ - template - 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, fmt::format_string fmt, ArgTs&&...args) const { - this->_logStrNoThrow<_MemLogWriter, LevelV, false>(fileName, funcName, lineNo, memData, - memLen, "", msg); + this->_log<_MemLogWriter, LevelV, false>(fileName, funcName, lineNo, memData, "", + std::move(fmt), std::forward(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 - 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, fmt::format_string 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(); - fmt::format_to(std::back_inserter(_mBuf), fmt, std::forward(args)...); + fmt::format_to(std::back_inserter(_mBuf), std::move(fmt), std::forward(args)...); _mBuf.push_back('\0'); } - this->_logStrNoThrow(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 - 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 +461,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 _mSelfCompCls; bt2s::optional _mSelfComp; bt2s::optional _mSelfMsgIter; @@ -596,20 +477,27 @@ private: mutable std::vector _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 +505,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 +529,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. + * Calls logMem() on `_logger` to log using the level `_lvl`. */ -#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. - */ -#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)) +#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__) /* - * BT_CPPLOG_MEM_STR_EX() with specific logging levels. + * Calls logErrno() on `_logger` to log using the level `_lvl` and + * initial message `_initMsg`. */ -#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)) - -/* - * Calls logErrnoNoThrow() on `_logger` to log using the level `_lvl` - * and initial message `_init_msg` without appending nor throwing. - */ -#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__) - -/* - * Calls logErrnoStrNoThrow() on `_logger` to log using the level `_lvl` - * and initial message `_init_msg` without appending nor throwing. - */ -#define BT_CPPLOG_ERRNO_STR_EX(_lvl, _logger, _init_msg, _msg) \ - (_logger).logErrnoStrNoThrow<(_lvl), false>(__FILE__, __func__, __LINE__, (_init_msg), (_msg)) +#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__) /* - * BT_CPPLOG_ERRNO_STR_EX() with specific logging levels. + * 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_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)) +#define BT_CPPLOGE_APPEND_CAUSE_SPEC(_logger, _fmt, ...) \ + (_logger).template log(__FILE__, __func__, __LINE__, (_fmt), \ + ##__VA_ARGS__) /* - * BT_CPPLOG_ERRNO_STR_EX() with specific logging levels and using the - * default logger. + * BT_CPPLOGE_APPEND_CAUSE_SPEC() 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)) +#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(__FILE__, __func__, __LINE__, (_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`. - */ -#define BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(_logger, _exc_cls, _fmt, ...) \ - (_logger).logErrorAndThrow(__FILE__, __func__, __LINE__, (_fmt), ##__VA_ARGS__) +#define BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(_logger, _excCls, _fmt, ...) \ + (_logger).template logErrorAndThrow(__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(__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(__FILE__, __func__, __LINE__, (_fmt), ##__VA_ARGS__) + (_logger).template logErrorAndRethrow(__FILE__, __func__, __LINE__, (_fmt), ##__VA_ARGS__) /* * BT_CPPLOGE_APPEND_CAUSE_AND_RETHROW_SPEC() using the default logger. @@ -903,84 +661,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(__FILE__, __func__, __LINE__, (_msg)) +#define BT_CPPLOGE_ERRNO_APPEND_CAUSE_SPEC(_logger, _initMsg, _fmt, ...) \ + (_logger).template logErrno( \ + __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(__FILE__, __func__, __LINE__, (_init_msg), \ - (_fmt), ##__VA_ARGS__) +#define BT_CPPLOGE_ERRNO_APPEND_CAUSE_AND_THROW_SPEC(_logger, _excCls, _initMsg, _fmt, ...) \ + (_logger).template logErrorErrnoAndThrow(__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(__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(__FILE__, __func__, __LINE__, (_init_msg), (_fmt), \ - ##__VA_ARGS__) +#define BT_CPPLOGE_ERRNO_APPEND_CAUSE_AND_RETHROW_SPEC(_logger, _initMsg, _fmt, ...) \ + (_logger).template logErrorErrnoAndRethrow(__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(__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 index 00000000..2270a8fb --- /dev/null +++ b/src/cpp-common/bt2c/make-span.hpp @@ -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 +inline constexpr bt2s::span 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 index 05ab3d79..00000000 --- a/src/cpp-common/bt2c/span.hpp +++ /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 -inline constexpr bt2s::span 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/span-lite/span.hpp b/src/cpp-common/vendor/span-lite/span.hpp index 3d2d86a4..9a7182f5 100644 --- a/src/cpp-common/vendor/span-lite/span.hpp +++ b/src/cpp-common/vendor/span-lite/span.hpp @@ -1870,7 +1870,7 @@ using span_lite::byte_span; #endif // span_FEATURE( BYTE_SPAN ) -#if span_HAVE( STRUCT_BINDING ) +#if !span_USES_STD_SPAN && span_HAVE( STRUCT_BINDING ) #if span_CPP14_OR_GREATER # include @@ -1938,7 +1938,7 @@ span_constexpr ElementType const & get( nonstd::span const } // end namespace std -#endif // span_HAVE( STRUCT_BINDING ) +#endif // !span_USES_STD_SPAN && span_HAVE( STRUCT_BINDING ) #if ! span_USES_STD_SPAN span_RESTORE_WARNINGS() diff --git a/src/cpp-common/vendor/wise-enum/optional.h b/src/cpp-common/vendor/wise-enum/optional.h new file mode 100644 index 00000000..6b0dab14 --- /dev/null +++ b/src/cpp-common/vendor/wise-enum/optional.h @@ -0,0 +1,82 @@ +#pragma once + +#include "optional_common.h" + +#include +#include + +#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 optional { +public: + static_assert(std::is_enum::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 + WISE_ENUM_CONSTEXPR_14 T value_or(U &&u) { + if (m_active) + return m_t; + else + return std::forward(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 index 00000000..c8f7b4f2 --- /dev/null +++ b/src/cpp-common/vendor/wise-enum/optional_common.h @@ -0,0 +1,23 @@ +#pragma once + +#ifdef WISE_ENUM_NO_EXCEPT + +#include +#define WISE_ENUM_OPTIONAL_BAD_ACCESS std::abort() + +#else + +#include + +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 index 00000000..db50027d --- /dev/null +++ b/src/cpp-common/vendor/wise-enum/wise_enum.h @@ -0,0 +1,108 @@ +#pragma once + +#include "wise_enum_detail.h" +#include "wise_enum_generated.h" + +#include +#include +#include +#include + +/* + 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 +constexpr string_type to_string(T t) { + return wise_enum_detail_to_string(t, detail::Tag{}); +} + +// Enumerators trait class. Each value is also available as a template variable +// for C++14 and on +template +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{})) range = + wise_enum_detail_array(detail::Tag{}); + + // This variable is equal to the number of enumerators for the wise enum type. + static constexpr std::size_t size = range.size(); +}; + +template +constexpr decltype( + wise_enum_detail_array(detail::Tag{})) enumerators::range; + +template +constexpr std::size_t enumerators::size; + +#if __cplusplus >= 201402 +template +constexpr auto &range = enumerators::range; + +template +constexpr std::size_t size = enumerators::size; +#endif + +// A type trait; this allows checking if a type is a wise_enum in generic code +template +using is_wise_enum = detail::is_wise_enum; + +#if __cplusplus >= 201402 +template +static constexpr bool is_wise_enum_v = is_wise_enum::value; +#endif + +// Converts a string literal into a wise enum. Returns an optional; if no +// enumerator has name matching the string, the optional is returned empty. +template +WISE_ENUM_CONSTEXPR_14 optional_type from_string(string_type s) { + auto it = + std::find_if(enumerators::range.begin(), enumerators::range.end(), + [=](const detail::value_and_name &x) { + return ::wise_enum::detail::compare(x.name, s); + }); + if (it == enumerators::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 index 00000000..1accbe78 --- /dev/null +++ b/src/cpp-common/vendor/wise-enum/wise_enum_detail.h @@ -0,0 +1,208 @@ +#pragma once + +#include +#include +#include + +// optional type needed for interface +#ifndef WISE_ENUM_OPTIONAL_TYPE +#if __cplusplus >= 201703L +#include +namespace wise_enum { +template +using optional_type = std::optional; +} +#else +#include "optional.h" +namespace wise_enum { +template +using optional_type = wise_enum::optional; +} +#endif +#else +namespace wise_enum { +template +using optional_type = WISE_ENUM_OPTIONAL_TYPE; +} +#endif + +// Choice of string_view if type defined, otherwise use string literal +#ifndef WISE_ENUM_STRING_TYPE +#if __cplusplus >= 201703L +#include +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 +struct value_and_name { + T value; + string_type name; +}; + +template +struct Tag {}; + +constexpr void wise_enum_detail_array(...); + +template +struct is_wise_enum + : std::integral_constant< + bool, !std::is_same{}))>::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 ::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, \ + num_enums> \ + wise_enum_detail_array(::wise_enum::detail::Tag) { \ + return {{WISE_ENUM_IMPL_EXPAND(loop(WISE_ENUM_IMPL_DESC_PAIR, name, \ + WISE_ENUM_IMPL_COMMA, __VA_ARGS__))}}; \ + } \ + \ + template \ + friendly WISE_ENUM_CONSTEXPR_14 ::wise_enum::string_type \ + wise_enum_detail_to_string(T e, ::wise_enum::detail::Tag) { \ + 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 index 00000000..f83c8aef --- /dev/null +++ b/src/cpp-common/vendor/wise-enum/wise_enum_generated.h @@ -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/lib/lib-logging.c b/src/lib/lib-logging.c index a22e000f..6d98a0ce 100644 --- a/src/lib/lib-logging.c +++ b/src/lib/lib-logging.c @@ -497,8 +497,8 @@ static inline void format_trace(char **buf_ch, bool extended, { char tmp_prefix[TMP_PREFIX_LEN]; - if (trace->name.value) { - BUF_APPEND(", %sname=\"%s\"", PRFIELD(trace->name.value)); + if (trace->name) { + BUF_APPEND(", %sname=\"%s\"", PRFIELD(trace->name)); } if (!extended) { @@ -534,9 +534,9 @@ static inline void format_stream_class(char **buf_ch, bool extended, BUF_APPEND(", %sid=%" PRIu64, PRFIELD(stream_class->id)); - if (stream_class->name.value) { + if (stream_class->name) { BUF_APPEND(", %sname=\"%s\"", - PRFIELD(stream_class->name.value)); + PRFIELD(stream_class->name)); } if (!extended) { @@ -593,9 +593,9 @@ static inline void format_event_class(char **buf_ch, bool extended, BUF_APPEND(", %sid=%" PRIu64, PRFIELD(event_class->id)); - if (event_class->name.value) { + if (event_class->name) { BUF_APPEND(", %sname=\"%s\"", - PRFIELD(event_class->name.value)); + PRFIELD(event_class->name)); } if (!extended) { @@ -610,9 +610,9 @@ static inline void format_event_class(char **buf_ch, bool extended, (int) event_class->log_level.value))); } - if (event_class->emf_uri.value) { + if (event_class->emf_uri) { BUF_APPEND(", %semf-uri=\"%s\"", - PRFIELD(event_class->emf_uri.value)); + PRFIELD(event_class->emf_uri)); } BUF_APPEND(", %sspecific-context-fc-addr=%p, %spayload-fc-addr=%p", @@ -649,8 +649,8 @@ static inline void format_stream(char **buf_ch, bool extended, BUF_APPEND(", %sid=%" PRIu64, PRFIELD(stream->id)); - if (stream->name.value) { - BUF_APPEND(", %sname=\"%s\"", PRFIELD(stream->name.value)); + if (stream->name) { + BUF_APPEND(", %sname=\"%s\"", PRFIELD(stream->name)); } if (!extended) { @@ -777,8 +777,8 @@ static inline void format_clock_class(char **buf_ch, bool extended, { char tmp_prefix[TMP_PREFIX_LEN]; - if (clock_class->name.value) { - BUF_APPEND(", %sname=\"%s\"", PRFIELD(clock_class->name.value)); + if (clock_class->name) { + BUF_APPEND(", %sname=\"%s\"", PRFIELD(clock_class->name)); } BUF_APPEND(", %sfreq=%" PRIu64, PRFIELD(clock_class->frequency)); @@ -787,9 +787,9 @@ static inline void format_clock_class(char **buf_ch, bool extended, return; } - if (clock_class->description.value) { + if (clock_class->description) { BUF_APPEND(", %spartial-descr=\"%.32s\"", - PRFIELD(clock_class->description.value)); + PRFIELD(clock_class->description)); } if (clock_class->uuid.value) { diff --git a/src/lib/trace-ir/clock-class.c b/src/lib/trace-ir/clock-class.c index 10030155..886501ec 100644 --- a/src/lib/trace-ir/clock-class.c +++ b/src/lib/trace-ir/clock-class.c @@ -35,18 +35,8 @@ void destroy_clock_class(struct bt_object *obj) BT_LIB_LOGD("Destroying clock class: %!+K", clock_class); BT_OBJECT_PUT_REF_AND_RESET(clock_class->user_attributes); - if (clock_class->name.str) { - g_string_free(clock_class->name.str, TRUE); - clock_class->name.str = NULL; - clock_class->name.value = NULL; - } - - if (clock_class->description.str) { - g_string_free(clock_class->description.str, TRUE); - clock_class->description.str = NULL; - clock_class->description.value = NULL; - } - + g_free(clock_class->name); + g_free(clock_class->description); bt_object_pool_finalize(&clock_class->cs_pool); g_free(clock_class); } @@ -91,18 +81,6 @@ struct bt_clock_class *bt_clock_class_create(bt_self_component *self_comp) goto error; } - clock_class->name.str = g_string_new(NULL); - if (!clock_class->name.str) { - BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate a GString."); - goto error; - } - - clock_class->description.str = g_string_new(NULL); - if (!clock_class->description.str) { - BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate a GString."); - goto error; - } - clock_class->frequency = UINT64_C(1000000000); clock_class->origin_is_unix_epoch = BT_TRUE; set_base_offset(clock_class); @@ -132,7 +110,7 @@ BT_EXPORT const char *bt_clock_class_get_name(const struct bt_clock_class *clock_class) { BT_ASSERT_PRE_DEV_CLK_CLS_NON_NULL(clock_class); - return clock_class->name.value; + return clock_class->name; } BT_EXPORT @@ -143,8 +121,8 @@ enum bt_clock_class_set_name_status bt_clock_class_set_name( BT_ASSERT_PRE_CLK_CLS_NON_NULL(clock_class); BT_ASSERT_PRE_NAME_NON_NULL(name); BT_ASSERT_PRE_DEV_CLOCK_CLASS_HOT(clock_class); - g_string_assign(clock_class->name.str, name); - clock_class->name.value = clock_class->name.str->str; + g_free(clock_class->name); + clock_class->name = g_strdup(name); BT_LIB_LOGD("Set clock class's name: %!+K", clock_class); return BT_FUNC_STATUS_OK; } @@ -154,7 +132,7 @@ const char *bt_clock_class_get_description( const struct bt_clock_class *clock_class) { BT_ASSERT_PRE_DEV_CLK_CLS_NON_NULL(clock_class); - return clock_class->description.value; + return clock_class->description; } BT_EXPORT @@ -165,8 +143,8 @@ enum bt_clock_class_set_description_status bt_clock_class_set_description( BT_ASSERT_PRE_CLK_CLS_NON_NULL(clock_class); BT_ASSERT_PRE_DESCR_NON_NULL(descr); BT_ASSERT_PRE_DEV_CLOCK_CLASS_HOT(clock_class); - g_string_assign(clock_class->description.str, descr); - clock_class->description.value = clock_class->description.str->str; + g_free(clock_class->description); + clock_class->description = g_strdup(descr); BT_LIB_LOGD("Set clock class's description: %!+K", clock_class); return BT_FUNC_STATUS_OK; diff --git a/src/lib/trace-ir/clock-class.h b/src/lib/trace-ir/clock-class.h index e2e90412..54eeb0c8 100644 --- a/src/lib/trace-ir/clock-class.h +++ b/src/lib/trace-ir/clock-class.h @@ -27,19 +27,8 @@ struct bt_clock_class { /* Owned by this */ struct bt_value *user_attributes; - struct { - GString *str; - - /* NULL or `str->str` above */ - const char *value; - } name; - - struct { - GString *str; - - /* NULL or `str->str` above */ - const char *value; - } description; + gchar *name; + gchar *description; uint64_t frequency; uint64_t precision; diff --git a/src/lib/trace-ir/event-class.c b/src/lib/trace-ir/event-class.c index 0d907175..76ad226b 100644 --- a/src/lib/trace-ir/event-class.c +++ b/src/lib/trace-ir/event-class.c @@ -41,16 +41,8 @@ void destroy_event_class(struct bt_object *obj) BT_LIB_LOGD("Destroying event class: %!+E", event_class); BT_OBJECT_PUT_REF_AND_RESET(event_class->user_attributes); - if (event_class->name.str) { - g_string_free(event_class->name.str, TRUE); - event_class->name.str = NULL; - } - - if (event_class->emf_uri.str) { - g_string_free(event_class->emf_uri.str, TRUE); - event_class->emf_uri.str = NULL; - } - + g_free(event_class->name); + g_free(event_class->emf_uri); BT_LOGD_STR("Putting context field class."); BT_OBJECT_PUT_REF_AND_RESET(event_class->specific_context_fc); BT_LOGD_STR("Putting payload field class."); @@ -119,17 +111,6 @@ struct bt_event_class *create_event_class_with_id( event_class->id = id; bt_property_uint_init(&event_class->log_level, BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE, 0); - event_class->name.str = g_string_new(NULL); - if (!event_class->name.str) { - BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate a GString."); - goto error; - } - - event_class->emf_uri.str = g_string_new(NULL); - if (!event_class->emf_uri.str) { - BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate a GString."); - goto error; - } ret = bt_object_pool_initialize(&event_class->event_pool, (bt_object_pool_new_object_func) bt_event_new, @@ -187,7 +168,7 @@ BT_EXPORT const char *bt_event_class_get_name(const struct bt_event_class *event_class) { BT_ASSERT_PRE_DEV_EC_NON_NULL(event_class); - return event_class->name.value; + return event_class->name; } BT_EXPORT @@ -198,8 +179,8 @@ enum bt_event_class_set_name_status bt_event_class_set_name( BT_ASSERT_PRE_EC_NON_NULL(event_class); BT_ASSERT_PRE_NAME_NON_NULL(name); BT_ASSERT_PRE_DEV_EVENT_CLASS_HOT(event_class); - g_string_assign(event_class->name.str, name); - event_class->name.value = event_class->name.str->str; + g_free(event_class->name); + event_class->name = g_strdup(name); BT_LIB_LOGD("Set event class's name: %!+E", event_class); return BT_FUNC_STATUS_OK; } @@ -240,7 +221,7 @@ BT_EXPORT const char *bt_event_class_get_emf_uri(const struct bt_event_class *event_class) { BT_ASSERT_PRE_DEV_EC_NON_NULL(event_class); - return event_class->emf_uri.value; + return event_class->emf_uri; } BT_EXPORT @@ -252,8 +233,8 @@ enum bt_event_class_set_emf_uri_status bt_event_class_set_emf_uri( BT_ASSERT_PRE_EC_NON_NULL(event_class); BT_ASSERT_PRE_NON_NULL("emf-uri", emf_uri, "EMF URI"); BT_ASSERT_PRE_DEV_EVENT_CLASS_HOT(event_class); - g_string_assign(event_class->emf_uri.str, emf_uri); - event_class->emf_uri.value = event_class->emf_uri.str->str; + g_free(event_class->emf_uri); + event_class->emf_uri = g_strdup(emf_uri); BT_LIB_LOGD("Set event class's EMF URI: %!+E", event_class); return BT_FUNC_STATUS_OK; } diff --git a/src/lib/trace-ir/event-class.h b/src/lib/trace-ir/event-class.h index 67d93695..ccbc0009 100644 --- a/src/lib/trace-ir/event-class.h +++ b/src/lib/trace-ir/event-class.h @@ -29,22 +29,12 @@ struct bt_event_class { /* Owned by this */ struct bt_value *user_attributes; - struct { - GString *str; - - /* NULL or `str->str` above */ - const char *value; - } name; + gchar *name; uint64_t id; struct bt_property_uint log_level; - struct { - GString *str; - - /* NULL or `str->str` above */ - const char *value; - } emf_uri; + gchar *emf_uri; /* Pool of `struct bt_event *` */ struct bt_object_pool event_pool; diff --git a/src/lib/trace-ir/stream-class.c b/src/lib/trace-ir/stream-class.c index 08395849..c9970861 100644 --- a/src/lib/trace-ir/stream-class.c +++ b/src/lib/trace-ir/stream-class.c @@ -47,12 +47,7 @@ void destroy_stream_class(struct bt_object *obj) stream_class->event_classes = NULL; } - if (stream_class->name.str) { - g_string_free(stream_class->name.str, TRUE); - stream_class->name.str = NULL; - stream_class->name.value = NULL; - } - + g_free(stream_class->name); BT_LOGD_STR("Putting packet context field class."); BT_OBJECT_PUT_REF_AND_RESET(stream_class->packet_context_fc); BT_LOGD_STR("Putting event common context field class."); @@ -117,12 +112,6 @@ struct bt_stream_class *create_stream_class_with_id( goto error; } - stream_class->name.str = g_string_new(NULL); - if (!stream_class->name.str) { - BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate a GString."); - goto error; - } - stream_class->id = id; stream_class->assigns_automatic_event_class_id = true; stream_class->assigns_automatic_stream_id = true; @@ -203,7 +192,7 @@ BT_EXPORT const char *bt_stream_class_get_name(const struct bt_stream_class *stream_class) { BT_ASSERT_PRE_DEV_SC_NON_NULL(stream_class); - return stream_class->name.value; + return stream_class->name; } BT_EXPORT @@ -215,8 +204,8 @@ enum bt_stream_class_set_name_status bt_stream_class_set_name( BT_ASSERT_PRE_SC_NON_NULL(stream_class); BT_ASSERT_PRE_NAME_NON_NULL(name); BT_ASSERT_PRE_DEV_STREAM_CLASS_HOT(stream_class); - g_string_assign(stream_class->name.str, name); - stream_class->name.value = stream_class->name.str->str; + g_free(stream_class->name); + stream_class->name = g_strdup(name); BT_LIB_LOGD("Set stream class's name: %!+S", stream_class); return BT_FUNC_STATUS_OK; } diff --git a/src/lib/trace-ir/stream-class.h b/src/lib/trace-ir/stream-class.h index 771a5899..a1d9ab60 100644 --- a/src/lib/trace-ir/stream-class.h +++ b/src/lib/trace-ir/stream-class.h @@ -23,12 +23,7 @@ struct bt_stream_class { /* Owned by this */ struct bt_value *user_attributes; - struct { - GString *str; - - /* NULL or `str->str` above */ - const char *value; - } name; + gchar *name; uint64_t id; bool assigns_automatic_event_class_id; diff --git a/src/lib/trace-ir/stream.c b/src/lib/trace-ir/stream.c index 7cb124f4..471623e8 100644 --- a/src/lib/trace-ir/stream.c +++ b/src/lib/trace-ir/stream.c @@ -37,12 +37,7 @@ void destroy_stream(struct bt_object *obj) BT_LIB_LOGD("Destroying stream object: %!+s", stream); BT_OBJECT_PUT_REF_AND_RESET(stream->user_attributes); - if (stream->name.str) { - g_string_free(stream->name.str, TRUE); - stream->name.str = NULL; - stream->name.value = NULL; - } - + g_free(stream->name); BT_LOGD_STR("Putting stream's class."); bt_object_put_ref(stream->class); bt_object_pool_finalize(&stream->packet_pool); @@ -114,12 +109,6 @@ struct bt_stream *create_stream_with_id(struct bt_stream_class *stream_class, goto error; } - stream->name.str = g_string_new(NULL); - if (!stream->name.str) { - BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate a GString."); - goto error; - } - stream->id = id; ret = bt_object_pool_initialize(&stream->packet_pool, (bt_object_pool_new_object_func) bt_packet_new, @@ -211,7 +200,7 @@ BT_EXPORT const char *bt_stream_get_name(const struct bt_stream *stream) { BT_ASSERT_PRE_DEV_STREAM_NON_NULL(stream); - return stream->name.value; + return stream->name; } BT_EXPORT @@ -222,8 +211,8 @@ enum bt_stream_set_name_status bt_stream_set_name(struct bt_stream *stream, BT_ASSERT_PRE_STREAM_NON_NULL(stream); BT_ASSERT_PRE_NAME_NON_NULL(name); BT_ASSERT_PRE_DEV_STREAM_HOT(stream); - g_string_assign(stream->name.str, name); - stream->name.value = stream->name.str->str; + g_free(stream->name); + stream->name = g_strdup(name); BT_LIB_LOGD("Set stream's name: %!+s", stream); return BT_FUNC_STATUS_OK; } diff --git a/src/lib/trace-ir/stream.h b/src/lib/trace-ir/stream.h index 89d7bf73..89e236a6 100644 --- a/src/lib/trace-ir/stream.h +++ b/src/lib/trace-ir/stream.h @@ -26,12 +26,7 @@ struct bt_stream { /* Owned by this */ struct bt_stream_class *class; - struct { - GString *str; - - /* NULL or `str->str` above */ - const char *value; - } name; + gchar *name; uint64_t id; diff --git a/src/lib/trace-ir/trace.c b/src/lib/trace-ir/trace.c index 8cc005a7..ef9581ee 100644 --- a/src/lib/trace-ir/trace.c +++ b/src/lib/trace-ir/trace.c @@ -105,11 +105,7 @@ void destroy_trace(struct bt_object *obj) } } - if (trace->name.str) { - g_string_free(trace->name.str, TRUE); - trace->name.str = NULL; - trace->name.value = NULL; - } + g_free(trace->name); if (trace->environment) { BT_LOGD_STR("Destroying environment attributes."); @@ -170,12 +166,6 @@ struct bt_trace *bt_trace_create(struct bt_trace_class *tc) goto error; } - trace->name.str = g_string_new(NULL); - if (!trace->name.str) { - BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate one GString."); - goto error; - } - trace->environment = bt_attributes_create(); if (!trace->environment) { BT_LIB_LOGE_APPEND_CAUSE("Cannot create empty attributes object."); @@ -205,7 +195,7 @@ BT_EXPORT const char *bt_trace_get_name(const struct bt_trace *trace) { BT_ASSERT_PRE_DEV_TRACE_NON_NULL(trace); - return trace->name.value; + return trace->name; } BT_EXPORT @@ -216,8 +206,8 @@ enum bt_trace_set_name_status bt_trace_set_name(struct bt_trace *trace, BT_ASSERT_PRE_TRACE_NON_NULL(trace); BT_ASSERT_PRE_NAME_NON_NULL(name); BT_ASSERT_PRE_DEV_TRACE_HOT(trace); - g_string_assign(trace->name.str, name); - trace->name.value = trace->name.str->str; + g_free(trace->name); + trace->name = g_strdup(name); BT_LIB_LOGD("Set trace's name: %!+t", trace); return BT_FUNC_STATUS_OK; } diff --git a/src/lib/trace-ir/trace.h b/src/lib/trace-ir/trace.h index 294e8943..ed0df692 100644 --- a/src/lib/trace-ir/trace.h +++ b/src/lib/trace-ir/trace.h @@ -31,12 +31,7 @@ struct bt_trace { /* Owned by this */ struct bt_trace_class *class; - struct { - GString *str; - - /* NULL or `str->str` above */ - const char *value; - } name; + gchar *name; struct { bt_uuid_t uuid; diff --git a/src/plugins/ctf/common/bfcr/bfcr.cpp b/src/plugins/ctf/common/bfcr/bfcr.cpp deleted file mode 100644 index f59f65d0..00000000 --- a/src/plugins/ctf/common/bfcr/bfcr.cpp +++ /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 - * - * Babeltrace - CTF binary field class reader (BFCR) - */ - -#include -#include -#include -#include -#include - -#include - -#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 index f2fe8796..00000000 --- a/src/plugins/ctf/common/bfcr/bfcr.hpp +++ /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 - * - * Babeltrace - CTF binary field class reader (BFCR) - */ - -#ifndef CTF_BFCR_H -#define CTF_BFCR_H - -#include -#include - -#include - -#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: - * - * - #BT_BFCR_STATUS_OK: Everything is okay; - * continue the decoding process. - * - #BT_BFCR_STATUS_ERROR: 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: - * - * - #BT_BFCR_STATUS_OK: Decoding is done. - * - #BT_BFCR_STATUS_EOF: 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. - * - #BT_BFCR_STATUS_INVAL: Invalid argument. - * - #BT_BFCR_STATUS_ERROR: 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: - * - * - #BT_BFCR_STATUS_OK: decoding is done. - * - #BT_BFCR_STATUS_EOF: 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. - * - #BT_BFCR_STATUS_INVAL: invalid argument. - * - #BT_BFCR_STATUS_ERROR: 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 index a6a7e9f7..00000000 --- a/src/plugins/ctf/common/metadata/ast.hpp +++ /dev/null @@ -1,458 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2011-2012 Mathieu Desnoyers - */ - -#ifndef _CTF_AST_H -#define _CTF_AST_H - -#include -#include -#include - -#include - -#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 index ef178c53..00000000 --- a/src/plugins/ctf/common/metadata/ctf-meta-configure-ir-trace.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2019 Philippe Proulx - */ - -#include - -#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 index f94f19e6..00000000 --- a/src/plugins/ctf/common/metadata/ctf-meta-configure-ir-trace.hpp +++ /dev/null @@ -1,14 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2019 Philippe Proulx - */ - -#ifndef _CTF_META_CONFIGURE_IR_TRACE_H -#define _CTF_META_CONFIGURE_IR_TRACE_H - -#include - -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 index 1f7ffe57..00000000 --- a/src/plugins/ctf/common/metadata/ctf-meta-resolve.cpp +++ /dev/null @@ -1,1261 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2016-2018 Philippe Proulx - * Copyright 2015 Jérémie Galarneau - */ - -#include -#include -#include -#include - -#include - -#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 index e3ecfd07..00000000 --- a/src/plugins/ctf/common/metadata/ctf-meta-translate.cpp +++ /dev/null @@ -1,651 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2018 Philippe Proulx - */ - -#include -#include - -#include - -#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 index bea62bf9..00000000 --- a/src/plugins/ctf/common/metadata/ctf-meta-update-alignments.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2020 Philippe Proulx - */ - -#include - -#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 index ab10dd4f..00000000 --- a/src/plugins/ctf/common/metadata/ctf-meta-update-default-clock-classes.cpp +++ /dev/null @@ -1,180 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2018 Philippe Proulx - */ - -#include -#include - -#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 index c7902383..00000000 --- a/src/plugins/ctf/common/metadata/ctf-meta-update-in-ir.cpp +++ /dev/null @@ -1,259 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2018 Philippe Proulx - */ - -#include -#include -#include - -#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 index 23c65745..00000000 --- a/src/plugins/ctf/common/metadata/ctf-meta-update-meanings.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2018 Philippe Proulx - */ - -#include -#include - -#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 index a8f5add6..00000000 --- a/src/plugins/ctf/common/metadata/ctf-meta-update-stream-class-config.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2019 Philippe Proulx - */ - -#include - -#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 index 6c3bfc97..00000000 --- a/src/plugins/ctf/common/metadata/ctf-meta-update-text-array-sequence.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2018 Philippe Proulx - */ - -#include - -#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 index 65e4c9fe..00000000 --- a/src/plugins/ctf/common/metadata/ctf-meta-update-value-storing-indexes.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2018 Philippe Proulx - */ - -#include -#include - -#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 index 9a01c593..00000000 --- a/src/plugins/ctf/common/metadata/ctf-meta-validate.cpp +++ /dev/null @@ -1,333 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2018 Philippe Proulx - */ - -#include - -#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 index 5294ecec..00000000 --- a/src/plugins/ctf/common/metadata/ctf-meta-visitors.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2018 Philippe Proulx - */ - -#ifndef _CTF_META_VISITORS_H -#define _CTF_META_VISITORS_H - -#include - -#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 index 6d7e274a..00000000 --- a/src/plugins/ctf/common/metadata/ctf-meta-warn-meaningless-header-fields.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2018 Philippe Proulx - */ - -#include -#include - -#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 index 87469d3b..00000000 --- a/src/plugins/ctf/common/metadata/ctf-meta.hpp +++ /dev/null @@ -1,1748 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2018 Philippe Proulx - */ - -#ifndef _CTF_META_H -#define _CTF_META_H - -#include -#include -#include - -#include - -#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(©_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(©_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(©_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(©_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(©_fc->base, &fc->base); - ctf_field_path_copy_content(©_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 index 2150465b..00000000 --- a/src/plugins/ctf/common/metadata/decoder-packetized-file-stream-to-buf.cpp +++ /dev/null @@ -1,267 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2016-2017 Philippe Proulx - */ - -#include -#include -#include -#include - -#include - -#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 index 8d831536..00000000 --- a/src/plugins/ctf/common/metadata/decoder-packetized-file-stream-to-buf.hpp +++ /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 - -#include - -#include - -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 index deaeedb4..00000000 --- a/src/plugins/ctf/common/metadata/decoder.cpp +++ /dev/null @@ -1,473 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2016-2017 Philippe Proulx - */ - -#include -#include -#include -#include -#include -#include - -#include - -#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 index d4385f4c..00000000 --- a/src/plugins/ctf/common/metadata/decoder.hpp +++ /dev/null @@ -1,161 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2016-2017 Philippe Proulx - */ - -#ifndef _METADATA_DECODER_H -#define _METADATA_DECODER_H - -#include -#include - -#include - -#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 index 7c2d5d38..00000000 --- a/src/plugins/ctf/common/metadata/lexer.lpp +++ /dev/null @@ -1,121 +0,0 @@ -%{ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2010 Mathieu Desnoyers - * - * Common Trace Formal Lexer - */ - -#include -#include - -#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); -[^*\n]* /* eat anything that's not a '*' */ -"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */ -\n -"*"+"/" 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 index 058a6b4b..00000000 --- a/src/plugins/ctf/common/metadata/logging.cpp +++ /dev/null @@ -1,10 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright (c) 2017 Jérémie Galarneau - */ - -#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 index 234a1d60..00000000 --- a/src/plugins/ctf/common/metadata/logging.hpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright (c) 2017 Jérémie Galarneau - */ - -#ifndef CTF_METADATA_LOGGING_H -#define CTF_METADATA_LOGGING_H - -#include - -#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 index bdf31e02..00000000 --- a/src/plugins/ctf/common/metadata/objstack.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2013 Mathieu Desnoyers - * - * Common Trace Format Object Stack. - */ - -#include - -#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 index 2c91e140..00000000 --- a/src/plugins/ctf/common/metadata/objstack.hpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2013 Mathieu Desnoyers - * - * Common Trace Format Object Stack. - */ - -#ifndef _OBJSTACK_H -#define _OBJSTACK_H - -#include - -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 index e35c3621..00000000 --- a/src/plugins/ctf/common/metadata/parser-wrap.hpp +++ /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 index eb6e32c7..00000000 --- a/src/plugins/ctf/common/metadata/parser.ypp +++ /dev/null @@ -1,2607 +0,0 @@ -%{ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2010 - Mathieu Desnoyers - * - * Common Trace Format Metadata Grammar. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 IDENTIFIER ID_TYPE -%token CTF_ERROR -%union -{ - long long ll; - unsigned long long ull; - char c; - char *s; - struct ctf_node *n; -} - -%type CTF_STRING_LITERAL CTF_CHARACTER_LITERAL - -%type keywords - -%type CTF_INTEGER_LITERAL -%type postfix_expression unary_expression unary_expression_or_range - -%type declaration -%type event_declaration -%type stream_declaration -%type env_declaration -%type trace_declaration -%type clock_declaration -%type callsite_declaration -%type integer_declaration_specifiers -%type declaration_specifiers -%type alias_declaration_specifiers - -%type field_class_declarator_list -%type integer_field_class_specifier -%type field_class_specifier -%type struct_class_specifier -%type variant_field_class_specifier -%type enum_field_class_specifier -%type struct_or_variant_declaration_list -%type struct_or_variant_declaration -%type struct_or_variant_declarator_list -%type struct_or_variant_declarator -%type enumerator_list -%type enumerator -%type abstract_declarator_list -%type abstract_declarator -%type direct_abstract_declarator -%type alias_abstract_declarator_list -%type alias_abstract_declarator -%type direct_alias_abstract_declarator -%type declarator -%type direct_declarator -%type field_class_declarator -%type direct_field_class_declarator -%type pointer -%type ctf_assignment_expression_list -%type 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 index 1f6f144d..00000000 --- a/src/plugins/ctf/common/metadata/scanner-symbols.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2011-2012 Mathieu Desnoyers - */ - -#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 index dd16e977..00000000 --- a/src/plugins/ctf/common/metadata/scanner.hpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2011-2012 Mathieu Desnoyers - */ - -#ifndef _CTF_SCANNER_H -#define _CTF_SCANNER_H - -#include - -#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 index c53c4d8a..00000000 --- a/src/plugins/ctf/common/metadata/visitor-generate-ir.cpp +++ /dev/null @@ -1,4744 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2010 Mathieu Desnoyers - * Copyright 2015-2018 Philippe Proulx - * - * Common Trace Format metadata visitor (generates CTF IR objects). - */ - -#include - -#include -#include -#include -#include -#include - -#include - -#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 index 84c504f9..00000000 --- a/src/plugins/ctf/common/metadata/visitor-parent-links.cpp +++ /dev/null @@ -1,441 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2010 Mathieu Desnoyers - * - * Common Trace Format Metadata Parent Link Creator. - */ - -#include - -#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 index 4fad1360..00000000 --- a/src/plugins/ctf/common/metadata/visitor-semantic-validator.cpp +++ /dev/null @@ -1,996 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright 2010 Mathieu Desnoyers - * - * Common Trace Format Metadata Semantic Validator. - */ - -#include - -#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 index 33ad4a27..00000000 --- a/src/plugins/ctf/common/msg-iter/msg-iter.cpp +++ /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 - * - * Babeltrace - CTF message iterator - */ - -#include -#include -#include -#include -#include - -#include - -#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 index 0b49c1c6..00000000 --- a/src/plugins/ctf/common/msg-iter/msg-iter.hpp +++ /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 - * - * Babeltrace - CTF message iterator - */ - -#ifndef CTF_MSG_ITER_H -#define CTF_MSG_ITER_H - -#include -#include -#include - -#include - -#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: - * - * - #CTF_MSG_ITER_MEDIUM_STATUS_OK: 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. - * - #CTF_MSG_ITER_MEDIUM_STATUS_AGAIN: 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. - * - #CTF_MSG_ITER_MEDIUM_STATUS_EOF: 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. - * - #CTF_MSG_ITER_MEDIUM_STATUS_ERROR: 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 index 7db4dde9..00000000 --- a/src/plugins/ctf/common/print.hpp +++ /dev/null @@ -1,35 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright (c) 2016 Philippe Proulx - * - * Define PRINT_PREFIX and PRINT_ERR_STREAM, then include this file. - */ - -#ifndef CTF_BTR_PRINT_H -#define CTF_BTR_PRINT_H - -#include - -#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 index 00000000..4ee3548c --- /dev/null +++ b/src/plugins/ctf/common/src/bfcr/bfcr.cpp @@ -0,0 +1,1271 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2015-2016 Philippe Proulx + * + * 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(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 index 00000000..984b695c --- /dev/null +++ b/src/plugins/ctf/common/src/bfcr/bfcr.hpp @@ -0,0 +1,358 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2015-2016 Philippe Proulx + * + * Babeltrace - CTF binary field class reader (BFCR) + */ + +#ifndef CTF_BFCR_H +#define CTF_BFCR_H + +#include +#include + +#include + +#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: + * + * - #BT_BFCR_STATUS_OK: Everything is okay; + * continue the decoding process. + * - #BT_BFCR_STATUS_ERROR: 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: + * + * - #BT_BFCR_STATUS_OK: Decoding is done. + * - #BT_BFCR_STATUS_EOF: 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. + * - #BT_BFCR_STATUS_INVAL: Invalid argument. + * - #BT_BFCR_STATUS_ERROR: 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: + * + * - #BT_BFCR_STATUS_OK: decoding is done. + * - #BT_BFCR_STATUS_EOF: 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. + * - #BT_BFCR_STATUS_INVAL: invalid argument. + * - #BT_BFCR_STATUS_ERROR: 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 index 00000000..0c3b52d7 --- /dev/null +++ b/src/plugins/ctf/common/src/clk-cls-cfg.hpp @@ -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 + +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 index 00000000..597cb3a4 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/ast.hpp @@ -0,0 +1,611 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2011-2012 Mathieu Desnoyers + */ + +#ifndef _CTF_AST_H +#define _CTF_AST_H + +#include + +#include +#include +#include + +#include + +#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; + + 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 index 00000000..dbcbbbd8 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-configure-ir-trace.cpp @@ -0,0 +1,39 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2019 Philippe Proulx + */ + +#include + +#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 index 00000000..2adffb53 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-configure-ir-trace.hpp @@ -0,0 +1,14 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2019 Philippe Proulx + */ + +#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 index 00000000..4420746a --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-resolve.cpp @@ -0,0 +1,1250 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2016-2018 Philippe Proulx + * Copyright 2015 Jérémie Galarneau + */ + +#include + +#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 index 00000000..b62dabf6 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-translate.cpp @@ -0,0 +1,656 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2018 Philippe Proulx + */ + +#include +#include + +#include + +#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 index 00000000..bea62bf9 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-alignments.cpp @@ -0,0 +1,161 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2020 Philippe Proulx + */ + +#include + +#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 index 00000000..cd9acdf2 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-default-clock-classes.cpp @@ -0,0 +1,178 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2018 Philippe Proulx + */ + +#include + +#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 index 00000000..c7902383 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-in-ir.cpp @@ -0,0 +1,259 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2018 Philippe Proulx + */ + +#include +#include +#include + +#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 index 00000000..23c65745 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-meanings.cpp @@ -0,0 +1,204 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2018 Philippe Proulx + */ + +#include +#include + +#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 index 00000000..a8f5add6 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-stream-class-config.cpp @@ -0,0 +1,58 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2019 Philippe Proulx + */ + +#include + +#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 index 00000000..6c3bfc97 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-text-array-sequence.cpp @@ -0,0 +1,146 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2018 Philippe Proulx + */ + +#include + +#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 index 00000000..65e4c9fe --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-update-value-storing-indexes.cpp @@ -0,0 +1,149 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2018 Philippe Proulx + */ + +#include +#include + +#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 index 00000000..cb4e2b88 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-validate.cpp @@ -0,0 +1,328 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2018 Philippe Proulx + */ + +#include + +#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 index 00000000..1a6f708f --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-visitors.hpp @@ -0,0 +1,46 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2018 Philippe Proulx + */ + +#ifndef _CTF_META_VISITORS_H +#define _CTF_META_VISITORS_H + +#include + +#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 index 00000000..f09a6b33 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta-warn-meaningless-header-fields.cpp @@ -0,0 +1,118 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2018 Philippe Proulx + */ + +#include + +#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 index 00000000..5efa7106 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/ctf-meta.hpp @@ -0,0 +1,1776 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2018 Philippe Proulx + */ + +#ifndef _CTF_META_H +#define _CTF_META_H + +#include +#include +#include + +#include + +#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(©_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(©_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(©_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(©_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(©_fc->base, &fc->base); + ctf_field_path_copy_content(©_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 index 00000000..b6de4d61 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/decoder-packetized-file-stream-to-buf.cpp @@ -0,0 +1,253 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2016-2017 Philippe Proulx + */ + +#include +#include +#include + +#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 index 00000000..6190b061 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/decoder-packetized-file-stream-to-buf.hpp @@ -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 + +#include + +#include + +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 index 00000000..7e5e8bb1 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/decoder.cpp @@ -0,0 +1,475 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2016-2017 Philippe Proulx + */ + +#include +#include +#include + +#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 index 00000000..b4dbce87 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/decoder.hpp @@ -0,0 +1,194 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2016-2017 Philippe Proulx + */ + +#ifndef _METADATA_DECODER_H +#define _METADATA_DECODER_H + +#include + +#include + +#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; + +/* + * 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 index 00000000..8bc0eeda --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/lexer.lpp @@ -0,0 +1,119 @@ +%{ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2010 Mathieu Desnoyers + * + * 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); +[^*\n]* /* eat anything that's not a '*' */ +"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */ +\n +"*"+"/" 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 index 00000000..ee019a3c --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/logging.hpp @@ -0,0 +1,26 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright (c) 2017 Jérémie Galarneau + */ + +#ifndef CTF_METADATA_LOGGING_H +#define CTF_METADATA_LOGGING_H + +#include + +#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 index 00000000..d124b3f3 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/objstack.cpp @@ -0,0 +1,123 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2013 Mathieu Desnoyers + * + * 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 index 00000000..cc17d433 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/objstack.hpp @@ -0,0 +1,29 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2013 Mathieu Desnoyers + * + * Common Trace Format Object Stack. + */ + +#ifndef _OBJSTACK_H +#define _OBJSTACK_H + +#include + +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 index 00000000..bfc0e907 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/parser-wrap.hpp @@ -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 index 00000000..bf2d90c5 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/parser.ypp @@ -0,0 +1,2616 @@ +%{ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2010 - Mathieu Desnoyers + * + * 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 IDENTIFIER ID_TYPE +%token CTF_ERROR +%union +{ + long long ll; + unsigned long long ull; + char c; + char *s; + struct ctf_node *n; +} + +%type CTF_STRING_LITERAL CTF_CHARACTER_LITERAL + +%type keywords + +%type CTF_INTEGER_LITERAL +%type postfix_expression unary_expression unary_expression_or_range + +%type declaration +%type event_declaration +%type stream_declaration +%type env_declaration +%type trace_declaration +%type clock_declaration +%type callsite_declaration +%type integer_declaration_specifiers +%type declaration_specifiers +%type alias_declaration_specifiers + +%type field_class_declarator_list +%type integer_field_class_specifier +%type field_class_specifier +%type struct_class_specifier +%type variant_field_class_specifier +%type enum_field_class_specifier +%type struct_or_variant_declaration_list +%type struct_or_variant_declaration +%type struct_or_variant_declarator_list +%type struct_or_variant_declarator +%type enumerator_list +%type enumerator +%type abstract_declarator_list +%type abstract_declarator +%type direct_abstract_declarator +%type alias_abstract_declarator_list +%type alias_abstract_declarator +%type direct_alias_abstract_declarator +%type declarator +%type direct_declarator +%type field_class_declarator +%type direct_field_class_declarator +%type pointer +%type ctf_assignment_expression_list +%type 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 index 00000000..1f6f144d --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/scanner-symbols.hpp @@ -0,0 +1,40 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2011-2012 Mathieu Desnoyers + */ + +#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 index 00000000..4f2a1f86 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/scanner.hpp @@ -0,0 +1,54 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2011-2012 Mathieu Desnoyers + */ + +#ifndef _CTF_SCANNER_H +#define _CTF_SCANNER_H + +#include + +#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 index 00000000..48034a3f --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/visitor-generate-ir.cpp @@ -0,0 +1,4667 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2010 Mathieu Desnoyers + * Copyright 2015-2018 Philippe Proulx + * + * Common Trace Format metadata visitor (generates CTF IR objects). + */ + +#include +#include + +#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 index 00000000..90faaee0 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/visitor-parent-links.cpp @@ -0,0 +1,442 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2010 Mathieu Desnoyers + * + * Common Trace Format Metadata Parent Link Creator. + */ + +#include +#include + +#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 index 00000000..59cec938 --- /dev/null +++ b/src/plugins/ctf/common/src/metadata/tsdl/visitor-semantic-validator.cpp @@ -0,0 +1,999 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright 2010 Mathieu Desnoyers + * + * Common Trace Format Metadata Semantic Validator. + */ + +#include +#include + +#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 index 00000000..50a545bb --- /dev/null +++ b/src/plugins/ctf/common/src/msg-iter/msg-iter.cpp @@ -0,0 +1,3063 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright (c) 2015-2018 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2015-2018 Philippe Proulx + * + * Babeltrace - CTF message iterator + */ + +#include +#include +#include + +#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 index 00000000..f9bb7f2a --- /dev/null +++ b/src/plugins/ctf/common/src/msg-iter/msg-iter.hpp @@ -0,0 +1,365 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation + * Copyright (c) 2015-2016 Philippe Proulx + * + * Babeltrace - CTF message iterator + */ + +#ifndef CTF_MSG_ITER_H +#define CTF_MSG_ITER_H + +#include +#include +#include + +#include + +#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: + * + * - #CTF_MSG_ITER_MEDIUM_STATUS_OK: 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. + * - #CTF_MSG_ITER_MEDIUM_STATUS_AGAIN: 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. + * - #CTF_MSG_ITER_MEDIUM_STATUS_EOF: 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. + * - #CTF_MSG_ITER_MEDIUM_STATUS_ERROR: 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; + +/** + * 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 */ diff --git a/src/plugins/ctf/fs-sink/fs-sink-ctf-meta.hpp b/src/plugins/ctf/fs-sink/fs-sink-ctf-meta.hpp index 6cde44fe..7161fb35 100644 --- a/src/plugins/ctf/fs-sink/fs-sink-ctf-meta.hpp +++ b/src/plugins/ctf/fs-sink/fs-sink-ctf-meta.hpp @@ -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 = diff --git a/src/plugins/ctf/fs-sink/fs-sink-stream.cpp b/src/plugins/ctf/fs-sink/fs-sink-stream.cpp index 6611744b..e070e435 100644 --- a/src/plugins/ctf/fs-sink/fs-sink-stream.cpp +++ b/src/plugins/ctf/fs-sink/fs-sink-stream.cpp @@ -9,11 +9,6 @@ #include -#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(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; } diff --git a/src/plugins/ctf/fs-sink/fs-sink-stream.hpp b/src/plugins/ctf/fs-sink/fs-sink-stream.hpp index 8d559c6a..8c309525 100644 --- a/src/plugins/ctf/fs-sink/fs-sink-stream.hpp +++ b/src/plugins/ctf/fs-sink/fs-sink-stream.hpp @@ -12,21 +12,30 @@ #include +#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; }; diff --git a/src/plugins/ctf/fs-sink/fs-sink-trace.cpp b/src/plugins/ctf/fs-sink/fs-sink-trace.cpp index 5466dd64..cebf19f6 100644 --- a/src/plugins/ctf/fs-sink/fs-sink-trace.cpp +++ b/src/plugins/ctf/fs-sink/fs-sink-trace.cpp @@ -9,11 +9,6 @@ #include -#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; } diff --git a/src/plugins/ctf/fs-sink/fs-sink-trace.hpp b/src/plugins/ctf/fs-sink/fs-sink-trace.hpp index 0da8b4b0..c9b16436 100644 --- a/src/plugins/ctf/fs-sink/fs-sink-trace.hpp +++ b/src/plugins/ctf/fs-sink/fs-sink-trace.hpp @@ -11,13 +11,23 @@ #include +#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); diff --git a/src/plugins/ctf/fs-sink/fs-sink.cpp b/src/plugins/ctf/fs-sink/fs-sink.cpp index 00084b79..6b0c88da 100644 --- a/src/plugins/ctf/fs-sink/fs-sink.cpp +++ b/src/plugins/ctf/fs-sink/fs-sink.cpp @@ -9,12 +9,8 @@ #include -#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) diff --git a/src/plugins/ctf/fs-sink/fs-sink.hpp b/src/plugins/ctf/fs-sink/fs-sink.hpp index 3c1e0128..529ae346 100644 --- a/src/plugins/ctf/fs-sink/fs-sink.hpp +++ b/src/plugins/ctf/fs-sink/fs-sink.hpp @@ -11,16 +11,22 @@ #include +#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 diff --git a/src/plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.cpp b/src/plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.cpp index db7af865..c45a1685 100644 --- a/src/plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.cpp +++ b/src/plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.cpp @@ -15,13 +15,19 @@ #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, }; diff --git a/src/plugins/ctf/fs-sink/translate-trace-ir-to-ctf-ir.cpp b/src/plugins/ctf/fs-sink/translate-trace-ir-to-ctf-ir.cpp index 72a29140..ca634b95 100644 --- a/src/plugins/ctf/fs-sink/translate-trace-ir-to-ctf-ir.cpp +++ b/src/plugins/ctf/fs-sink/translate-trace-ir-to-ctf-ir.cpp @@ -12,13 +12,10 @@ #include -#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(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(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(bt_value_get_type(val))); goto end; } } diff --git a/src/plugins/ctf/fs-src/data-stream-file.cpp b/src/plugins/ctf/fs-src/data-stream-file.cpp index 4a500221..d2f7e102 100644 --- a/src/plugins/ctf/fs-src/data-stream-file.cpp +++ b/src/plugins/ctf/fs-src/data-stream-file.cpp @@ -7,28 +7,20 @@ */ #include -#include #include #include -#include -#include - -#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(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(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 +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 +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(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(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(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_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(); - 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)); } diff --git a/src/plugins/ctf/fs-src/data-stream-file.hpp b/src/plugins/ctf/fs-src/data-stream-file.hpp index 297c859f..05a6db13 100644 --- a/src/plugins/ctf/fs-src/data-stream-file.hpp +++ b/src/plugins/ctf/fs-src/data-stream-file.hpp @@ -7,72 +7,167 @@ #ifndef CTF_FS_DS_FILE_H #define CTF_FS_DS_FILE_H +#include +#include +#include + #include #include #include -#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; + + 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; - /* 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 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; -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 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_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; -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 */ diff --git a/src/plugins/ctf/fs-src/file.cpp b/src/plugins/ctf/fs-src/file.cpp index 25a29d0a..13e279cd 100644 --- a/src/plugins/ctf/fs-src/file.cpp +++ b/src/plugins/ctf/fs-src/file.cpp @@ -8,95 +8,38 @@ #include #include -#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; } diff --git a/src/plugins/ctf/fs-src/file.hpp b/src/plugins/ctf/fs-src/file.hpp index 779c9177..ee6441cb 100644 --- a/src/plugins/ctf/fs-src/file.hpp +++ b/src/plugins/ctf/fs-src/file.hpp @@ -7,11 +7,31 @@ #ifndef CTF_FS_FILE_H #define CTF_FS_FILE_H +#include +#include + #include -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; + + 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); diff --git a/src/plugins/ctf/fs-src/fs.cpp b/src/plugins/ctf/fs-src/fs.cpp index 5306b421..e86d30ce 100644 --- a/src/plugins/ctf/fs-src/fs.cpp +++ b/src/plugins/ctf/fs-src/fs.cpp @@ -7,29 +7,26 @@ * Babeltrace CTF file system Reader Component */ +#include + #include -#include #include -#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(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(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(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( + 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(); - 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(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_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_trace, sc, static_cast(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(parentLogger); + ctf_fs_trace->path = path; + ctf_fs_trace->metadata = bt2s::make_unique(); - 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& 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& dest = dest_trace->ds_file_groups; + std::vector& 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( + 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 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(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, ¤t_tracer_info); + int ret = extract_tracer_info(trace, ¤t_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(¤t_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(¤t_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(¤t_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 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 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(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; } diff --git a/src/plugins/ctf/fs-src/fs.hpp b/src/plugins/ctf/fs-src/fs.hpp index fadef78b..c9ca2a90 100644 --- a/src/plugins/ctf/fs-src/fs.hpp +++ b/src/plugins/ctf/fs-src/fs.hpp @@ -14,184 +14,112 @@ #include -#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; /* 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; - /* - * 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 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; - /* 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; - /* 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 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; - /* 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 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 */ diff --git a/src/plugins/ctf/fs-src/metadata.cpp b/src/plugins/ctf/fs-src/metadata.cpp index ad215f9f..bf905d3a 100644 --- a/src/plugins/ctf/fs-src/metadata.cpp +++ b/src/plugins/ctf/fs-src/metadata.cpp @@ -5,26 +5,15 @@ * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation */ -#include -#include -#include - -#include - -#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(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); - } -} diff --git a/src/plugins/ctf/fs-src/metadata.hpp b/src/plugins/ctf/fs-src/metadata.hpp index 60790ada..14d7cc19 100644 --- a/src/plugins/ctf/fs-src/metadata.hpp +++ b/src/plugins/ctf/fs-src/metadata.hpp @@ -11,24 +11,20 @@ #include -#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); diff --git a/src/plugins/ctf/fs-src/query.cpp b/src/plugins/ctf/fs-src/query.cpp index fa73ab19..4143f9c0 100644 --- a/src/plugins/ctf/fs-src/query.cpp +++ b/src/plugins/ctf/fs-src/query.cpp @@ -12,14 +12,14 @@ #include -#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; } diff --git a/src/plugins/ctf/fs-src/query.hpp b/src/plugins/ctf/fs-src/query.hpp index 053540ff..2c7aca09 100644 --- a/src/plugins/ctf/fs-src/query.hpp +++ b/src/plugins/ctf/fs-src/query.hpp @@ -9,19 +9,18 @@ #ifndef BABELTRACE_PLUGIN_CTF_FS_QUERY_H #define BABELTRACE_PLUGIN_CTF_FS_QUERY_H -#include +#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 */ diff --git a/src/plugins/ctf/lttng-live/data-stream.cpp b/src/plugins/ctf/lttng-live/data-stream.cpp index 4bba7ddb..8f4ae873 100644 --- a/src/plugins/ctf/lttng-live/data-stream.cpp +++ b/src/plugins/ctf/lttng-live/data-stream.cpp @@ -7,23 +7,20 @@ * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation */ +#include + #include -#include #include +#include #include -#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(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--; } diff --git a/src/plugins/ctf/lttng-live/data-stream.hpp b/src/plugins/ctf/lttng-live/data-stream.hpp index d49a9506..675bbdbb 100644 --- a/src/plugins/ctf/lttng-live/data-stream.hpp +++ b/src/plugins/ctf/lttng-live/data-stream.hpp @@ -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 */ diff --git a/src/plugins/ctf/lttng-live/lttng-live.cpp b/src/plugins/ctf/lttng-live/lttng-live.cpp index 35cbff95..63681810 100644 --- a/src/plugins/ctf/lttng-live/lttng-live.cpp +++ b/src/plugins/ctf/lttng-live/lttng-live.cpp @@ -9,17 +9,14 @@ */ #include -#include #include -#include - -#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" @@ -36,314 +33,147 @@ #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(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_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(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(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, - <tng_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( + 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(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, <tng_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; + } } diff --git a/src/plugins/ctf/lttng-live/lttng-live.hpp b/src/plugins/ctf/lttng-live/lttng-live.hpp index 9ca87401..9dbc432a 100644 --- a/src/plugins/ctf/lttng-live/lttng-live.hpp +++ b/src/plugins/ctf/lttng-live/lttng-live.hpp @@ -16,9 +16,38 @@ #include -#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; + + 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 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; + + 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; + + 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 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; + + 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 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; + + 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; + + 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 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& buf); enum lttng_live_iterator_status lttng_live_get_next_index(struct lttng_live_msg_iter *lttng_live_msg_iter, diff --git a/src/plugins/ctf/lttng-live/lttng-viewer-abi.hpp b/src/plugins/ctf/lttng-live/lttng-viewer-abi.hpp index bf9abae4..926ace11 100644 --- a/src/plugins/ctf/lttng-live/lttng-viewer-abi.hpp +++ b/src/plugins/ctf/lttng-live/lttng-viewer-abi.hpp @@ -11,7 +11,9 @@ #include -#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. */ diff --git a/src/plugins/ctf/lttng-live/metadata.cpp b/src/plugins/ctf/lttng-live/metadata.cpp index b081d639..693042d7 100644 --- a/src/plugins/ctf/lttng-live/metadata.cpp +++ b/src/plugins/ctf/lttng-live/metadata.cpp @@ -6,22 +6,13 @@ * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation */ -#include -#include -#include -#include - -#include - -#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 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(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; } diff --git a/src/plugins/ctf/lttng-live/metadata.hpp b/src/plugins/ctf/lttng-live/metadata.hpp index 49596c3b..7c2d7659 100644 --- a/src/plugins/ctf/lttng-live/metadata.hpp +++ b/src/plugins/ctf/lttng-live/metadata.hpp @@ -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 */ diff --git a/src/plugins/ctf/lttng-live/viewer-connection.cpp b/src/plugins/ctf/lttng-live/viewer-connection.cpp index 5ea98cdd..46cfd2c4 100644 --- a/src/plugins/ctf/lttng-live/viewer-connection.cpp +++ b/src/plugins/ctf/lttng-live/viewer-connection.cpp @@ -11,13 +11,9 @@ #include -#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" @@ -25,119 +21,32 @@ #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(<tng_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 ? "" : viewer_connection->target_hostname->str, !viewer_connection->session_name ? "" : 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(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 = , */ - 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 = , */ - 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 = , */ - 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& 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 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(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(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(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(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(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(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(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(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(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; } diff --git a/src/plugins/ctf/lttng-live/viewer-connection.hpp b/src/plugins/ctf/lttng-live/viewer-connection.hpp index 67e71e0c..0f284581 100644 --- a/src/plugins/ctf/lttng-live/viewer-connection.hpp +++ b/src/plugins/ctf/lttng-live/viewer-connection.hpp @@ -7,12 +7,17 @@ #ifndef LTTNG_LIVE_VIEWER_CONNECTION_H #define LTTNG_LIVE_VIEWER_CONNECTION_H +#include + #include #include #include -#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; + + 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 */ diff --git a/src/plugins/text/details/write.c b/src/plugins/text/details/write.c index 1962f5df..5c9f9e75 100644 --- a/src/plugins/text/details/write.c +++ b/src/plugins/text/details/write.c @@ -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(); } diff --git a/src/plugins/text/pretty/print.c b/src/plugins/text/pretty/print.c index a08235e8..4c7e1833 100644 --- a/src/plugins/text/pretty/print.c +++ b/src/plugins/text/pretty/print.c @@ -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 diff --git a/src/plugins/utils/muxer/comp.cpp b/src/plugins/utils/muxer/comp.cpp index ea2df4d0..fb2a1119 100644 --- a/src/plugins/utils/muxer/comp.cpp +++ b/src/plugins/utils/muxer/comp.cpp @@ -13,7 +13,7 @@ namespace bt2mux { Comp::Comp(const bt2::SelfFilterComponent selfComp, const bt2::ConstMapValue params, void *) : bt2::UserFilterComponent {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()); diff --git a/src/plugins/utils/muxer/msg-iter.cpp b/src/plugins/utils/muxer/msg-iter.cpp index b1d86945..2754bb11 100644 --- a/src/plugins/utils/muxer/msg-iter.cpp +++ b/src/plugins/utils/muxer/msg-iter.cpp @@ -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; } diff --git a/src/plugins/utils/muxer/upstream-msg-iter.cpp b/src/plugins/utils/muxer/upstream-msg-iter.cpp index 28f5be47..ea597da2 100644 --- a/src/plugins/utils/muxer/upstream-msg-iter.cpp +++ b/src/plugins/utils/muxer/upstream-msg-iter.cpp @@ -33,45 +33,45 @@ namespace { bt2::OptionalBorrowedObject 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; } } diff --git a/src/plugins/utils/muxer/upstream-msg-iter.hpp b/src/plugins/utils/muxer/upstream-msg-iter.hpp index 2ae663f8..4d89da39 100644 --- a/src/plugins/utils/muxer/upstream-msg-iter.hpp +++ b/src/plugins/utils/muxer/upstream-msg-iter.hpp @@ -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 index 7446a35d..00000000 --- a/tests/bindings/python/bt2/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -htmlcov -.coverage diff --git a/tests/data/plugins/src.ctf.lttng-live/cli-multi-domains.expect b/tests/data/plugins/src.ctf.lttng-live/cli-multi-domains.expect index 9c7db7cf..5c534621 100644 --- a/tests/data/plugins/src.ctf.lttng-live/cli-multi-domains.expect +++ b/tests/data/plugins/src.ctf.lttng-live/cli-multi-domains.expect @@ -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 diff --git a/tests/lib/conds/clk-cls-compat-postconds-triggers.cpp b/tests/lib/conds/clk-cls-compat-postconds-triggers.cpp index a8a4d626..aa7e6876 100644 --- a/tests/lib/conds/clk-cls-compat-postconds-triggers.cpp +++ b/tests/lib/conds/clk-cls-compat-postconds-triggers.cpp @@ -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 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>( ClockClsCompatRunIn {msgType1, createClockCls1, msgType2, createClockCls2}, - CondTrigger::Type::POST, condId, fmt::format("{}-{}", msgType1, msgType2))); + CondTrigger::Type::Post, condId, fmt::format("{}-{}", msgType1, msgType2))); } } }; diff --git a/tests/lib/conds/conds-triggers.cpp b/tests/lib/conds/conds-triggers.cpp index 3e1cfe86..02fe33ce 100644 --- a/tests/lib/conds/conds-triggers.cpp +++ b/tests/lib/conds/conds-triggers.cpp @@ -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); diff --git a/tests/lib/conds/utils.cpp b/tests/lib/conds/utils.cpp index b7d2c487..4d4e3b1d 100644 --- a/tests/lib/conds/utils.cpp +++ b/tests/lib/conds/utils.cpp @@ -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 : "")} { } diff --git a/tests/lib/conds/utils.hpp b/tests/lib/conds/utils.hpp index d8abfafe..2ea53bc4 100644 --- a/tests/lib/conds/utils.hpp +++ b/tests/lib/conds/utils.hpp @@ -37,8 +37,8 @@ public: */ enum class Type { - PRE, - POST, + Pre, + Post, }; protected: diff --git a/tests/plugins/flt.lttng-utils.debug-info/test-dwarf.c b/tests/plugins/flt.lttng-utils.debug-info/test-dwarf.c index b74eabf4..e50d1c44 100644 --- a/tests/plugins/flt.lttng-utils.debug-info/test-dwarf.c +++ b/tests/plugins/flt.lttng-utils.debug-info/test-dwarf.c @@ -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; diff --git a/tests/plugins/flt.utils.muxer/test-clock-compatibility.cpp b/tests/plugins/flt.utils.muxer/test-clock-compatibility.cpp index c922d8cc..ef05d1d5 100644 --- a/tests/plugins/flt.utils.muxer/test-clock-compatibility.cpp +++ b/tests/plugins/flt.utils.muxer/test-clock-compatibility.cpp @@ -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 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 {10} : bt2s::nullopt}); const auto srcComp2 = diff --git a/tests/plugins/src.ctf.fs/field/test-field.sh b/tests/plugins/src.ctf.fs/field/test-field.sh index df035d36..7c73aa2b 100755 --- a/tests/plugins/src.ctf.fs/field/test-field.sh +++ b/tests/plugins/src.ctf.fs/field/test-field.sh @@ -21,13 +21,27 @@ data_dir=$BT_TESTS_DATADIR/plugins/src.ctf.fs/field test_pass() { local -r mp_path=$1 local -r output_dir=$(mktemp -d) + local -r py_cmd=( + "$BT_TESTS_PYTHON_BIN" "$data_dir/data_from_mp.py" + "$mp_path" "$output_dir" + ) - run_python "$BT_TESTS_PYTHON_BIN" "$data_dir/data_from_mp.py" "$mp_path" "$output_dir" + if ! bt_run_in_py_env "${py_cmd[@]}"; then + fail "Failed to run \`${py_cmd[*]}\`" + return 1 + fi local -r res_path=$(mktemp) - - bt_cli "$res_path" /dev/null --plugin-path="$data_dir" \ + local -r cli_cmd=( + "$res_path" /dev/null --plugin-path="$data_dir" -c sink.test-text.single "$output_dir/trace" + ) + + if ! bt_cli "${cli_cmd[@]}"; then + fail "Failed to run \`bt_cli ${cli_cmd[*]}\`" + return 1 + fi + bt_diff "$res_path" "$output_dir/expect" ok $? "$mp_path" rm -rf "$output_dir" "$res_path" diff --git a/tests/python-plugin-provider/.gitignore b/tests/python-plugin-provider/.gitignore deleted file mode 100644 index 7446a35d..00000000 --- a/tests/python-plugin-provider/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -htmlcov -.coverage diff --git a/tests/utils/utils.sh b/tests/utils/utils.sh index 9081a88e..f3d4d945 100644 --- a/tests/utils/utils.sh +++ b/tests/utils/utils.sh @@ -239,6 +239,16 @@ bt_diff() { local -r expected_file=$1 local -r actual_file=$2 + if [[ ! -e $expected_file ]]; then + echo "ERROR: expected file \`$expected_file\` doesn't exist" >&2 + return 1 + fi + + if [[ ! -e $actual_file ]]; then + echo "ERROR: actual file \`$actual_file\` doesn't exist" >&2 + return 1 + fi + diff -u <(bt_remove_cr_inline "$expected_file") <(bt_remove_cr_inline "$actual_file") 1>&2 } @@ -430,7 +440,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