sessiond: validate existence of field reference received from LTTng-UST
[lttng-tools.git] / src / bin / lttng-sessiond / field.hpp
CommitLineData
0220be14
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#ifndef LTTNG_FIELD_H
9#define LTTNG_FIELD_H
10
6e01cdc6
JG
11#include <common/format.hpp>
12
13#include <vendor/optional.hpp>
14
0220be14
JG
15#include <memory>
16#include <string>
17#include <type_traits>
18#include <vector>
19
0220be14
JG
20namespace lttng {
21namespace sessiond {
22namespace trace {
23
24class field_visitor;
25class type_visitor;
26
24ed18f2
JG
27enum class byte_order {
28 BIG_ENDIAN_,
29 LITTLE_ENDIAN_,
30};
31
eda1aa02
JG
32class field_location {
33public:
34 enum class root {
35 PACKET_HEADER,
36 PACKET_CONTEXT,
37 EVENT_RECORD_HEADER,
38 EVENT_RECORD_COMMON_CONTEXT,
39 EVENT_RECORD_SPECIFIC_CONTEXT,
40 EVENT_RECORD_PAYLOAD,
41 };
42
43 using elements = std::vector<std::string>;
44
45 field_location(root lookup_root, elements elements);
46 bool operator==(const field_location& other) const noexcept;
47
48 const root root_;
49 const elements elements_;
50};
51
0220be14
JG
52/*
53 * Field, and the various field types, represents fields as exposed by the
54 * LTTng tracers. These classes do not attempt to describe the complete spectrum of the CTF
55 * specification.
56 */
57
58class type {
59public:
60 using cuptr = std::unique_ptr<const type>;
61
62 static byte_order reverse_byte_order(byte_order byte_order) noexcept;
63
64 bool operator==(const type& other) const noexcept;
65 bool operator!=(const type& other) const noexcept;
66 virtual ~type();
67 virtual void accept(type_visitor& visitor) const = 0;
68
69 const unsigned int alignment;
70
71protected:
72 type(unsigned int alignment);
73
74private:
75 virtual bool _is_equal(const type& rhs) const noexcept = 0;
76};
77
78class field {
79public:
80 using cuptr = std::unique_ptr<const field>;
81
82 field(std::string name, type::cuptr type);
83 void accept(field_visitor& visitor) const;
84 bool operator==(const field& other) const noexcept;
85
86 const std::string name;
87 const type::cuptr _type;
88};
89
90class integer_type : public type {
91public:
92 enum class signedness {
93 SIGNED,
94 UNSIGNED,
95 };
96
97 enum class base {
98 BINARY = 2,
99 OCTAL = 8,
100 DECIMAL = 10,
101 HEXADECIMAL = 16,
102 };
103
e7360180
JG
104 enum class role {
105 DEFAULT_CLOCK_TIMESTAMP,
106 /* Packet header field class specific roles. */
107 DATA_STREAM_CLASS_ID,
108 DATA_STREAM_ID,
109 PACKET_MAGIC_NUMBER,
110 /* Packet context field class specific roles. */
111 DISCARDED_EVENT_RECORD_COUNTER_SNAPSHOT,
112 PACKET_CONTENT_LENGTH,
113 PACKET_END_DEFAULT_CLOCK_TIMESTAMP,
114 PACKET_SEQUENCE_NUMBER,
115 PACKET_TOTAL_LENGTH,
116 /* Event record field class roles. */
117 EVENT_RECORD_CLASS_ID,
118 };
119
120 using roles = std::vector<role>;
121
0220be14
JG
122 integer_type(unsigned int alignment,
123 byte_order byte_order,
124 unsigned int size,
125 signedness signedness,
e7360180
JG
126 base base,
127 roles roles = {});
0220be14
JG
128
129 virtual void accept(type_visitor& visitor) const override;
130
131 const enum byte_order byte_order;
132 const unsigned int size;
65cd3c0c
JG
133 /*
134 * signedness and base are suffixed with '_' to work-around a bug in older
135 * GCCs (before 6) that do not recognize hidden/shadowed enumeration as valid
136 * nested-name-specifiers.
137 */
138 const signedness signedness_;
139 const base base_;
e7360180 140 const roles roles_;
0220be14
JG
141
142protected:
143 virtual bool _is_equal(const type& other) const noexcept override;
144};
145
146class floating_point_type : public type {
147public:
148 floating_point_type(unsigned int alignment,
149 byte_order byte_order,
150 unsigned int exponent_digits,
151 unsigned int mantissa_digits);
152
153 virtual void accept(type_visitor& visitor) const override final;
154
155 const enum byte_order byte_order;
156 const unsigned int exponent_digits;
157 const unsigned int mantissa_digits;
158
159private:
160 virtual bool _is_equal(const type& other) const noexcept override final;
161};
162
163class enumeration_type : public integer_type {
164protected:
165 enumeration_type(unsigned int alignment,
166 enum byte_order byte_order,
167 unsigned int size,
168 enum signedness signedness,
e7360180
JG
169 enum base base,
170 integer_type::roles roles = {});
0220be14
JG
171
172 virtual void accept(type_visitor& visitor) const = 0;
173};
174
175namespace details {
176template <class MappingIntegerType>
177class enumeration_mapping_range {
178public:
179 using range_integer_t = MappingIntegerType;
180
181 enumeration_mapping_range(MappingIntegerType in_begin, MappingIntegerType in_end) :
182 begin{in_begin}, end{in_end}
183 {
184 }
185
186 const range_integer_t begin, end;
187};
188
189template <class MappingIntegerType>
190bool operator==(const enumeration_mapping_range<MappingIntegerType>& lhs,
191 const enumeration_mapping_range<MappingIntegerType>& rhs) noexcept
192{
193 return lhs.begin == rhs.begin && lhs.end == rhs.end;
194}
195
196template <class MappingIntegerType>
197class enumeration_mapping {
198public:
199 using range_t = enumeration_mapping_range<MappingIntegerType>;
200
201 enumeration_mapping(const enumeration_mapping<MappingIntegerType>& other) = delete;
202 enumeration_mapping(const enumeration_mapping<MappingIntegerType>&& other) :
203 name{std::move(other.name)}, range{other.range}
204 {
205 }
206
207 /* Mapping with an implicit value. */
208 enumeration_mapping(std::string in_name) : name{std::move(in_name)}
209 {
210 }
211
212 enumeration_mapping(std::string in_name, range_t in_range) : name{std::move(in_name)}, range{in_range}
213 {
214 }
215
216 const std::string name;
217 const nonstd::optional<range_t> range;
218};
219
220template <class MappingIntegerType>
221bool operator==(const enumeration_mapping<MappingIntegerType>& lhs,
222 const enumeration_mapping<MappingIntegerType>& rhs) noexcept
223{
224 return lhs.name == rhs.name && lhs.range == rhs.range;
225}
226} /* namespace details */
227
228template <class MappingIntegerType>
229class typed_enumeration_type : public enumeration_type {
230public:
231 using mapping = details::enumeration_mapping<MappingIntegerType>;
232 using mappings = std::vector<mapping>;
233
234 static_assert(std::is_integral<MappingIntegerType>::value &&
235 sizeof(MappingIntegerType) == 8,
236 "MappingIntegerType must be either int64_t or uint64_t");
237
238 typed_enumeration_type(unsigned int in_alignment,
239 enum byte_order in_byte_order,
240 unsigned int in_size,
0220be14 241 enum base in_base,
e7360180
JG
242 const std::shared_ptr<const mappings>& in_mappings,
243 integer_type::roles in_roles = {}) :
0220be14
JG
244 enumeration_type(in_alignment,
245 in_byte_order,
246 in_size,
e7360180
JG
247 std::is_signed<MappingIntegerType>::value ?
248 integer_type::signedness::SIGNED :
249 integer_type::signedness::UNSIGNED,
250 in_base,
251 std::move(in_roles)),
0220be14
JG
252 _mappings{std::move(in_mappings)}
253 {
254 }
255
256 virtual void accept(type_visitor& visitor) const override final;
257
258 const std::shared_ptr<const mappings> _mappings;
259
260private:
261 virtual bool _is_equal(const type& base_other) const noexcept override final
262 {
263 const auto& other = static_cast<const typed_enumeration_type<MappingIntegerType>&>(
264 base_other);
265
266 return integer_type::_is_equal(base_other) && *this->_mappings == *other._mappings;
267 }
268};
269
270/* Aliases for all allowed enumeration mapping types. */
271using signed_enumeration_type = typed_enumeration_type<int64_t>;
272using unsigned_enumeration_type = typed_enumeration_type<uint64_t>;
273
274class array_type : public type {
275public:
276 array_type(unsigned int alignment, type::cuptr element_type);
277
d7bfb9b0 278 const type::cuptr element_type;
0220be14
JG
279
280protected:
281 virtual bool _is_equal(const type& base_other) const noexcept override;
282};
283
284class static_length_array_type : public array_type {
285public:
286 static_length_array_type(unsigned int alignment,
287 type::cuptr element_type,
288 uint64_t in_length);
289
290 virtual void accept(type_visitor& visitor) const override final;
291
292 const uint64_t length;
293
294private:
295 virtual bool _is_equal(const type& base_other) const noexcept override final;
296};
297
298class dynamic_length_array_type : public array_type {
299public:
300 dynamic_length_array_type(unsigned int alignment,
301 type::cuptr element_type,
eda1aa02 302 field_location length_field_location);
0220be14
JG
303
304 virtual void accept(type_visitor& visitor) const override final;
305
eda1aa02 306 const field_location length_field_location;
0220be14
JG
307
308private:
309 virtual bool _is_equal(const type& base_other) const noexcept override final;
310};
311
e7360180
JG
312class static_length_blob_type : public type {
313public:
314 enum class role {
315 /* Packet header field class specific role. */
316 TRACE_CLASS_UUID,
317 };
318
319 using roles = std::vector<role>;
320
321 static_length_blob_type(unsigned int alignment, uint64_t in_length_bytes, roles roles = {});
322
323 virtual void accept(type_visitor& visitor) const override final;
324
325 const uint64_t length_bytes;
326 const roles roles_;
327
328private:
329 virtual bool _is_equal(const type& base_other) const noexcept override final;
330};
331
332class dynamic_length_blob_type : public type {
333public:
eda1aa02 334 dynamic_length_blob_type(unsigned int alignment, field_location length_field_location);
e7360180
JG
335
336 virtual void accept(type_visitor& visitor) const override final;
337
eda1aa02 338 const field_location length_field_location;
e7360180
JG
339
340private:
341 virtual bool _is_equal(const type& base_other) const noexcept override final;
342};
343
0220be14
JG
344class string_type : public type {
345public:
346 enum class encoding {
347 ASCII,
348 UTF8,
349 };
350
351 string_type(unsigned int alignment, enum encoding encoding);
352
65cd3c0c
JG
353 /*
354 * encoding is suffixed with '_' to work-around a bug in older
355 * GCCs (before 6) that do not recognize hidden/shadowed enumeration as valid
356 * nested-name-specifiers.
357 */
358 const encoding encoding_;
0220be14
JG
359
360protected:
361 virtual bool _is_equal(const type& base_other) const noexcept override;
362};
363
364class static_length_string_type : public string_type {
365public:
366 static_length_string_type(
367 unsigned int alignment, enum encoding in_encoding, uint64_t length);
368 virtual void accept(type_visitor& visitor) const override final;
369
370 const uint64_t length;
371
372private:
373 virtual bool _is_equal(const type& base_other) const noexcept override final;
374};
375
376class dynamic_length_string_type : public string_type {
377public:
378 dynamic_length_string_type(unsigned int alignment,
379 enum encoding in_encoding,
eda1aa02 380 field_location length_field_location);
0220be14
JG
381 virtual void accept(type_visitor& visitor) const override final;
382
eda1aa02 383 const field_location length_field_location;
0220be14
JG
384
385private:
386 virtual bool _is_equal(const type& base_other) const noexcept override final;
387};
388
389class null_terminated_string_type : public string_type {
390public:
391 null_terminated_string_type(unsigned int alignment, enum encoding in_encoding);
392 virtual void accept(type_visitor& visitor) const override final;
393};
394
395class structure_type : public type {
396public:
397 using fields = std::vector<field::cuptr>;
398
399 structure_type(unsigned int alignment, fields in_fields);
400
401 virtual void accept(type_visitor& visitor) const override final;
402
403 const fields _fields;
404
405private:
406 virtual bool _is_equal(const type& base_other) const noexcept override final;
407};
408
409class variant_type : public type {
410public:
411 using choices = std::vector<field::cuptr>;
412
eda1aa02
JG
413 variant_type(unsigned int alignment,
414 field_location selector_field_location,
415 choices in_choices);
0220be14
JG
416
417 virtual void accept(type_visitor& visitor) const override final;
418
eda1aa02 419 const field_location selector_field_location;
0220be14 420 const choices _choices;
eda1aa02 421;
0220be14
JG
422
423private:
424 virtual bool _is_equal(const type& base_other) const noexcept override final;
425};
426
427class field_visitor {
428public:
429 virtual ~field_visitor() = default;
430 virtual void visit(const field& field) = 0;
431
432protected:
433 field_visitor() = default;
434};
435
436class type_visitor {
437public:
438 virtual ~type_visitor() = default;
439 virtual void visit(const integer_type& type) = 0;
440 virtual void visit(const floating_point_type& type) = 0;
441 virtual void visit(const signed_enumeration_type& type) = 0;
442 virtual void visit(const unsigned_enumeration_type& type) = 0;
443 virtual void visit(const static_length_array_type& type) = 0;
444 virtual void visit(const dynamic_length_array_type& type) = 0;
e7360180
JG
445 virtual void visit(const static_length_blob_type& type) = 0;
446 virtual void visit(const dynamic_length_blob_type& type) = 0;
0220be14
JG
447 virtual void visit(const null_terminated_string_type& type) = 0;
448 virtual void visit(const static_length_string_type& type) = 0;
449 virtual void visit(const dynamic_length_string_type& type) = 0;
450 virtual void visit(const structure_type& type) = 0;
451 virtual void visit(const variant_type& type) = 0;
452
453protected:
454 type_visitor() = default;
455};
456
457} /* namespace trace */
458} /* namespace sessiond */
459} /* namespace lttng */
460
6e01cdc6
JG
461/*
462 * Due to a bug in g++ < 7.1, this specialization must be enclosed in the fmt namespace,
463 * see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480.
464 */
465namespace fmt {
466template <>
467struct formatter<lttng::sessiond::trace::field_location> : formatter<std::string> {
468 template <typename FormatCtx>
469 typename FormatCtx::iterator format(
470 const lttng::sessiond::trace::field_location& location, FormatCtx& ctx)
471 {
472 std::string location_str{"["};
473
474 switch (location.root_) {
475 case lttng::sessiond::trace::field_location::root::PACKET_HEADER:
476 location_str += "\"packet-header\"";
477 break;
478 case lttng::sessiond::trace::field_location::root::PACKET_CONTEXT:
479 location_str += "\"packet-context\"";
480 break;
481 case lttng::sessiond::trace::field_location::root::EVENT_RECORD_HEADER:
482 location_str += "\"event-record-header\"";
483 break;
484 case lttng::sessiond::trace::field_location::root::EVENT_RECORD_COMMON_CONTEXT:
485 location_str += "\"event-record-common-context\"";
486 break;
487 case lttng::sessiond::trace::field_location::root::EVENT_RECORD_SPECIFIC_CONTEXT:
488 location_str += "\"event-record-specific-context\"";
489 break;
490 case lttng::sessiond::trace::field_location::root::EVENT_RECORD_PAYLOAD:
491 location_str += "\"event-record-payload\"";
492 break;
493 }
494
495 for (const auto &name : location.elements_) {
496 location_str += ", \"" + name + "\"";
497 }
498
499 location_str += "]";
500 return format_to(ctx.out(), location_str);
501 }
502};
503} /* namespace fmt */
504
0220be14 505#endif /* LTTNG_FIELD_H */
This page took 0.045361 seconds and 4 git commands to generate.