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