From 1a100a55814db7cbcd5e2e73faabd01245c43e3f Mon Sep 17 00:00:00 2001 From: Simon Marchi Date: Mon, 21 Feb 2022 19:54:51 -0500 Subject: [PATCH] lib: add BLOB field class types MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Add support for BLOB field classes and fields, with the intent of supporting CTF2‑SPEC‑2.0's BLOB field class types [1]. A BLOB is a sequence of binary data included as-is in the trace. A BLOB field class has a media type property, which describes the kind of content its instances hold. There are three variations of a BLOB field class, analogous to the array field classes: - static length BLOB - dynamic length BLOB without a length field - dynamic length BLOB with a length field Static length BLOBs have a fixed length, set in the field class. Dynamic length BLOBs have a variable length, set in each field instance of the field class. Dynamic length BLOBs with a length field have a length field location, set in the field class, pointing to a preceding field that holds the length of the BLOB. Philippe updated the documentation. [1] https://diamon.org/ctf/CTF2-SPEC-2.0.html#blob-fc Change-Id: Ib9d7bd12d598fbc6b7ed5d80d8cdfcf294e4254d Signed-off-by: Simon Marchi Reviewed-on: https://review.lttng.org/c/babeltrace/+/7350 Tested-by: jenkins Reviewed-by: Philippe Proulx Reviewed-on: https://review.lttng.org/c/babeltrace/+/12687 --- doc/api/libbabeltrace2/Doxyfile.in | 32 ++ include/babeltrace2/trace-ir/field-class.h | 437 +++++++++++++++++- include/babeltrace2/trace-ir/field-location.h | 3 + include/babeltrace2/trace-ir/field.h | 163 ++++++- src/common/common.h | 10 + src/lib/assert-cond.h | 27 ++ src/lib/lib-logging.c | 34 ++ src/lib/trace-ir/field-class.c | 246 ++++++++++ src/lib/trace-ir/field-class.h | 16 + src/lib/trace-ir/field.c | 149 ++++++ src/lib/trace-ir/field.h | 7 + 11 files changed, 1117 insertions(+), 7 deletions(-) diff --git a/doc/api/libbabeltrace2/Doxyfile.in b/doc/api/libbabeltrace2/Doxyfile.in index 12e11382..64a4e89b 100644 --- a/doc/api/libbabeltrace2/Doxyfile.in +++ b/doc/api/libbabeltrace2/Doxyfile.in @@ -63,6 +63,10 @@ ALIASES += bt_pre_is_enum_fc{1}="@pre \bt_p{\1} is an \link api-t ALIASES += bt_pre_is_uenum_fc{1}="@pre \bt_p{\1} is an unsigned \link api-tir-fc-enum enumeration field class\endlink." ALIASES += bt_pre_is_senum_fc{1}="@pre \bt_p{\1} is a signed \link api-tir-fc-enum enumeration field class\endlink." ALIASES += bt_pre_is_string_fc{1}="@pre \bt_p{\1} is a \link api-tir-fc-string string field class\endlink." +ALIASES += bt_pre_is_blob_fc{1}="@pre \bt_p{\1} is a BLOB \link api-tir-fc-blob field class\endlink." +ALIASES += bt_pre_is_sblob_fc{1}="@pre \bt_p{\1} is a static \link api-tir-fc-blob BLOB field class\endlink." +ALIASES += bt_pre_is_dblob_fc{1}="@pre \bt_p{\1} is a dynamic \link api-tir-fc-blob BLOB field class\endlink." +ALIASES += bt_pre_is_dblob_wl_fc{1}="@pre \bt_p{\1} is a dynamic \link api-tir-fc-blob BLOB field class\endlink (instances with a linked length field)." ALIASES += bt_pre_is_struct_fc{1}="@pre \bt_p{\1} is a \link api-tir-fc-struct structure field class\endlink." ALIASES += bt_pre_is_array_fc{1}="@pre \bt_p{\1} is an array \link api-tir-fc-array field class\endlink." ALIASES += bt_pre_is_sarray_fc{1}="@pre \bt_p{\1} is a static \link api-tir-fc-array array field class\endlink." @@ -90,6 +94,9 @@ ALIASES += bt_pre_is_enum_field{1}="@pre \bt_p{\1} is an \link ap ALIASES += bt_pre_is_uenum_field{1}="@pre \bt_p{\1} is an unsigned \link api-tir-field-enum enumeration field\endlink." ALIASES += bt_pre_is_senum_field{1}="@pre \bt_p{\1} is a signed \link api-tir-field-enum enumeration field\endlink." ALIASES += bt_pre_is_string_field{1}="@pre \bt_p{\1} is a \link api-tir-field-string string field\endlink." +ALIASES += bt_pre_is_blob_field{1}="@pre \bt_p{\1} is a \link api-tir-field-blob BLOB field\endlink." +ALIASES += bt_pre_is_sblob_field{1}="@pre \bt_p{\1} is a static \link api-tir-field-blob BLOB field\endlink." +ALIASES += bt_pre_is_dblob_field{1}="@pre \bt_p{\1} is a dynamic \link api-tir-field-blob BLOB field\endlink." ALIASES += bt_pre_is_struct_field{1}="@pre \bt_p{\1} is a \link api-tir-field-struct structure field\endlink." ALIASES += bt_pre_is_array_field{1}="@pre \bt_p{\1} is an \link api-tir-field-array array field\endlink." ALIASES += bt_pre_is_sarray_field{1}="@pre \bt_p{\1} is a static \link api-tir-field-array array field\endlink." @@ -122,6 +129,7 @@ ALIASES += bt_pre_is_se_msg{1}="@pre \bt_p{\1} is a \link api-msg # Aliases: preconditions: MIP version ALIASES += bt_pre_tc_with_mip{2}="@pre \bt_p{\1} was created from a \bt_comp which belongs to a trace processing \bt_graph with the effective \bt_mip version \2." ALIASES += bt_pre_fc_with_mip{2}="@pre \bt_p{\1} was created from a \bt_trace_cls which was created from a \bt_comp which belongs to a trace processing \bt_graph with the effective \bt_mip version \2." +ALIASES += bt_pre_field_with_mip{2}="@pre The class of \bt_p{\1} was created from a \bt_trace_cls which was created from a \bt_comp which belongs to a trace processing \bt_graph with the effective \bt_mip version \2." ALIASES += bt_pre_trace_with_mip{2}="@pre The \link api-tir-trace-cls class\endlink of \bt_p{\1} was created from a \bt_comp which belongs to a trace processing \bt_graph with the effective \bt_mip version \2." ALIASES += bt_pre_clock_cls_with_mip{2}="@pre \bt_p{\1} was created from a \bt_comp which belongs to a trace processing \bt_graph with the effective \bt_mip version \2." @@ -137,6 +145,9 @@ ALIASES += bt_enum_fc="\link api-tir-fc-enum enumeration field cl ALIASES += bt_senum_fc="signed \link api-tir-fc-enum enumeration field class\endlink" ALIASES += bt_uenum_fc="unsigned \link api-tir-fc-enum enumeration field class\endlink" ALIASES += bt_string_fc="\link api-tir-fc-string string field class\endlink" +ALIASES += bt_blob_fc="\link api-tir-fc-blob BLOB field class\endlink" +ALIASES += bt_sblob_fc="static \link api-tir-fc-blob BLOB field class\endlink" +ALIASES += bt_dblob_fc="dynamic \link api-tir-fc-blob BLOB field class\endlink" ALIASES += bt_struct_fc="\link api-tir-fc-struct structure field class\endlink" ALIASES += bt_array_fc="\link api-tir-fc-array array field class\endlink" ALIASES += bt_sarray_fc="static \link api-tir-fc-array array field class\endlink" @@ -156,6 +167,9 @@ ALIASES += bt_c_enum_fc="\link api-tir-fc-enum Enumeration field ALIASES += bt_c_senum_fc="Signed \link api-tir-fc-enum enumeration field class\endlink" ALIASES += bt_c_uenum_fc="Unsigned \link api-tir-fc-enum enumeration field class\endlink" ALIASES += bt_c_string_fc="\link api-tir-fc-string String field class\endlink" +ALIASES += bt_c_blob_fc="\link api-tir-fc-blob BLOB field class\endlink" +ALIASES += bt_c_sblob_fc="Static \link api-tir-fc-blob BLOB field class\endlink" +ALIASES += bt_c_dblob_fc="Dynamic \link api-tir-fc-blob BLOB field class\endlink" ALIASES += bt_c_struct_fc="\link api-tir-fc-struct Structure field class\endlink" ALIASES += bt_c_array_fc="\link api-tir-fc-array Array field class\endlink" ALIASES += bt_c_sarray_fc="Static \link api-tir-fc-array array field class\endlink" @@ -175,6 +189,9 @@ ALIASES += bt_p_enum_fc="\link api-tir-fc-enum enumeration field ALIASES += bt_p_senum_fc="signed \link api-tir-fc-enum enumeration field classes\endlink" ALIASES += bt_p_uenum_fc="unsigned \link api-tir-fc-enum enumeration field classes\endlink" ALIASES += bt_p_string_fc="\link api-tir-fc-string string field classes\endlink" +ALIASES += bt_p_blob_fc="\link api-tir-fc-blob BLOB field classes\endlink" +ALIASES += bt_p_sblob_fc="static \link api-tir-fc-blob BLOB field classes\endlink" +ALIASES += bt_p_dblob_fc="dynamic \link api-tir-fc-blob BLOB field classes\endlink" ALIASES += bt_p_struct_fc="\link api-tir-fc-struct structure field classes\endlink" ALIASES += bt_p_array_fc="\link api-tir-fc-array array field classes\endlink" ALIASES += bt_p_sarray_fc="static \link api-tir-fc-array array field classes\endlink" @@ -194,6 +211,9 @@ ALIASES += bt_cp_enum_fc="\link api-tir-fc-enum Enumeration field ALIASES += bt_cp_senum_fc="Signed \link api-tir-fc-enum enumeration field classes\endlink" ALIASES += bt_cp_uenum_fc="Unsigned \link api-tir-fc-enum enumeration field classes\endlink" ALIASES += bt_cp_string_fc="\link api-tir-fc-string String field classes\endlink" +ALIASES += bt_cp_blob_fc="\link api-tir-fc-blob BLOB field classes\endlink" +ALIASES += bt_cp_sblob_fc="Static \link api-tir-fc-blob BLOB field classes\endlink" +ALIASES += bt_cp_dblob_fc="Dynamic \link api-tir-fc-blob BLOB field classes\endlink" ALIASES += bt_cp_struct_fc="\link api-tir-fc-struct Structure field classes\endlink" ALIASES += bt_cp_array_fc="\link api-tir-fc-array Array field classes\endlink" ALIASES += bt_cp_sarray_fc="Static \link api-tir-fc-array array field classes\endlink" @@ -215,6 +235,9 @@ ALIASES += bt_enum_field="\link api-tir-field-enum enumeration fi ALIASES += bt_senum_field="signed \link api-tir-field-enum enumeration field\endlink" ALIASES += bt_uenum_field="unsigned \link api-tir-field-enum enumeration field\endlink" ALIASES += bt_string_field="\link api-tir-field-string string field\endlink" +ALIASES += bt_blob_field="\link api-tir-field-blob BLOB field\endlink" +ALIASES += bt_sblob_field="static \link api-tir-field-blob BLOB field\endlink" +ALIASES += bt_dblob_field="dynamic \link api-tir-field-blob BLOB field\endlink" ALIASES += bt_struct_field="\link api-tir-field-struct structure field\endlink" ALIASES += bt_array_field="\link api-tir-field-array array field\endlink" ALIASES += bt_sarray_field="static \link api-tir-field-array array field\endlink" @@ -236,6 +259,9 @@ ALIASES += bt_c_enum_field="\link api-tir-field-enum Enumeration ALIASES += bt_c_senum_field="Signed \link api-tir-field-enum enumeration field\endlink" ALIASES += bt_c_uenum_field="Unsigned \link api-tir-field-enum enumeration field\endlink" ALIASES += bt_c_string_field="\link api-tir-field-string String field\endlink" +ALIASES += bt_c_blob_field="\link api-tir-field-blob BLOB field\endlink" +ALIASES += bt_c_sblob_field="Static \link api-tir-field-blob BLOB field\endlink" +ALIASES += bt_c_dblob_field="Dynamic \link api-tir-field-blob BLOB field\endlink" ALIASES += bt_c_struct_field="\link api-tir-field-struct Structure field\endlink" ALIASES += bt_c_array_field="\link api-tir-field-array Array field\endlink" ALIASES += bt_c_sarray_field="Static \link api-tir-field-array array field\endlink" @@ -257,6 +283,9 @@ ALIASES += bt_p_enum_field="\link api-tir-field-enum enumeration ALIASES += bt_p_senum_field="signed \link api-tir-field-enum enumeration fields\endlink" ALIASES += bt_p_uenum_field="unsigned \link api-tir-field-enum enumeration fields\endlink" ALIASES += bt_p_string_field="\link api-tir-field-string string fields\endlink" +ALIASES += bt_p_blob_field="\link api-tir-field-blob BLOB fields\endlink" +ALIASES += bt_p_sblob_field="static \link api-tir-field-blob BLOB fields\endlink" +ALIASES += bt_p_dblob_field="dynamic \link api-tir-field-blob BLOB fields\endlink" ALIASES += bt_p_struct_field="\link api-tir-field-struct structure fields\endlink" ALIASES += bt_p_array_field="\link api-tir-field-array array fields\endlink" ALIASES += bt_p_sarray_field="static \link api-tir-field-array array fields\endlink" @@ -278,6 +307,9 @@ ALIASES += bt_cp_enum_field="\link api-tir-field-enum Enumeration ALIASES += bt_cp_senum_field="Signed \link api-tir-field-enum enumeration fields\endlink" ALIASES += bt_cp_uenum_field="Unsigned \link api-tir-field-enum enumeration fields\endlink" ALIASES += bt_cp_string_field="\link api-tir-field-string String fields\endlink" +ALIASES += bt_cp_blob_field="\link api-tir-field-blob BLOB fields\endlink" +ALIASES += bt_cp_sblob_field="Static \link api-tir-field-blob BLOB fields\endlink" +ALIASES += bt_cp_dblob_field="Dynamic \link api-tir-field-blob BLOB fields\endlink" ALIASES += bt_cp_struct_field="\link api-tir-field-struct Structure fields\endlink" ALIASES += bt_cp_array_field="\link api-tir-field-array Array fields\endlink" ALIASES += bt_cp_sarray_field="Static \link api-tir-field-array array fields\endlink" diff --git a/include/babeltrace2/trace-ir/field-class.h b/include/babeltrace2/trace-ir/field-class.h index 5d49edc5..13533c8b 100644 --- a/include/babeltrace2/trace-ir/field-class.h +++ b/include/babeltrace2/trace-ir/field-class.h @@ -51,6 +51,7 @@ categories: - \ref api-tir-fc-enum "Enumeration" (unsigned and signed) - \ref api-tir-fc-real "Real" (single-precision and double-precision) - \ref api-tir-fc-string "String" + - \ref api-tir-fc-blob "BLOB" (static and dynamic)
Container
@@ -147,6 +148,22 @@ functions for each type of \em concrete (non-abstract) field class: \ref api-tir-fc-string "String" #BT_FIELD_CLASS_TYPE_STRING bt_field_class_string_create() + + Static \ref api-tir-fc-blob "BLOB" + #BT_FIELD_CLASS_TYPE_STATIC_BLOB + bt_field_class_blob_static_create() + + + Dynamic \ref api-tir-fc-blob "BLOB" + (instances without a linked length field) + #BT_FIELD_CLASS_TYPE_DYNAMIC_BLOB_WITHOUT_LENGTH_FIELD + bt_field_class_blob_dynamic_without_length_field_location_create() + + + Dynamic \ref api-tir-fc-blob "BLOB" + (instances with a linked length field) + #BT_FIELD_CLASS_TYPE_DYNAMIC_BLOB_WITH_LENGTH_FIELD + bt_field_class_blob_dynamic_with_length_field_location_create() Static \ref api-tir-fc-array "array" #BT_FIELD_CLASS_TYPE_STATIC_ARRAY @@ -550,6 +567,102 @@ Create a string field class with bt_field_class_string_create(). A string field class has no specific properties. +

