vscode: Add configurations to run the executables under the debugger
[lttng-tools.git] / src / bin / lttng-sessiond / ctf2-trace-class-visitor.cpp
1 /*
2 * Copyright (C) 2022 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 * Copyright (C) 2022 Simon Marchi <simon.marchi@efficios.com>
4 *
5 * SPDX-License-Identifier: GPL-2.0-only
6 *
7 */
8
9 #include "clock-class.hpp"
10 #include "ctf2-trace-class-visitor.hpp"
11
12 #include <common/exception.hpp>
13 #include <common/format.hpp>
14
15 #include <vendor/nlohmann/json.hpp>
16
17 #include <algorithm>
18 #include <utility>
19
20 namespace lsc = lttng::sessiond::ctf2;
21 namespace lst = lttng::sessiond::trace;
22
23 namespace json = nlohmann;
24
25 namespace {
26 const unsigned int spaces_per_indent = 2;
27 const std::string record_separator = "\x1e";
28
29 json::json make_json_fragment(const char *type)
30 {
31 return { { "type", type } };
32 }
33
34 json::json to_json(const lst::field_location& location)
35 {
36 json::json location_array;
37
38 switch (location.root_) {
39 case lst::field_location::root::PACKET_HEADER:
40 location_array.push_back("packet-header");
41 break;
42 case lst::field_location::root::PACKET_CONTEXT:
43 location_array.push_back("packet-context");
44 break;
45 case lst::field_location::root::EVENT_RECORD_HEADER:
46 location_array.push_back("event-record-header");
47 break;
48 case lst::field_location::root::EVENT_RECORD_COMMON_CONTEXT:
49 location_array.push_back("event-record-common-context");
50 break;
51 case lst::field_location::root::EVENT_RECORD_SPECIFIC_CONTEXT:
52 location_array.push_back("event-record-specific-context");
53 break;
54 case lst::field_location::root::EVENT_RECORD_PAYLOAD:
55 location_array.push_back("event-record-payload");
56 break;
57 }
58
59 std::copy(location.elements_.begin(),
60 location.elements_.end(),
61 std::back_inserter(location_array));
62 return location_array;
63 }
64
65 const char *get_role_name(lst::integer_type::role role)
66 {
67 switch (role) {
68 case lst::integer_type::role::DEFAULT_CLOCK_TIMESTAMP:
69 return "default-clock-timestamp";
70 case lst::integer_type::role::DATA_STREAM_CLASS_ID:
71 return "data-stream-class-id";
72 case lst::integer_type::role::DATA_STREAM_ID:
73 return "data-stream-id";
74 case lst::integer_type::role::PACKET_MAGIC_NUMBER:
75 return "packet-magic-number";
76 case lst::integer_type::role::DISCARDED_EVENT_RECORD_COUNTER_SNAPSHOT:
77 return "discarded-event-record-counter-snapshot";
78 case lst::integer_type::role::PACKET_CONTENT_LENGTH:
79 return "packet-content-length";
80 case lst::integer_type::role::PACKET_END_DEFAULT_CLOCK_TIMESTAMP:
81 return "packet-end-default-clock-timestamp";
82 case lst::integer_type::role::PACKET_SEQUENCE_NUMBER:
83 return "packet-sequence-number";
84 case lst::integer_type::role::PACKET_TOTAL_LENGTH:
85 return "packet-total-length";
86 case lst::integer_type::role::EVENT_RECORD_CLASS_ID:
87 return "event-record-class-id";
88 default:
89 abort();
90 }
91 }
92
93 const char *get_role_name(lst::static_length_blob_type::role role)
94 {
95 switch (role) {
96 case lst::static_length_blob_type::role::METADATA_STREAM_UUID:
97 return "metadata-stream-uuid";
98 default:
99 abort();
100 }
101 }
102
103 namespace ctf2 {
104 class trace_environment_visitor : public lst::trace_class_environment_visitor {
105 public:
106 trace_environment_visitor() = default; /* NOLINT clang-tidy 14 identifies this as a move
107 constructor. */
108
109 void visit(const lst::environment_field<int64_t>& field) override
110 {
111 _visit(field);
112 }
113
114 void visit(const lst::environment_field<const char *>& field) override
115 {
116 _visit(field);
117 }
118
119 /* Only call once. */
120 json::json move_fragment()
121 {
122 return std::move(_environment);
123 }
124
125 private:
126 template <class FieldType>
127 void _visit(const FieldType& field)
128 {
129 _environment[field.name] = field.value;
130 }
131
132 json::json _environment;
133 };
134
135 class field_visitor : public lttng::sessiond::trace::field_visitor,
136 public lttng::sessiond::trace::type_visitor {
137 public:
138 field_visitor() = default; /* NOLINT clang-tidy 14 identifies this as a move constructor. */
139
140 /* Only call once. */
141 json::json move_fragment()
142 {
143 return std::move(_fragment);
144 }
145
146 private:
147 void visit(const lst::field& field) final
148 {
149 field_visitor field_type_visitor;
150 field.get_type().accept(field_type_visitor);
151
152 _fragment["name"] = field.name;
153 _fragment["field-class"] = field_type_visitor.move_fragment();
154 }
155
156 void visit(const lst::integer_type& type) final
157 {
158 _fragment["type"] = type.signedness_ == lst::integer_type::signedness::SIGNED ?
159 "fixed-length-signed-integer" :
160 "fixed-length-unsigned-integer";
161 _fragment["length"] = type.size;
162 _fragment["byte-order"] = type.byte_order == lst::byte_order::BIG_ENDIAN_ ?
163 "big-endian" :
164 "little-endian";
165 _fragment["alignment"] = type.alignment;
166 _fragment["preferred-display-base"] = (unsigned int) type.base_;
167
168 if (type.roles_.size() > 0) {
169 json::json role_array = json::json::array();
170
171 for (const auto role : type.roles_) {
172 role_array.push_back(get_role_name(role));
173 }
174
175 _fragment["roles"] = std::move(role_array);
176 }
177 }
178
179 void visit(const lst::floating_point_type& type) final
180 {
181 _fragment["type"] = "fixed-length-floating-point-number";
182 _fragment["length"] = type.exponent_digits + type.mantissa_digits;
183 _fragment["byte-order"] = type.byte_order == lst::byte_order::BIG_ENDIAN_ ?
184 "big-endian" :
185 "little-endian";
186 _fragment["alignment"] = type.alignment;
187 }
188
189 template <class EnumerationType>
190 void visit_enumeration(const EnumerationType& type)
191 {
192 _fragment["type"] =
193 std::is_signed<
194 typename EnumerationType::mapping::range_t::range_integer_t>::value ?
195 "fixed-length-signed-enumeration" :
196 "fixed-length-unsigned-enumeration";
197 _fragment["length"] = type.size;
198 _fragment["byte-order"] = type.byte_order == lst::byte_order::BIG_ENDIAN_ ?
199 "big-endian" :
200 "little-endian";
201 _fragment["alignment"] = type.alignment;
202 _fragment["preferred-display-base"] = (unsigned int) type.base_;
203
204 if (type.roles_.size() > 0) {
205 if (std::is_signed<typename EnumerationType::mapping::range_t::
206 range_integer_t>::value) {
207 LTTNG_THROW_ERROR(
208 fmt::format("Failed to serialize {}: unexpected role",
209 _fragment["type"]));
210 }
211
212 auto role_array = json::json::array();
213
214 for (const auto role : type.roles_) {
215 role_array.push_back(get_role_name(role));
216 }
217
218 _fragment["roles"] = std::move(role_array);
219 }
220
221 if (type.mappings_->size() < 1) {
222 LTTNG_THROW_ERROR(fmt::format(
223 "Failed to serialize {}: enumeration must have at least one mapping",
224 _fragment["type"]));
225 }
226
227 json::json mappings_value;
228 for (const auto& mapping : *type.mappings_) {
229 mappings_value[mapping.name] = { { mapping.range.begin,
230 mapping.range.end } };
231 }
232
233 _fragment["mappings"] = std::move(mappings_value);
234 }
235
236 void visit(const lst::signed_enumeration_type& type) final
237 {
238 visit_enumeration(type);
239 }
240
241 void visit(const lst::unsigned_enumeration_type& type) final
242 {
243 visit_enumeration(type);
244 }
245
246 void visit(const lst::static_length_array_type& type) final
247 {
248 _fragment["type"] = "static-length-array";
249
250 ::ctf2::field_visitor element_visitor;
251 type.element_type->accept(element_visitor);
252 _fragment["element-field-class"] = element_visitor.move_fragment();
253
254 if (type.alignment != 0) {
255 _fragment["minimum-alignment"] = type.alignment;
256 }
257
258 _fragment["length"] = type.length;
259 }
260
261 void visit(const lst::dynamic_length_array_type& type) final
262 {
263 _fragment["type"] = "dynamic-length-array";
264
265 ::ctf2::field_visitor element_visitor;
266 type.element_type->accept(element_visitor);
267 _fragment["element-field-class"] = element_visitor.move_fragment();
268
269 if (type.alignment != 0) {
270 _fragment["minimum-alignment"] = type.alignment;
271 }
272
273 _fragment["length-field-location"] = to_json(type.length_field_location);
274 }
275
276 void visit(const lst::static_length_blob_type& type) final
277 {
278 _fragment["type"] = "static-length-blob";
279 _fragment["length"] = type.length_bytes;
280
281 if (type.roles_.size() > 0) {
282 auto role_array = json::json::array();
283
284 for (const auto role : type.roles_) {
285 role_array.push_back(get_role_name(role));
286 }
287
288 _fragment["roles"] = std::move(role_array);
289 }
290 }
291
292 void visit(const lst::dynamic_length_blob_type& type) final
293 {
294 _fragment["type"] = "dynamic-length-blob";
295 _fragment["length-field-location"] = to_json(type.length_field_location);
296 }
297
298 void visit(const lst::null_terminated_string_type& type __attribute__((unused))) final
299 {
300 _fragment["type"] = "null-terminated-string";
301 }
302
303 void visit(const lst::structure_type& type) final
304 {
305 _fragment["type"] = "structure";
306
307 if (type.alignment != 0) {
308 _fragment["minimum-alignment"] = type.alignment;
309 }
310
311 auto member_classes_value = json::json::array();
312 for (const auto& field : type.fields_) {
313 ::ctf2::field_visitor member_visitor;
314 json::json member_class;
315
316 field->accept(member_visitor);
317 member_classes_value.emplace_back(member_visitor.move_fragment());
318 }
319
320 _fragment["member-classes"] = std::move(member_classes_value);
321 }
322
323 template <class MappingIntegerType>
324 void visit_variant(const lst::variant_type<MappingIntegerType>& type)
325 {
326 _fragment["type"] = "variant";
327 _fragment["selector-field-location"] = to_json(type.selector_field_location);
328
329 auto options_value = json::json::array();
330 for (const auto& option : type.choices_) {
331 ::ctf2::field_visitor option_visitor;
332 json::json member_class;
333
334 /* TODO missing selector-field-range. */
335 member_class["selector-field-ranges"] = { { option.first.range.begin,
336 option.first.range.end } };
337 option.second->accept(option_visitor);
338 member_class["field-class"] = option_visitor.move_fragment();
339 options_value.emplace_back(std::move(member_class));
340 }
341
342 _fragment["options"] = std::move(options_value);
343 }
344
345 void visit(const lst::variant_type<int64_t>& type) final
346 {
347 visit_variant(type);
348 }
349
350 void visit(const lst::variant_type<uint64_t>& type) final
351 {
352 visit_variant(type);
353 }
354
355 void visit(const lst::static_length_string_type& type) final
356 {
357 _fragment["type"] = "static-length-string";
358 _fragment["length"] = type.length;
359 }
360
361 void visit(const lst::dynamic_length_string_type& type) final
362 {
363 _fragment["type"] = "dynamic-length-string";
364 _fragment["length-field-location"] = to_json(type.length_field_location);
365 }
366
367 json::json _fragment;
368 };
369 } /* namespace ctf2 */
370
371 }; /* namespace */
372
373 lsc::trace_class_visitor::trace_class_visitor(
374 lsc::append_metadata_fragment_function append_metadata_fragment) :
375 _append_metadata_fragment(std::move(append_metadata_fragment))
376 {
377 }
378
379 void lsc::trace_class_visitor::visit(const lst::trace_class& trace_class)
380 {
381 {
382 auto preamble_fragment = make_json_fragment("preamble");
383
384 preamble_fragment["version"] = 2;
385 preamble_fragment["uuid"] = trace_class.uuid;
386 append_metadata_fragment(preamble_fragment);
387 }
388
389 auto trace_class_fragment = make_json_fragment("trace-class");
390
391 ::ctf2::trace_environment_visitor environment_visitor;
392 trace_class.accept(environment_visitor);
393 trace_class_fragment["environment"] = environment_visitor.move_fragment();
394
395 const auto packet_header = trace_class.packet_header();
396 if (packet_header) {
397 ::ctf2::field_visitor field_visitor;
398
399 packet_header->accept(field_visitor);
400 trace_class_fragment["packet-header-field-class"] = field_visitor.move_fragment();
401 }
402
403 append_metadata_fragment(trace_class_fragment);
404 }
405
406 void lsc::trace_class_visitor::visit(const lst::clock_class& clock_class)
407 {
408 auto clock_class_fragment = make_json_fragment("clock-class");
409
410 json::json offset;
411 offset.update({ { "seconds", clock_class.offset / clock_class.frequency },
412 { "cycles", clock_class.offset % clock_class.frequency } });
413
414 clock_class_fragment.update({ { "name", clock_class.name },
415 { "description", clock_class.description },
416 { "frequency", clock_class.frequency },
417 { "offset", std::move(offset) } });
418
419 if (clock_class.uuid) {
420 clock_class_fragment["uuid"] = *clock_class.uuid;
421 }
422
423 append_metadata_fragment(clock_class_fragment);
424 }
425
426 void lsc::trace_class_visitor::visit(const lst::stream_class& stream_class)
427 {
428 auto stream_class_fragment = make_json_fragment("data-stream-class");
429
430 stream_class_fragment["id"] = stream_class.id;
431 if (stream_class.default_clock_class_name) {
432 stream_class_fragment["default-clock-class-name"] =
433 *stream_class.default_clock_class_name;
434 }
435
436 const auto packet_context = stream_class.packet_context();
437 if (packet_context) {
438 ::ctf2::field_visitor visitor;
439
440 packet_context->accept(visitor);
441 stream_class_fragment["packet-context-field-class"] = visitor.move_fragment();
442 }
443
444 const auto event_header = stream_class.event_header();
445 if (event_header) {
446 ::ctf2::field_visitor visitor;
447
448 event_header->accept(visitor);
449 stream_class_fragment["event-record-header-field-class"] = visitor.move_fragment();
450 }
451
452 const auto event_context = stream_class.event_context();
453 if (event_context) {
454 ::ctf2::field_visitor visitor;
455
456 event_context->accept(visitor);
457 stream_class_fragment["event-record-common-context-field-class"] =
458 visitor.move_fragment();
459 }
460
461 append_metadata_fragment(stream_class_fragment);
462 }
463
464 void lsc::trace_class_visitor::visit(const lst::event_class& event_class)
465 {
466 auto event_class_fragment = make_json_fragment("event-record-class");
467
468 event_class_fragment["id"] = event_class.id;
469 event_class_fragment["data-stream-class-id"] = event_class.stream_class_id;
470 event_class_fragment["name"] = event_class.name;
471
472 if (event_class.payload) {
473 ::ctf2::field_visitor visitor;
474
475 event_class.payload->accept(visitor);
476 event_class_fragment["payload-field-class"] = visitor.move_fragment();
477 }
478
479 append_metadata_fragment(event_class_fragment);
480 }
481
482 void lsc::trace_class_visitor::append_metadata_fragment(const nlohmann::json& fragment) const
483 {
484 _append_metadata_fragment(record_separator + fragment.dump(spaces_per_indent).c_str());
485 }
This page took 0.038119 seconds and 4 git commands to generate.