Commit | Line | Data |
---|---|---|
e5aa0be3 PP |
1 | # The MIT License (MIT) |
2 | # | |
4a90140d | 3 | # Copyright (c) 2014-2020 Philippe Proulx <pproulx@efficios.com> |
e5aa0be3 | 4 | # |
1378f213 PP |
5 | # Permission is hereby granted, free of charge, to any person obtaining |
6 | # a copy of this software and associated documentation files (the | |
7 | # "Software"), to deal in the Software without restriction, including | |
8 | # without limitation the rights to use, copy, modify, merge, publish, | |
9 | # distribute, sublicense, and/or sell copies of the Software, and to | |
10 | # permit persons to whom the Software is furnished to do so, subject to | |
11 | # the following conditions: | |
e5aa0be3 | 12 | # |
1378f213 PP |
13 | # The above copyright notice and this permission notice shall be |
14 | # included in all copies or substantial portions of the Software. | |
e5aa0be3 | 15 | # |
1378f213 PP |
16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
17 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
18 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
19 | # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
20 | # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | |
21 | # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | |
22 | # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
e5aa0be3 | 23 | |
4810b707 | 24 | import barectf.tsdl182gen as barectf_tsdl182gen |
8c7c6ed2 | 25 | import barectf.template as barectf_template |
4810b707 PP |
26 | import barectf.config as barectf_config |
27 | import barectf.version as barectf_version | |
acfb8213 | 28 | import itertools |
e5aa0be3 | 29 | import datetime |
d6483c83 | 30 | import collections |
acfb8213 | 31 | import copy |
4810b707 PP |
32 | |
33 | ||
d6483c83 PP |
34 | # A file generated by a `CodeGenerator` object. |
35 | # | |
36 | # A generated file has a name (influenced by the configuration's | |
37 | # file name prefix option) and contents. | |
4810b707 PP |
38 | class _GeneratedFile: |
39 | def __init__(self, name, contents): | |
40 | self._name = name | |
41 | self._contents = contents | |
42 | ||
43 | @property | |
44 | def name(self): | |
45 | return self._name | |
46 | ||
47 | @property | |
48 | def contents(self): | |
49 | return self._contents | |
50 | ||
51 | ||
d6483c83 PP |
52 | # A barectf code generator. |
53 | # | |
54 | # Build a code generator with a barectf configuration. | |
55 | # | |
56 | # A code generator can generate the TSDL `metadata` file and C source | |
57 | # and header files. | |
4810b707 PP |
58 | class CodeGenerator: |
59 | def __init__(self, configuration): | |
60 | self._config = configuration | |
61 | self._file_name_prefix = configuration.options.code_generation_options.file_name_prefix | |
62 | self._ccode_gen = _CCodeGenerator(configuration) | |
63 | self._c_headers = None | |
64 | self._c_sources = None | |
65 | self._metadata_stream = None | |
66 | ||
67 | @property | |
68 | def _barectf_header_name(self): | |
69 | return f'{self._file_name_prefix}.h' | |
70 | ||
7db1a1f5 PP |
71 | @property |
72 | def _bitfield_header_name(self): | |
73 | return f'{self._file_name_prefix}-bitfield.h' | |
74 | ||
4810b707 PP |
75 | def generate_c_headers(self): |
76 | if self._c_headers is None: | |
4810b707 | 77 | self._c_headers = [ |
7db1a1f5 PP |
78 | _GeneratedFile(self._barectf_header_name, self._ccode_gen.generate_header()), |
79 | _GeneratedFile(self._bitfield_header_name, self._ccode_gen.generate_bitfield_header()), | |
4810b707 PP |
80 | ] |
81 | ||
82 | return self._c_headers | |
83 | ||
84 | def generate_c_sources(self): | |
85 | if self._c_sources is None: | |
86 | self._c_sources = [ | |
87 | _GeneratedFile(f'{self._file_name_prefix}.c', | |
7db1a1f5 PP |
88 | self._ccode_gen.generate_c_src(self._barectf_header_name, |
89 | self._bitfield_header_name)) | |
4810b707 PP |
90 | ] |
91 | ||
92 | return self._c_sources | |
93 | ||
94 | def generate_metadata_stream(self): | |
95 | if self._metadata_stream is None: | |
96 | self._metadata_stream = _GeneratedFile('metadata', | |
97 | barectf_tsdl182gen._from_config(self._config)) | |
98 | ||
99 | return self._metadata_stream | |
e5aa0be3 PP |
100 | |
101 | ||
d6483c83 PP |
102 | # A tuple containing serialization and size computation function |
103 | # templates for a given operation. | |
104 | _OpTemplates = collections.namedtuple('_OpTemplates', ['serialize', 'size']) | |
70e191bd PP |
105 | |
106 | ||
d6483c83 PP |
107 | # Base class of any operation within source code. |
108 | # | |
109 | # Any operation has: | |
110 | # | |
111 | # * An offset at which to start to write within the current byte. | |
112 | # | |
113 | # * A field type. | |
114 | # | |
115 | # * A list of names which, when joined with `_`, form the generic C | |
116 | # source variable name. | |
117 | # | |
118 | # * Serialization and size computation templates to generate the | |
119 | # operation's source code for those functions. | |
120 | class _Op: | |
121 | def __init__(self, offset_in_byte, ft, names, templates): | |
acfb8213 PP |
122 | assert(offset_in_byte >= 0 and offset_in_byte < 8) |
123 | self._offset_in_byte = offset_in_byte | |
4810b707 | 124 | self._ft = ft |
d6483c83 PP |
125 | self._names = copy.copy(names) |
126 | self._templates = templates | |
e5aa0be3 PP |
127 | |
128 | @property | |
acfb8213 PP |
129 | def offset_in_byte(self): |
130 | return self._offset_in_byte | |
e5aa0be3 | 131 | |
acfb8213 | 132 | @property |
4810b707 PP |
133 | def ft(self): |
134 | return self._ft | |
acfb8213 PP |
135 | |
136 | @property | |
137 | def names(self): | |
138 | return self._names | |
e5aa0be3 | 139 | |
d6483c83 PP |
140 | @property |
141 | def top_name(self): | |
142 | return self._names[-1] | |
e5aa0be3 | 143 | |
d6483c83 PP |
144 | def _render_template(self, templ, **kwargs): |
145 | return templ.render(op=self, root_ft_prefixes=_RootFtPrefixes, | |
146 | root_ft_prefix_names=_ROOT_FT_PREFIX_NAMES, **kwargs) | |
147 | ||
148 | def serialize_str(self, **kwargs): | |
149 | return self._render_template(self._templates.serialize, **kwargs) | |
150 | ||
151 | def size_str(self, **kwargs): | |
152 | return self._render_template(self._templates.size, **kwargs) | |
153 | ||
154 | ||
155 | # An "align" operation. | |
156 | class _AlignOp(_Op): | |
157 | def __init__(self, offset_in_byte, ft, names, templates, value): | |
158 | super().__init__(offset_in_byte, ft, names, templates) | |
acfb8213 | 159 | self._value = value |
e5aa0be3 | 160 | |
acfb8213 PP |
161 | @property |
162 | def value(self): | |
163 | return self._value | |
e5aa0be3 | 164 | |
e5aa0be3 | 165 | |
d6483c83 PP |
166 | # A "write" operation. |
167 | class _WriteOp(_Op): | |
4810b707 | 168 | pass |
70e191bd | 169 | |
e5aa0be3 | 170 | |
d6483c83 PP |
171 | # A builder of a chain of operations. |
172 | # | |
173 | # Such a builder is closely connected to a `_CCodeGenerator` object | |
174 | # using it to find generic templates. | |
175 | # | |
176 | # Call append_root_ft() to make an operation builder append operations | |
177 | # to itself for each member, recursively, of the structure field type. | |
178 | # | |
179 | # Get an operation builder's operations with its `ops` property. | |
180 | class _OpsBuilder: | |
181 | def __init__(self, cg): | |
acfb8213 PP |
182 | self._last_alignment = None |
183 | self._last_bit_array_size = None | |
d6483c83 | 184 | self._ops = [] |
acfb8213 PP |
185 | self._names = [] |
186 | self._offset_in_byte = 0 | |
d6483c83 | 187 | self._cg = cg |
acfb8213 | 188 | |
d6483c83 PP |
189 | @property |
190 | def ops(self): | |
191 | return self._ops | |
192 | ||
193 | # Creates and appends the operations for the members, recursively, | |
194 | # of the root structure field type `ft` named `name`. | |
195 | # | |
196 | # `spec_serialize_write_templates` is a mapping of first level | |
197 | # member names to specialized serialization "write" templates. | |
198 | def append_root_ft(self, ft, name, spec_serialize_write_templates=None): | |
4810b707 | 199 | if ft is None: |
acfb8213 | 200 | return |
e5aa0be3 | 201 | |
d6483c83 PP |
202 | if spec_serialize_write_templates is None: |
203 | spec_serialize_write_templates = {} | |
204 | ||
205 | assert type(ft) is barectf_config.StructureFieldType | |
206 | assert len(self._names) == 0 | |
207 | self._append_ft(ft, name, spec_serialize_write_templates) | |
208 | ||
209 | # Creates and appends the operations of a given field type `ft` | |
210 | # named `name`. | |
211 | # | |
212 | # See append_root_ft() for `spec_serialize_write_templates`. | |
213 | def _append_ft(self, ft, name, spec_serialize_write_templates): | |
214 | def top_name(): | |
215 | return self._names[-1] | |
216 | ||
217 | # Appends a "write" operation for the field type `ft`. | |
218 | # | |
219 | # This function considers `spec_serialize_write_templates` to | |
220 | # override generic templates. | |
221 | def append_write_op(ft): | |
222 | assert type(ft) is not barectf_config.StructureFieldType | |
223 | offset_in_byte = self._offset_in_byte | |
224 | ||
225 | if isinstance(ft, barectf_config._BitArrayFieldType): | |
226 | self._offset_in_byte += ft.size | |
227 | self._offset_in_byte %= 8 | |
228 | ||
229 | serialize_write_templ = None | |
230 | ||
231 | if len(self._names) == 2: | |
232 | serialize_write_templ = spec_serialize_write_templates.get(top_name()) | |
233 | ||
234 | if serialize_write_templ is None: | |
235 | if isinstance(ft, barectf_config._IntegerFieldType): | |
236 | serialize_write_templ = self._cg._serialize_write_int_statements_templ | |
237 | elif type(ft) is barectf_config.RealFieldType: | |
238 | serialize_write_templ = self._cg._serialize_write_real_statements_templ | |
239 | else: | |
240 | assert type(ft) is barectf_config.StringFieldType | |
241 | serialize_write_templ = self._cg._serialize_write_string_statements_templ | |
242 | ||
243 | size_write_templ = None | |
e5aa0be3 | 244 | |
d6483c83 PP |
245 | if isinstance(ft, barectf_config._BitArrayFieldType): |
246 | size_write_templ = self._cg._size_write_bit_array_statements_templ | |
247 | elif type(ft) is barectf_config.StringFieldType: | |
248 | size_write_templ = self._cg._size_write_string_statements_templ | |
249 | ||
250 | self._ops.append(_WriteOp(offset_in_byte, ft, self._names, | |
251 | _OpTemplates(serialize_write_templ, size_write_templ))) | |
252 | ||
253 | # Creates and appends an "align" operation for the field type | |
254 | # `ft` if needed. | |
255 | # | |
256 | # This function updates the builder's state. | |
257 | def try_append_align_op(alignment, do_align, ft): | |
258 | def align(v, alignment): | |
259 | return (v + (alignment - 1)) & -alignment | |
260 | ||
261 | offset_in_byte = self._offset_in_byte | |
262 | self._offset_in_byte = align(self._offset_in_byte, alignment) % 8 | |
263 | ||
264 | if do_align and alignment > 1: | |
265 | self._ops.append(_AlignOp(offset_in_byte, ft, self._names, | |
266 | _OpTemplates(self._cg._serialize_align_statements_templ, | |
267 | self._cg._size_align_statements_templ), | |
268 | alignment)) | |
acfb8213 | 269 | |
d6483c83 PP |
270 | # Returns whether or not, considering the alignment requirement |
271 | # `align_req` and the builder's current state, we must create | |
272 | # and append an "align" operation. | |
273 | def must_align(align_req): | |
274 | return self._last_alignment != align_req or self._last_bit_array_size % align_req != 0 | |
acfb8213 | 275 | |
d6483c83 PP |
276 | # push field type's name to the builder's name stack initially |
277 | self._names.append(name) | |
acfb8213 | 278 | |
4810b707 | 279 | if isinstance(ft, (barectf_config.StringFieldType, barectf_config._ArrayFieldType)): |
d6483c83 PP |
280 | assert type(ft) is barectf_config.StringFieldType or top_name() == 'uuid' |
281 | ||
282 | # strings and arrays are always byte-aligned | |
283 | do_align = must_align(8) | |
acfb8213 PP |
284 | self._last_alignment = 8 |
285 | self._last_bit_array_size = 8 | |
d6483c83 PP |
286 | try_append_align_op(8, do_align, ft) |
287 | append_write_op(ft) | |
4810b707 | 288 | else: |
d6483c83 | 289 | do_align = must_align(ft.alignment) |
4810b707 PP |
290 | self._last_alignment = ft.alignment |
291 | ||
292 | if type(ft) is barectf_config.StructureFieldType: | |
293 | self._last_bit_array_size = ft.alignment | |
acfb8213 | 294 | else: |
4810b707 | 295 | self._last_bit_array_size = ft.size |
70e191bd | 296 | |
d6483c83 | 297 | try_append_align_op(ft.alignment, do_align, ft) |
70e191bd | 298 | |
4810b707 PP |
299 | if type(ft) is barectf_config.StructureFieldType: |
300 | for member_name, member in ft.members.items(): | |
d6483c83 | 301 | self._append_ft(member.field_type, member_name, spec_serialize_write_templates) |
70e191bd | 302 | else: |
d6483c83 PP |
303 | append_write_op(ft) |
304 | ||
305 | # exiting for this field type: pop its name | |
306 | del self._names[-1] | |
70e191bd | 307 | |
70e191bd | 308 | |
d6483c83 PP |
309 | # The operations for an event. |
310 | # | |
311 | # The available operations are: | |
312 | # | |
313 | # * Specific context operations. | |
314 | # * Payload operations. | |
315 | class _EventOps: | |
316 | def __init__(self, spec_ctx_ops, payload_ops): | |
317 | self._spec_ctx_ops = copy.copy(spec_ctx_ops) | |
318 | self._payload_ops = copy.copy(payload_ops) | |
70e191bd | 319 | |
d6483c83 PP |
320 | @property |
321 | def spec_ctx_ops(self): | |
322 | return self._spec_ctx_ops | |
acfb8213 | 323 | |
d6483c83 PP |
324 | @property |
325 | def payload_ops(self): | |
326 | return self._payload_ops | |
acfb8213 | 327 | |
70e191bd | 328 | |
d6483c83 PP |
329 | # The operations for a stream. |
330 | # | |
331 | # The available operations are: | |
332 | # | |
333 | # * Packet header operations. | |
334 | # * Packet context operations. | |
335 | # * Event header operations. | |
336 | # * Event common context operations. | |
337 | # * Event operations (`_EventOps`). | |
338 | class _StreamOps: | |
339 | def __init__(self, pkt_header_ops, pkt_ctx_ops, ev_header_ops, | |
340 | ev_common_ctx_ops, ev_ops): | |
341 | self._pkt_header_ops = copy.copy(pkt_header_ops) | |
342 | self._pkt_ctx_ops = copy.copy(pkt_ctx_ops) | |
343 | self._ev_header_ops = copy.copy(ev_header_ops) | |
344 | self._ev_common_ctx_ops = copy.copy(ev_common_ctx_ops) | |
345 | self._ev_ops = copy.copy(ev_ops) | |
70e191bd | 346 | |
d6483c83 PP |
347 | @property |
348 | def pkt_header_ops(self): | |
349 | return self._pkt_header_ops | |
350 | ||
351 | @property | |
352 | def pkt_ctx_ops(self): | |
353 | return self._pkt_ctx_ops | |
354 | ||
355 | @property | |
356 | def ev_header_ops(self): | |
357 | return self._ev_header_ops | |
358 | ||
359 | @property | |
360 | def ev_common_ctx_ops(self): | |
361 | return self._ev_common_ctx_ops | |
362 | ||
363 | @property | |
364 | def ev_ops(self): | |
365 | return self._ev_ops | |
366 | ||
367 | ||
368 | # The C variable name prefixes for the six kinds of root field types. | |
1b49c7b8 | 369 | class _RootFtPrefixes: |
d6483c83 PP |
370 | TPH = 'tph' |
371 | SPC = 'spc' | |
372 | SEH = 'seh' | |
373 | SEC = 'sec' | |
374 | EC = 'ec' | |
375 | EP = 'ep' | |
376 | ||
377 | ||
378 | # The human-readable names of the `_RootFtPrefixes` members. | |
379 | _ROOT_FT_PREFIX_NAMES = { | |
380 | _RootFtPrefixes.TPH: 'packet header', | |
381 | _RootFtPrefixes.SPC: 'packet context', | |
382 | _RootFtPrefixes.SEH: 'event header', | |
383 | _RootFtPrefixes.SEC: 'event common context', | |
384 | _RootFtPrefixes.EC: 'specific context', | |
385 | _RootFtPrefixes.EP: 'payload', | |
acfb8213 | 386 | } |
e5aa0be3 PP |
387 | |
388 | ||
d6483c83 PP |
389 | # A named function parameter for a given field type. |
390 | _FtParam = collections.namedtuple('_FtParam', ['ft', 'name']) | |
391 | ||
392 | ||
393 | # A C code generator. | |
394 | # | |
395 | # Such a code generator can generate: | |
396 | # | |
397 | # * The bitfield header (generate_bitfield_header()). | |
398 | # * The public header (generate_header()). | |
399 | # * The source code (generate_c_src()). | |
4810b707 | 400 | class _CCodeGenerator: |
e5aa0be3 PP |
401 | def __init__(self, cfg): |
402 | self._cfg = cfg | |
d6483c83 PP |
403 | self._iden_prefix = cfg.options.code_generation_options.identifier_prefix |
404 | self._saved_serialization_ops = {} | |
405 | self._templ_filters = { | |
406 | 'ft_c_type': self._ft_c_type, | |
407 | 'open_func_params_str': self._open_func_params_str, | |
408 | 'trace_func_params_str': self._trace_func_params_str, | |
409 | 'serialize_ev_common_ctx_func_params_str': self._serialize_ev_common_ctx_func_params_str, | |
1b49c7b8 | 410 | } |
d6483c83 PP |
411 | self._func_proto_params_templ = self._create_template('func-proto-params.j2') |
412 | self._serialize_align_statements_templ = self._create_template('serialize-align-statements.j2') | |
413 | self._serialize_write_int_statements_templ = self._create_template('serialize-write-int-statements.j2') | |
414 | self._serialize_write_real_statements_templ = self._create_template('serialize-write-real-statements.j2') | |
415 | self._serialize_write_string_statements_templ = self._create_template('serialize-write-string-statements.j2') | |
416 | self._serialize_write_magic_statements_templ = self._create_template('serialize-write-magic-statements.j2') | |
417 | self._serialize_write_uuid_statements_templ = self._create_template('serialize-write-uuid-statements.j2') | |
418 | self._serialize_write_stream_type_id_statements_templ = self._create_template('serialize-write-stream-type-id-statements.j2') | |
419 | self._serialize_write_time_statements_templ = self._create_template('serialize-write-time-statements.j2') | |
420 | self._serialize_write_packet_size_statements_templ = self._create_template('serialize-write-packet-size-statements.j2') | |
421 | self._serialize_write_skip_save_statements_templ = self._create_template('serialize-write-skip-save-statements.j2') | |
422 | self._serialize_write_ev_type_id_statements_templ = self._create_template('serialize-write-ev-type-id-statements.j2') | |
423 | self._size_align_statements_templ = self._create_template('size-align-statements.j2') | |
424 | self._size_write_bit_array_statements_templ = self._create_template('size-write-bit-array-statements.j2') | |
425 | self._size_write_string_statements_templ = self._create_template('size-write-string-statements.j2') | |
426 | ||
427 | # Creates and returns a template named `name` which is a file | |
428 | # template if `is_file_template` is `True`. | |
429 | # | |
430 | # `name` is the file name, including the `.j2` extension, within the | |
431 | # `c` directory. | |
432 | # | |
433 | # Such a template has the filters custom filters | |
434 | # `self._templ_filters`. | |
435 | def _create_template_base(self, name: str, is_file_template: bool): | |
436 | return barectf_template._Template(f'c/{name}', is_file_template, self._cfg, | |
437 | self._templ_filters) | |
438 | ||
439 | # Creates and returns a non-file template named `name`. | |
440 | # | |
441 | # See _create_template_base() for `name`. | |
8c7c6ed2 | 442 | def _create_template(self, name: str) -> barectf_template._Template: |
d6483c83 | 443 | return self._create_template_base(name, False) |
8c7c6ed2 | 444 | |
d6483c83 PP |
445 | # Creates and returns a file template named `name`. |
446 | # | |
447 | # See _create_template_base() for `name`. | |
8c7c6ed2 | 448 | def _create_file_template(self, name: str) -> barectf_template._Template: |
d6483c83 | 449 | return self._create_template_base(name, True) |
8c7c6ed2 | 450 | |
d6483c83 | 451 | # Trace type of this code generator's barectf configuration. |
4810b707 PP |
452 | @property |
453 | def _trace_type(self): | |
454 | return self._cfg.trace.type | |
27bc6f1e | 455 | |
d6483c83 PP |
456 | # Returns the C type for the field type `ft`. |
457 | def _ft_c_type(self, ft): | |
4810b707 PP |
458 | if isinstance(ft, barectf_config._IntegerFieldType): |
459 | sign_prefix = 'u' if isinstance(ft, barectf_config.UnsignedIntegerFieldType) else '' | |
460 | ||
461 | if ft.size <= 8: | |
462 | sz = 8 | |
463 | elif ft.size <= 16: | |
464 | sz = 16 | |
465 | elif ft.size <= 32: | |
466 | sz = 32 | |
467 | else: | |
d6483c83 | 468 | assert ft.size <= 64 |
4810b707 PP |
469 | sz = 64 |
470 | ||
471 | return f'{sign_prefix}int{sz}_t' | |
472 | elif type(ft) is barectf_config.RealFieldType: | |
473 | if ft.size == 32 and ft.alignment == 32: | |
474 | return 'float' | |
475 | elif ft.size == 64 and ft.alignment == 64: | |
476 | return 'double' | |
477 | else: | |
478 | return 'uint64_t' | |
e5aa0be3 | 479 | else: |
4810b707 PP |
480 | assert type(ft) is barectf_config.StringFieldType |
481 | return 'const char *' | |
e5aa0be3 | 482 | |
d6483c83 PP |
483 | # Returns the function prototype parameters for the members of the |
484 | # root structure field type `root_ft`. | |
485 | # | |
486 | # Each parameter has the prefix `name_prefix` followed with `_`. | |
487 | # | |
488 | # Members of which the name is in `exclude_set` are excluded. | |
489 | def _proto_params_str(self, root_ft, name_prefix, exclude_set=None): | |
490 | if root_ft is None: | |
491 | return | |
e5aa0be3 | 492 | |
4810b707 PP |
493 | if exclude_set is None: |
494 | exclude_set = set() | |
495 | ||
d6483c83 | 496 | params = [] |
e5aa0be3 | 497 | |
d6483c83 | 498 | for member_name, member in root_ft.members.items(): |
4810b707 | 499 | if member_name in exclude_set: |
e5aa0be3 PP |
500 | continue |
501 | ||
d6483c83 | 502 | params.append(_FtParam(member.field_type, member_name)) |
e5aa0be3 | 503 | |
d6483c83 | 504 | return self._func_proto_params_templ.render(params=params, prefix=name_prefix) |
4810b707 | 505 | |
d6483c83 PP |
506 | # Returns the packet opening function prototype parameters for the |
507 | # stream type `stream_type`. | |
508 | def _open_func_params_str(self, stream_type): | |
509 | parts = [] | |
510 | parts.append(self._proto_params_str(self._trace_type._pkt_header_ft, _RootFtPrefixes.TPH, | |
511 | {'magic', 'stream_id', 'uuid'})) | |
e5aa0be3 | 512 | |
4810b707 PP |
513 | exclude_set = { |
514 | 'timestamp_begin', | |
515 | 'timestamp_end', | |
516 | 'packet_size', | |
517 | 'content_size', | |
518 | 'events_discarded', | |
519 | } | |
d6483c83 PP |
520 | parts.append(self._proto_params_str(stream_type._pkt_ctx_ft, _RootFtPrefixes.SPC, |
521 | exclude_set)) | |
522 | return ''.join(parts) | |
e5aa0be3 | 523 | |
d6483c83 PP |
524 | # Returns the tracing function prototype parameters for the stream |
525 | # and event types `stream_ev_types`. | |
526 | def _trace_func_params_str(self, stream_ev_types): | |
527 | stream_type = stream_ev_types[0] | |
528 | ev_type = stream_ev_types[1] | |
529 | parts = [] | |
e5aa0be3 | 530 | |
4810b707 | 531 | if stream_type._ev_header_ft is not None: |
d6483c83 PP |
532 | parts.append(self._proto_params_str(stream_type._ev_header_ft, _RootFtPrefixes.SEH, |
533 | {'id', 'timestamp'})) | |
4810b707 PP |
534 | |
535 | if stream_type.event_common_context_field_type is not None: | |
d6483c83 PP |
536 | parts.append(self._proto_params_str(stream_type.event_common_context_field_type, |
537 | _RootFtPrefixes.SEC)) | |
4810b707 PP |
538 | |
539 | if ev_type.specific_context_field_type is not None: | |
d6483c83 PP |
540 | parts.append(self._proto_params_str(ev_type.specific_context_field_type, |
541 | _RootFtPrefixes.EC)) | |
4810b707 PP |
542 | |
543 | if ev_type.payload_field_type is not None: | |
d6483c83 | 544 | parts.append(self._proto_params_str(ev_type.payload_field_type, _RootFtPrefixes.EP)) |
e5aa0be3 | 545 | |
d6483c83 | 546 | return ''.join(parts) |
4810b707 | 547 | |
d6483c83 PP |
548 | # Returns the event header serialization function prototype |
549 | # parameters for the stream type `stream_type`. | |
550 | def _serialize_ev_common_ctx_func_params_str(self, stream_type): | |
551 | return self._proto_params_str(stream_type.event_common_context_field_type, | |
552 | _RootFtPrefixes.SEC); | |
e5aa0be3 | 553 | |
d6483c83 PP |
554 | # Generates the bitfield header file contents. |
555 | def generate_bitfield_header(self): | |
556 | return self._create_file_template('bitfield.h.j2').render() | |
e5aa0be3 | 557 | |
d6483c83 PP |
558 | # Generates the public header file contents. |
559 | def generate_header(self): | |
560 | return self._create_file_template('barectf.h.j2').render(root_ft_prefixes=_RootFtPrefixes) | |
3cb793a1 | 561 | |
d6483c83 PP |
562 | # Generates the source code file contents. |
563 | def generate_c_src(self, header_file_name, bitfield_header_file_name): | |
564 | # Creates and returns the operations for all the stream and for | |
565 | # all their events. | |
566 | def create_stream_ops(): | |
567 | stream_ser_ops = {} | |
568 | ||
569 | for stream_type in self._trace_type.stream_types: | |
570 | pkt_header_ser_ops = [] | |
571 | builder = _OpsBuilder(self) | |
572 | pkt_header_ft = self._trace_type._pkt_header_ft | |
573 | ||
574 | # packet header serialization operations | |
575 | if pkt_header_ft is not None: | |
576 | spec_serialize_write_templates = { | |
577 | 'magic': self._serialize_write_magic_statements_templ, | |
578 | 'uuid': self._serialize_write_uuid_statements_templ, | |
579 | 'stream_id': self._serialize_write_stream_type_id_statements_templ, | |
580 | } | |
581 | builder.append_root_ft(pkt_header_ft, _RootFtPrefixes.TPH, | |
582 | spec_serialize_write_templates) | |
583 | pkt_header_ser_ops = copy.copy(builder.ops) | |
584 | ||
585 | # packet context serialization operations | |
586 | first_op_index = len(builder.ops) | |
587 | spec_serialize_write_templates = { | |
588 | 'timestamp_begin': self._serialize_write_time_statements_templ, | |
589 | 'packet_size': self._serialize_write_packet_size_statements_templ, | |
590 | 'timestamp_end': self._serialize_write_skip_save_statements_templ, | |
591 | 'events_discarded': self._serialize_write_skip_save_statements_templ, | |
592 | 'content_size': self._serialize_write_skip_save_statements_templ, | |
593 | } | |
594 | builder.append_root_ft(stream_type._pkt_ctx_ft, _RootFtPrefixes.SPC, | |
595 | spec_serialize_write_templates) | |
596 | pkt_ctx_ser_ops = copy.copy(builder.ops[first_op_index:]) | |
597 | ||
598 | # event header serialization operations | |
599 | builder = _OpsBuilder(self) | |
600 | ev_header_ser_ops = [] | |
601 | ||
602 | if stream_type._ev_header_ft is not None: | |
603 | spec_serialize_write_templates = { | |
604 | 'timestamp': self._serialize_write_time_statements_templ, | |
605 | 'id': self._serialize_write_ev_type_id_statements_templ, | |
606 | } | |
607 | builder.append_root_ft(stream_type._ev_header_ft, _RootFtPrefixes.SEH, | |
608 | spec_serialize_write_templates) | |
609 | ev_header_ser_ops = copy.copy(builder.ops) | |
610 | ||
611 | # event common context serialization operations | |
612 | ev_common_ctx_ser_ops = [] | |
613 | ||
614 | if stream_type.event_common_context_field_type is not None: | |
615 | first_op_index = len(builder.ops) | |
616 | builder.append_root_ft(stream_type.event_common_context_field_type, | |
617 | _RootFtPrefixes.SEC) | |
618 | ev_common_ctx_ser_ops = copy.copy(builder.ops[first_op_index:]) | |
619 | ||
620 | # serialization operations specific to each event type | |
621 | ev_ser_ops = {} | |
622 | ||
623 | for ev_type in stream_type.event_types: | |
624 | ev_builder = copy.copy(builder) | |
625 | ||
626 | # specific context serialization operations | |
627 | spec_ctx_ser_ops = [] | |
628 | ||
629 | if ev_type.specific_context_field_type is not None: | |
630 | first_op_index = len(ev_builder.ops) | |
631 | ev_builder.append_root_ft(ev_type.specific_context_field_type, | |
632 | _RootFtPrefixes.EC) | |
633 | spec_ctx_ser_ops = copy.copy(ev_builder.ops[first_op_index:]) | |
634 | ||
635 | # payload serialization operations | |
636 | payload_ser_ops = [] | |
637 | ||
638 | if ev_type.payload_field_type is not None: | |
639 | first_op_index = len(ev_builder.ops) | |
640 | ev_builder.append_root_ft(ev_type.payload_field_type, _RootFtPrefixes.EP) | |
641 | payload_ser_ops = copy.copy(ev_builder.ops[first_op_index:]) | |
642 | ||
643 | ev_ser_ops[ev_type] = _EventOps(spec_ctx_ser_ops, payload_ser_ops) | |
644 | ||
645 | stream_ser_ops[stream_type] = _StreamOps(pkt_header_ser_ops, pkt_ctx_ser_ops, | |
646 | ev_header_ser_ops, ev_common_ctx_ser_ops, | |
647 | ev_ser_ops) | |
648 | ||
649 | return stream_ser_ops | |
650 | ||
651 | # Returns the "write" operation for the packet context member | |
652 | # named `member_name` within the stream type `stream_type`. | |
653 | def stream_op_pkt_ctx_op(stream_type, member_name): | |
654 | for op in stream_ops[stream_type].pkt_ctx_ops: | |
655 | if op.top_name == member_name and type(op) is _WriteOp: | |
656 | return op | |
657 | ||
658 | stream_ops = create_stream_ops() | |
659 | return self._create_file_template('barectf.c.j2').render(header_file_name=header_file_name, | |
660 | bitfield_header_file_name=bitfield_header_file_name, | |
661 | root_ft_prefixes=_RootFtPrefixes, | |
662 | root_ft_prefix_names=_ROOT_FT_PREFIX_NAMES, | |
663 | stream_ops=stream_ops, | |
664 | stream_op_pkt_ctx_op=stream_op_pkt_ctx_op) |