From 5530345d36682a874a188c237d1dcd0db80b42e4 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Tue, 6 Dec 2022 14:52:32 -0500 Subject: [PATCH] Implement variant type Signed-off-by: Mathieu Desnoyers --- include/side/trace.h | 79 ++++++++++++++++++++++++++++++++++++++++++++ src/tracer.c | 45 +++++++++++++++++++++++++ tests/unit/test.c | 36 ++++++++++++++++++++ 3 files changed, 160 insertions(+) diff --git a/include/side/trace.h b/include/side/trace.h index f03b4fc..e341047 100644 --- a/include/side/trace.h +++ b/include/side/trace.h @@ -82,6 +82,7 @@ struct side_tracer_dynamic_struct_visitor_ctx; struct side_event_description; struct side_arg_dynamic_struct; struct side_events_register_handle; +struct side_arg_variant; enum side_type_label { /* Stack-copy basic types */ @@ -107,6 +108,7 @@ enum side_type_label { /* Stack-copy compound types */ SIDE_TYPE_STRUCT, + SIDE_TYPE_VARIANT, SIDE_TYPE_ARRAY, SIDE_TYPE_VLA, SIDE_TYPE_VLA_VISITOR, @@ -471,6 +473,7 @@ struct side_type { struct side_type_vla side_vla; struct side_type_vla_visitor side_vla_visitor; const struct side_type_struct *side_struct; + const struct side_type_variant *side_variant; /* Stack-copy enumeration types */ struct side_type_enum side_enum; @@ -481,6 +484,20 @@ struct side_type { } SIDE_PACKED u; } SIDE_PACKED; +struct side_variant_option { + int64_t range_begin; + int64_t range_end; + const struct side_type side_type; +} SIDE_PACKED; + +struct side_type_variant { + const struct side_type selector; + const struct side_variant_option *options; + const struct side_attr *attr; + uint32_t nr_options; + uint32_t nr_attr; +} SIDE_PACKED; + struct side_event_field { const char *field_name; struct side_type side_type; @@ -513,6 +530,7 @@ struct side_arg_static { /* Stack-copy compound types */ const struct side_arg_vec *side_struct; + const struct side_arg_variant *side_variant; const struct side_arg_vec *side_array; const struct side_arg_vec *side_vla; void *side_vla_app_visitor_ctx; @@ -601,6 +619,11 @@ struct side_arg { } SIDE_PACKED u; } SIDE_PACKED; +struct side_arg_variant { + struct side_arg selector; + struct side_arg option; +} SIDE_PACKED; + struct side_arg_vec { const struct side_arg *sav; uint32_t len; @@ -845,6 +868,16 @@ struct side_event_description { .side_type = _type, \ } +#define side_option_range(_range_begin, _range_end, _type) \ + { \ + .range_begin = _range_begin, \ + .range_end = _range_end, \ + .side_type = _type, \ + } + +#define side_option(_value, _type) \ + side_option_range(_value, _value, SIDE_PARAM(_type)) + /* Host endian */ #define side_type_u8(_attr) _side_type_integer(SIDE_TYPE_U8, false, SIDE_TYPE_BYTE_ORDER_HOST, sizeof(uint8_t), 0, SIDE_PARAM(_attr)) #define side_type_u16(_attr) _side_type_integer(SIDE_TYPE_U16, false, SIDE_TYPE_BYTE_ORDER_HOST, sizeof(uint16_t), 0, SIDE_PARAM(_attr)) @@ -993,6 +1026,33 @@ struct side_event_description { SIDE_COMPOUND_LITERAL(const struct side_type_struct, \ _side_type_struct_define(SIDE_PARAM(_fields), SIDE_PARAM(_attr))) +#define side_type_variant(_variant) \ + { \ + .type = SIDE_TYPE_VARIANT, \ + .u = { \ + .side_variant = _variant, \ + }, \ + } +#define side_field_variant(_name, _variant) \ + _side_field(_name, side_type_variant(SIDE_PARAM(_variant))) + +#define _side_type_variant_define(_selector, _options, _attr) \ + { \ + .selector = _selector, \ + .options = _options, \ + .attr = _attr, \ + .nr_options = SIDE_ARRAY_SIZE(SIDE_PARAM(_options)), \ + .nr_attr = SIDE_ARRAY_SIZE(SIDE_PARAM(_attr)), \ + } + +#define side_define_variant(_identifier, _selector, _options, _attr) \ + const struct side_type_variant _identifier = \ + _side_type_variant_define(SIDE_PARAM(_selector), SIDE_PARAM(_options), SIDE_PARAM(_attr)) + +#define side_variant_literal(_selector, _options, _attr) \ + SIDE_COMPOUND_LITERAL(const struct side_type_variant, \ + _side_type_variant_define(SIDE_PARAM(_selector), SIDE_PARAM(_options), SIDE_PARAM(_attr))) + #define side_type_array(_elem_type, _length, _attr) \ { \ .type = SIDE_TYPE_ARRAY, \ @@ -1350,6 +1410,9 @@ struct side_event_description { #define side_field_list(...) \ SIDE_COMPOUND_LITERAL(const struct side_event_field, __VA_ARGS__) +#define side_option_list(...) \ + SIDE_COMPOUND_LITERAL(const struct side_variant_option, __VA_ARGS__) + /* Stack-copy field arguments */ #define side_arg_null(_val) { .type = SIDE_TYPE_NULL } @@ -1374,6 +1437,22 @@ struct side_event_description { #define side_arg_float_binary128(_val) { .type = SIDE_TYPE_FLOAT_BINARY128, .u = { .side_static = { .float_value = { .side_float_binary128 = (_val) } } } } #define side_arg_struct(_side_type) { .type = SIDE_TYPE_STRUCT, .u = { .side_static = { .side_struct = (_side_type) } } } + +#define side_arg_define_variant(_identifier, _selector_val, _option) \ + const struct side_arg_variant _identifier = { \ + .selector = _selector_val, \ + .option = _option, \ + } +#define side_arg_variant(_side_variant) \ + { \ + .type = SIDE_TYPE_VARIANT, \ + .u = { \ + .side_static = { \ + .side_variant = (_side_variant), \ + }, \ + }, \ + } + #define side_arg_array(_side_type) { .type = SIDE_TYPE_ARRAY, .u = { .side_static = { .side_array = (_side_type) } } } #define side_arg_vla(_side_type) { .type = SIDE_TYPE_VLA, .u = { .side_static = { .side_vla = (_side_type) } } } #define side_arg_vla_visitor(_ctx) { .type = SIDE_TYPE_VLA_VISITOR, .u = { .side_static = { .side_vla_app_visitor_ctx = (_ctx) } } } diff --git a/src/tracer.c b/src/tracer.c index 8dd9388..32e4969 100644 --- a/src/tracer.c +++ b/src/tracer.c @@ -30,6 +30,8 @@ static struct side_tracer_handle *tracer_handle; static void tracer_print_struct(const struct side_type *type_desc, const struct side_arg_vec *side_arg_vec); static +void tracer_print_variant(const struct side_type *type_desc, const struct side_arg_variant *side_arg_variant); +static void tracer_print_array(const struct side_type *type_desc, const struct side_arg_vec *side_arg_vec); static void tracer_print_vla(const struct side_type *type_desc, const struct side_arg_vec *side_arg_vec); @@ -951,6 +953,9 @@ void tracer_print_type(const struct side_type *type_desc, const struct side_arg case SIDE_TYPE_STRUCT: tracer_print_struct(type_desc, item->u.side_static.side_struct); break; + case SIDE_TYPE_VARIANT: + tracer_print_variant(type_desc, item->u.side_static.side_variant); + break; case SIDE_TYPE_ARRAY: tracer_print_array(type_desc, item->u.side_static.side_array); break; @@ -1058,6 +1063,46 @@ void tracer_print_struct(const struct side_type *type_desc, const struct side_ar printf(" }"); } +static +void tracer_print_variant(const struct side_type *type_desc, const struct side_arg_variant *side_arg_variant) +{ + const struct side_type_variant *side_type_variant = type_desc->u.side_variant; + const struct side_type *selector_type = &side_type_variant->selector; + union int64_value v64; + uint32_t i; + + if (selector_type->type != side_arg_variant->selector.type) { + fprintf(stderr, "ERROR: Unexpected variant selector type\n"); + abort(); + } + switch (selector_type->type) { + case SIDE_TYPE_U8: + case SIDE_TYPE_U16: + case SIDE_TYPE_U32: + case SIDE_TYPE_U64: + case SIDE_TYPE_S8: + case SIDE_TYPE_S16: + case SIDE_TYPE_S32: + case SIDE_TYPE_S64: + break; + default: + fprintf(stderr, "ERROR: Expecting integer variant selector type\n"); + abort(); + } + v64 = tracer_load_integer_value(&selector_type->u.side_integer, + &side_arg_variant->selector.u.side_static.integer_value, 0, NULL); + for (i = 0; i < side_type_variant->nr_options; i++) { + const struct side_variant_option *option = &side_type_variant->options[i]; + + if (v64.s >= option->range_begin && v64.s <= option->range_end) { + tracer_print_type(&option->side_type, &side_arg_variant->option); + return; + } + } + fprintf(stderr, "ERROR: Variant selector value unknown %" PRId64 "\n", v64.s); + abort(); +} + static void tracer_print_array(const struct side_type *type_desc, const struct side_arg_vec *side_arg_vec) { diff --git a/tests/unit/test.c b/tests/unit/test.c index f258a37..8c41f8b 100644 --- a/tests/unit/test.c +++ b/tests/unit/test.c @@ -2209,6 +2209,41 @@ void test_string_utf(void) ); } +static side_define_variant(myvariantdef, + side_type_u32(side_attr_list()), + side_option_list( + side_option_range(1, 3, side_type_u16(side_attr_list())), + side_option(5, side_type_string(side_attr_list())), + ), + side_attr_list() +); + +side_static_event(my_provider_event_variant, "myprovider", "myeventvariant", SIDE_LOGLEVEL_DEBUG, + side_field_list( + side_field_variant("variant1", &myvariantdef), + side_field_variant("variant2", &myvariantdef), + side_field_u8("z", side_attr_list()), + ), + side_attr_list() +); + +static +void test_variant(void) +{ + side_event_cond(my_provider_event_variant) { + side_arg_define_variant(myvariant1, side_arg_u32(2), side_arg_u16(4)); + side_arg_define_variant(myvariant2, side_arg_u32(5), side_arg_string("abc")); + + side_event_call(my_provider_event_variant, + side_arg_list( + side_arg_variant(&myvariant1), + side_arg_variant(&myvariant2), + side_arg_u8(55), + ) + ); + } +} + int main() { test_fields(); @@ -2260,5 +2295,6 @@ int main() test_gather_enum(); test_gather_string(); test_string_utf(); + test_variant(); return 0; } -- 2.34.1