Commit | Line | Data |
---|---|---|
44c440bc | 1 | /* |
0235b0db | 2 | * SPDX-License-Identifier: MIT |
44c440bc | 3 | * |
0235b0db | 4 | * Copyright 2018 Philippe Proulx <pproulx@efficios.com> |
44c440bc PP |
5 | */ |
6 | ||
3fadfbc0 | 7 | #include <babeltrace2/babeltrace.h> |
91d81473 | 8 | #include "common/macros.h" |
578e048b MJ |
9 | #include "common/assert.h" |
10 | #include "compat/glib.h" | |
44c440bc | 11 | #include <glib.h> |
c4f23e30 | 12 | #include <stdbool.h> |
44c440bc PP |
13 | #include <stdint.h> |
14 | #include <string.h> | |
15 | #include <inttypes.h> | |
578e048b | 16 | #include "common/assert.h" |
44c440bc PP |
17 | |
18 | #include "ctf-meta-visitors.h" | |
19 | ||
83ebb7f1 PP |
20 | static |
21 | void force_update_field_class_in_ir(struct ctf_field_class *fc, bool in_ir) | |
22 | { | |
23 | uint64_t i; | |
24 | ||
25 | if (!fc) { | |
26 | goto end; | |
27 | } | |
28 | ||
29 | fc->in_ir = in_ir; | |
30 | ||
31 | switch (fc->type) { | |
32 | case CTF_FIELD_CLASS_TYPE_STRUCT: | |
33 | { | |
34 | struct ctf_field_class_struct *struct_fc = (void *) fc; | |
35 | ||
36 | for (i = 0; i < struct_fc->members->len; i++) { | |
37 | struct ctf_named_field_class *named_fc = | |
38 | ctf_field_class_struct_borrow_member_by_index( | |
39 | struct_fc, i); | |
40 | ||
41 | force_update_field_class_in_ir(named_fc->fc, in_ir); | |
42 | } | |
43 | ||
44 | break; | |
45 | } | |
46 | case CTF_FIELD_CLASS_TYPE_VARIANT: | |
47 | { | |
48 | struct ctf_named_field_class *named_fc; | |
49 | struct ctf_field_class_variant *var_fc = (void *) fc; | |
50 | ||
51 | for (i = 0; i < var_fc->options->len; i++) { | |
52 | named_fc = | |
53 | ctf_field_class_variant_borrow_option_by_index( | |
54 | var_fc, i); | |
55 | ||
56 | force_update_field_class_in_ir(named_fc->fc, in_ir); | |
57 | } | |
58 | ||
59 | break; | |
60 | } | |
61 | case CTF_FIELD_CLASS_TYPE_ARRAY: | |
62 | case CTF_FIELD_CLASS_TYPE_SEQUENCE: | |
63 | { | |
64 | struct ctf_field_class_array_base *array_fc = (void *) fc; | |
65 | ||
66 | force_update_field_class_in_ir(array_fc->elem_fc, in_ir); | |
67 | break; | |
68 | } | |
69 | default: | |
70 | break; | |
71 | } | |
72 | ||
73 | end: | |
74 | return; | |
75 | } | |
76 | ||
44c440bc | 77 | static |
5cd6d0e5 | 78 | void update_field_class_in_ir(struct ctf_field_class *fc, |
44c440bc PP |
79 | GHashTable *ft_dependents) |
80 | { | |
81 | int64_t i; | |
82 | ||
5cd6d0e5 | 83 | if (!fc) { |
44c440bc PP |
84 | goto end; |
85 | } | |
86 | ||
864cad70 PP |
87 | switch (fc->type) { |
88 | case CTF_FIELD_CLASS_TYPE_INT: | |
89 | case CTF_FIELD_CLASS_TYPE_ENUM: | |
44c440bc | 90 | { |
5cd6d0e5 | 91 | struct ctf_field_class_int *int_fc = (void *) fc; |
44c440bc | 92 | |
2de73462 PP |
93 | /* |
94 | * Conditions to be in trace IR; one of: | |
95 | * | |
96 | * 1. Does NOT have a mapped clock class AND does not | |
97 | * have a special meaning. | |
98 | * 2. Another field class depends on it. | |
99 | */ | |
100 | if ((!int_fc->mapped_clock_class && | |
101 | int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE) || | |
5cd6d0e5 | 102 | bt_g_hash_table_contains(ft_dependents, fc)) { |
5cd6d0e5 | 103 | fc->in_ir = true; |
44c440bc PP |
104 | } |
105 | ||
106 | break; | |
107 | } | |
864cad70 | 108 | case CTF_FIELD_CLASS_TYPE_STRUCT: |
44c440bc | 109 | { |
5cd6d0e5 | 110 | struct ctf_field_class_struct *struct_fc = (void *) fc; |
44c440bc | 111 | |
b2c863b0 PP |
112 | /* |
113 | * Make it part of IR if it's empty because it was | |
114 | * originally empty. | |
115 | */ | |
116 | if (struct_fc->members->len == 0) { | |
117 | fc->in_ir = true; | |
118 | } | |
119 | ||
44c440bc | 120 | /* Reverse order */ |
5cd6d0e5 PP |
121 | for (i = (int64_t) struct_fc->members->len - 1; i >= 0; i--) { |
122 | struct ctf_named_field_class *named_fc = | |
123 | ctf_field_class_struct_borrow_member_by_index( | |
124 | struct_fc, i); | |
44c440bc | 125 | |
5cd6d0e5 | 126 | update_field_class_in_ir(named_fc->fc, ft_dependents); |
44c440bc | 127 | |
5cd6d0e5 | 128 | if (named_fc->fc->in_ir) { |
44c440bc | 129 | /* At least one member is part of IR */ |
5cd6d0e5 | 130 | fc->in_ir = true; |
44c440bc PP |
131 | } |
132 | } | |
133 | ||
134 | break; | |
135 | } | |
864cad70 | 136 | case CTF_FIELD_CLASS_TYPE_VARIANT: |
44c440bc | 137 | { |
5cd6d0e5 PP |
138 | struct ctf_named_field_class *named_fc; |
139 | struct ctf_field_class_variant *var_fc = (void *) fc; | |
44c440bc PP |
140 | |
141 | /* | |
142 | * Reverse order, although it is not important for this | |
5cd6d0e5 PP |
143 | * loop because a field class within a variant field |
144 | * type's option cannot depend on a field class in | |
145 | * another option of the same variant field class. | |
44c440bc | 146 | */ |
5cd6d0e5 PP |
147 | for (i = (int64_t) var_fc->options->len - 1; i >= 0; i--) { |
148 | named_fc = | |
149 | ctf_field_class_variant_borrow_option_by_index( | |
150 | var_fc, i); | |
44c440bc | 151 | |
5cd6d0e5 | 152 | update_field_class_in_ir(named_fc->fc, ft_dependents); |
44c440bc | 153 | |
5cd6d0e5 | 154 | if (named_fc->fc->in_ir) { |
44c440bc | 155 | /* At least one option is part of IR */ |
5cd6d0e5 | 156 | fc->in_ir = true; |
44c440bc PP |
157 | } |
158 | } | |
159 | ||
5cd6d0e5 | 160 | if (fc->in_ir) { |
44c440bc PP |
161 | /* |
162 | * At least one option will make it to IR. In | |
163 | * this case, make all options part of IR | |
164 | * because the variant's tag could still select | |
165 | * (dynamically) a removed option. This can mean | |
166 | * having an empty structure as an option, for | |
167 | * example, but at least all the options are | |
168 | * selectable. | |
169 | */ | |
5cd6d0e5 PP |
170 | for (i = 0; i < var_fc->options->len; i++) { |
171 | ctf_field_class_variant_borrow_option_by_index( | |
172 | var_fc, i)->fc->in_ir = true; | |
44c440bc PP |
173 | } |
174 | ||
175 | /* | |
5cd6d0e5 PP |
176 | * This variant field class is part of IR and |
177 | * depends on a tag field class (which must also | |
44c440bc PP |
178 | * be part of IR). |
179 | */ | |
5cd6d0e5 PP |
180 | g_hash_table_insert(ft_dependents, var_fc->tag_fc, |
181 | var_fc->tag_fc); | |
44c440bc PP |
182 | } |
183 | ||
184 | break; | |
185 | } | |
864cad70 PP |
186 | case CTF_FIELD_CLASS_TYPE_ARRAY: |
187 | case CTF_FIELD_CLASS_TYPE_SEQUENCE: | |
44c440bc | 188 | { |
5cd6d0e5 | 189 | struct ctf_field_class_array_base *array_fc = (void *) fc; |
44c440bc | 190 | |
5cd6d0e5 PP |
191 | update_field_class_in_ir(array_fc->elem_fc, ft_dependents); |
192 | fc->in_ir = array_fc->elem_fc->in_ir; | |
44c440bc | 193 | |
864cad70 | 194 | if (fc->type == CTF_FIELD_CLASS_TYPE_ARRAY) { |
5cd6d0e5 | 195 | struct ctf_field_class_array *arr_fc = (void *) fc; |
44c440bc | 196 | |
5cd6d0e5 PP |
197 | assert(arr_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE || |
198 | arr_fc->meaning == CTF_FIELD_CLASS_MEANING_UUID); | |
44c440bc PP |
199 | |
200 | /* | |
5cd6d0e5 | 201 | * UUID field class: nothing depends on this, so |
44c440bc PP |
202 | * it's not part of IR. |
203 | */ | |
5cd6d0e5 PP |
204 | if (arr_fc->meaning == CTF_FIELD_CLASS_MEANING_UUID) { |
205 | fc->in_ir = false; | |
206 | array_fc->elem_fc->in_ir = false; | |
44c440bc | 207 | } |
864cad70 | 208 | } else if (fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE) { |
5cd6d0e5 PP |
209 | if (fc->in_ir) { |
210 | struct ctf_field_class_sequence *seq_fc = (void *) fc; | |
44c440bc PP |
211 | |
212 | /* | |
5cd6d0e5 PP |
213 | * This sequence field class is part of |
214 | * IR and depends on a length field class | |
44c440bc PP |
215 | * (which must also be part of IR). |
216 | */ | |
217 | g_hash_table_insert(ft_dependents, | |
5cd6d0e5 | 218 | seq_fc->length_fc, seq_fc->length_fc); |
44c440bc PP |
219 | } |
220 | } | |
221 | ||
222 | break; | |
223 | } | |
224 | default: | |
5cd6d0e5 | 225 | fc->in_ir = true; |
44c440bc PP |
226 | break; |
227 | } | |
228 | ||
229 | end: | |
230 | return; | |
231 | } | |
232 | ||
233 | /* | |
5cd6d0e5 PP |
234 | * Scopes and field classes are processed in reverse order because we need |
235 | * to know if a given integer field class has dependents (sequence or | |
236 | * variant field classes) when we reach it. Dependents can only be located | |
237 | * after the length/tag field class in the metadata tree. | |
44c440bc PP |
238 | */ |
239 | BT_HIDDEN | |
240 | int ctf_trace_class_update_in_ir(struct ctf_trace_class *ctf_tc) | |
241 | { | |
242 | int ret = 0; | |
243 | uint64_t i; | |
244 | ||
245 | GHashTable *ft_dependents = g_hash_table_new(g_direct_hash, | |
246 | g_direct_equal); | |
247 | ||
248 | BT_ASSERT(ft_dependents); | |
249 | ||
250 | for (i = 0; i < ctf_tc->stream_classes->len; i++) { | |
251 | struct ctf_stream_class *sc = ctf_tc->stream_classes->pdata[i]; | |
252 | uint64_t j; | |
253 | ||
254 | for (j = 0; j < sc->event_classes->len; j++) { | |
255 | struct ctf_event_class *ec = sc->event_classes->pdata[j]; | |
256 | ||
257 | if (ec->is_translated) { | |
258 | continue; | |
259 | } | |
260 | ||
5cd6d0e5 PP |
261 | update_field_class_in_ir(ec->payload_fc, ft_dependents); |
262 | update_field_class_in_ir(ec->spec_context_fc, | |
44c440bc PP |
263 | ft_dependents); |
264 | } | |
265 | ||
266 | if (!sc->is_translated) { | |
5cd6d0e5 | 267 | update_field_class_in_ir(sc->event_common_context_fc, |
44c440bc | 268 | ft_dependents); |
83ebb7f1 PP |
269 | force_update_field_class_in_ir(sc->event_header_fc, |
270 | false); | |
5cd6d0e5 | 271 | update_field_class_in_ir(sc->packet_context_fc, |
44c440bc PP |
272 | ft_dependents); |
273 | } | |
274 | } | |
275 | ||
276 | if (!ctf_tc->is_translated) { | |
83ebb7f1 PP |
277 | force_update_field_class_in_ir(ctf_tc->packet_header_fc, |
278 | false); | |
44c440bc PP |
279 | } |
280 | ||
281 | g_hash_table_destroy(ft_dependents); | |
282 | return ret; | |
283 | } |