Commit | Line | Data |
---|---|---|
44c440bc PP |
1 | /* |
2 | * Copyright 2018 Philippe Proulx <pproulx@efficios.com> | |
3 | * | |
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
5 | * of this software and associated documentation files (the "Software"), to deal | |
6 | * in the Software without restriction, including without limitation the rights | |
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
8 | * copies of the Software, and to permit persons to whom the Software is | |
9 | * furnished to do so, subject to the following conditions: | |
10 | * | |
11 | * The above copyright notice and this permission notice shall be included in | |
12 | * all copies or substantial portions of the Software. | |
13 | * | |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
20 | * SOFTWARE. | |
21 | */ | |
22 | ||
350ad6c1 | 23 | #define BT_LOG_TAG "LIB/RESOLVE-FIELD-PATH" |
c2d9d9cf | 24 | #include "lib/logging.h" |
44c440bc | 25 | |
578e048b MJ |
26 | #include "lib/assert-pre.h" |
27 | #include "common/assert.h" | |
3fadfbc0 | 28 | #include <babeltrace2/trace-ir/field-path-const.h> |
44c440bc PP |
29 | #include <limits.h> |
30 | #include <stdint.h> | |
31 | #include <inttypes.h> | |
32 | #include <glib.h> | |
33 | ||
578e048b MJ |
34 | #include "field-class.h" |
35 | #include "field-path.h" | |
36 | #include "resolve-field-path.h" | |
37 | ||
44c440bc | 38 | static |
5cd6d0e5 PP |
39 | bool find_field_class_recursive(struct bt_field_class *fc, |
40 | struct bt_field_class *tgt_fc, struct bt_field_path *field_path) | |
44c440bc PP |
41 | { |
42 | bool found = false; | |
43 | ||
5cd6d0e5 | 44 | if (tgt_fc == fc) { |
44c440bc PP |
45 | found = true; |
46 | goto end; | |
47 | } | |
48 | ||
864cad70 | 49 | switch (fc->type) { |
b38aea74 PP |
50 | case BT_FIELD_CLASS_TYPE_OPTION: |
51 | { | |
52 | struct bt_field_class_option *opt_fc = (void *) fc; | |
b38aea74 PP |
53 | struct bt_field_path_item item = { |
54 | .type = BT_FIELD_PATH_ITEM_TYPE_CURRENT_OPTION_CONTENT, | |
55 | .index = UINT64_C(-1), | |
56 | }; | |
57 | ||
58 | bt_field_path_append_item(field_path, &item); | |
59 | found = find_field_class_recursive(opt_fc->content_fc, | |
60 | tgt_fc, field_path); | |
61 | if (found) { | |
62 | goto end; | |
63 | } | |
64 | ||
65 | bt_field_path_remove_last_item(field_path); | |
66 | break; | |
67 | } | |
864cad70 | 68 | case BT_FIELD_CLASS_TYPE_STRUCTURE: |
45c51519 PP |
69 | case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR: |
70 | case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR: | |
71 | case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR: | |
44c440bc | 72 | { |
5cd6d0e5 PP |
73 | struct bt_field_class_named_field_class_container *container_fc = |
74 | (void *) fc; | |
44c440bc PP |
75 | uint64_t i; |
76 | ||
5cd6d0e5 PP |
77 | for (i = 0; i < container_fc->named_fcs->len; i++) { |
78 | struct bt_named_field_class *named_fc = | |
45c51519 | 79 | container_fc->named_fcs->pdata[i]; |
66ddcddf PP |
80 | struct bt_field_path_item item = { |
81 | .type = BT_FIELD_PATH_ITEM_TYPE_INDEX, | |
82 | .index = i, | |
83 | }; | |
44c440bc | 84 | |
66ddcddf | 85 | bt_field_path_append_item(field_path, &item); |
5cd6d0e5 PP |
86 | found = find_field_class_recursive(named_fc->fc, |
87 | tgt_fc, field_path); | |
44c440bc PP |
88 | if (found) { |
89 | goto end; | |
90 | } | |
91 | ||
66ddcddf | 92 | bt_field_path_remove_last_item(field_path); |
44c440bc PP |
93 | } |
94 | ||
95 | break; | |
96 | } | |
864cad70 PP |
97 | case BT_FIELD_CLASS_TYPE_STATIC_ARRAY: |
98 | case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY: | |
44c440bc | 99 | { |
5cd6d0e5 | 100 | struct bt_field_class_array *array_fc = (void *) fc; |
66ddcddf PP |
101 | struct bt_field_path_item item = { |
102 | .type = BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT, | |
103 | .index = UINT64_C(-1), | |
104 | }; | |
44c440bc | 105 | |
66ddcddf | 106 | bt_field_path_append_item(field_path, &item); |
5cd6d0e5 PP |
107 | found = find_field_class_recursive(array_fc->element_fc, |
108 | tgt_fc, field_path); | |
66ddcddf PP |
109 | if (found) { |
110 | goto end; | |
111 | } | |
112 | ||
113 | bt_field_path_remove_last_item(field_path); | |
44c440bc PP |
114 | break; |
115 | } | |
116 | default: | |
117 | break; | |
118 | } | |
119 | ||
120 | end: | |
121 | return found; | |
122 | } | |
123 | ||
124 | static | |
5cd6d0e5 | 125 | int find_field_class(struct bt_field_class *root_fc, |
e7ceb9df | 126 | enum bt_field_path_scope root_scope, struct bt_field_class *tgt_fc, |
44c440bc PP |
127 | struct bt_field_path **ret_field_path) |
128 | { | |
129 | int ret = 0; | |
130 | struct bt_field_path *field_path = NULL; | |
131 | ||
5cd6d0e5 | 132 | if (!root_fc) { |
44c440bc PP |
133 | goto end; |
134 | } | |
135 | ||
136 | field_path = bt_field_path_create(); | |
137 | if (!field_path) { | |
138 | ret = -1; | |
139 | goto end; | |
140 | } | |
141 | ||
142 | field_path->root = root_scope; | |
5cd6d0e5 | 143 | if (!find_field_class_recursive(root_fc, tgt_fc, field_path)) { |
44c440bc | 144 | /* Not found here */ |
65300d60 | 145 | BT_OBJECT_PUT_REF_AND_RESET(field_path); |
44c440bc PP |
146 | } |
147 | ||
148 | end: | |
149 | *ret_field_path = field_path; | |
150 | return ret; | |
151 | } | |
152 | ||
153 | static | |
5cd6d0e5 | 154 | struct bt_field_path *find_field_class_in_ctx(struct bt_field_class *fc, |
44c440bc PP |
155 | struct bt_resolve_field_path_context *ctx) |
156 | { | |
157 | struct bt_field_path *field_path = NULL; | |
158 | int ret; | |
159 | ||
e7ceb9df | 160 | ret = find_field_class(ctx->packet_context, BT_FIELD_PATH_SCOPE_PACKET_CONTEXT, |
5cd6d0e5 | 161 | fc, &field_path); |
44c440bc PP |
162 | if (ret || field_path) { |
163 | goto end; | |
164 | } | |
165 | ||
5cd6d0e5 | 166 | ret = find_field_class(ctx->event_common_context, |
e7ceb9df | 167 | BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT, fc, &field_path); |
44c440bc PP |
168 | if (ret || field_path) { |
169 | goto end; | |
170 | } | |
171 | ||
5cd6d0e5 | 172 | ret = find_field_class(ctx->event_specific_context, |
e7ceb9df | 173 | BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT, fc, &field_path); |
44c440bc PP |
174 | if (ret || field_path) { |
175 | goto end; | |
176 | } | |
177 | ||
e7ceb9df | 178 | ret = find_field_class(ctx->event_payload, BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD, |
5cd6d0e5 | 179 | fc, &field_path); |
44c440bc PP |
180 | if (ret || field_path) { |
181 | goto end; | |
182 | } | |
183 | ||
184 | end: | |
185 | return field_path; | |
186 | } | |
187 | ||
bdb288b3 | 188 | BT_ASSERT_PRE_DEV_FUNC |
44c440bc PP |
189 | static inline |
190 | bool target_is_before_source(struct bt_field_path *src_field_path, | |
191 | struct bt_field_path *tgt_field_path) | |
192 | { | |
193 | bool is_valid = true; | |
194 | uint64_t src_i = 0, tgt_i = 0; | |
195 | ||
196 | if (tgt_field_path->root < src_field_path->root) { | |
197 | goto end; | |
198 | } | |
199 | ||
200 | if (tgt_field_path->root > src_field_path->root) { | |
201 | is_valid = false; | |
202 | goto end; | |
203 | } | |
204 | ||
205 | BT_ASSERT(tgt_field_path->root == src_field_path->root); | |
206 | ||
66ddcddf PP |
207 | for (src_i = 0, tgt_i = 0; src_i < src_field_path->items->len && |
208 | tgt_i < tgt_field_path->items->len; src_i++, tgt_i++) { | |
209 | struct bt_field_path_item *src_fp_item = | |
210 | bt_field_path_borrow_item_by_index_inline( | |
211 | src_field_path, src_i); | |
212 | struct bt_field_path_item *tgt_fp_item = | |
213 | bt_field_path_borrow_item_by_index_inline( | |
214 | tgt_field_path, tgt_i); | |
215 | ||
216 | if (src_fp_item->type == BT_FIELD_PATH_ITEM_TYPE_INDEX && | |
217 | tgt_fp_item->type == BT_FIELD_PATH_ITEM_TYPE_INDEX) { | |
218 | if (tgt_fp_item->index > src_fp_item->index) { | |
219 | is_valid = false; | |
220 | goto end; | |
221 | } | |
44c440bc PP |
222 | } |
223 | ||
224 | src_i++; | |
225 | tgt_i++; | |
226 | } | |
227 | ||
228 | end: | |
229 | return is_valid; | |
230 | } | |
231 | ||
bdb288b3 | 232 | BT_ASSERT_PRE_DEV_FUNC |
44c440bc | 233 | static inline |
5cd6d0e5 | 234 | struct bt_field_class *borrow_root_field_class( |
e7ceb9df | 235 | struct bt_resolve_field_path_context *ctx, enum bt_field_path_scope scope) |
44c440bc PP |
236 | { |
237 | switch (scope) { | |
e7ceb9df | 238 | case BT_FIELD_PATH_SCOPE_PACKET_CONTEXT: |
44c440bc | 239 | return ctx->packet_context; |
e7ceb9df | 240 | case BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT: |
44c440bc | 241 | return ctx->event_common_context; |
e7ceb9df | 242 | case BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT: |
44c440bc | 243 | return ctx->event_specific_context; |
e7ceb9df | 244 | case BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD: |
44c440bc PP |
245 | return ctx->event_payload; |
246 | default: | |
247 | abort(); | |
248 | } | |
249 | ||
250 | return NULL; | |
251 | } | |
252 | ||
bdb288b3 | 253 | BT_ASSERT_PRE_DEV_FUNC |
44c440bc | 254 | static inline |
66ddcddf PP |
255 | struct bt_field_class *borrow_child_field_class( |
256 | struct bt_field_class *parent_fc, | |
257 | struct bt_field_path_item *fp_item) | |
44c440bc | 258 | { |
5cd6d0e5 | 259 | struct bt_field_class *child_fc = NULL; |
44c440bc | 260 | |
864cad70 | 261 | switch (parent_fc->type) { |
b38aea74 PP |
262 | case BT_FIELD_CLASS_TYPE_OPTION: |
263 | { | |
264 | struct bt_field_class_option *opt_fc = (void *) parent_fc; | |
265 | ||
266 | BT_ASSERT(fp_item->type == | |
267 | BT_FIELD_PATH_ITEM_TYPE_CURRENT_OPTION_CONTENT); | |
268 | child_fc = opt_fc->content_fc; | |
269 | break; | |
270 | } | |
864cad70 | 271 | case BT_FIELD_CLASS_TYPE_STRUCTURE: |
45c51519 PP |
272 | case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR: |
273 | case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR: | |
274 | case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR: | |
44c440bc | 275 | { |
45c51519 PP |
276 | struct bt_field_class_named_field_class_container *container_fc = |
277 | (void *) parent_fc; | |
66ddcddf | 278 | struct bt_named_field_class *named_fc; |
44c440bc | 279 | |
66ddcddf | 280 | BT_ASSERT(fp_item->type == BT_FIELD_PATH_ITEM_TYPE_INDEX); |
45c51519 | 281 | named_fc = container_fc->named_fcs->pdata[fp_item->index]; |
5cd6d0e5 | 282 | child_fc = named_fc->fc; |
44c440bc PP |
283 | break; |
284 | } | |
864cad70 PP |
285 | case BT_FIELD_CLASS_TYPE_STATIC_ARRAY: |
286 | case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY: | |
44c440bc | 287 | { |
5cd6d0e5 | 288 | struct bt_field_class_array *array_fc = (void *) parent_fc; |
44c440bc | 289 | |
66ddcddf PP |
290 | BT_ASSERT(fp_item->type == |
291 | BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT); | |
5cd6d0e5 | 292 | child_fc = array_fc->element_fc; |
44c440bc PP |
293 | break; |
294 | } | |
295 | default: | |
296 | break; | |
297 | } | |
298 | ||
5cd6d0e5 | 299 | return child_fc; |
44c440bc PP |
300 | } |
301 | ||
bdb288b3 | 302 | BT_ASSERT_PRE_DEV_FUNC |
44c440bc | 303 | static inline |
5cd6d0e5 | 304 | bool target_field_path_in_different_scope_has_struct_fc_only( |
44c440bc PP |
305 | struct bt_field_path *src_field_path, |
306 | struct bt_field_path *tgt_field_path, | |
307 | struct bt_resolve_field_path_context *ctx) | |
308 | { | |
309 | bool is_valid = true; | |
310 | uint64_t i = 0; | |
5cd6d0e5 | 311 | struct bt_field_class *fc; |
44c440bc PP |
312 | |
313 | if (src_field_path->root == tgt_field_path->root) { | |
314 | goto end; | |
315 | } | |
316 | ||
5cd6d0e5 | 317 | fc = borrow_root_field_class(ctx, tgt_field_path->root); |
44c440bc | 318 | |
66ddcddf PP |
319 | for (i = 0; i < tgt_field_path->items->len; i++) { |
320 | struct bt_field_path_item *fp_item = | |
321 | bt_field_path_borrow_item_by_index_inline( | |
322 | tgt_field_path, i); | |
44c440bc | 323 | |
864cad70 PP |
324 | if (fc->type == BT_FIELD_CLASS_TYPE_STATIC_ARRAY || |
325 | fc->type == BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY || | |
b38aea74 | 326 | fc->type == BT_FIELD_CLASS_TYPE_OPTION || |
45c51519 PP |
327 | fc->type == BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR || |
328 | fc->type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR || | |
329 | fc->type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR) { | |
44c440bc PP |
330 | is_valid = false; |
331 | goto end; | |
332 | } | |
333 | ||
66ddcddf PP |
334 | BT_ASSERT(fp_item->type == BT_FIELD_PATH_ITEM_TYPE_INDEX); |
335 | fc = borrow_child_field_class(fc, fp_item); | |
44c440bc PP |
336 | } |
337 | ||
338 | end: | |
339 | return is_valid; | |
340 | } | |
341 | ||
bdb288b3 | 342 | BT_ASSERT_PRE_DEV_FUNC |
44c440bc | 343 | static inline |
5cd6d0e5 | 344 | bool lca_is_structure_field_class(struct bt_field_path *src_field_path, |
44c440bc PP |
345 | struct bt_field_path *tgt_field_path, |
346 | struct bt_resolve_field_path_context *ctx) | |
347 | { | |
348 | bool is_valid = true; | |
5cd6d0e5 PP |
349 | struct bt_field_class *src_fc; |
350 | struct bt_field_class *tgt_fc; | |
351 | struct bt_field_class *prev_fc = NULL; | |
44c440bc PP |
352 | uint64_t src_i = 0, tgt_i = 0; |
353 | ||
354 | if (src_field_path->root != tgt_field_path->root) { | |
355 | goto end; | |
356 | } | |
357 | ||
5cd6d0e5 PP |
358 | src_fc = borrow_root_field_class(ctx, src_field_path->root); |
359 | tgt_fc = borrow_root_field_class(ctx, tgt_field_path->root); | |
360 | BT_ASSERT(src_fc); | |
361 | BT_ASSERT(tgt_fc); | |
44c440bc | 362 | |
66ddcddf PP |
363 | for (src_i = 0, tgt_i = 0; src_i < src_field_path->items->len && |
364 | tgt_i < tgt_field_path->items->len; src_i++, tgt_i++) { | |
365 | struct bt_field_path_item *src_fp_item = | |
366 | bt_field_path_borrow_item_by_index_inline( | |
367 | src_field_path, src_i); | |
368 | struct bt_field_path_item *tgt_fp_item = | |
369 | bt_field_path_borrow_item_by_index_inline( | |
370 | tgt_field_path, tgt_i); | |
44c440bc | 371 | |
5cd6d0e5 PP |
372 | if (src_fc != tgt_fc) { |
373 | if (!prev_fc) { | |
44c440bc PP |
374 | /* |
375 | * This is correct: the LCA is the root | |
e6276565 PP |
376 | * scope field class, which must be a |
377 | * structure field class. | |
44c440bc PP |
378 | */ |
379 | break; | |
380 | } | |
381 | ||
864cad70 | 382 | if (prev_fc->type != BT_FIELD_CLASS_TYPE_STRUCTURE) { |
44c440bc PP |
383 | is_valid = false; |
384 | } | |
385 | ||
386 | break; | |
387 | } | |
388 | ||
5cd6d0e5 | 389 | prev_fc = src_fc; |
66ddcddf PP |
390 | src_fc = borrow_child_field_class(src_fc, src_fp_item); |
391 | tgt_fc = borrow_child_field_class(tgt_fc, tgt_fp_item); | |
44c440bc PP |
392 | } |
393 | ||
394 | end: | |
395 | return is_valid; | |
396 | } | |
397 | ||
bdb288b3 | 398 | BT_ASSERT_PRE_DEV_FUNC |
44c440bc | 399 | static inline |
5cd6d0e5 | 400 | bool lca_to_target_has_struct_fc_only(struct bt_field_path *src_field_path, |
44c440bc PP |
401 | struct bt_field_path *tgt_field_path, |
402 | struct bt_resolve_field_path_context *ctx) | |
403 | { | |
404 | bool is_valid = true; | |
5cd6d0e5 PP |
405 | struct bt_field_class *src_fc; |
406 | struct bt_field_class *tgt_fc; | |
44c440bc PP |
407 | uint64_t src_i = 0, tgt_i = 0; |
408 | ||
409 | if (src_field_path->root != tgt_field_path->root) { | |
410 | goto end; | |
411 | } | |
412 | ||
5cd6d0e5 PP |
413 | src_fc = borrow_root_field_class(ctx, src_field_path->root); |
414 | tgt_fc = borrow_root_field_class(ctx, tgt_field_path->root); | |
415 | BT_ASSERT(src_fc); | |
416 | BT_ASSERT(tgt_fc); | |
417 | BT_ASSERT(src_fc == tgt_fc); | |
44c440bc PP |
418 | |
419 | /* Find LCA */ | |
66ddcddf PP |
420 | for (src_i = 0, tgt_i = 0; src_i < src_field_path->items->len && |
421 | tgt_i < tgt_field_path->items->len; src_i++, tgt_i++) { | |
422 | struct bt_field_path_item *src_fp_item = | |
423 | bt_field_path_borrow_item_by_index_inline( | |
424 | src_field_path, src_i); | |
425 | struct bt_field_path_item *tgt_fp_item = | |
426 | bt_field_path_borrow_item_by_index_inline( | |
427 | tgt_field_path, tgt_i); | |
44c440bc PP |
428 | |
429 | if (src_i != tgt_i) { | |
5cd6d0e5 | 430 | /* Next field class is different: LCA is `tgt_fc` */ |
44c440bc PP |
431 | break; |
432 | } | |
433 | ||
66ddcddf PP |
434 | src_fc = borrow_child_field_class(src_fc, src_fp_item); |
435 | tgt_fc = borrow_child_field_class(tgt_fc, tgt_fp_item); | |
44c440bc PP |
436 | } |
437 | ||
5cd6d0e5 | 438 | /* Only structure field classes to the target */ |
66ddcddf PP |
439 | for (; tgt_i < tgt_field_path->items->len; tgt_i++) { |
440 | struct bt_field_path_item *tgt_fp_item = | |
441 | bt_field_path_borrow_item_by_index_inline( | |
442 | tgt_field_path, tgt_i); | |
44c440bc | 443 | |
864cad70 PP |
444 | if (tgt_fc->type == BT_FIELD_CLASS_TYPE_STATIC_ARRAY || |
445 | tgt_fc->type == BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY || | |
b38aea74 | 446 | tgt_fc->type == BT_FIELD_CLASS_TYPE_OPTION || |
45c51519 PP |
447 | tgt_fc->type == BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR || |
448 | tgt_fc->type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR || | |
449 | tgt_fc->type == BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR) { | |
44c440bc PP |
450 | is_valid = false; |
451 | goto end; | |
452 | } | |
453 | ||
66ddcddf | 454 | tgt_fc = borrow_child_field_class(tgt_fc, tgt_fp_item); |
44c440bc PP |
455 | } |
456 | ||
457 | end: | |
458 | return is_valid; | |
459 | } | |
460 | ||
bdb288b3 | 461 | BT_ASSERT_PRE_DEV_FUNC |
44c440bc | 462 | static inline |
5cd6d0e5 PP |
463 | bool field_path_is_valid(struct bt_field_class *src_fc, |
464 | struct bt_field_class *tgt_fc, | |
44c440bc PP |
465 | struct bt_resolve_field_path_context *ctx) |
466 | { | |
467 | bool is_valid = true; | |
5cd6d0e5 PP |
468 | struct bt_field_path *src_field_path = find_field_class_in_ctx( |
469 | src_fc, ctx); | |
470 | struct bt_field_path *tgt_field_path = find_field_class_in_ctx( | |
471 | tgt_fc, ctx); | |
44c440bc PP |
472 | |
473 | if (!src_field_path) { | |
bdb288b3 | 474 | BT_ASSERT_PRE_DEV_MSG("Cannot find requesting field class in " |
5cd6d0e5 | 475 | "resolving context: %!+F", src_fc); |
44c440bc PP |
476 | is_valid = false; |
477 | goto end; | |
478 | } | |
479 | ||
480 | if (!tgt_field_path) { | |
bdb288b3 | 481 | BT_ASSERT_PRE_DEV_MSG("Cannot find target field class in " |
5cd6d0e5 | 482 | "resolving context: %!+F", tgt_fc); |
44c440bc PP |
483 | is_valid = false; |
484 | goto end; | |
485 | } | |
486 | ||
487 | /* Target must be before source */ | |
488 | if (!target_is_before_source(src_field_path, tgt_field_path)) { | |
bdb288b3 | 489 | BT_ASSERT_PRE_DEV_MSG("Target field class is located after " |
e6276565 | 490 | "requesting field class: %![req-fc-]+F, %![tgt-fc-]+F", |
5cd6d0e5 | 491 | src_fc, tgt_fc); |
44c440bc PP |
492 | is_valid = false; |
493 | goto end; | |
494 | } | |
495 | ||
496 | /* | |
497 | * If target is in a different scope than source, there are no | |
5cd6d0e5 | 498 | * array or variant field classes on the way to the target. |
44c440bc | 499 | */ |
5cd6d0e5 | 500 | if (!target_field_path_in_different_scope_has_struct_fc_only( |
44c440bc | 501 | src_field_path, tgt_field_path, ctx)) { |
bdb288b3 | 502 | BT_ASSERT_PRE_DEV_MSG("Target field class is located in a " |
e6276565 PP |
503 | "different scope than requesting field class, " |
504 | "but within an array or a variant field class: " | |
5cd6d0e5 PP |
505 | "%![req-fc-]+F, %![tgt-fc-]+F", |
506 | src_fc, tgt_fc); | |
44c440bc PP |
507 | is_valid = false; |
508 | goto end; | |
509 | } | |
510 | ||
e6276565 | 511 | /* Same scope: LCA must be a structure field class */ |
5cd6d0e5 | 512 | if (!lca_is_structure_field_class(src_field_path, tgt_field_path, ctx)) { |
bdb288b3 | 513 | BT_ASSERT_PRE_DEV_MSG("Lowest common ancestor of target and " |
e6276565 | 514 | "requesting field classes is not a structure field class: " |
5cd6d0e5 PP |
515 | "%![req-fc-]+F, %![tgt-fc-]+F", |
516 | src_fc, tgt_fc); | |
44c440bc PP |
517 | is_valid = false; |
518 | goto end; | |
519 | } | |
520 | ||
521 | /* Same scope: path from LCA to target has no array/variant FTs */ | |
5cd6d0e5 | 522 | if (!lca_to_target_has_struct_fc_only(src_field_path, tgt_field_path, |
44c440bc | 523 | ctx)) { |
bdb288b3 | 524 | BT_ASSERT_PRE_DEV_MSG("Path from lowest common ancestor of target " |
e6276565 PP |
525 | "and requesting field classes to target field class " |
526 | "contains an array or a variant field class: " | |
5cd6d0e5 | 527 | "%![req-fc-]+F, %![tgt-fc-]+F", src_fc, tgt_fc); |
44c440bc PP |
528 | is_valid = false; |
529 | goto end; | |
530 | } | |
531 | ||
532 | end: | |
65300d60 PP |
533 | bt_object_put_ref(src_field_path); |
534 | bt_object_put_ref(tgt_field_path); | |
44c440bc PP |
535 | return is_valid; |
536 | } | |
537 | ||
538 | static | |
5cd6d0e5 PP |
539 | struct bt_field_path *resolve_field_path(struct bt_field_class *src_fc, |
540 | struct bt_field_class *tgt_fc, | |
44c440bc PP |
541 | struct bt_resolve_field_path_context *ctx) |
542 | { | |
bdb288b3 | 543 | BT_ASSERT_PRE_DEV(field_path_is_valid(src_fc, tgt_fc, ctx), |
e6276565 | 544 | "Invalid target field class: %![req-fc-]+F, %![tgt-fc-]+F", |
5cd6d0e5 PP |
545 | src_fc, tgt_fc); |
546 | return find_field_class_in_ctx(tgt_fc, ctx); | |
44c440bc PP |
547 | } |
548 | ||
549 | BT_HIDDEN | |
5cd6d0e5 | 550 | int bt_resolve_field_paths(struct bt_field_class *fc, |
44c440bc PP |
551 | struct bt_resolve_field_path_context *ctx) |
552 | { | |
553 | int ret = 0; | |
554 | ||
5cd6d0e5 | 555 | BT_ASSERT(fc); |
44c440bc | 556 | |
5cd6d0e5 | 557 | /* Resolving part for dynamic array and variant field classes */ |
864cad70 | 558 | switch (fc->type) { |
b38aea74 PP |
559 | case BT_FIELD_CLASS_TYPE_OPTION: |
560 | { | |
561 | struct bt_field_class_option *opt_fc = (void *) fc; | |
562 | ||
563 | if (opt_fc->selector_fc) { | |
564 | BT_ASSERT(!opt_fc->selector_field_path); | |
565 | opt_fc->selector_field_path = resolve_field_path( | |
566 | fc, opt_fc->selector_fc, ctx); | |
567 | if (!opt_fc->selector_field_path) { | |
568 | ret = -1; | |
569 | goto end; | |
570 | } | |
571 | } | |
572 | ||
573 | break; | |
574 | } | |
864cad70 | 575 | case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY: |
44c440bc | 576 | { |
9c08c816 | 577 | struct bt_field_class_array_dynamic *dyn_array_fc = (void *) fc; |
44c440bc | 578 | |
5cd6d0e5 PP |
579 | if (dyn_array_fc->length_fc) { |
580 | BT_ASSERT(!dyn_array_fc->length_field_path); | |
581 | dyn_array_fc->length_field_path = resolve_field_path( | |
582 | fc, dyn_array_fc->length_fc, ctx); | |
583 | if (!dyn_array_fc->length_field_path) { | |
44c440bc PP |
584 | ret = -1; |
585 | goto end; | |
586 | } | |
587 | } | |
588 | ||
589 | break; | |
590 | } | |
45c51519 PP |
591 | case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR: |
592 | case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR: | |
44c440bc | 593 | { |
45c51519 PP |
594 | struct bt_field_class_variant_with_selector *var_fc = |
595 | (void *) fc; | |
5cd6d0e5 PP |
596 | |
597 | if (var_fc->selector_fc) { | |
598 | BT_ASSERT(!var_fc->selector_field_path); | |
599 | var_fc->selector_field_path = | |
600 | resolve_field_path(fc, | |
45c51519 | 601 | (void *) var_fc->selector_fc, ctx); |
5cd6d0e5 | 602 | if (!var_fc->selector_field_path) { |
44c440bc PP |
603 | ret = -1; |
604 | goto end; | |
605 | } | |
606 | } | |
607 | } | |
608 | default: | |
609 | break; | |
610 | } | |
611 | ||
612 | /* Recursive part */ | |
864cad70 | 613 | switch (fc->type) { |
b38aea74 PP |
614 | case BT_FIELD_CLASS_TYPE_OPTION: |
615 | { | |
616 | struct bt_field_class_option *opt_fc = (void *) fc; | |
617 | ||
618 | ret = bt_resolve_field_paths(opt_fc->content_fc, ctx); | |
619 | break; | |
620 | } | |
864cad70 | 621 | case BT_FIELD_CLASS_TYPE_STRUCTURE: |
45c51519 PP |
622 | case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR: |
623 | case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR: | |
624 | case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR: | |
44c440bc | 625 | { |
5cd6d0e5 PP |
626 | struct bt_field_class_named_field_class_container *container_fc = |
627 | (void *) fc; | |
44c440bc PP |
628 | uint64_t i; |
629 | ||
5cd6d0e5 PP |
630 | for (i = 0; i < container_fc->named_fcs->len; i++) { |
631 | struct bt_named_field_class *named_fc = | |
45c51519 | 632 | container_fc->named_fcs->pdata[i]; |
44c440bc | 633 | |
5cd6d0e5 | 634 | ret = bt_resolve_field_paths(named_fc->fc, ctx); |
44c440bc PP |
635 | if (ret) { |
636 | goto end; | |
637 | } | |
638 | } | |
639 | ||
640 | break; | |
641 | } | |
864cad70 PP |
642 | case BT_FIELD_CLASS_TYPE_STATIC_ARRAY: |
643 | case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY: | |
44c440bc | 644 | { |
5cd6d0e5 | 645 | struct bt_field_class_array *array_fc = (void *) fc; |
44c440bc | 646 | |
5cd6d0e5 | 647 | ret = bt_resolve_field_paths(array_fc->element_fc, ctx); |
44c440bc PP |
648 | break; |
649 | } | |
650 | default: | |
651 | break; | |
652 | } | |
653 | ||
654 | end: | |
655 | return ret; | |
656 | } |