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