refactor: session: provide an iterator over consumer data channel keys
[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 "field.hpp"
9 #include "ust-app.hpp"
10 #include "ust-field-quirks.hpp"
11 #include "ust-registry-session.hpp"
12 #include "ust-registry.hpp"
13
14 #include <common/exception.hpp>
15 #include <common/make-unique.hpp>
16
17 #include <unordered_map>
18 #include <utility>
19
20 namespace lst = lttng::sessiond::trace;
21 namespace lsu = lttng::sessiond::ust;
22
23 /*
24 * fmtlib helper that must be under the same namespace as lttng_ust_ctl_abstract_types
25 * (global).
26 */
27 static int format_as(lttng_ust_ctl_abstract_types type)
28 {
29 return fmt::underlying(type);
30 }
31
32 namespace {
33 /*
34 * Type enclosing the session information that may be required during the decoding
35 * of the lttng_ust_ctl_field array provided by applications on registration of
36 * an event.
37 */
38 class session_attributes {
39 public:
40 using registry_enum_getter_fn =
41 std::function<lsu::registry_enum::const_rcu_protected_reference(const char *name,
42 uint64_t id)>;
43
44 session_attributes(registry_enum_getter_fn reg_enum_getter,
45 lst::byte_order native_trace_byte_order) :
46 get_registry_enum{ std::move(reg_enum_getter) },
47 _native_trace_byte_order{ native_trace_byte_order }
48 {
49 }
50
51 const registry_enum_getter_fn get_registry_enum;
52 const lst::byte_order _native_trace_byte_order;
53 };
54
55 /* Used to publish fields on which a field being decoded has an implicit dependency. */
56 using publish_field_fn = std::function<void(lst::field::uptr)>;
57
58 /* Look-up field from a field location. */
59 using lookup_field_fn = std::function<const lst::field&(const lst::field_location&)>;
60
61 lst::type::cuptr
62 create_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
63 const lttng_ust_ctl_field *end,
64 const session_attributes& session_attributes,
65 const lttng_ust_ctl_field **next_ust_ctl_field,
66 const publish_field_fn& publish_field,
67 const lookup_field_fn& lookup_field,
68 lst::field_location::root lookup_root,
69 lst::field_location::elements& current_field_location_elements,
70 lsu::ctl_field_quirks quirks);
71
72 void create_field_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
73 const lttng_ust_ctl_field *end,
74 const session_attributes& session_attributes,
75 const lttng_ust_ctl_field **next_ust_ctl_field,
76 const publish_field_fn& publish_field,
77 const lookup_field_fn& lookup_field,
78 lst::field_location::root lookup_root,
79 lst::field_location::elements& current_field_location_elements,
80 lsu::ctl_field_quirks quirks);
81
82 template <class UstCtlEncodingType>
83 enum lst::null_terminated_string_type::encoding
84 ust_ctl_encoding_to_string_field_encoding(UstCtlEncodingType encoding)
85 {
86 static const std::unordered_map<UstCtlEncodingType,
87 enum lst::null_terminated_string_type::encoding>
88 encoding_conversion_map = {
89 { (UstCtlEncodingType) lttng_ust_ctl_encode_ASCII,
90 lst::null_terminated_string_type::encoding::ASCII },
91 { (UstCtlEncodingType) lttng_ust_ctl_encode_UTF8,
92 lst::null_terminated_string_type::encoding::UTF8 },
93 };
94
95 const auto encoding_it = encoding_conversion_map.find(encoding);
96 if (encoding_it == encoding_conversion_map.end()) {
97 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
98 "Unknown lttng_ust_ctl_string_encodings value `{}` encountered when decoding integer field",
99 encoding));
100 }
101
102 return encoding_it->second;
103 }
104
105 template <class UstCtlBaseType>
106 enum lst::integer_type::base ust_ctl_base_to_integer_field_base(UstCtlBaseType base)
107 {
108 static const std::unordered_map<UstCtlBaseType, enum lst::integer_type::base>
109 base_conversion_map = { { 2, lst::integer_type::base::BINARY },
110 { 8, lst::integer_type::base::OCTAL },
111 { 10, lst::integer_type::base::DECIMAL },
112 { 16, lst::integer_type::base::HEXADECIMAL } };
113
114 const auto base_it = base_conversion_map.find(base);
115 if (base_it == base_conversion_map.end()) {
116 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
117 "Unknown integer base value `{}` encountered when decoding integer field",
118 base));
119 }
120
121 return base_it->second;
122 }
123
124 lst::type::cuptr
125 create_integer_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
126 const lttng_ust_ctl_field *end,
127 const session_attributes& session_attributes,
128 const lttng_ust_ctl_field **next_ust_ctl_field,
129 lsu::ctl_field_quirks quirks __attribute__((unused)))
130 {
131 if (current >= end) {
132 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
133 "End of {} array reached unexpectedly during decoding", typeid(*current)));
134 }
135
136 const auto base = ust_ctl_base_to_integer_field_base(current->type.u.integer.base);
137 const auto signedness = current->type.u.integer.signedness ?
138 lst::integer_type::signedness::SIGNED :
139 lst::integer_type::signedness::UNSIGNED;
140 const auto byte_order = current->type.u.integer.reverse_byte_order ?
141 lst::type::reverse_byte_order(session_attributes._native_trace_byte_order) :
142 session_attributes._native_trace_byte_order;
143
144 *next_ust_ctl_field = current + 1;
145
146 return lttng::make_unique<const lst::integer_type>(current->type.u.integer.alignment,
147 byte_order,
148 current->type.u.integer.size,
149 signedness,
150 base);
151 }
152
153 lst::type::cuptr
154 create_floating_point_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
155 const lttng_ust_ctl_field *end,
156 const session_attributes& session_attributes,
157 const lttng_ust_ctl_field **next_ust_ctl_field,
158 lsu::ctl_field_quirks quirks __attribute__((unused)))
159 {
160 if (current >= end) {
161 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
162 "End of {} array reached unexpectedly during decoding", typeid(*current)));
163 }
164
165 *next_ust_ctl_field = current + 1;
166
167 const auto byte_order = current->type.u._float.reverse_byte_order ?
168 lst::type::reverse_byte_order(session_attributes._native_trace_byte_order) :
169 session_attributes._native_trace_byte_order;
170
171 try {
172 return lttng::make_unique<const lst::floating_point_type>(
173 current->type.u._float.alignment,
174 byte_order,
175 current->type.u._float.exp_dig,
176 current->type.u._float.mant_dig);
177 } catch (lttng::invalid_argument_error& ex) {
178 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
179 "Invalid floating point attribute in {}: {}", typeid(*current), ex.what()));
180 }
181 }
182
183 lst::type::cuptr
184 create_enumeration_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
185 const lttng_ust_ctl_field *end,
186 const session_attributes& session_attributes,
187 const lttng_ust_ctl_field **next_ust_ctl_field,
188 lsu::ctl_field_quirks quirks __attribute__((unused)))
189 {
190 if (current >= end) {
191 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
192 "End of {} array reached unexpectedly during decoding", typeid(*current)));
193 }
194
195 uint64_t enumeration_id;
196 const auto& enum_uctl_field = *current;
197 const char *enumeration_name;
198 const auto *enum_container_uctl_type =
199 &current->type.u.legacy.basic.enumeration.container_type;
200
201 if (enum_uctl_field.type.atype == lttng_ust_ctl_atype_enum_nestable) {
202 /* Nestable enumeration fields are followed by their container type. */
203 ++current;
204 if (current >= end) {
205 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
206 "Array of {} is too short to contain nestable enumeration's container",
207 typeid(*current)));
208 }
209
210 if (current->type.atype != lttng_ust_ctl_atype_integer) {
211 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
212 "Invalid type of nestable enum container: type id = {}",
213 current->type.atype));
214 }
215
216 enum_container_uctl_type = &current->type.u.integer;
217 enumeration_id = enum_uctl_field.type.u.enum_nestable.id;
218 enumeration_name = enum_uctl_field.type.u.enum_nestable.name;
219 } else {
220 enumeration_id = enum_uctl_field.type.u.legacy.basic.enumeration.id;
221 enumeration_name = enum_uctl_field.type.u.legacy.basic.enumeration.name;
222 }
223
224 *next_ust_ctl_field = current + 1;
225
226 const auto base = ust_ctl_base_to_integer_field_base(enum_container_uctl_type->base);
227 const auto byte_order = enum_container_uctl_type->reverse_byte_order ?
228 lst::integer_type::reverse_byte_order(session_attributes._native_trace_byte_order) :
229 session_attributes._native_trace_byte_order;
230 const auto signedness = enum_container_uctl_type->signedness ?
231 lst::integer_type::signedness::SIGNED :
232 lst::integer_type::signedness::UNSIGNED;
233
234 if (signedness == lst::integer_type::signedness::SIGNED) {
235 const auto& enum_registry = static_cast<const lsu::registry_signed_enum&>(
236 *session_attributes.get_registry_enum(enumeration_name, enumeration_id));
237
238 return lttng::make_unique<const lst::signed_enumeration_type>(
239 enum_container_uctl_type->alignment,
240 byte_order,
241 enum_container_uctl_type->size,
242 base,
243 enum_registry._mappings);
244 } else {
245 const auto& enum_registry = static_cast<const lsu::registry_unsigned_enum&>(
246 *session_attributes.get_registry_enum(enumeration_name, enumeration_id));
247
248 return lttng::make_unique<const lst::unsigned_enumeration_type>(
249 enum_container_uctl_type->alignment,
250 byte_order,
251 enum_container_uctl_type->size,
252 base,
253 enum_registry._mappings);
254 }
255 }
256
257 lst::type::cuptr
258 create_string_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
259 const lttng_ust_ctl_field *end,
260 const session_attributes& session_attributes
261 __attribute__((unused)),
262 const lttng_ust_ctl_field **next_ust_ctl_field,
263 lsu::ctl_field_quirks quirks __attribute__((unused)))
264 {
265 if (current >= end) {
266 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
267 "End of {} array reached unexpectedly during decoding", typeid(*current)));
268 }
269
270 const auto& string_uctl_field = *current;
271 *next_ust_ctl_field = current + 1;
272
273 const auto encoding =
274 ust_ctl_encoding_to_string_field_encoding(string_uctl_field.type.u.string.encoding);
275
276 return lttng::make_unique<const lst::null_terminated_string_type>(1, encoding);
277 }
278
279 lst::type::cuptr
280 create_integer_type_from_ust_ctl_basic_type(const lttng_ust_ctl_basic_type& type,
281 const session_attributes& session_attributes)
282 {
283 /* Checked by caller. */
284 LTTNG_ASSERT(type.atype == lttng_ust_ctl_atype_integer);
285
286 const auto byte_order = type.u.basic.integer.reverse_byte_order ?
287 lst::integer_type::reverse_byte_order(session_attributes._native_trace_byte_order) :
288 session_attributes._native_trace_byte_order;
289 const auto signedness = type.u.basic.integer.signedness ?
290 lst::integer_type::signedness::SIGNED :
291 lst::integer_type::signedness::UNSIGNED;
292 const auto base = ust_ctl_base_to_integer_field_base(type.u.basic.integer.base);
293 const auto size = type.u.basic.integer.size;
294 const auto alignment = type.u.basic.integer.alignment;
295
296 return lttng::make_unique<const lst::integer_type>(
297 alignment, byte_order, size, signedness, base);
298 }
299
300 lst::type::cuptr
301 create_array_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
302 const lttng_ust_ctl_field *end,
303 const session_attributes& session_attributes,
304 const lttng_ust_ctl_field **next_ust_ctl_field,
305 lsu::ctl_field_quirks quirks __attribute__((unused)))
306 {
307 if (current >= end) {
308 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
309 "End of {} array reached unexpectedly during decoding", typeid(*current)));
310 }
311
312 const auto& array_uctl_field = *current;
313 uint32_t array_alignment, array_length;
314 lst::type::cuptr element_type;
315 nonstd::optional<enum lst::string_type::encoding> element_encoding;
316
317 array_length = array_uctl_field.type.u.legacy.array.length;
318 array_alignment = 0;
319
320 const auto& element_uctl_type = array_uctl_field.type.u.legacy.array.elem_type;
321 if (element_uctl_type.atype != lttng_ust_ctl_atype_integer) {
322 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
323 "Unexpected legacy array element type: atype = {}, expected atype = lttng_ust_ctl_atype_integer ({})",
324 element_uctl_type.atype,
325 lttng_ust_ctl_atype_integer));
326 }
327
328 element_type =
329 create_integer_type_from_ust_ctl_basic_type(element_uctl_type, session_attributes);
330 if (element_uctl_type.atype == lttng_ust_ctl_atype_integer &&
331 element_uctl_type.u.basic.integer.encoding != lttng_ust_ctl_encode_none) {
332 /* Element represents a text character. */
333 element_encoding = ust_ctl_encoding_to_string_field_encoding(
334 element_uctl_type.u.basic.integer.encoding);
335 }
336
337 *next_ust_ctl_field = current + 1;
338
339 if (element_encoding) {
340 const auto integer_element_size =
341 static_cast<const lst::integer_type&>(*element_type).size;
342
343 if (integer_element_size != 8) {
344 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
345 "Unexpected legacy array element type: integer has encoding but size is not 8: size = {}",
346 integer_element_size));
347 }
348
349 /* Array is a static-length string. */
350 return lttng::make_unique<lst::static_length_string_type>(
351 array_alignment, *element_encoding, array_length);
352 }
353
354 return lttng::make_unique<lst::static_length_array_type>(
355 array_alignment, std::move(element_type), array_length);
356 }
357
358 lst::type::cuptr create_array_nestable_type_from_ust_ctl_fields(
359 const lttng_ust_ctl_field *current,
360 const lttng_ust_ctl_field *end,
361 const session_attributes& session_attributes,
362 const lttng_ust_ctl_field **next_ust_ctl_field,
363 const publish_field_fn& publish_field,
364 const lookup_field_fn& lookup_field,
365 lst::field_location::root lookup_root,
366 lst::field_location::elements& current_field_location_elements,
367 lsu::ctl_field_quirks quirks)
368 {
369 if (current >= end) {
370 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
371 "End of {} array reached unexpectedly during decoding", typeid(*current)));
372 }
373
374 const auto& array_uctl_field = *current;
375 uint32_t array_alignment, array_length;
376 lst::type::cuptr element_type;
377 nonstd::optional<enum lst::string_type::encoding> element_encoding;
378
379 array_length = array_uctl_field.type.u.array_nestable.length;
380 array_alignment = array_uctl_field.type.u.array_nestable.alignment;
381
382 /* Nestable array fields are followed by their element type. */
383 const auto& element_uctl_field = *(current + 1);
384
385 /* next_ust_ctl_field is updated as needed. */
386 element_type = create_type_from_ust_ctl_fields(&element_uctl_field,
387 end,
388 session_attributes,
389 next_ust_ctl_field,
390 publish_field,
391 lookup_field,
392 lookup_root,
393 current_field_location_elements,
394 quirks);
395 if (element_uctl_field.type.atype == lttng_ust_ctl_atype_integer &&
396 element_uctl_field.type.u.integer.encoding != lttng_ust_ctl_encode_none) {
397 /* Element represents a text character. */
398 element_encoding = ust_ctl_encoding_to_string_field_encoding(
399 element_uctl_field.type.u.integer.encoding);
400 }
401
402 if (element_encoding) {
403 const auto integer_element_size =
404 static_cast<const lst::integer_type&>(*element_type).size;
405
406 if (integer_element_size != 8) {
407 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
408 "Unexpected array element type: integer has encoding but size is not 8: size = {}",
409 integer_element_size));
410 }
411
412 /* Array is a static-length string. */
413 return lttng::make_unique<lst::static_length_string_type>(
414 array_alignment, *element_encoding, array_length);
415 }
416
417 return lttng::make_unique<lst::static_length_array_type>(
418 array_alignment, std::move(element_type), array_length);
419 }
420
421 /*
422 * For legacy sequence types, LTTng-UST expresses both the sequence and sequence
423 * length as part of the same lttng_ust_ctl_field entry.
424 */
425 lst::type::cuptr create_sequence_type_from_ust_ctl_fields(
426 const lttng_ust_ctl_field *current,
427 const lttng_ust_ctl_field *end,
428 const session_attributes& session_attributes,
429 const lttng_ust_ctl_field **next_ust_ctl_field,
430 const publish_field_fn& publish_field,
431 lst::field_location::root lookup_root,
432 lst::field_location::elements& current_field_location_elements,
433 lsu::ctl_field_quirks quirks __attribute__((unused)))
434 {
435 if (current >= end) {
436 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
437 "End of {} array reached unexpectedly during decoding", typeid(*current)));
438 }
439
440 const auto& sequence_uctl_field = *current;
441 const auto& element_uctl_type = sequence_uctl_field.type.u.legacy.sequence.elem_type;
442 const auto& length_uctl_type = sequence_uctl_field.type.u.legacy.sequence.length_type;
443 const auto sequence_alignment = 0U;
444
445 if (element_uctl_type.atype != lttng_ust_ctl_atype_integer) {
446 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
447 "Unexpected legacy sequence element type: atype = {}, expected atype = lttng_ust_ctl_atype_integer ({})",
448 element_uctl_type.atype,
449 lttng_ust_ctl_atype_integer));
450 }
451
452 if (length_uctl_type.atype != lttng_ust_ctl_atype_integer) {
453 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
454 "Unexpected legacy sequence length field type: atype = {}, expected atype = lttng_ust_ctl_atype_integer ({})",
455 length_uctl_type.atype,
456 lttng_ust_ctl_atype_integer));
457 }
458
459 nonstd::optional<enum lst::string_type::encoding> element_encoding;
460 if (element_uctl_type.atype == lttng_ust_ctl_atype_integer &&
461 element_uctl_type.u.basic.integer.encoding != lttng_ust_ctl_encode_none) {
462 /* Element represents a text character. */
463 element_encoding = ust_ctl_encoding_to_string_field_encoding(
464 element_uctl_type.u.basic.integer.encoding);
465 }
466
467 auto length_field_name = lttng::format("_{}_length", sequence_uctl_field.name);
468 auto element_type =
469 create_integer_type_from_ust_ctl_basic_type(element_uctl_type, session_attributes);
470 auto length_type =
471 create_integer_type_from_ust_ctl_basic_type(length_uctl_type, session_attributes);
472
473 lst::field_location::elements length_field_location_elements =
474 current_field_location_elements;
475 length_field_location_elements.emplace_back(length_field_name);
476
477 lst::field_location length_field_location{ lookup_root,
478 std::move(length_field_location_elements) };
479
480 /* Publish an implicit length field _before_ the sequence field. */
481 publish_field(lttng::make_unique<lst::field>(std::move(length_field_name),
482 std::move(length_type)));
483
484 *next_ust_ctl_field = current + 1;
485
486 if (element_encoding) {
487 const auto integer_element_size =
488 static_cast<const lst::integer_type&>(*element_type).size;
489
490 if (integer_element_size != 8) {
491 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
492 "Unexpected legacy array element type: integer has encoding but size is not 8: size = {}",
493 integer_element_size));
494 }
495
496 /* Sequence is a dynamic-length string. */
497 return lttng::make_unique<lst::dynamic_length_string_type>(
498 sequence_alignment, *element_encoding, std::move(length_field_location));
499 }
500
501 return lttng::make_unique<lst::dynamic_length_array_type>(
502 sequence_alignment, std::move(element_type), std::move(length_field_location));
503 }
504
505 lst::type::cuptr create_sequence_nestable_type_from_ust_ctl_fields(
506 const lttng_ust_ctl_field *current,
507 const lttng_ust_ctl_field *end,
508 const session_attributes& session_attributes,
509 const lttng_ust_ctl_field **next_ust_ctl_field,
510 const publish_field_fn& publish_field,
511 const lookup_field_fn& lookup_field,
512 lst::field_location::root lookup_root,
513 lst::field_location::elements& current_field_location_elements,
514 lsu::ctl_field_quirks quirks)
515 {
516 if (current >= end) {
517 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
518 "End of {} array reached unexpectedly during decoding", typeid(*current)));
519 }
520
521 const auto& sequence_uctl_field = *current;
522 const auto sequence_alignment = sequence_uctl_field.type.u.sequence_nestable.alignment;
523 const auto *length_field_name = sequence_uctl_field.type.u.sequence_nestable.length_name;
524
525 /* Nestable sequence fields are followed by their element type. */
526 const auto& element_uctl_field = *(current + 1);
527
528 nonstd::optional<enum lst::string_type::encoding> element_encoding;
529 if (element_uctl_field.type.atype == lttng_ust_ctl_atype_integer &&
530 element_uctl_field.type.u.integer.encoding != lttng_ust_ctl_encode_none) {
531 /* Element represents a text character. */
532 element_encoding = ust_ctl_encoding_to_string_field_encoding(
533 element_uctl_field.type.u.integer.encoding);
534 }
535
536 /* next_ust_ctl_field is updated as needed. */
537 auto element_type = create_type_from_ust_ctl_fields(&element_uctl_field,
538 end,
539 session_attributes,
540 next_ust_ctl_field,
541 publish_field,
542 lookup_field,
543 lookup_root,
544 current_field_location_elements,
545 quirks);
546
547 if (lttng_strnlen(sequence_uctl_field.type.u.sequence_nestable.length_name,
548 sizeof(sequence_uctl_field.type.u.sequence_nestable.length_name)) ==
549 sizeof(sequence_uctl_field.type.u.sequence_nestable.length_name)) {
550 LTTNG_THROW_PROTOCOL_ERROR("Sequence length field name is not null terminated");
551 }
552
553 lst::field_location::elements length_field_location_elements =
554 current_field_location_elements;
555 length_field_location_elements.emplace_back(length_field_name);
556
557 lst::field_location length_field_location{ lookup_root,
558 std::move(length_field_location_elements) };
559
560 /* Validate existence of length field (throws if not found). */
561 const auto& length_field = lookup_field(length_field_location);
562 const auto *integer_selector_field =
563 dynamic_cast<const lst::integer_type *>(&length_field.get_type());
564 if (!integer_selector_field) {
565 LTTNG_THROW_PROTOCOL_ERROR(
566 "Invalid selector field type referenced from sequence: expected integer or enumeration");
567 }
568
569 if (element_encoding) {
570 const auto integer_element_size =
571 static_cast<const lst::integer_type&>(*element_type).size;
572
573 if (integer_element_size != 8) {
574 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
575 "Unexpected array element type: integer has encoding but size is not 8: size = {}",
576 integer_element_size));
577 }
578
579 /* Sqeuence is a dynamic-length string. */
580 return lttng::make_unique<lst::dynamic_length_string_type>(
581 sequence_alignment, *element_encoding, std::move(length_field_location));
582 }
583
584 return lttng::make_unique<lst::dynamic_length_array_type>(
585 sequence_alignment, std::move(element_type), std::move(length_field_location));
586 }
587
588 lst::type::cuptr
589 create_structure_field_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
590 const lttng_ust_ctl_field *end,
591 const session_attributes& session_attributes
592 __attribute__((unused)),
593 const lttng_ust_ctl_field **next_ust_ctl_field,
594 lsu::ctl_field_quirks quirks __attribute__((unused)))
595 {
596 if (current >= end) {
597 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
598 "End of {} array reached unexpectedly during decoding", typeid(*current)));
599 }
600
601 uint32_t field_count;
602 uint32_t alignment;
603 const auto& structure_uctl_field = *current;
604
605 if (structure_uctl_field.type.atype == lttng_ust_ctl_atype_struct) {
606 field_count = structure_uctl_field.type.u.legacy._struct.nr_fields;
607 alignment = 0;
608 } else {
609 field_count = structure_uctl_field.type.u.struct_nestable.nr_fields;
610 alignment = structure_uctl_field.type.u.struct_nestable.alignment;
611 }
612
613 if (field_count != 0) {
614 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
615 "Only empty structures are supported by LTTng-UST: nr_fields = {}",
616 field_count));
617 }
618
619 *next_ust_ctl_field = current + 1;
620 return lttng::make_unique<lst::structure_type>(alignment, lst::structure_type::fields());
621 }
622
623 template <class VariantSelectorMappingIntegerType>
624 typename lst::variant_type<VariantSelectorMappingIntegerType>::choices
625 create_typed_variant_choices(const lttng_ust_ctl_field *current,
626 const lttng_ust_ctl_field *end,
627 const session_attributes& session_attributes,
628 const lttng_ust_ctl_field **next_ust_ctl_field,
629 lookup_field_fn lookup_field,
630 lst::field_location::root lookup_root,
631 lst::field_location::elements& current_field_location_elements,
632 unsigned int choice_count,
633 const lst::field& selector_field,
634 lsu::ctl_field_quirks quirks)
635 {
636 typename lst::variant_type<VariantSelectorMappingIntegerType>::choices choices;
637 const auto& typed_enumeration =
638 static_cast<const lst::typed_enumeration_type<VariantSelectorMappingIntegerType>&>(
639 selector_field.get_type());
640
641 for (unsigned int i = 0; i < choice_count; i++) {
642 create_field_from_ust_ctl_fields(
643 current,
644 end,
645 session_attributes,
646 next_ust_ctl_field,
647 [&choices, &typed_enumeration, &selector_field, quirks](
648 lst::field::uptr field) {
649 /*
650 * Find the enumeration mapping that matches the
651 * field's name.
652 */
653 const auto mapping_it = std::find_if(
654 typed_enumeration.mappings_->begin(),
655 typed_enumeration.mappings_->end(),
656 [&field,
657 quirks](const typename std::remove_reference<
658 decltype(typed_enumeration)>::type::mapping&
659 mapping) {
660 if (static_cast<bool>(
661 quirks &
662 lsu::ctl_field_quirks::
663 UNDERSCORE_PREFIXED_VARIANT_TAG_MAPPINGS)) {
664 /*
665 * Check if they match with
666 * a prepended underscore
667 * and, if not, perform the
668 * regular check.
669 */
670 if ((std::string("_") + field->name) ==
671 mapping.name) {
672 return true;
673 }
674 }
675
676 return mapping.name == field->name;
677 });
678
679 if (mapping_it == typed_enumeration.mappings_->end()) {
680 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
681 "Invalid variant choice: `{}` does not match any mapping in `{}` enumeration",
682 field->name,
683 selector_field.name));
684 }
685
686 choices.emplace_back(*mapping_it, field->move_type());
687 },
688 lookup_field,
689 lookup_root,
690 current_field_location_elements,
691 quirks);
692
693 current = *next_ust_ctl_field;
694 }
695
696 return choices;
697 }
698
699 lst::type::cuptr create_variant_field_from_ust_ctl_fields(
700 const lttng_ust_ctl_field *current,
701 const lttng_ust_ctl_field *end,
702 const session_attributes& session_attributes,
703 const lttng_ust_ctl_field **next_ust_ctl_field,
704 const lookup_field_fn& lookup_field,
705 lst::field_location::root lookup_root,
706 lst::field_location::elements& current_field_location_elements,
707 lsu::ctl_field_quirks quirks)
708 {
709 if (current >= end) {
710 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
711 "End of {} array reached unexpectedly during decoding", typeid(*current)));
712 }
713
714 const auto& variant_uctl_field = *current;
715 current++;
716
717 uint32_t alignment;
718 uint32_t choice_count;
719 const char *tag_name;
720
721 if (variant_uctl_field.type.atype == lttng_ust_ctl_atype_variant) {
722 alignment = 0;
723 choice_count = variant_uctl_field.type.u.legacy.variant.nr_choices;
724 tag_name = variant_uctl_field.type.u.legacy.variant.tag_name;
725 } else {
726 alignment = variant_uctl_field.type.u.variant_nestable.alignment;
727 choice_count = variant_uctl_field.type.u.variant_nestable.nr_choices;
728 tag_name = variant_uctl_field.type.u.variant_nestable.tag_name;
729 }
730
731 lst::field_location::elements selector_field_location_elements =
732 current_field_location_elements;
733 selector_field_location_elements.emplace_back(tag_name);
734
735 lst::field_location selector_field_location{ lookup_root,
736 std::move(selector_field_location_elements) };
737
738 /* Validate existence of selector field (throws if not found). */
739 const auto& selector_field = lookup_field(selector_field_location);
740 const auto *enumeration_selector_type =
741 dynamic_cast<const lst::enumeration_type *>(&selector_field.get_type());
742 if (!enumeration_selector_type) {
743 LTTNG_THROW_PROTOCOL_ERROR(
744 "Invalid selector field type referenced from variant: expected enumeration");
745 }
746
747 const bool selector_is_signed = enumeration_selector_type->signedness_ ==
748 lst::integer_type::signedness::SIGNED;
749
750 /* Choices follow. next_ust_ctl_field is updated as needed. */
751 if (selector_is_signed) {
752 lst::variant_type<lst::signed_enumeration_type::mapping::range_t::range_integer_t>::
753 choices choices = create_typed_variant_choices<int64_t>(
754 current,
755 end,
756 session_attributes,
757 next_ust_ctl_field,
758 lookup_field,
759 lookup_root,
760 current_field_location_elements,
761 choice_count,
762 selector_field,
763 quirks);
764
765 return lttng::make_unique<lst::variant_type<int64_t>>(
766 alignment, std::move(selector_field_location), std::move(choices));
767 } else {
768 lst::variant_type<
769 lst::unsigned_enumeration_type::mapping::range_t::range_integer_t>::choices
770 choices = create_typed_variant_choices<uint64_t>(
771 current,
772 end,
773 session_attributes,
774 next_ust_ctl_field,
775 lookup_field,
776 lookup_root,
777 current_field_location_elements,
778 choice_count,
779 selector_field,
780 quirks);
781
782 return lttng::make_unique<lst::variant_type<uint64_t>>(
783 alignment, std::move(selector_field_location), std::move(choices));
784 }
785 }
786
787 lst::type::cuptr
788 create_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
789 const lttng_ust_ctl_field *end,
790 const session_attributes& session_attributes,
791 const lttng_ust_ctl_field **next_ust_ctl_field,
792 const publish_field_fn& publish_field,
793 const lookup_field_fn& lookup_field,
794 lst::field_location::root lookup_root,
795 lst::field_location::elements& current_field_location_elements,
796 lsu::ctl_field_quirks quirks)
797 {
798 switch (current->type.atype) {
799 case lttng_ust_ctl_atype_integer:
800 return create_integer_type_from_ust_ctl_fields(
801 current, end, session_attributes, next_ust_ctl_field, quirks);
802 case lttng_ust_ctl_atype_enum:
803 case lttng_ust_ctl_atype_enum_nestable:
804 return create_enumeration_type_from_ust_ctl_fields(
805 current, end, session_attributes, next_ust_ctl_field, quirks);
806 case lttng_ust_ctl_atype_float:
807 return create_floating_point_type_from_ust_ctl_fields(
808 current, end, session_attributes, next_ust_ctl_field, quirks);
809 case lttng_ust_ctl_atype_string:
810 return create_string_type_from_ust_ctl_fields(
811 current, end, session_attributes, next_ust_ctl_field, quirks);
812 case lttng_ust_ctl_atype_array:
813 return create_array_type_from_ust_ctl_fields(
814 current, end, session_attributes, next_ust_ctl_field, quirks);
815 case lttng_ust_ctl_atype_array_nestable:
816 return create_array_nestable_type_from_ust_ctl_fields(
817 current,
818 end,
819 session_attributes,
820 next_ust_ctl_field,
821 publish_field,
822 lookup_field,
823 lookup_root,
824 current_field_location_elements,
825 quirks);
826 case lttng_ust_ctl_atype_sequence:
827 return create_sequence_type_from_ust_ctl_fields(current,
828 end,
829 session_attributes,
830 next_ust_ctl_field,
831 publish_field,
832 lookup_root,
833 current_field_location_elements,
834 quirks);
835 case lttng_ust_ctl_atype_sequence_nestable:
836 return create_sequence_nestable_type_from_ust_ctl_fields(
837 current,
838 end,
839 session_attributes,
840 next_ust_ctl_field,
841 publish_field,
842 lookup_field,
843 lookup_root,
844 current_field_location_elements,
845 quirks);
846 case lttng_ust_ctl_atype_struct:
847 case lttng_ust_ctl_atype_struct_nestable:
848 return create_structure_field_from_ust_ctl_fields(
849 current, end, session_attributes, next_ust_ctl_field, quirks);
850 case lttng_ust_ctl_atype_variant:
851 case lttng_ust_ctl_atype_variant_nestable:
852 return create_variant_field_from_ust_ctl_fields(current,
853 end,
854 session_attributes,
855 next_ust_ctl_field,
856 lookup_field,
857 lookup_root,
858 current_field_location_elements,
859 quirks);
860 default:
861 LTTNG_THROW_PROTOCOL_ERROR(
862 lttng::format("Unknown {} value `{}` encountered while converting {} to {}",
863 typeid(current->type.atype),
864 current->type.atype,
865 typeid(*current),
866 typeid(lst::type::cuptr::element_type)));
867 }
868 }
869
870 void create_field_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
871 const lttng_ust_ctl_field *end,
872 const session_attributes& session_attributes,
873 const lttng_ust_ctl_field **next_ust_ctl_field,
874 const publish_field_fn& publish_field,
875 const lookup_field_fn& lookup_field,
876 lst::field_location::root lookup_root,
877 lst::field_location::elements& current_field_location_elements,
878 lsu::ctl_field_quirks quirks)
879 {
880 LTTNG_ASSERT(current < end);
881
882 if (lttng_strnlen(current->name, sizeof(current->name)) == sizeof(current->name)) {
883 LTTNG_THROW_PROTOCOL_ERROR(
884 lttng::format("Name of {} is not null-terminated", typeid(*current)));
885 }
886
887 publish_field(lttng::make_unique<lst::field>(
888 current->name,
889 create_type_from_ust_ctl_fields(current,
890 end,
891 session_attributes,
892 next_ust_ctl_field,
893 publish_field,
894 lookup_field,
895 lookup_root,
896 current_field_location_elements,
897 quirks)));
898 }
899
900 std::vector<lst::field::cuptr>::iterator
901 lookup_field_in_vector(std::vector<lst::field::cuptr>& fields, const lst::field_location& location)
902 {
903 if (location.elements_.size() != 1) {
904 LTTNG_THROW_ERROR(lttng::format(
905 "Unexpected field location received during field look-up: location = {}",
906 location));
907 }
908
909 /*
910 * In the context of fields received from LTTng-UST, field
911 * look-up is extremely naive as the protocol can only
912 * express empty structures. It is safe to assume that
913 * location has a depth of 1 and directly refers to a field
914 * in the 'fields' vector.
915 */
916 const auto field_it =
917 std::find_if(fields.begin(), fields.end(), [location](lst::field::cuptr& field) {
918 return field->name == location.elements_[0];
919 });
920
921 if (field_it == fields.end()) {
922 LTTNG_THROW_PROTOCOL_ERROR(
923 lttng::format("Failed to look-up field: location = {}", location));
924 }
925
926 return field_it;
927 }
928
929 /*
930 * `lttng_ust_ctl_field`s can be nested, in which case creating a field will consume
931 * more than one lttng_ust_ctl_field. create_field_from_ust_ctl_fields returns the
932 * position of the next lttng_ust_ctl_field to consume or `end` when the last field
933 * is consumed.
934 *
935 * Always returns a new field, throws on error.
936 */
937 std::vector<lst::field::cuptr>
938 create_fields_from_ust_ctl_fields(const lsu::registry_session& session,
939 const lttng_ust_ctl_field *current,
940 const lttng_ust_ctl_field *end,
941 lst::field_location::root lookup_root,
942 lsu::ctl_field_quirks quirks)
943 {
944 std::vector<lst::field::cuptr> fields;
945 const auto trace_native_byte_order = session.abi.byte_order;
946 const session_attributes session_attributes{
947 [&session](const char *enum_name, uint64_t enum_id) {
948 return session.enumeration(enum_name, enum_id);
949 },
950 trace_native_byte_order
951 };
952 /* Location of field being created. */
953 lst::field_location::elements current_field_location_elements;
954
955 while (current < end) {
956 auto *next_field = current;
957
958 /*
959 * create_field_from_ust_ctl_fields will consume one field at a time.
960 * However, some fields expressed by LTTng-UST's protocol are expended
961 * to multiple event fields (legacy sequence fields implicitly define
962 * their length field).
963 *
964 * The lambda allows the factory functions to push as many fields as
965 * needed depending on the decoded field's type.
966 */
967 create_field_from_ust_ctl_fields(
968 current,
969 end,
970 session_attributes,
971 &next_field,
972 [&fields](lst::field::cuptr field) {
973 /* Publishing a field simply adds it to the converted
974 * fields. */
975 fields.emplace_back(std::move(field));
976 },
977 [&fields](const lst::field_location& location)
978 -> lookup_field_fn::result_type {
979 /* Resolve location to a previously-constructed field. */
980 return **lookup_field_in_vector(fields, location);
981 },
982 lookup_root,
983 current_field_location_elements,
984 quirks);
985
986 current = next_field;
987 }
988
989 return fields;
990 }
991 } /* namespace */
992
993 std::vector<lst::field::cuptr>
994 lsu::create_trace_fields_from_ust_ctl_fields(const lsu::registry_session& session,
995 const lttng_ust_ctl_field *fields,
996 std::size_t field_count,
997 lst::field_location::root lookup_root,
998 lsu::ctl_field_quirks quirks)
999 {
1000 return create_fields_from_ust_ctl_fields(
1001 session, fields, fields + field_count, lookup_root, quirks);
1002 }
This page took 0.049515 seconds and 4 git commands to generate.