\anchor api-tir-fc-blob BLOB field classes

+ +@image html fc-blob.png + +BLOB field classes are +classes of \bt_p_blob_field. + +BLOB fields contain zero or more bytes of binary data. + +@note + BLOB field classes are only available when the \bt_trace_cls from + which you create them was created from a \bt_comp which belongs + to a trace processing \bt_graph with the effective \bt_mip + version 1. + +A BLOB field class is an \em abstract field class: you cannot create +one. The concrete BLOB field classes are: + +
+
Static BLOB field class
+
+ Its instances (static BLOB fields) contain a fixed number of bytes. + + Create with bt_field_class_blob_static_create(). + + A static BLOB field class has the following specific property: + +
+
+ \anchor api-tir-fc-sblob-prop-len + Length +
+
+ Number of bytes contained in the instances (static BLOB + fields) of the static BLOB field class. + + You cannot change the length once the static BLOB field class is + created. + + Get a static BLOB field class's length with + bt_field_class_blob_static_get_length(). +
+
+
+ +
Dynamic BLOB field class
+
+ Its instances (dynamic BLOB fields) contain a variable number + of bytes. + + There are two types of dynamic BLOB field classes: instances + without or with a linked length field. See + \ref api-tir-fc-link "Fields with links to other fields" + to learn more. + + @image html dblob-link.png "A dynamic blob field linked to an unsigned integer length field." + + Create with + bt_field_class_blob_dynamic_without_length_field_location_create() + or bt_field_class_blob_dynamic_with_length_field_location_create(). + + The class of a dynamic BLOB field with a linked length field has + the following specific property: + +
+
+ \anchor api-tir-fc-dblob-prop-len-fl + Length field location +
+
+ \bt_c_field_loc to locate the linked length field of an + instance. + + Get a dynamic BLOB field class's length field location with + bt_field_class_blob_dynamic_with_length_field_borrow_length_field_location_const(). +
+
+
+
+ +BLOB field classes have the following common property: + +
+
+ \anchor api-tir-fc-blob-prop-media-type + Media type +
+
+ IANA media type + of instances of the BLOB field class. + + Use bt_field_class_blob_set_media_type() and + bt_field_class_blob_get_media_type(). +
+
+

