sessiond: express field references as locations instead of names
[lttng-tools.git] / src / bin / lttng-sessiond / ust-field-convert.cpp
1 /*
2 * Copyright (C) 2022 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 */
7
8 #include "ust-field-convert.hpp"
9
10 #include <common/make-unique.hpp>
11
12 #include <unordered_map>
13
14 namespace lst = lttng::sessiond::trace;
15 namespace lsu = lttng::sessiond::ust;
16 namespace {
17
18 /*
19 * Type enclosing the session information that may be required during the decoding
20 * of the lttng_ust_ctl_field array provided by applications on registration of
21 * an event.
22 */
23 class session_attributes {
24 public:
25 using registry_enum_getter_fn =
26 std::function<lsu::registry_enum::const_rcu_protected_reference(
27 const char *name, uint64_t id)>;
28
29 session_attributes(registry_enum_getter_fn reg_enum_getter,
30 lst::byte_order native_trace_byte_order) :
31 get_registry_enum{reg_enum_getter}, _native_trace_byte_order{native_trace_byte_order}
32 {
33 }
34
35 const registry_enum_getter_fn get_registry_enum;
36 const lst::byte_order _native_trace_byte_order;
37 };
38
39 /* Used to publish fields on which a field being decoded has an implicit dependency. */
40 using publish_field_fn = std::function<void(lst::field::cuptr)>;
41
42 lst::type::cuptr create_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
43 const lttng_ust_ctl_field *end,
44 const session_attributes& session_attributes,
45 const lttng_ust_ctl_field **next_ust_ctl_field,
46 publish_field_fn publish_field,
47 lst::field_location::root lookup_root,
48 lst::field_location::elements& current_field_location_elements);
49
50 void create_field_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
51 const lttng_ust_ctl_field *end,
52 const session_attributes& session_attributes,
53 const lttng_ust_ctl_field **next_ust_ctl_field,
54 publish_field_fn publish_field,
55 lst::field_location::root lookup_root,
56 lst::field_location::elements& current_field_location_elements);
57
58 template <class UstCtlEncodingType>
59 enum lst::null_terminated_string_type::encoding ust_ctl_encoding_to_string_field_encoding(UstCtlEncodingType encoding)
60 {
61 static const std::unordered_map<UstCtlEncodingType, enum lst::null_terminated_string_type::encoding>
62 encoding_conversion_map = {
63 {(UstCtlEncodingType) lttng_ust_ctl_encode_ASCII,
64 lst::null_terminated_string_type::encoding::ASCII},
65 {(UstCtlEncodingType) lttng_ust_ctl_encode_UTF8,
66 lst::null_terminated_string_type::encoding::UTF8},
67 };
68
69 const auto encoding_it = encoding_conversion_map.find(encoding);
70 if (encoding_it == encoding_conversion_map.end()) {
71 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
72 "Unknown lttng_ust_ctl_string_encodings value `{}` encountered when decoding integer field",
73 encoding));
74 }
75
76 return encoding_it->second;
77 }
78
79 template <class UstCtlBaseType>
80 enum lst::integer_type::base ust_ctl_base_to_integer_field_base(UstCtlBaseType base)
81 {
82 static const std::unordered_map<UstCtlBaseType, enum lst::integer_type::base>
83 base_conversion_map = {{2, lst::integer_type::base::BINARY},
84 {8, lst::integer_type::base::OCTAL},
85 {10, lst::integer_type::base::DECIMAL},
86 {16, lst::integer_type::base::HEXADECIMAL}};
87
88 const auto base_it = base_conversion_map.find(base);
89 if (base_it == base_conversion_map.end()) {
90 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
91 "Unknown integer base value `{}` encountered when decoding integer field",
92 base));
93 }
94
95 return base_it->second;
96 }
97
98 lst::type::cuptr create_integer_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
99 const lttng_ust_ctl_field *end,
100 const session_attributes& session_attributes,
101 const lttng_ust_ctl_field **next_ust_ctl_field)
102 {
103 if (current >= end) {
104 LTTNG_THROW_PROTOCOL_ERROR(
105 fmt::format("End of {} array reached unexpectedly during decoding",
106 typeid(*current)));
107 }
108
109 const auto base = ust_ctl_base_to_integer_field_base(current->type.u.integer.base);
110 const auto signedness = current->type.u.integer.signedness ?
111 lst::integer_type::signedness::SIGNED :
112 lst::integer_type::signedness::UNSIGNED;
113 const auto byte_order = current->type.u.integer.reverse_byte_order ?
114 lst::type::reverse_byte_order(session_attributes._native_trace_byte_order) :
115 session_attributes._native_trace_byte_order;
116
117 *next_ust_ctl_field = current + 1;
118
119 return lttng::make_unique<const lst::integer_type>(current->type.u.integer.alignment,
120 byte_order, current->type.u.integer.size, signedness, base);
121 }
122
123 lst::type::cuptr create_floating_point_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
124 const lttng_ust_ctl_field *end,
125 const session_attributes& session_attributes,
126 const lttng_ust_ctl_field **next_ust_ctl_field)
127 {
128 if (current >= end) {
129 LTTNG_THROW_PROTOCOL_ERROR(
130 fmt::format("End of {} array reached unexpectedly during decoding",
131 typeid(*current)));
132 }
133
134 *next_ust_ctl_field = current + 1;
135
136 const auto byte_order = current->type.u._float.reverse_byte_order ?
137 lst::type::reverse_byte_order(session_attributes._native_trace_byte_order) :
138 session_attributes._native_trace_byte_order;
139
140 try {
141 return lttng::make_unique<const lst::floating_point_type>(
142 current->type.u._float.alignment, byte_order,
143 current->type.u._float.exp_dig, current->type.u._float.mant_dig);
144 } catch (lttng::invalid_argument_error& ex) {
145 LTTNG_THROW_PROTOCOL_ERROR(fmt::format("Invalid floating point attribute in {}: {}",
146 typeid(*current), ex.what()));
147 }
148 }
149
150 lst::type::cuptr create_enumeration_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
151 const lttng_ust_ctl_field *end,
152 const session_attributes& session_attributes,
153 const lttng_ust_ctl_field **next_ust_ctl_field)
154 {
155 if (current >= end) {
156 LTTNG_THROW_PROTOCOL_ERROR(
157 fmt::format("End of {} array reached unexpectedly during decoding",
158 typeid(*current)));
159 }
160
161 uint64_t enumeration_id;
162 const auto& enum_uctl_field = *current;
163 const char *enumeration_name;
164 const auto *enum_container_uctl_type =
165 &current->type.u.legacy.basic.enumeration.container_type;
166
167 if (enum_uctl_field.type.atype == lttng_ust_ctl_atype_enum_nestable) {
168 /* Nestable enumeration fields are followed by their container type. */
169 ++current;
170 if (current >= end) {
171 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
172 "Array of {} is too short to contain nestable enumeration's container",
173 typeid(*current)));
174 }
175
176 if (current->type.atype != lttng_ust_ctl_atype_integer) {
177 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
178 "Invalid type of nestable enum container: type id = {}",
179 current->type.atype));
180 }
181
182 enum_container_uctl_type = &current->type.u.integer;
183 enumeration_id = enum_uctl_field.type.u.enum_nestable.id;
184 enumeration_name = enum_uctl_field.type.u.enum_nestable.name;
185 } else {
186 enumeration_id = enum_uctl_field.type.u.legacy.basic.enumeration.id;
187 enumeration_name = enum_uctl_field.type.u.legacy.basic.enumeration.name;
188 }
189
190 *next_ust_ctl_field = current + 1;
191
192 const auto base = ust_ctl_base_to_integer_field_base(enum_container_uctl_type->base);
193 const auto byte_order = enum_container_uctl_type->reverse_byte_order ?
194 lst::integer_type::reverse_byte_order(
195 session_attributes._native_trace_byte_order) :
196 session_attributes._native_trace_byte_order;
197 const auto signedness = enum_container_uctl_type->signedness ?
198 lst::integer_type::signedness::SIGNED :
199 lst::integer_type::signedness::UNSIGNED;
200
201 if (signedness == lst::integer_type::signedness::SIGNED) {
202 const auto& enum_registry = static_cast<const lsu::registry_signed_enum&>(
203 *session_attributes.get_registry_enum(
204 enumeration_name, enumeration_id));
205
206 return lttng::make_unique<const lst::signed_enumeration_type>(
207 enum_container_uctl_type->alignment, byte_order,
208 enum_container_uctl_type->size, base,
209 enum_registry._mappings);
210 } else {
211 const auto& enum_registry = static_cast<const lsu::registry_unsigned_enum&>(
212 *session_attributes.get_registry_enum(
213 enumeration_name, enumeration_id));
214
215 return lttng::make_unique<const lst::unsigned_enumeration_type>(
216 enum_container_uctl_type->alignment, byte_order,
217 enum_container_uctl_type->size, base,
218 enum_registry._mappings);
219 }
220 }
221
222 lst::type::cuptr create_string_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
223 const lttng_ust_ctl_field *end,
224 const session_attributes& session_attributes __attribute__((unused)),
225 const lttng_ust_ctl_field **next_ust_ctl_field)
226 {
227 if (current >= end) {
228 LTTNG_THROW_PROTOCOL_ERROR(
229 fmt::format("End of {} array reached unexpectedly during decoding",
230 typeid(*current)));
231 }
232
233 const auto& string_uctl_field = *current;
234 *next_ust_ctl_field = current + 1;
235
236 const auto encoding = ust_ctl_encoding_to_string_field_encoding(
237 string_uctl_field.type.u.string.encoding);
238
239 return lttng::make_unique<const lst::null_terminated_string_type>(1, encoding);
240 }
241
242 lst::type::cuptr create_integer_type_from_ust_ctl_basic_type(
243 const lttng_ust_ctl_basic_type& type, const session_attributes& session_attributes)
244 {
245 /* Checked by caller. */
246 LTTNG_ASSERT(type.atype == lttng_ust_ctl_atype_integer);
247
248 const auto byte_order = type.u.basic.integer.reverse_byte_order ?
249 lst::integer_type::reverse_byte_order(
250 session_attributes._native_trace_byte_order) :
251 session_attributes._native_trace_byte_order;
252 const auto signedness = type.u.basic.integer.signedness ?
253 lst::integer_type::signedness::SIGNED :
254 lst::integer_type::signedness::UNSIGNED;
255 const auto base = ust_ctl_base_to_integer_field_base(type.u.basic.integer.base);
256 const auto size = type.u.basic.integer.size;
257 const auto alignment = type.u.basic.integer.alignment;
258
259 return lttng::make_unique<const lst::integer_type>(
260 alignment, byte_order, size, signedness, base);
261 }
262
263 lst::type::cuptr create_array_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
264 const lttng_ust_ctl_field *end,
265 const session_attributes& session_attributes,
266 const lttng_ust_ctl_field **next_ust_ctl_field)
267 {
268 if (current >= end) {
269 LTTNG_THROW_PROTOCOL_ERROR(
270 fmt::format("End of {} array reached unexpectedly during decoding",
271 typeid(*current)));
272 }
273
274 const auto& array_uctl_field = *current;
275 uint32_t array_alignment, array_length;
276 lst::type::cuptr element_type;
277 nonstd::optional<enum lst::string_type::encoding> element_encoding;
278
279 array_length = array_uctl_field.type.u.legacy.array.length;
280 array_alignment = 0;
281
282 const auto& element_uctl_type = array_uctl_field.type.u.legacy.array.elem_type;
283 if (element_uctl_type.atype != lttng_ust_ctl_atype_integer) {
284 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
285 "Unexpected legacy array element type: atype = {}, expected atype = lttng_ust_ctl_atype_integer ({})",
286 element_uctl_type.atype, lttng_ust_ctl_atype_integer));
287 }
288
289 element_type = create_integer_type_from_ust_ctl_basic_type(
290 element_uctl_type, session_attributes);
291 if (element_uctl_type.atype == lttng_ust_ctl_atype_integer &&
292 element_uctl_type.u.basic.integer.encoding != lttng_ust_ctl_encode_none) {
293 /* Element represents a text character. */
294 element_encoding = ust_ctl_encoding_to_string_field_encoding(
295 element_uctl_type.u.basic.integer.encoding);
296 }
297
298 *next_ust_ctl_field = current + 1;
299
300 if (element_encoding) {
301 const auto integer_element_size =
302 static_cast<const lst::integer_type&>(*element_type).size;
303
304 if (integer_element_size != 8) {
305 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
306 "Unexpected legacy array element type: integer has encoding but size is not 8: size = {}",
307 integer_element_size));
308 }
309
310 /* Array is a static-length string. */
311 return lttng::make_unique<lst::static_length_string_type>(
312 array_alignment, *element_encoding, array_length);
313 }
314
315 return lttng::make_unique<lst::static_length_array_type>(
316 array_alignment, std::move(element_type), array_length);
317 }
318
319 lst::type::cuptr create_array_nestable_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
320 const lttng_ust_ctl_field *end,
321 const session_attributes& session_attributes,
322 const lttng_ust_ctl_field **next_ust_ctl_field,
323 publish_field_fn publish_field,
324 lst::field_location::root lookup_root,
325 lst::field_location::elements &current_field_location_elements)
326 {
327 if (current >= end) {
328 LTTNG_THROW_PROTOCOL_ERROR(
329 fmt::format("End of {} array reached unexpectedly during decoding",
330 typeid(*current)));
331 }
332
333 const auto& array_uctl_field = *current;
334 uint32_t array_alignment, array_length;
335 lst::type::cuptr element_type;
336 nonstd::optional<enum lst::string_type::encoding> element_encoding;
337
338 array_length = array_uctl_field.type.u.array_nestable.length;
339 array_alignment = array_uctl_field.type.u.array_nestable.alignment;
340
341 /* Nestable array fields are followed by their element type. */
342 const auto& element_uctl_field = *(current + 1);
343
344 /* next_ust_ctl_field is updated as needed. */
345 element_type = create_type_from_ust_ctl_fields(&element_uctl_field, end, session_attributes,
346 next_ust_ctl_field, publish_field, lookup_root,
347 current_field_location_elements);
348 if (element_uctl_field.type.atype == lttng_ust_ctl_atype_integer &&
349 element_uctl_field.type.u.integer.encoding != lttng_ust_ctl_encode_none) {
350 /* Element represents a text character. */
351 element_encoding = ust_ctl_encoding_to_string_field_encoding(
352 element_uctl_field.type.u.integer.encoding);
353 }
354
355 if (element_encoding) {
356 const auto integer_element_size =
357 static_cast<const lst::integer_type&>(*element_type).size;
358
359 if (integer_element_size != 8) {
360 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
361 "Unexpected array element type: integer has encoding but size is not 8: size = {}",
362 integer_element_size));
363 }
364
365 /* Array is a static-length string. */
366 return lttng::make_unique<lst::static_length_string_type>(
367 array_alignment, *element_encoding, array_length);
368 }
369
370 return lttng::make_unique<lst::static_length_array_type>(
371 array_alignment, std::move(element_type), array_length);
372 }
373
374 /*
375 * For legacy sequence types, LTTng-UST expresses both the sequence and sequence
376 * length as part of the same lttng_ust_ctl_field entry.
377 */
378 lst::type::cuptr create_sequence_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
379 const lttng_ust_ctl_field *end,
380 const session_attributes& session_attributes,
381 const lttng_ust_ctl_field **next_ust_ctl_field,
382 publish_field_fn publish_field,
383 lst::field_location::root lookup_root,
384 lst::field_location::elements &current_field_location_elements)
385 {
386 if (current >= end) {
387 LTTNG_THROW_PROTOCOL_ERROR(
388 fmt::format("End of {} array reached unexpectedly during decoding",
389 typeid(*current)));
390 }
391
392 const auto& sequence_uctl_field = *current;
393 const auto& element_uctl_type = sequence_uctl_field.type.u.legacy.sequence.elem_type;
394 const auto& length_uctl_type = sequence_uctl_field.type.u.legacy.sequence.length_type;
395 const auto sequence_alignment = 0U;
396
397 if (element_uctl_type.atype != lttng_ust_ctl_atype_integer) {
398 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
399 "Unexpected legacy sequence element type: atype = {}, expected atype = lttng_ust_ctl_atype_integer ({})",
400 element_uctl_type.atype, lttng_ust_ctl_atype_integer));
401 }
402
403 if (length_uctl_type.atype != lttng_ust_ctl_atype_integer) {
404 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
405 "Unexpected legacy sequence length field type: atype = {}, expected atype = lttng_ust_ctl_atype_integer ({})",
406 length_uctl_type.atype, lttng_ust_ctl_atype_integer));
407 }
408
409 nonstd::optional<enum lst::string_type::encoding> element_encoding;
410 if (element_uctl_type.atype == lttng_ust_ctl_atype_integer &&
411 element_uctl_type.u.basic.integer.encoding != lttng_ust_ctl_encode_none) {
412 /* Element represents a text character. */
413 element_encoding = ust_ctl_encoding_to_string_field_encoding(
414 element_uctl_type.u.basic.integer.encoding);
415 }
416
417 const auto length_field_name = fmt::format("_{}_length", sequence_uctl_field.name);
418 auto element_type = create_integer_type_from_ust_ctl_basic_type(
419 element_uctl_type, session_attributes);
420 auto length_type = create_integer_type_from_ust_ctl_basic_type(
421 length_uctl_type, session_attributes);
422
423 lst::field_location::elements length_field_location_elements =
424 current_field_location_elements;
425 length_field_location_elements.emplace_back(length_field_name);
426
427 const lst::field_location length_field_location{
428 lookup_root, std::move(length_field_location_elements)};
429
430 /* Publish an implicit length field _before_ the sequence field. */
431 publish_field(lttng::make_unique<lst::field>(std::move(length_field_name), std::move(length_type)));
432
433 *next_ust_ctl_field = current + 1;
434
435 if (element_encoding) {
436 const auto integer_element_size =
437 static_cast<const lst::integer_type&>(*element_type).size;
438
439 if (integer_element_size != 8) {
440 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
441 "Unexpected legacy array element type: integer has encoding but size is not 8: size = {}",
442 integer_element_size));
443 }
444
445 /* Sequence is a dynamic-length string. */
446 return lttng::make_unique<lst::dynamic_length_string_type>(sequence_alignment,
447 *element_encoding, std::move(length_field_location));
448 }
449
450 return lttng::make_unique<lst::dynamic_length_array_type>(sequence_alignment,
451 std::move(element_type), std::move(length_field_location));
452 }
453
454 lst::type::cuptr create_sequence_nestable_type_from_ust_ctl_fields(
455 const lttng_ust_ctl_field *current,
456 const lttng_ust_ctl_field *end,
457 const session_attributes& session_attributes,
458 const lttng_ust_ctl_field **next_ust_ctl_field,
459 publish_field_fn publish_field,
460 lst::field_location::root lookup_root,
461 lst::field_location::elements &current_field_location_elements)
462 {
463 if (current >= end) {
464 LTTNG_THROW_PROTOCOL_ERROR(
465 fmt::format("End of {} array reached unexpectedly during decoding",
466 typeid(*current)));
467 }
468
469 const auto& sequence_uctl_field = *current;
470 const auto sequence_alignment = sequence_uctl_field.type.u.sequence_nestable.alignment;
471 const auto *length_field_name = sequence_uctl_field.type.u.sequence_nestable.length_name;
472
473 /* Nestable sequence fields are followed by their element type. */
474 const auto& element_uctl_field = *(current + 1);
475
476 nonstd::optional<enum lst::string_type::encoding> element_encoding;
477 if (element_uctl_field.type.atype == lttng_ust_ctl_atype_integer &&
478 element_uctl_field.type.u.integer.encoding != lttng_ust_ctl_encode_none) {
479 /* Element represents a text character. */
480 element_encoding = ust_ctl_encoding_to_string_field_encoding(
481 element_uctl_field.type.u.integer.encoding);
482 }
483
484 /* next_ust_ctl_field is updated as needed. */
485 auto element_type = create_type_from_ust_ctl_fields(&element_uctl_field, end,
486 session_attributes, next_ust_ctl_field, publish_field, lookup_root,
487 current_field_location_elements);
488
489 if (lttng_strnlen(sequence_uctl_field.type.u.sequence_nestable.length_name,
490 sizeof(sequence_uctl_field.type.u.sequence_nestable.length_name)) ==
491 sizeof(sequence_uctl_field.type.u.sequence_nestable.length_name)) {
492 LTTNG_THROW_PROTOCOL_ERROR("Sequence length field name is not null terminated");
493 }
494
495
496 lst::field_location::elements length_field_location_elements =
497 current_field_location_elements;
498 length_field_location_elements.emplace_back(std::move(length_field_name));
499
500 const lst::field_location length_field_location{
501 lookup_root, std::move(length_field_location_elements)};
502
503 if (element_encoding) {
504 const auto integer_element_size =
505 static_cast<const lst::integer_type&>(*element_type).size;
506
507 if (integer_element_size != 8) {
508 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
509 "Unexpected array element type: integer has encoding but size is not 8: size = {}",
510 integer_element_size));
511 }
512
513 /* Sqeuence is a dynamic-length string. */
514 return lttng::make_unique<lst::dynamic_length_string_type>(sequence_alignment,
515 *element_encoding, std::move(length_field_location));
516 }
517
518 return lttng::make_unique<lst::dynamic_length_array_type>(sequence_alignment,
519 std::move(element_type), std::move(length_field_location));
520 }
521
522 lst::type::cuptr create_structure_field_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
523 const lttng_ust_ctl_field *end,
524 const session_attributes& session_attributes __attribute__((unused)),
525 const lttng_ust_ctl_field **next_ust_ctl_field)
526 {
527 if (current >= end) {
528 LTTNG_THROW_PROTOCOL_ERROR(
529 fmt::format("End of {} array reached unexpectedly during decoding",
530 typeid(*current)));
531 }
532
533 uint32_t field_count;
534 uint32_t alignment;
535 const auto& structure_uctl_field = *current;
536
537 if (structure_uctl_field.type.atype == lttng_ust_ctl_atype_struct) {
538 field_count = structure_uctl_field.type.u.legacy._struct.nr_fields;
539 alignment = 0;
540 } else {
541 field_count = structure_uctl_field.type.u.struct_nestable.nr_fields;
542 alignment = structure_uctl_field.type.u.struct_nestable.alignment;
543 }
544
545 if (field_count != 0) {
546 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
547 "Only empty structures are supported by LTTng-UST: nr_fields = {}",
548 field_count));
549 }
550
551 *next_ust_ctl_field = current + 1;
552 return lttng::make_unique<lst::structure_type>(alignment, lst::structure_type::fields());
553 }
554
555 lst::type::cuptr create_variant_field_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
556 const lttng_ust_ctl_field *end,
557 const session_attributes& session_attributes,
558 const lttng_ust_ctl_field **next_ust_ctl_field,
559 lst::field_location::root lookup_root,
560 lst::field_location::elements &current_field_location_elements)
561 {
562 if (current >= end) {
563 LTTNG_THROW_PROTOCOL_ERROR(
564 fmt::format("End of {} array reached unexpectedly during decoding",
565 typeid(*current)));
566 }
567
568 const auto& variant_uctl_field = *current;
569 current++;
570
571 uint32_t alignment;
572 uint32_t choice_count;
573 const char *tag_name;
574
575 if (variant_uctl_field.type.atype == lttng_ust_ctl_atype_variant) {
576 alignment = 0;
577 choice_count = variant_uctl_field.type.u.legacy.variant.nr_choices;
578 tag_name = variant_uctl_field.type.u.legacy.variant.tag_name;
579 } else {
580 alignment = variant_uctl_field.type.u.variant_nestable.alignment;
581 choice_count = variant_uctl_field.type.u.variant_nestable.nr_choices;
582 tag_name = variant_uctl_field.type.u.variant_nestable.tag_name;
583 }
584
585 lst::field_location::elements selector_field_location_elements =
586 current_field_location_elements;
587 selector_field_location_elements.emplace_back(tag_name);
588
589 const lst::field_location selector_field_location{
590 lookup_root, std::move(selector_field_location_elements)};
591
592 /* Choices follow. next_ust_ctl_field is updated as needed. */
593 lst::variant_type::choices choices;
594 for (unsigned int i = 0; i < choice_count; i++) {
595 create_field_from_ust_ctl_fields(
596 current, end, session_attributes, next_ust_ctl_field,
597 [&choices](lst::field::cuptr field) {
598 choices.emplace_back(std::move(field));
599 },
600 lookup_root, current_field_location_elements);
601
602 current = *next_ust_ctl_field;
603 }
604
605 return lttng::make_unique<lst::variant_type>(
606 alignment, std::move(selector_field_location), std::move(choices));
607 }
608
609 lst::type::cuptr create_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
610 const lttng_ust_ctl_field *end,
611 const session_attributes& session_attributes,
612 const lttng_ust_ctl_field **next_ust_ctl_field,
613 publish_field_fn publish_field,
614 lst::field_location::root lookup_root,
615 lst::field_location::elements &current_field_location_elements)
616 {
617 switch (current->type.atype) {
618 case lttng_ust_ctl_atype_integer:
619 return create_integer_type_from_ust_ctl_fields(
620 current, end, session_attributes, next_ust_ctl_field);
621 case lttng_ust_ctl_atype_enum:
622 case lttng_ust_ctl_atype_enum_nestable:
623 return create_enumeration_type_from_ust_ctl_fields(
624 current, end, session_attributes, next_ust_ctl_field);
625 case lttng_ust_ctl_atype_float:
626 return create_floating_point_type_from_ust_ctl_fields(
627 current, end, session_attributes, next_ust_ctl_field);
628 case lttng_ust_ctl_atype_string:
629 return create_string_type_from_ust_ctl_fields(
630 current, end, session_attributes, next_ust_ctl_field);
631 case lttng_ust_ctl_atype_array:
632 return create_array_type_from_ust_ctl_fields(current, end, session_attributes,
633 next_ust_ctl_field);
634 case lttng_ust_ctl_atype_array_nestable:
635 return create_array_nestable_type_from_ust_ctl_fields(current, end,
636 session_attributes, next_ust_ctl_field, publish_field, lookup_root,
637 current_field_location_elements);
638 case lttng_ust_ctl_atype_sequence:
639 return create_sequence_type_from_ust_ctl_fields(current, end, session_attributes,
640 next_ust_ctl_field, publish_field, lookup_root,
641 current_field_location_elements);
642 case lttng_ust_ctl_atype_sequence_nestable:
643 return create_sequence_nestable_type_from_ust_ctl_fields(current, end,
644 session_attributes, next_ust_ctl_field, publish_field, lookup_root,
645 current_field_location_elements);
646 case lttng_ust_ctl_atype_struct:
647 case lttng_ust_ctl_atype_struct_nestable:
648 return create_structure_field_from_ust_ctl_fields(
649 current, end, session_attributes, next_ust_ctl_field);
650 case lttng_ust_ctl_atype_variant:
651 case lttng_ust_ctl_atype_variant_nestable:
652 return create_variant_field_from_ust_ctl_fields(current, end, session_attributes,
653 next_ust_ctl_field, lookup_root, current_field_location_elements);
654 default:
655 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
656 "Unknown {} value `{}` encountered while converting {} to {}",
657 typeid(current->type.atype), current->type.atype, typeid(*current),
658 typeid(lst::type::cuptr::element_type)));
659 }
660 }
661
662 void create_field_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
663 const lttng_ust_ctl_field *end,
664 const session_attributes& session_attributes,
665 const lttng_ust_ctl_field **next_ust_ctl_field,
666 publish_field_fn publish_field,
667 lst::field_location::root lookup_root,
668 lst::field_location::elements& current_field_location_elements)
669 {
670 LTTNG_ASSERT(current < end);
671
672 if (lttng_strnlen(current->name, sizeof(current->name)) == sizeof(current->name)) {
673 LTTNG_THROW_PROTOCOL_ERROR(
674 fmt::format("Name of {} is not null-terminated", typeid(*current)));
675 }
676
677 publish_field(lttng::make_unique<lst::field>(current->name,
678 create_type_from_ust_ctl_fields(current, end, session_attributes,
679 next_ust_ctl_field, publish_field,
680 lookup_root,
681 current_field_location_elements)));
682 }
683
684 /*
685 * `lttng_ust_ctl_field`s can be nested, in which case creating a field will consume
686 * more than one lttng_ust_ctl_field. create_field_from_ust_ctl_fields returns the
687 * position of the next lttng_ust_ctl_field to consume or `end` when the last field
688 * is consumed.
689 *
690 * Always returns a new field, throws on error.
691 */
692 std::vector<lst::field::cuptr> create_fields_from_ust_ctl_fields(
693 const lsu::registry_session& session,
694 const lttng_ust_ctl_field *current,
695 const lttng_ust_ctl_field *end,
696 lst::field_location::root lookup_root)
697 {
698 std::vector<lst::field::cuptr> fields;
699 const auto trace_native_byte_order = session.abi.byte_order;
700 const session_attributes session_attributes{
701 [&session](const char *enum_name, uint64_t enum_id) {
702 return session.get_enumeration(enum_name, enum_id);
703 },
704 trace_native_byte_order};
705 /* Location of field being created. */
706 lst::field_location::elements current_field_location_elements;
707
708 while (current < end) {
709 auto *next_field = current;
710
711 /*
712 * create_field_from_ust_ctl_fields will consume one field at a time.
713 * However, some fields expressed by LTTng-UST's protocol are expended
714 * to multiple event fields (legacy sequence fields implicitly define
715 * their length field).
716 *
717 * The lambda allows the factory functions to push as many fields as
718 * needed depending on the decoded field's type.
719 */
720 create_field_from_ust_ctl_fields(current, end, session_attributes, &next_field,
721 [&fields](lst::field::cuptr field) {
722 fields.emplace_back(std::move(field));
723 },
724 lookup_root,
725 current_field_location_elements);
726
727 current = next_field;
728 }
729
730 return fields;
731 }
732 } /* namespace */
733
734 std::vector<lst::field::cuptr> lsu::create_trace_fields_from_ust_ctl_fields(
735 const lsu::registry_session& session,
736 const lttng_ust_ctl_field *fields,
737 std::size_t field_count,
738 lst::field_location::root lookup_root)
739 {
740 return create_fields_from_ust_ctl_fields(session, fields, fields + field_count, lookup_root);
741 }
This page took 0.045895 seconds and 4 git commands to generate.