refactor: session: provide an iterator over consumer data channel keys
[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
16d64977
JG
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"
d7bfb9b0 13
6e01cdc6 14#include <common/exception.hpp>
d7bfb9b0
JG
15#include <common/make-unique.hpp>
16
17#include <unordered_map>
cd9adb8b 18#include <utility>
d7bfb9b0
JG
19
20namespace lst = lttng::sessiond::trace;
21namespace lsu = lttng::sessiond::ust;
d7bfb9b0 22
8b75cd77
JG
23/*
24 * fmtlib helper that must be under the same namespace as lttng_ust_ctl_abstract_types
25 * (global).
26 */
27static int format_as(lttng_ust_ctl_abstract_types type)
28{
29 return fmt::underlying(type);
30}
31
32namespace {
d7bfb9b0
JG
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 */
38class session_attributes {
39public:
40 using registry_enum_getter_fn =
28ab034a
JG
41 std::function<lsu::registry_enum::const_rcu_protected_reference(const char *name,
42 uint64_t id)>;
d7bfb9b0
JG
43
44 session_attributes(registry_enum_getter_fn reg_enum_getter,
28ab034a 45 lst::byte_order native_trace_byte_order) :
cd9adb8b 46 get_registry_enum{ std::move(reg_enum_getter) },
28ab034a 47 _native_trace_byte_order{ native_trace_byte_order }
d7bfb9b0
JG
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. */
45110cdd 56using publish_field_fn = std::function<void(lst::field::uptr)>;
d7bfb9b0 57
6e01cdc6 58/* Look-up field from a field location. */
28ab034a
JG
59using lookup_field_fn = std::function<const lst::field&(const lst::field_location&)>;
60
61lst::type::cuptr
62create_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,
cd9adb8b
JG
66 const publish_field_fn& publish_field,
67 const lookup_field_fn& lookup_field,
28ab034a
JG
68 lst::field_location::root lookup_root,
69 lst::field_location::elements& current_field_location_elements,
70 lsu::ctl_field_quirks quirks);
d7bfb9b0
JG
71
72void create_field_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
28ab034a
JG
73 const lttng_ust_ctl_field *end,
74 const session_attributes& session_attributes,
75 const lttng_ust_ctl_field **next_ust_ctl_field,
cd9adb8b
JG
76 const publish_field_fn& publish_field,
77 const lookup_field_fn& lookup_field,
28ab034a
JG
78 lst::field_location::root lookup_root,
79 lst::field_location::elements& current_field_location_elements,
80 lsu::ctl_field_quirks quirks);
d7bfb9b0
JG
81
82template <class UstCtlEncodingType>
28ab034a
JG
83enum lst::null_terminated_string_type::encoding
84ust_ctl_encoding_to_string_field_encoding(UstCtlEncodingType encoding)
d7bfb9b0 85{
28ab034a
JG
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 };
d7bfb9b0
JG
94
95 const auto encoding_it = encoding_conversion_map.find(encoding);
96 if (encoding_it == encoding_conversion_map.end()) {
f9a41357 97 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
28ab034a
JG
98 "Unknown lttng_ust_ctl_string_encodings value `{}` encountered when decoding integer field",
99 encoding));
d7bfb9b0
JG
100 }
101
102 return encoding_it->second;
103}
104
105template <class UstCtlBaseType>
106enum 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>
28ab034a
JG
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 } };
d7bfb9b0
JG
113
114 const auto base_it = base_conversion_map.find(base);
115 if (base_it == base_conversion_map.end()) {
f9a41357 116 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
28ab034a
JG
117 "Unknown integer base value `{}` encountered when decoding integer field",
118 base));
d7bfb9b0
JG
119 }
120
121 return base_it->second;
122}
123
28ab034a
JG
124lst::type::cuptr
125create_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)))
d7bfb9b0
JG
130{
131 if (current >= end) {
f9a41357 132 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
28ab034a 133 "End of {} array reached unexpectedly during decoding", typeid(*current)));
d7bfb9b0
JG
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 ?
28ab034a
JG
138 lst::integer_type::signedness::SIGNED :
139 lst::integer_type::signedness::UNSIGNED;
d7bfb9b0 140 const auto byte_order = current->type.u.integer.reverse_byte_order ?
28ab034a
JG
141 lst::type::reverse_byte_order(session_attributes._native_trace_byte_order) :
142 session_attributes._native_trace_byte_order;
d7bfb9b0
JG
143
144 *next_ust_ctl_field = current + 1;
145
146 return lttng::make_unique<const lst::integer_type>(current->type.u.integer.alignment,
28ab034a
JG
147 byte_order,
148 current->type.u.integer.size,
149 signedness,
150 base);
d7bfb9b0
JG
151}
152
28ab034a
JG
153lst::type::cuptr
154create_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)))
d7bfb9b0
JG
159{
160 if (current >= end) {
f9a41357 161 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
28ab034a 162 "End of {} array reached unexpectedly during decoding", typeid(*current)));
d7bfb9b0
JG
163 }
164
165 *next_ust_ctl_field = current + 1;
166
167 const auto byte_order = current->type.u._float.reverse_byte_order ?
28ab034a
JG
168 lst::type::reverse_byte_order(session_attributes._native_trace_byte_order) :
169 session_attributes._native_trace_byte_order;
d7bfb9b0
JG
170
171 try {
172 return lttng::make_unique<const lst::floating_point_type>(
28ab034a
JG
173 current->type.u._float.alignment,
174 byte_order,
175 current->type.u._float.exp_dig,
176 current->type.u._float.mant_dig);
d7bfb9b0 177 } catch (lttng::invalid_argument_error& ex) {
f9a41357 178 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
28ab034a 179 "Invalid floating point attribute in {}: {}", typeid(*current), ex.what()));
d7bfb9b0
JG
180 }
181}
182
28ab034a
JG
183lst::type::cuptr
184create_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)))
d7bfb9b0
JG
189{
190 if (current >= end) {
f9a41357 191 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
28ab034a 192 "End of {} array reached unexpectedly during decoding", typeid(*current)));
d7bfb9b0
JG
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 =
28ab034a 199 &current->type.u.legacy.basic.enumeration.container_type;
d7bfb9b0
JG
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) {
f9a41357 205 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
28ab034a
JG
206 "Array of {} is too short to contain nestable enumeration's container",
207 typeid(*current)));
d7bfb9b0
JG
208 }
209
210 if (current->type.atype != lttng_ust_ctl_atype_integer) {
f9a41357
JG
211 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
212 "Invalid type of nestable enum container: type id = {}",
213 current->type.atype));
d7bfb9b0
JG
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 ?
28ab034a
JG
228 lst::integer_type::reverse_byte_order(session_attributes._native_trace_byte_order) :
229 session_attributes._native_trace_byte_order;
24ed18f2 230 const auto signedness = enum_container_uctl_type->signedness ?
28ab034a
JG
231 lst::integer_type::signedness::SIGNED :
232 lst::integer_type::signedness::UNSIGNED;
d7bfb9b0 233
24ed18f2 234 if (signedness == lst::integer_type::signedness::SIGNED) {
d7bfb9b0 235 const auto& enum_registry = static_cast<const lsu::registry_signed_enum&>(
28ab034a 236 *session_attributes.get_registry_enum(enumeration_name, enumeration_id));
d7bfb9b0
JG
237
238 return lttng::make_unique<const lst::signed_enumeration_type>(
28ab034a
JG
239 enum_container_uctl_type->alignment,
240 byte_order,
241 enum_container_uctl_type->size,
242 base,
243 enum_registry._mappings);
d7bfb9b0
JG
244 } else {
245 const auto& enum_registry = static_cast<const lsu::registry_unsigned_enum&>(
28ab034a 246 *session_attributes.get_registry_enum(enumeration_name, enumeration_id));
d7bfb9b0
JG
247
248 return lttng::make_unique<const lst::unsigned_enumeration_type>(
28ab034a
JG
249 enum_container_uctl_type->alignment,
250 byte_order,
251 enum_container_uctl_type->size,
252 base,
253 enum_registry._mappings);
d7bfb9b0
JG
254 }
255}
256
28ab034a
JG
257lst::type::cuptr
258create_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)))
d7bfb9b0
JG
264{
265 if (current >= end) {
f9a41357 266 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
28ab034a 267 "End of {} array reached unexpectedly during decoding", typeid(*current)));
d7bfb9b0
JG
268 }
269
270 const auto& string_uctl_field = *current;
271 *next_ust_ctl_field = current + 1;
272
28ab034a
JG
273 const auto encoding =
274 ust_ctl_encoding_to_string_field_encoding(string_uctl_field.type.u.string.encoding);
d7bfb9b0
JG
275
276 return lttng::make_unique<const lst::null_terminated_string_type>(1, encoding);
277}
278
28ab034a
JG
279lst::type::cuptr
280create_integer_type_from_ust_ctl_basic_type(const lttng_ust_ctl_basic_type& type,
281 const session_attributes& session_attributes)
d7bfb9b0
JG
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 ?
28ab034a
JG
287 lst::integer_type::reverse_byte_order(session_attributes._native_trace_byte_order) :
288 session_attributes._native_trace_byte_order;
d7bfb9b0 289 const auto signedness = type.u.basic.integer.signedness ?
28ab034a
JG
290 lst::integer_type::signedness::SIGNED :
291 lst::integer_type::signedness::UNSIGNED;
d7bfb9b0
JG
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>(
28ab034a 297 alignment, byte_order, size, signedness, base);
d7bfb9b0
JG
298}
299
28ab034a
JG
300lst::type::cuptr
301create_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)))
d7bfb9b0
JG
306{
307 if (current >= end) {
f9a41357 308 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
28ab034a 309 "End of {} array reached unexpectedly during decoding", typeid(*current)));
d7bfb9b0
JG
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) {
f9a41357 322 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
28ab034a
JG
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));
d7bfb9b0
JG
326 }
327
28ab034a
JG
328 element_type =
329 create_integer_type_from_ust_ctl_basic_type(element_uctl_type, session_attributes);
d7bfb9b0 330 if (element_uctl_type.atype == lttng_ust_ctl_atype_integer &&
28ab034a 331 element_uctl_type.u.basic.integer.encoding != lttng_ust_ctl_encode_none) {
d7bfb9b0
JG
332 /* Element represents a text character. */
333 element_encoding = ust_ctl_encoding_to_string_field_encoding(
28ab034a 334 element_uctl_type.u.basic.integer.encoding);
d7bfb9b0
JG
335 }
336
337 *next_ust_ctl_field = current + 1;
338
339 if (element_encoding) {
340 const auto integer_element_size =
28ab034a 341 static_cast<const lst::integer_type&>(*element_type).size;
d7bfb9b0
JG
342
343 if (integer_element_size != 8) {
f9a41357 344 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
28ab034a
JG
345 "Unexpected legacy array element type: integer has encoding but size is not 8: size = {}",
346 integer_element_size));
d7bfb9b0
JG
347 }
348
349 /* Array is a static-length string. */
350 return lttng::make_unique<lst::static_length_string_type>(
28ab034a 351 array_alignment, *element_encoding, array_length);
d7bfb9b0
JG
352 }
353
354 return lttng::make_unique<lst::static_length_array_type>(
28ab034a 355 array_alignment, std::move(element_type), array_length);
d7bfb9b0
JG
356}
357
28ab034a
JG
358lst::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,
cd9adb8b
JG
363 const publish_field_fn& publish_field,
364 const lookup_field_fn& lookup_field,
28ab034a
JG
365 lst::field_location::root lookup_root,
366 lst::field_location::elements& current_field_location_elements,
367 lsu::ctl_field_quirks quirks)
d7bfb9b0
JG
368{
369 if (current >= end) {
f9a41357 370 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
28ab034a 371 "End of {} array reached unexpectedly during decoding", typeid(*current)));
d7bfb9b0
JG
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. */
28ab034a
JG
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);
d7bfb9b0 395 if (element_uctl_field.type.atype == lttng_ust_ctl_atype_integer &&
28ab034a 396 element_uctl_field.type.u.integer.encoding != lttng_ust_ctl_encode_none) {
d7bfb9b0
JG
397 /* Element represents a text character. */
398 element_encoding = ust_ctl_encoding_to_string_field_encoding(
28ab034a 399 element_uctl_field.type.u.integer.encoding);
d7bfb9b0
JG
400 }
401
402 if (element_encoding) {
403 const auto integer_element_size =
28ab034a 404 static_cast<const lst::integer_type&>(*element_type).size;
d7bfb9b0
JG
405
406 if (integer_element_size != 8) {
f9a41357 407 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
28ab034a
JG
408 "Unexpected array element type: integer has encoding but size is not 8: size = {}",
409 integer_element_size));
d7bfb9b0
JG
410 }
411
412 /* Array is a static-length string. */
413 return lttng::make_unique<lst::static_length_string_type>(
28ab034a 414 array_alignment, *element_encoding, array_length);
d7bfb9b0
JG
415 }
416
417 return lttng::make_unique<lst::static_length_array_type>(
28ab034a 418 array_alignment, std::move(element_type), array_length);
d7bfb9b0
JG
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 */
28ab034a
JG
425lst::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,
cd9adb8b 430 const publish_field_fn& publish_field,
28ab034a
JG
431 lst::field_location::root lookup_root,
432 lst::field_location::elements& current_field_location_elements,
433 lsu::ctl_field_quirks quirks __attribute__((unused)))
d7bfb9b0
JG
434{
435 if (current >= end) {
f9a41357 436 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
28ab034a 437 "End of {} array reached unexpectedly during decoding", typeid(*current)));
d7bfb9b0
JG
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) {
f9a41357 446 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
28ab034a
JG
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));
d7bfb9b0
JG
450 }
451
452 if (length_uctl_type.atype != lttng_ust_ctl_atype_integer) {
f9a41357 453 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
28ab034a
JG
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));
d7bfb9b0
JG
457 }
458
459 nonstd::optional<enum lst::string_type::encoding> element_encoding;
460 if (element_uctl_type.atype == lttng_ust_ctl_atype_integer &&
28ab034a 461 element_uctl_type.u.basic.integer.encoding != lttng_ust_ctl_encode_none) {
d7bfb9b0
JG
462 /* Element represents a text character. */
463 element_encoding = ust_ctl_encoding_to_string_field_encoding(
28ab034a 464 element_uctl_type.u.basic.integer.encoding);
d7bfb9b0
JG
465 }
466
f9a41357 467 auto length_field_name = lttng::format("_{}_length", sequence_uctl_field.name);
28ab034a
JG
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);
d7bfb9b0 472
eda1aa02 473 lst::field_location::elements length_field_location_elements =
28ab034a 474 current_field_location_elements;
eda1aa02
JG
475 length_field_location_elements.emplace_back(length_field_name);
476
cd9adb8b
JG
477 lst::field_location length_field_location{ lookup_root,
478 std::move(length_field_location_elements) };
eda1aa02 479
d7bfb9b0 480 /* Publish an implicit length field _before_ the sequence field. */
28ab034a
JG
481 publish_field(lttng::make_unique<lst::field>(std::move(length_field_name),
482 std::move(length_type)));
d7bfb9b0
JG
483
484 *next_ust_ctl_field = current + 1;
485
486 if (element_encoding) {
487 const auto integer_element_size =
28ab034a 488 static_cast<const lst::integer_type&>(*element_type).size;
d7bfb9b0
JG
489
490 if (integer_element_size != 8) {
f9a41357 491 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
28ab034a
JG
492 "Unexpected legacy array element type: integer has encoding but size is not 8: size = {}",
493 integer_element_size));
d7bfb9b0
JG
494 }
495
496 /* Sequence is a dynamic-length string. */
28ab034a
JG
497 return lttng::make_unique<lst::dynamic_length_string_type>(
498 sequence_alignment, *element_encoding, std::move(length_field_location));
d7bfb9b0
JG
499 }
500
28ab034a
JG
501 return lttng::make_unique<lst::dynamic_length_array_type>(
502 sequence_alignment, std::move(element_type), std::move(length_field_location));
d7bfb9b0
JG
503}
504
505lst::type::cuptr create_sequence_nestable_type_from_ust_ctl_fields(
28ab034a
JG
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,
cd9adb8b
JG
510 const publish_field_fn& publish_field,
511 const lookup_field_fn& lookup_field,
28ab034a
JG
512 lst::field_location::root lookup_root,
513 lst::field_location::elements& current_field_location_elements,
514 lsu::ctl_field_quirks quirks)
d7bfb9b0
JG
515{
516 if (current >= end) {
f9a41357 517 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
28ab034a 518 "End of {} array reached unexpectedly during decoding", typeid(*current)));
d7bfb9b0
JG
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 &&
28ab034a 530 element_uctl_field.type.u.integer.encoding != lttng_ust_ctl_encode_none) {
d7bfb9b0
JG
531 /* Element represents a text character. */
532 element_encoding = ust_ctl_encoding_to_string_field_encoding(
28ab034a 533 element_uctl_field.type.u.integer.encoding);
d7bfb9b0
JG
534 }
535
536 /* next_ust_ctl_field is updated as needed. */
28ab034a
JG
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);
d7bfb9b0
JG
546
547 if (lttng_strnlen(sequence_uctl_field.type.u.sequence_nestable.length_name,
28ab034a
JG
548 sizeof(sequence_uctl_field.type.u.sequence_nestable.length_name)) ==
549 sizeof(sequence_uctl_field.type.u.sequence_nestable.length_name)) {
d7bfb9b0
JG
550 LTTNG_THROW_PROTOCOL_ERROR("Sequence length field name is not null terminated");
551 }
552
eda1aa02 553 lst::field_location::elements length_field_location_elements =
28ab034a 554 current_field_location_elements;
5c7248cd 555 length_field_location_elements.emplace_back(length_field_name);
eda1aa02 556
cd9adb8b
JG
557 lst::field_location length_field_location{ lookup_root,
558 std::move(length_field_location_elements) };
eda1aa02 559
6e01cdc6 560 /* Validate existence of length field (throws if not found). */
28ab034a 561 const auto& length_field = lookup_field(length_field_location);
6e01cdc6 562 const auto *integer_selector_field =
28ab034a 563 dynamic_cast<const lst::integer_type *>(&length_field.get_type());
6e01cdc6 564 if (!integer_selector_field) {
28ab034a
JG
565 LTTNG_THROW_PROTOCOL_ERROR(
566 "Invalid selector field type referenced from sequence: expected integer or enumeration");
6e01cdc6
JG
567 }
568
d7bfb9b0
JG
569 if (element_encoding) {
570 const auto integer_element_size =
28ab034a 571 static_cast<const lst::integer_type&>(*element_type).size;
d7bfb9b0
JG
572
573 if (integer_element_size != 8) {
f9a41357 574 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
28ab034a
JG
575 "Unexpected array element type: integer has encoding but size is not 8: size = {}",
576 integer_element_size));
d7bfb9b0
JG
577 }
578
579 /* Sqeuence is a dynamic-length string. */
28ab034a
JG
580 return lttng::make_unique<lst::dynamic_length_string_type>(
581 sequence_alignment, *element_encoding, std::move(length_field_location));
d7bfb9b0
JG
582 }
583
28ab034a
JG
584 return lttng::make_unique<lst::dynamic_length_array_type>(
585 sequence_alignment, std::move(element_type), std::move(length_field_location));
d7bfb9b0
JG
586}
587
28ab034a
JG
588lst::type::cuptr
589create_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)))
d7bfb9b0
JG
595{
596 if (current >= end) {
f9a41357 597 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
28ab034a 598 "End of {} array reached unexpectedly during decoding", typeid(*current)));
d7bfb9b0
JG
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) {
f9a41357 614 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
28ab034a
JG
615 "Only empty structures are supported by LTTng-UST: nr_fields = {}",
616 field_count));
d7bfb9b0
JG
617 }
618
619 *next_ust_ctl_field = current + 1;
620 return lttng::make_unique<lst::structure_type>(alignment, lst::structure_type::fields());
621}
622
45110cdd 623template <class VariantSelectorMappingIntegerType>
28ab034a
JG
624typename lst::variant_type<VariantSelectorMappingIntegerType>::choices
625create_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)
45110cdd
JG
635{
636 typename lst::variant_type<VariantSelectorMappingIntegerType>::choices choices;
28ab034a
JG
637 const auto& typed_enumeration =
638 static_cast<const lst::typed_enumeration_type<VariantSelectorMappingIntegerType>&>(
45110cdd
JG
639 selector_field.get_type());
640
641 for (unsigned int i = 0; i < choice_count; i++) {
642 create_field_from_ust_ctl_fields(
28ab034a
JG
643 current,
644 end,
645 session_attributes,
646 next_ust_ctl_field,
9d89db29 647 [&choices, &typed_enumeration, &selector_field, quirks](
28ab034a
JG
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()) {
f9a41357 680 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
28ab034a
JG
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);
45110cdd
JG
692
693 current = *next_ust_ctl_field;
694 }
695
696 return choices;
697}
698
28ab034a
JG
699lst::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,
cd9adb8b 704 const lookup_field_fn& lookup_field,
28ab034a
JG
705 lst::field_location::root lookup_root,
706 lst::field_location::elements& current_field_location_elements,
707 lsu::ctl_field_quirks quirks)
d7bfb9b0
JG
708{
709 if (current >= end) {
f9a41357 710 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
28ab034a 711 "End of {} array reached unexpectedly during decoding", typeid(*current)));
d7bfb9b0
JG
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
eda1aa02 731 lst::field_location::elements selector_field_location_elements =
28ab034a 732 current_field_location_elements;
eda1aa02
JG
733 selector_field_location_elements.emplace_back(tag_name);
734
cd9adb8b
JG
735 lst::field_location selector_field_location{ lookup_root,
736 std::move(selector_field_location_elements) };
eda1aa02 737
6e01cdc6 738 /* Validate existence of selector field (throws if not found). */
28ab034a 739 const auto& selector_field = lookup_field(selector_field_location);
45110cdd 740 const auto *enumeration_selector_type =
28ab034a 741 dynamic_cast<const lst::enumeration_type *>(&selector_field.get_type());
45110cdd 742 if (!enumeration_selector_type) {
28ab034a
JG
743 LTTNG_THROW_PROTOCOL_ERROR(
744 "Invalid selector field type referenced from variant: expected enumeration");
6e01cdc6
JG
745 }
746
45110cdd 747 const bool selector_is_signed = enumeration_selector_type->signedness_ ==
28ab034a 748 lst::integer_type::signedness::SIGNED;
45110cdd 749
d7bfb9b0 750 /* Choices follow. next_ust_ctl_field is updated as needed. */
45110cdd
JG
751 if (selector_is_signed) {
752 lst::variant_type<lst::signed_enumeration_type::mapping::range_t::range_integer_t>::
28ab034a
JG
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);
45110cdd
JG
764
765 return lttng::make_unique<lst::variant_type<int64_t>>(
28ab034a 766 alignment, std::move(selector_field_location), std::move(choices));
45110cdd 767 } else {
28ab034a
JG
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);
d7bfb9b0 781
45110cdd 782 return lttng::make_unique<lst::variant_type<uint64_t>>(
28ab034a 783 alignment, std::move(selector_field_location), std::move(choices));
d7bfb9b0 784 }
d7bfb9b0
JG
785}
786
28ab034a
JG
787lst::type::cuptr
788create_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,
cd9adb8b
JG
792 const publish_field_fn& publish_field,
793 const lookup_field_fn& lookup_field,
28ab034a
JG
794 lst::field_location::root lookup_root,
795 lst::field_location::elements& current_field_location_elements,
796 lsu::ctl_field_quirks quirks)
d7bfb9b0
JG
797{
798 switch (current->type.atype) {
799 case lttng_ust_ctl_atype_integer:
800 return create_integer_type_from_ust_ctl_fields(
28ab034a 801 current, end, session_attributes, next_ust_ctl_field, quirks);
d7bfb9b0
JG
802 case lttng_ust_ctl_atype_enum:
803 case lttng_ust_ctl_atype_enum_nestable:
804 return create_enumeration_type_from_ust_ctl_fields(
28ab034a 805 current, end, session_attributes, next_ust_ctl_field, quirks);
d7bfb9b0
JG
806 case lttng_ust_ctl_atype_float:
807 return create_floating_point_type_from_ust_ctl_fields(
28ab034a 808 current, end, session_attributes, next_ust_ctl_field, quirks);
d7bfb9b0
JG
809 case lttng_ust_ctl_atype_string:
810 return create_string_type_from_ust_ctl_fields(
28ab034a 811 current, end, session_attributes, next_ust_ctl_field, quirks);
d7bfb9b0 812 case lttng_ust_ctl_atype_array:
63c3462c 813 return create_array_type_from_ust_ctl_fields(
28ab034a 814 current, end, session_attributes, next_ust_ctl_field, quirks);
d7bfb9b0 815 case lttng_ust_ctl_atype_array_nestable:
28ab034a
JG
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);
d7bfb9b0 826 case lttng_ust_ctl_atype_sequence:
28ab034a
JG
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);
d7bfb9b0 835 case lttng_ust_ctl_atype_sequence_nestable:
28ab034a
JG
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);
d7bfb9b0
JG
846 case lttng_ust_ctl_atype_struct:
847 case lttng_ust_ctl_atype_struct_nestable:
848 return create_structure_field_from_ust_ctl_fields(
28ab034a 849 current, end, session_attributes, next_ust_ctl_field, quirks);
d7bfb9b0
JG
850 case lttng_ust_ctl_atype_variant:
851 case lttng_ust_ctl_atype_variant_nestable:
28ab034a
JG
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);
d7bfb9b0 860 default:
28ab034a 861 LTTNG_THROW_PROTOCOL_ERROR(
f9a41357
JG
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)));
d7bfb9b0
JG
867 }
868}
869
870void create_field_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
28ab034a
JG
871 const lttng_ust_ctl_field *end,
872 const session_attributes& session_attributes,
873 const lttng_ust_ctl_field **next_ust_ctl_field,
cd9adb8b
JG
874 const publish_field_fn& publish_field,
875 const lookup_field_fn& lookup_field,
28ab034a
JG
876 lst::field_location::root lookup_root,
877 lst::field_location::elements& current_field_location_elements,
878 lsu::ctl_field_quirks quirks)
d7bfb9b0
JG
879{
880 LTTNG_ASSERT(current < end);
881
882 if (lttng_strnlen(current->name, sizeof(current->name)) == sizeof(current->name)) {
883 LTTNG_THROW_PROTOCOL_ERROR(
f9a41357 884 lttng::format("Name of {} is not null-terminated", typeid(*current)));
28ab034a
JG
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)));
d7bfb9b0
JG
898}
899
28ab034a
JG
900std::vector<lst::field::cuptr>::iterator
901lookup_field_in_vector(std::vector<lst::field::cuptr>& fields, const lst::field_location& location)
da9dd521
JG
902{
903 if (location.elements_.size() != 1) {
f9a41357 904 LTTNG_THROW_ERROR(lttng::format(
28ab034a
JG
905 "Unexpected field location received during field look-up: location = {}",
906 location));
da9dd521
JG
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 */
28ab034a
JG
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 });
da9dd521
JG
920
921 if (field_it == fields.end()) {
922 LTTNG_THROW_PROTOCOL_ERROR(
f9a41357 923 lttng::format("Failed to look-up field: location = {}", location));
da9dd521
JG
924 }
925
926 return field_it;
927}
928
d7bfb9b0
JG
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 */
28ab034a
JG
937std::vector<lst::field::cuptr>
938create_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)
d7bfb9b0
JG
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{
28ab034a
JG
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 };
eda1aa02
JG
952 /* Location of field being created. */
953 lst::field_location::elements current_field_location_elements;
d7bfb9b0
JG
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 */
6e01cdc6 967 create_field_from_ust_ctl_fields(
28ab034a
JG
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);
d7bfb9b0
JG
985
986 current = next_field;
987 }
988
989 return fields;
990}
991} /* namespace */
992
28ab034a
JG
993std::vector<lst::field::cuptr>
994lsu::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)
d7bfb9b0 999{
63c3462c 1000 return create_fields_from_ust_ctl_fields(
28ab034a 1001 session, fields, fields + field_count, lookup_root, quirks);
d7bfb9b0 1002}
This page took 0.087017 seconds and 4 git commands to generate.