\anchor api-tir-fc-array Array field classes

@image html fc-array.png @@ -1167,18 +1280,24 @@ Variant field classes have the following common property:

\anchor api-tir-fc-link Fields with links to other fields

-An instance of a \bt_darray_fc, a \bt_opt_fc, or a \bt_var_fc \em may -have a link to another, anterior field within the same \bt_pkt or -\bt_ev. +An instance of a \bt_dblob_fc, a \bt_darray_fc, a \bt_opt_fc, or a +\bt_var_fc \em may have a link to another, anterior field within the +same \bt_pkt or \bt_ev. This feature exists so that the linked field can contain the value of a dynamic property of the "dependent" field. Those properties are:
+
\bt_c_dblob_field
+
+ The linked field, a \bt_uint_field, contains the \b length (number + of bytes) of the dynamic BLOB field. +
+
\bt_c_darray_field
- The linked field, a \bt_uint_field, contains the \b length of the - dynamic array field. + The linked field, a \bt_uint_field, contains the \b length (number + of elements) of the dynamic array field.
\bt_c_opt_field
@@ -1249,6 +1368,7 @@ processing \bt_graph: The functions to borrow the field location of a field class are: + - bt_field_class_blob_dynamic_with_length_field_borrow_length_field_location_const() - bt_field_class_array_dynamic_with_length_field_borrow_length_field_location_const() - bt_field_class_option_with_selector_field_borrow_selector_field_location_const() - bt_field_class_variant_with_selector_field_borrow_selector_field_location_const() @@ -1487,6 +1607,52 @@ typedef enum bt_field_class_type { */ BT_FIELD_CLASS_TYPE_STRING = 1ULL << 9, + /*! + @brief + \bt_c_blob_fc. + + No field class has this type: use it with + bt_field_class_type_is(). + */ + BT_FIELD_CLASS_TYPE_BLOB = (1ULL << 29), + + /*! + @brief + \bt_c_sblob_fc. + + This type conceptually inherits #BT_FIELD_CLASS_TYPE_BLOB. + */ + BT_FIELD_CLASS_TYPE_STATIC_BLOB = (1ULL << 30) | BT_FIELD_CLASS_TYPE_BLOB, + + /*! + @brief + \bt_c_dblob_fc. + + This type conceptually inherits #BT_FIELD_CLASS_TYPE_BLOB. + + No field class has this type: use it with + bt_field_class_type_is(). + */ + BT_FIELD_CLASS_TYPE_DYNAMIC_BLOB = (1ULL << 31) | BT_FIELD_CLASS_TYPE_BLOB, + + /*! + @brief + \bt_c_dblob_fc (instances without a linked length field). + + This type conceptually inherits + #BT_FIELD_CLASS_TYPE_DYNAMIC_BLOB. + */ + BT_FIELD_CLASS_TYPE_DYNAMIC_BLOB_WITHOUT_LENGTH_FIELD = (1ULL << 32) | BT_FIELD_CLASS_TYPE_DYNAMIC_BLOB, + + /*! + @brief + \bt_c_dblob_fc (instances with a linked length field). + + This type conceptually inherits + #BT_FIELD_CLASS_TYPE_DYNAMIC_BLOB. + */ + BT_FIELD_CLASS_TYPE_DYNAMIC_BLOB_WITH_LENGTH_FIELD = (1ULL << 33) | BT_FIELD_CLASS_TYPE_DYNAMIC_BLOB, + /*! @brief \bt_c_struct_fc. @@ -2893,6 +3059,267 @@ extern bt_field_class *bt_field_class_string_create( /*! @} */ +/*! +@name BLOB field class +@{ +*/ + +/*! +@brief + Creates a \bt_sblob_fc having the length \bt_p{length} from the + trace class \bt_p{trace_class}. + +On success, the returned static BLOB field class has the following +property values: + + + + + + +
Property + Value +
\ref api-tir-fc-sarray-prop-len "Length" + \bt_p{length} +
\ref api-tir-fc-blob-prop-media-type "Media type" + application/octet-stream +
\ref api-tir-fc-prop-user-attrs "User attributes" + Empty \bt_map_val +
+ +@param[in] trace_class + Trace class from which to create a static BLOB field class. +@param[in] length + Length (number of bytes) of the instances of the static BLOB + field class to create. + +@returns + New static BLOB field class reference, or \c NULL on memory error. + +@bt_pre_not_null{trace_class} +@bt_pre_tc_with_mip{trace_class, 1} + +@sa bt_field_class_blob_dynamic_without_length_field_location_create() — + Creates a class of dynamic BLOB field without a linked length field. +@sa bt_field_class_blob_dynamic_with_length_field_location_create() — + Creates a class of dynamic BLOB field with a linked length field. +*/ +extern bt_field_class *bt_field_class_blob_static_create( + bt_trace_class *trace_class, uint64_t length) __BT_NOEXCEPT; + +/*! +@brief + Creates a \bt_dblob_fc (instances without a linked length field) + from the trace class \bt_p{trace_class}. + +On success, the returned dynamic BLOB field class has the following +property values: + + + + + + +
Property + Value +
\ref api-tir-fc-dblob-prop-len-fl "Length field location" + + \em None +
\ref api-tir-fc-blob-prop-media-type "Media type" + application/octet-stream +
\ref api-tir-fc-prop-user-attrs "User attributes" + Empty \bt_map_val +
+ +@param[in] trace_class + Trace class from which to create a dynamic BLOB field class. + +@returns + New dynamic BLOB field class reference (without a length field), + or \c NULL on memory error. + +@bt_pre_not_null{trace_class} +@bt_pre_tc_with_mip{trace_class, 1} + +@sa bt_field_class_blob_dynamic_with_length_field_location_create() — + Creates a class of dynamic BLOB field with a linked length field. +*/ +extern bt_field_class * +bt_field_class_blob_dynamic_without_length_field_location_create( + bt_trace_class *trace_class) __BT_NOEXCEPT; + +/*! +@brief + Creates a \bt_dblob_fc (instances with a linked length field) + having the length \bt_field_loc \bt_p{length_field_location} from + the trace class \bt_p{trace_class}. + +On success, the returned dynamic BLOB field class has the following +property values: + + + + + + +
Property + Value +
\ref api-tir-fc-dblob-prop-len-fl "Length field location" + + \bt_p{length_field_location}. + + See \ref api-tir-fc-link "Fields with links to other fields" + to learn more. +
\ref api-tir-fc-blob-prop-media-type "Media type" + application/octet-stream +
\ref api-tir-fc-prop-user-attrs "User attributes" + Empty \bt_map_val +
+ +@param[in] trace_class + Trace class from which to create a dynamic BLOB field class. +@param[in] length_field_location + Length field location of the dynamic BLOB field class to create. + +@returns + New dynamic BLOB field class reference (instances with a linked + length field), or \c NULL on memory error. + +@bt_pre_not_null{trace_class} +@bt_pre_tc_with_mip{trace_class, 1} +@bt_pre_not_null{length_field_location} + +@sa bt_field_class_blob_dynamic_without_length_field_location_create() — + Creates a class of dynamic BLOB field without a linked + length field. +*/ +extern bt_field_class * +bt_field_class_blob_dynamic_with_length_field_location_create( + bt_trace_class *trace_class, + const bt_field_location *length_field_location) __BT_NOEXCEPT; + +/*! +@brief + Returns the length of the \bt_sblob_fc \bt_p{field_class}. + +See the \ref api-tir-fc-sblob-prop-len "length" property. + +@param[in] field_class + Static BLOB field class of which to get the length (number of bytes + in instances). + +@returns + Length of \bt_p{field_class}. + +@bt_pre_not_null{field_class} +@bt_pre_is_sblob_fc{field_class} +@bt_pre_fc_with_mip{field_class, 1} +*/ +extern uint64_t bt_field_class_blob_static_get_length( + const bt_field_class *field_class) __BT_NOEXCEPT; + +/*! +@brief + Borrows the length field location from the \bt_dblob_fc (instances + with a linked length field) \bt_p{field_class}. + +See the \ref api-tir-fc-dblob-prop-len-fl "length field location" +property. + +@param[in] field_class + Dynamic BLOB field class from which to borrow the length + field location. + +@returns + Length field location of \bt_p{field_class}. + +@bt_pre_not_null{field_class} +@bt_pre_is_dblob_wl_fc{field_class} +@bt_pre_fc_with_mip{field_class, 1} +*/ +extern const bt_field_location * +bt_field_class_blob_dynamic_with_length_field_borrow_length_field_location_const( + const bt_field_class *field_class) __BT_NOEXCEPT; + +/*! +@brief + Status codes for bt_field_class_blob_set_media_type(). +*/ +typedef enum bt_field_class_blob_set_media_type_status { + /*! + @brief + Success. + */ + BT_FIELD_CLASS_BLOB_SET_MEDIA_TYPE_STATUS_OK = __BT_FUNC_STATUS_OK, + + /*! + @brief + Out of memory. + */ + BT_FIELD_CLASS_BLOB_SET_MEDIA_TYPE_STATUS_MEMORY_ERROR = __BT_FUNC_STATUS_MEMORY_ERROR, +} bt_field_class_blob_set_media_type_status; + +/*! +@brief + Sets the IANA media type of the \bt_blob_fc \bt_p{field_class} + to a copy of \bt_p{media_type}. + +See the \ref api-tir-fc-blob-prop-media-type "media type" property. + +@param[in] field_class + BLOB field class of which to set the media type to a copy of + \bt_p{media_type}. +@param[in] media_type + New media type of \bt_p{field_class} (copied). + +@retval #BT_FIELD_CLASS_BLOB_SET_MEDIA_TYPE_STATUS_OK + Success. +@retval #BT_FIELD_CLASS_BLOB_SET_MEDIA_TYPE_STATUS_MEMORY_ERROR + Out of memory. + +@bt_pre_not_null{field_class} +@bt_pre_hot{field_class} +@bt_pre_is_blob_fc{field_class} +@bt_pre_fc_with_mip{field_class, 1} + +@sa bt_field_class_blob_get_media_type() — + Returns the IANA media type of BLOB field class. +*/ +extern bt_field_class_blob_set_media_type_status +bt_field_class_blob_set_media_type(bt_field_class *field_class, + const char *media_type) __BT_NOEXCEPT; + +/*! +@brief + Returns the IANA media type of the \bt_blob_fc \bt_p{field_class}. + +See the \ref api-tir-fc-blob-prop-media-type "media type" property. + +If \bt_p{field_class} has no media type, this function returns \c NULL. + +@param[in] field_class + BLOB field class of which to get the media type. + +@returns + @parblock + Media type of \bt_p{field_class}, or \c NULL if none. + + The returned pointer remains valid as long as \bt_p{field_class} + is not modified. + @endparblock + +@bt_pre_not_null{field_class} +@bt_pre_is_blob_fc{field_class} +@bt_pre_fc_with_mip{field_class, 1} + +@sa bt_field_class_blob_set_media_type() — + Sets the media type of a BLOB field class. +*/ +extern const char *bt_field_class_blob_get_media_type( + const bt_field_class *field_class) __BT_NOEXCEPT; + +/*! @} */ + /*! @name Array field class @{ diff --git a/include/babeltrace2/trace-ir/field-location.h b/include/babeltrace2/trace-ir/field-location.h index 2e5c54f2..0b43c382 100644 --- a/include/babeltrace2/trace-ir/field-location.h +++ b/include/babeltrace2/trace-ir/field-location.h @@ -43,6 +43,9 @@ given \bt_field from a given root scope. A field location indicates how to reach: +- The length field of a \bt_dblob_field + (instances with a linked length field). + - The length field of a \bt_darray_field (instances with a linked length field). diff --git a/include/babeltrace2/trace-ir/field.h b/include/babeltrace2/trace-ir/field.h index dc393439..8ded1075 100644 --- a/include/babeltrace2/trace-ir/field.h +++ b/include/babeltrace2/trace-ir/field.h @@ -56,6 +56,7 @@ categories: - \ref api-tir-field-enum "Enumeration" (unsigned and signed) - \ref api-tir-field-real "Real" (single-precision and double-precision) - \ref api-tir-field-string "String" + - \ref api-tir-field-blob "BLOB" (static and dynamic)
Container
@@ -311,6 +312,48 @@ bt_field_string_append() and bt_field_string_append_with_length(). Clear a string field with bt_field_string_clear(). +

\anchor api-tir-field-blob BLOB fields

+ +BLOB fields are \bt_blob_fc instances. + +BLOB fields contain zero or more bytes of binary data. + +@note + BLOB fields are only available when the \bt_trace_cls from + which you create their classes was created from a \bt_comp + which belongs to a trace processing \bt_graph with the effective + \bt_mip version 1. + +A BLOB field is an \em abstract field. The concrete BLOB fields are: + +
+
Static BLOB field
+
+ A \bt_sblob_fc instance. + + A static BLOB field contains a fixed number of bytes. Its length + is \ref api-tir-fc-sblob-prop-len "given by its class". +
+ +
Dynamic BLOB field
+
+ A \bt_dblob_fc instance. + + A dynamic BLOB field contains a variable number of bytes, that is, + each instance of the same dynamic BLOB field class can contain a + different number of bytes. + + Set a dynamic BLOB field's length with + bt_field_blob_dynamic_set_length() before you get its data + with bt_field_blob_get_data(). +
+
+ +Get a BLOB field's length with bt_field_blob_get_length(). + +Get the data of a BLOB field with bt_field_blob_get_data() +or bt_field_blob_get_data_const(). +

\anchor api-tir-field-array Array fields

Array fields are \bt_array_fc instances. @@ -328,7 +371,7 @@ An array field is an \em abstract field. The concrete array fields are: is \ref api-tir-fc-sarray-prop-len "given by its class". -
Dynamic array field class
+
Dynamic array field
A \bt_darray_fc instance. @@ -1074,6 +1117,122 @@ extern void bt_field_string_clear(bt_field *field) __BT_NOEXCEPT; /*! @} */ +/*! +@name BLOB field +@{ +*/ + +/*! +@brief + Returns the length (number of bytes) of the \bt_blob_field \bt_p{field}. + +@param[in] field + BLOB field of which to get the length. + +@returns + Length of \bt_p{field}. + +@bt_pre_not_null{field} +@bt_pre_is_blob_field{field} +@bt_pre_field_with_mip{field, 1} +*/ +extern uint64_t bt_field_blob_get_length(const bt_field *field); + +/*! +@brief + Returns the writable data of the \bt_blob_field \bt_p{field}. + +@attention + If \bt_p{field} is a dynamic BLOB field, then it must have a length + (call bt_field_blob_dynamic_set_length()) before you call this + function. + +@param[in] field + BLOB field from which to get the writable data. + +@returns + @parblock + Writable data of \bt_p{field}. + + The returned pointer remains valid until \bt_p{field} is modified. + @endparblock + +@bt_pre_not_null{field} +@bt_pre_is_blob_field{field} +@bt_pre_hot{field} +@bt_pre_field_with_mip{field, 1} + +@sa bt_field_blob_get_data_const() — + Returns the readable data of a BLOB field. +*/ +extern uint8_t *bt_field_blob_get_data(bt_field *field); + +/*! +@brief + Returns the readable data of the \bt_blob_field \bt_p{field}. + +@param[in] field + BLOB field from which to get the readable data. + +@returns + @parblock + Readable data of \bt_p{field}. + + The returned pointer remains valid until \bt_p{field} is modified. + @endparblock + +@bt_pre_not_null{field} +@bt_pre_is_blob_field{field} +@bt_pre_field_with_mip{field, 1} + +@sa bt_field_blob_get_data() — + Returns the writable data of a BLOB field. +*/ +extern const uint8_t *bt_field_blob_get_data_const(const bt_field *field); + +/*! +@brief + Status codes for bt_field_blob_dynamic_set_length(). +*/ +typedef enum bt_field_blob_dynamic_set_length_status { + /*! + @brief + Success. + */ + BT_FIELD_DYNAMIC_BLOB_SET_LENGTH_STATUS_OK = __BT_FUNC_STATUS_OK, + + /*! + @brief + Out of memory. + */ + BT_FIELD_DYNAMIC_BLOB_SET_LENGTH_STATUS_MEMORY_ERROR = __BT_FUNC_STATUS_MEMORY_ERROR, +} bt_field_blob_dynamic_set_length_status; + +/*! +@brief + Sets the length (number of bytes) of the + \bt_dblob_field \bt_p{field}. + +@param[in] field + Dynamic BLOB field of which to set the length (number of bytes). +@param[in] length + New length of \bt_p{field}. + +@retval #BT_FIELD_DYNAMIC_BLOB_SET_LENGTH_STATUS_OK + Success. +@retval #BT_FIELD_DYNAMIC_BLOB_SET_LENGTH_STATUS_MEMORY_ERROR + Out of memory. + +@bt_pre_not_null{field} +@bt_pre_is_dblob_field{field} +@bt_pre_hot{field} +@bt_pre_field_with_mip{field, 1} +*/ +extern bt_field_blob_dynamic_set_length_status bt_field_blob_dynamic_set_length( + bt_field *field, uint64_t length); + +/*! @} */ + /*! @name Array field @{ @@ -1100,7 +1259,7 @@ extern uint64_t bt_field_array_get_length(const bt_field *field) __BT_NOEXCEPT; \bt_p{field}. @attention - If \bt_p{field} is a dynamic array field, it must have a length + If \bt_p{field} is a dynamic array field, then it must have a length (call bt_field_array_dynamic_set_length()) before you call this function. diff --git a/src/common/common.h b/src/common/common.h index 39a4fd77..4c91dfd6 100644 --- a/src/common/common.h +++ b/src/common/common.h @@ -436,6 +436,16 @@ const char *bt_common_field_class_type_string(enum bt_field_class_type class_typ return "VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD"; case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR_FIELD: return "VARIANT_WITH_SIGNED_INTEGER_SELECTOR_FIELD"; + case BT_FIELD_CLASS_TYPE_BLOB: + return "BT_FIELD_CLASS_TYPE_BLOB"; + case BT_FIELD_CLASS_TYPE_STATIC_BLOB: + return "BT_FIELD_CLASS_TYPE_STATIC_BLOB"; + case BT_FIELD_CLASS_TYPE_DYNAMIC_BLOB: + return "BT_FIELD_CLASS_TYPE_DYNAMIC_BLOB"; + case BT_FIELD_CLASS_TYPE_DYNAMIC_BLOB_WITHOUT_LENGTH_FIELD: + return "BT_FIELD_CLASS_TYPE_DYNAMIC_BLOB_WITHOUT_LENGTH_FIELD"; + case BT_FIELD_CLASS_TYPE_DYNAMIC_BLOB_WITH_LENGTH_FIELD: + return "BT_FIELD_CLASS_TYPE_DYNAMIC_BLOB_WITH_LENGTH_FIELD"; case __BT_FIELD_CLASS_TYPE_BIG_VALUE: bt_common_abort (); } diff --git a/src/lib/assert-cond.h b/src/lib/assert-cond.h index 93072f78..368164dd 100644 --- a/src/lib/assert-cond.h +++ b/src/lib/assert-cond.h @@ -358,6 +358,15 @@ #define _BT_ASSERT_PRE_FC_IS_VARIANT_WITH_SEL_ID(_fc_id) \ "is-variant-field-class-with-selector:" _fc_id +#define _BT_ASSERT_PRE_FC_IS_BLOB_ID(_fc_id) \ + "is-blob-field-class:" _fc_id + +#define _BT_ASSERT_PRE_FC_IS_BLOB_COND(_fc) \ + bt_field_class_type_is((_fc)->type, BT_FIELD_CLASS_TYPE_BLOB) + +#define _BT_ASSERT_PRE_FC_IS_BLOB_FMT(_name) \ + _name " is not a BLOB field class: %![fc-]+F" + #define _BT_ASSERT_PRE_FC_HAS_TYPE_COND(_fc, _type) \ (((const struct bt_field_class *) (_fc))->type == (_type)) @@ -436,6 +445,12 @@ _BT_ASSERT_PRE_FC_IS_VARIANT_WITH_SEL_COND(_fc), \ _BT_ASSERT_PRE_FC_IS_VARIANT_WITH_SEL_FMT(_name), (_fc)) +#define BT_ASSERT_PRE_FC_IS_BLOB(_fc_id, _fc, _name) \ + BT_ASSERT_PRE( \ + _BT_ASSERT_PRE_FC_IS_BLOB_ID(_fc_id), \ + _BT_ASSERT_PRE_FC_IS_BLOB_COND(_fc), \ + _BT_ASSERT_PRE_FC_IS_BLOB_FMT(_name), (_fc)) + #define BT_ASSERT_PRE_FC_HAS_TYPE_FROM_FUNC(_func, _fc_id, _fc, _type_id, _type, _name) \ BT_ASSERT_PRE_FROM_FUNC(_func, \ _BT_ASSERT_PRE_FC_HAS_TYPE_ID(_fc_id, _type_id), \ @@ -666,6 +681,18 @@ ((const struct bt_field *) (_field))->class->type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR_FIELD, \ _name " is not a variant field: %![field-]+f", (_field)) +#define BT_ASSERT_PRE_DEV_FIELD_IS_BLOB(_field_id, _field, _name) \ + BT_ASSERT_PRE_DEV( \ + "is-blob-field:" _field_id, \ + bt_field_class_type_is(_field->class->type, BT_FIELD_CLASS_TYPE_BLOB), \ + _name "is not a BLOB field: %![field-]+f", (_field)) + +#define BT_ASSERT_PRE_DEV_FIELD_IS_DYNAMIC_BLOB(_field_id, _field, _name) \ + BT_ASSERT_PRE_DEV( \ + "is-dynamic-blob-field:" _field_id, \ + bt_field_class_type_is(_field->class->type, BT_FIELD_CLASS_TYPE_DYNAMIC_BLOB), \ + _name "is not a dynamic BLOB field: %![field-]+f", (_field)) + #define BT_ASSERT_PRE_DEV_FIELD_IS_SET(_field_id, _field) \ BT_ASSERT_PRE_DEV("is-field-set:" _field_id, \ bt_field_is_set(_field), \ diff --git a/src/lib/lib-logging.c b/src/lib/lib-logging.c index 2a8f5009..91286458 100644 --- a/src/lib/lib-logging.c +++ b/src/lib/lib-logging.c @@ -155,6 +155,13 @@ static inline void format_array_field_class(char **buf_ch, const char *prefix, PRFIELD(bt_common_field_class_type_string(array_fc->element_fc->type))); } +static inline void format_blob_field_class(char **buf_ch, const char *prefix, + const struct bt_field_class_blob *field_class) +{ + BUF_APPEND(", %smedia-type=\"%s\"", + PRFIELD(field_class->media_type->str)); +} + static inline void format_field_class(char **buf_ch, bool extended, const char *prefix, const struct bt_field_class *field_class) { @@ -334,6 +341,33 @@ static inline void format_field_class(char **buf_ch, bool extended, break; } + case BT_FIELD_CLASS_TYPE_STATIC_BLOB: + { + const struct bt_field_class_blob_static *blob_fc = + (const void *) field_class; + + format_blob_field_class(buf_ch, prefix, (const void *) blob_fc); + BUF_APPEND(", %slength=%" PRIu64, PRFIELD(blob_fc->length)); + break; + } + case BT_FIELD_CLASS_TYPE_DYNAMIC_BLOB_WITHOUT_LENGTH_FIELD: + case BT_FIELD_CLASS_TYPE_DYNAMIC_BLOB_WITH_LENGTH_FIELD: + { + const struct bt_field_class_blob_dynamic *blob_fc = + (const void *) field_class; + + format_blob_field_class(buf_ch, prefix, (const void *) blob_fc); + + if (field_class->type == BT_FIELD_CLASS_TYPE_DYNAMIC_BLOB_WITH_LENGTH_FIELD) { + BT_ASSERT(blob_fc->length_fl); + SET_TMP_PREFIX("length-fl-"); + format_field_location(buf_ch, extended, tmp_prefix, + blob_fc->length_fl); + break; + } + + break; + } default: break; } diff --git a/src/lib/trace-ir/field-class.c b/src/lib/trace-ir/field-class.c index 07e35d9a..81889061 100644 --- a/src/lib/trace-ir/field-class.c +++ b/src/lib/trace-ir/field-class.c @@ -2854,6 +2854,252 @@ void bt_field_class_variant_option_set_user_attributes( user_attributes, __func__); } +BT_EXPORT +bt_field_class_blob_set_media_type_status bt_field_class_blob_set_media_type( + struct bt_field_class *fc, const char *media_type) +{ + struct bt_field_class_blob *fc_blob = (void *) fc; + + BT_ASSERT_PRE_FC_NON_NULL(fc); + BT_ASSERT_PRE_FC_IS_BLOB("field-class", fc, "Field class"); + BT_ASSERT_PRE_DEV_FC_HOT(fc); + BT_ASSERT_PRE_NON_NULL("media-type", media_type, "Media type"); + + g_string_assign(fc_blob->media_type, media_type); + + return BT_FIELD_CLASS_BLOB_SET_MEDIA_TYPE_STATUS_OK; +} + +BT_EXPORT +const char *bt_field_class_blob_get_media_type( + const bt_field_class *fc) +{ + struct bt_field_class_blob *fc_blob = (void *) fc; + + BT_ASSERT_PRE_FC_NON_NULL(fc); + BT_ASSERT_PRE_FC_IS_BLOB("field-class", fc, "Field class"); + + return fc_blob->media_type->str; +} + +static +int init_blob_field_class(struct bt_field_class_blob *fc, + enum bt_field_class_type type, + bt_object_release_func release_func, + bt_trace_class *trace_class) +{ + int ret; + + ret = init_field_class((void *) fc, type, release_func, + trace_class); + if (ret) { + goto end; + } + + fc->media_type = g_string_new("application/octet-stream"); + +end: + return ret; +} + +static +void destroy_blob_field_class(struct bt_object *obj) +{ + struct bt_field_class_blob *blob = (void *) obj; + + BT_ASSERT(obj); + g_string_free(blob->media_type, TRUE); + finalize_field_class((void *) obj); + g_free(obj); +} + +static +void destroy_static_blob_field_class(struct bt_object *obj) +{ + struct bt_field_class_blob_static *fc = (void *) obj; + + BT_ASSERT(fc); + BT_LIB_LOGD("Destroying static BLOB field class object: %!+F", fc); + + destroy_blob_field_class(obj); +} + +BT_EXPORT +struct bt_field_class *bt_field_class_blob_static_create( + struct bt_trace_class *trace_class, uint64_t length) +{ + struct bt_field_class_blob_static *blob_fc = NULL; + int ret; + + BT_ASSERT_PRE_NO_ERROR(); + BT_ASSERT_PRE_TC_NON_NULL(trace_class); + BT_ASSERT_PRE_TC_MIP_VERSION_GE(trace_class, 1); + + BT_LOGD_STR("Creating default static BLOB field class object."); + blob_fc = g_new0(struct bt_field_class_blob_static, 1); + if (!blob_fc) { + BT_LIB_LOGE_APPEND_CAUSE( + "Failed to allocate one static BLOB field class."); + goto error; + } + + ret = init_blob_field_class((void *) blob_fc, + BT_FIELD_CLASS_TYPE_STATIC_BLOB, + destroy_static_blob_field_class, + trace_class); + if (ret) { + goto end; + } + + blob_fc->length = length; + BT_LIB_LOGD("Created static BLOB field class object: %!+F", blob_fc); + goto end; + +error: + BT_OBJECT_PUT_REF_AND_RESET(blob_fc); + +end: + return (void *) blob_fc; +} + +BT_EXPORT +uint64_t bt_field_class_blob_static_get_length( + const bt_field_class *fc) +{ + const struct bt_field_class_blob_static *blob_fc = (const void *) fc; + + BT_ASSERT_PRE_DEV_FC_NON_NULL(fc); + BT_ASSERT_PRE_DEV_FC_HAS_TYPE("field-class", fc, + "static-blob-field-class", BT_FIELD_CLASS_TYPE_STATIC_BLOB, + "Field class"); + + return blob_fc->length; +} + +static +void destroy_dynamic_blob_field_class(struct bt_object *obj) +{ + struct bt_field_class_blob_dynamic *fc = (void *) obj; + + BT_ASSERT(fc); + BT_LIB_LOGD("Destroying dynamic BLOB field class object: %!+F", fc); + + bt_object_put_ref(fc->length_fl); + fc->length_fl = NULL; + + destroy_blob_field_class(obj); +} + +static +struct bt_field_class_blob_dynamic *create_dynamic_blob_field_class( + struct bt_trace_class *trace_class, enum bt_field_class_type type) +{ + struct bt_field_class_blob_dynamic *blob_fc = NULL; + int ret; + + BT_LOGD_STR("Creating default dynamic BLOB field class object."); + blob_fc = g_new0(struct bt_field_class_blob_dynamic, 1); + if (!blob_fc) { + BT_LIB_LOGE_APPEND_CAUSE( + "Failed to allocate one dynamic BLOB field class."); + goto error; + } + + ret = init_blob_field_class((void *) blob_fc, type, + destroy_dynamic_blob_field_class, trace_class); + if (ret) { + goto error; + } + + goto end; + +error: + BT_OBJECT_PUT_REF_AND_RESET(blob_fc); + +end: + return blob_fc; +} + +BT_EXPORT +struct bt_field_class *bt_field_class_blob_dynamic_without_length_field_location_create( + struct bt_trace_class *trace_class) +{ + struct bt_field_class_blob_dynamic *blob_fc = NULL; + + BT_ASSERT_PRE_NO_ERROR(); + BT_ASSERT_PRE_TC_NON_NULL(trace_class); + BT_ASSERT_PRE_TC_MIP_VERSION_GE(trace_class, 1); + + blob_fc = create_dynamic_blob_field_class(trace_class, + BT_FIELD_CLASS_TYPE_DYNAMIC_BLOB_WITHOUT_LENGTH_FIELD); + if (!blob_fc) { + goto error; + } + + BT_LIB_LOGD("Created dynamic BLOB field class without field location object: %!+F", + blob_fc); + + goto end; + +error: + BT_OBJECT_PUT_REF_AND_RESET(blob_fc); + +end: + return (void *) blob_fc; +} + +BT_EXPORT +struct bt_field_class *bt_field_class_blob_dynamic_with_length_field_location_create( + bt_trace_class *trace_class, + const bt_field_location *length_field_location) +{ + struct bt_field_class_blob_dynamic *blob_fc = NULL; + + BT_ASSERT_PRE_NO_ERROR(); + BT_ASSERT_PRE_TC_NON_NULL(trace_class); + BT_ASSERT_PRE_FL_NON_NULL(length_field_location); + BT_ASSERT_PRE_TC_MIP_VERSION_GE(trace_class, 1); + + blob_fc = create_dynamic_blob_field_class(trace_class, + BT_FIELD_CLASS_TYPE_DYNAMIC_BLOB_WITH_LENGTH_FIELD); + if (!blob_fc) { + goto error; + } + + blob_fc->length_fl = length_field_location; + bt_object_get_ref_no_null_check(length_field_location); + + BT_LIB_LOGD("Created dynamic BLOB field class with field location object: %!+F", + blob_fc); + + goto end; + +error: + BT_OBJECT_PUT_REF_AND_RESET(blob_fc); + +end: + return (void *) blob_fc; +} + +BT_EXPORT +const bt_field_location * +bt_field_class_blob_dynamic_with_length_field_borrow_length_field_location_const( + const bt_field_class *fc) +{ + const struct bt_field_class_blob_dynamic *blob_fc = (const void *) fc; + + BT_ASSERT_PRE_NO_ERROR(); + BT_ASSERT_PRE_FC_NON_NULL(fc); + BT_ASSERT_PRE_FC_HAS_TYPE("field-class", fc, + "dynamic-blob-field-class-with-length-field", + BT_FIELD_CLASS_TYPE_DYNAMIC_BLOB_WITH_LENGTH_FIELD, + "Field class"); + BT_ASSERT_PRE_FC_MIP_VERSION_GE(fc, 1); + BT_ASSERT(blob_fc->length_fl); + + return blob_fc->length_fl; +} + BT_EXPORT void bt_field_class_get_ref(const struct bt_field_class *field_class) { diff --git a/src/lib/trace-ir/field-class.h b/src/lib/trace-ir/field-class.h index a763d6c6..32209ab9 100644 --- a/src/lib/trace-ir/field-class.h +++ b/src/lib/trace-ir/field-class.h @@ -267,6 +267,22 @@ struct bt_field_class_variant_with_selector_field { } selector_field; }; +struct bt_field_class_blob { + struct bt_field_class common; + + GString *media_type; +}; + +struct bt_field_class_blob_static { + struct bt_field_class_blob common; + uint64_t length; +}; + +struct bt_field_class_blob_dynamic { + struct bt_field_class_blob common; + const struct bt_field_location *length_fl; +}; + void _bt_field_class_freeze(const struct bt_field_class *field_class); #ifdef BT_DEV_MODE diff --git a/src/lib/trace-ir/field.c b/src/lib/trace-ir/field.c index 8110e58a..19cb7971 100644 --- a/src/lib/trace-ir/field.c +++ b/src/lib/trace-ir/field.c @@ -134,6 +134,13 @@ struct bt_field_methods variant_field_methods = { .reset = reset_variant_field, }; +static +struct bt_field_methods blob_field_methods = { + .set_is_frozen = set_single_field_is_frozen, + .is_set = single_field_is_set, + .reset = reset_single_field, +}; + static struct bt_field *create_bool_field(struct bt_field_class *); @@ -164,6 +171,9 @@ struct bt_field *create_option_field(struct bt_field_class *); static struct bt_field *create_variant_field(struct bt_field_class *); +static +struct bt_field *create_blob_field(struct bt_field_class *); + static void destroy_bool_field(struct bt_field *field); @@ -191,6 +201,9 @@ void destroy_option_field(struct bt_field *field); static void destroy_variant_field(struct bt_field *field); +static +void destroy_blob_field(struct bt_field *field); + BT_EXPORT struct bt_field_class *bt_field_borrow_class(struct bt_field *field) { @@ -260,6 +273,11 @@ struct bt_field *bt_field_create(struct bt_field_class *fc) case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR_FIELD: field = create_variant_field(fc); break; + case BT_FIELD_CLASS_TYPE_STATIC_BLOB: + case BT_FIELD_CLASS_TYPE_DYNAMIC_BLOB_WITHOUT_LENGTH_FIELD: + case BT_FIELD_CLASS_TYPE_DYNAMIC_BLOB_WITH_LENGTH_FIELD: + field = create_blob_field(fc); + break; default: bt_common_abort(); } @@ -527,6 +545,43 @@ end: return (void *) var_field; } +static +struct bt_field *create_blob_field(struct bt_field_class *fc) +{ + struct bt_field_blob *blob_field; + + BT_LIB_LOGD("Creating BLOB field object: %![fc-]+F", fc); + blob_field = g_new0(struct bt_field_blob, 1); + if (!blob_field) { + BT_LIB_LOGE_APPEND_CAUSE( + "Failed to allocate one BLOB field."); + goto end; + } + + init_field((void *) blob_field, fc, &blob_field_methods); + + if (bt_field_class_type_is(fc->type, BT_FIELD_CLASS_TYPE_STATIC_BLOB)) { + struct bt_field_class_blob_static *blob_static_fc = + (void *) fc; + blob_field->length = blob_static_fc->length; + blob_field->data = g_malloc(blob_field->length); + if (!blob_field->data) { + BT_LIB_LOGE_APPEND_CAUSE( + "Failed to allocate BLOB field data: %![fc-]+F", + fc); + goto error; + } + } + + goto end; +error: + bt_field_destroy((void *) blob_field); + blob_field = NULL; + +end: + return (void *) blob_field; +} + static inline int init_array_field_fields(struct bt_field_array *array_field) { @@ -1290,6 +1345,81 @@ uint64_t bt_field_variant_get_selected_option_index( return var_field->selected_index; } +BT_EXPORT +uint8_t *bt_field_blob_get_data(struct bt_field *field) +{ + const struct bt_field_blob *blob_field = (const void *) field; + + BT_ASSERT_PRE_DEV_FIELD_NON_NULL(field); + BT_ASSERT_PRE_DEV_FIELD_IS_BLOB("field", field, "Field"); + BT_ASSERT_PRE_DEV_FIELD_HOT(field); + BT_ASSERT_PRE_DEV("blob-field-length-is-set", + blob_field->length > 0, + "BLOB field length is not set: %!+f", field); + + /* Assume that the user will fill the bytes. */ + bt_field_set_single(field, true); + + return blob_field->data; +} + +BT_EXPORT +const uint8_t *bt_field_blob_get_data_const(const struct bt_field *field) +{ + const struct bt_field_blob *blob_field = (const void *) field; + + BT_ASSERT_PRE_DEV_FIELD_NON_NULL(field); + BT_ASSERT_PRE_DEV_FIELD_IS_BLOB("field", field, "Field"); + + return blob_field->data; +} + +BT_EXPORT +enum bt_field_blob_dynamic_set_length_status bt_field_blob_dynamic_set_length( + struct bt_field *field, uint64_t length) +{ + int ret; + struct bt_field_blob *blob_field = (void *) field; + + BT_ASSERT_PRE_DEV_NO_ERROR(); + BT_ASSERT_PRE_DEV_FIELD_NON_NULL(field); + BT_ASSERT_PRE_DEV_FIELD_IS_DYNAMIC_BLOB("field", field, "Field"); + BT_ASSERT_PRE_DEV_FIELD_HOT(field); + + if (G_UNLIKELY(length > blob_field->length)) { + /* Make more room */ + uint8_t *data = g_realloc(blob_field->data, length); + + if (!data) { + BT_LIB_LOGE_APPEND_CAUSE( + "Failed to reallocate BLOB field data: %!+f", + field); + ret = BT_FIELD_DYNAMIC_BLOB_SET_LENGTH_STATUS_MEMORY_ERROR; + goto end; + } + + blob_field->data = data; + } + + blob_field->length = length; + ret = BT_FIELD_DYNAMIC_BLOB_SET_LENGTH_STATUS_OK; + +end: + return ret; +} + +BT_EXPORT +uint64_t bt_field_blob_get_length(const struct bt_field *field) +{ + const struct bt_field_blob *blob_field = (const void *) field; + + BT_ASSERT_PRE_DEV_FIELD_NON_NULL(field); + BT_ASSERT_PRE_DEV_FIELD_IS_BLOB("field", field, "Field"); + + return blob_field->length; +} + + static inline void bt_field_finalize(struct bt_field *field) { @@ -1384,6 +1514,20 @@ void destroy_variant_field(struct bt_field *field) g_free(field); } +static +void destroy_blob_field(struct bt_field *field) +{ + struct bt_field_blob *blob_field = (void *) field; + + BT_ASSERT(field); + BT_LIB_LOGD("Destroying BLOB field object: %!+f", field); + bt_field_finalize(field); + + g_free(blob_field->data); + + g_free(field); +} + static void destroy_array_field(struct bt_field *field) { @@ -1461,6 +1605,11 @@ void bt_field_destroy(struct bt_field *field) case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR_FIELD: destroy_variant_field(field); break; + case BT_FIELD_CLASS_TYPE_STATIC_BLOB: + case BT_FIELD_CLASS_TYPE_DYNAMIC_BLOB_WITHOUT_LENGTH_FIELD: + case BT_FIELD_CLASS_TYPE_DYNAMIC_BLOB_WITH_LENGTH_FIELD: + destroy_blob_field(field); + break; default: bt_common_abort(); } diff --git a/src/lib/trace-ir/field.h b/src/lib/trace-ir/field.h index bf90380a..c52bc25d 100644 --- a/src/lib/trace-ir/field.h +++ b/src/lib/trace-ir/field.h @@ -96,6 +96,13 @@ struct bt_field_variant { GPtrArray *fields; }; +struct bt_field_blob { + struct bt_field common; + + uint64_t length; + uint8_t *data; +}; + struct bt_field_array { struct bt_field common; -- 2.34.1