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 | ||
350ad6c1 | 7 | #define BT_LOG_TAG "LIB/RESOLVE-FIELD-PATH" |
c2d9d9cf | 8 | #include "lib/logging.h" |
44c440bc | 9 | |
d98421f2 | 10 | #include "lib/assert-cond.h" |
578e048b | 11 | #include "common/assert.h" |
43c59509 | 12 | #include <babeltrace2/trace-ir/field-path.h> |
c4f23e30 | 13 | #include <stdbool.h> |
44c440bc | 14 | #include <stdint.h> |
44c440bc PP |
15 | #include <glib.h> |
16 | ||
578e048b MJ |
17 | #include "field-class.h" |
18 | #include "field-path.h" | |
19 | #include "resolve-field-path.h" | |
5a3fec55 | 20 | #include "common/common.h" |
578e048b | 21 | |
44c440bc | 22 | static |
5cd6d0e5 PP |
23 | bool find_field_class_recursive(struct bt_field_class *fc, |
24 | struct bt_field_class *tgt_fc, struct bt_field_path *field_path) | |
44c440bc PP |
25 | { |
26 | bool found = false; | |
27 | ||
5cd6d0e5 | 28 | if (tgt_fc == fc) { |
44c440bc PP |
29 | found = true; |
30 | goto end; | |
31 | } | |
32 | ||
ebdb6693 | 33 | if (bt_field_class_type_is(fc->type, BT_FIELD_CLASS_TYPE_OPTION)) { |
b38aea74 | 34 | struct bt_field_class_option *opt_fc = (void *) fc; |
b38aea74 PP |
35 | struct bt_field_path_item item = { |
36 | .type = BT_FIELD_PATH_ITEM_TYPE_CURRENT_OPTION_CONTENT, | |
37 | .index = UINT64_C(-1), | |
38 | }; | |
39 | ||
40 | bt_field_path_append_item(field_path, &item); | |
41 | found = find_field_class_recursive(opt_fc->content_fc, | |
42 | tgt_fc, field_path); | |
43 | if (found) { | |
44 | goto end; | |
45 | } | |
46 | ||
47 | bt_field_path_remove_last_item(field_path); | |
ebdb6693 PP |
48 | } else if (fc->type == BT_FIELD_CLASS_TYPE_STRUCTURE || |
49 | bt_field_class_type_is(fc->type, | |
50 | BT_FIELD_CLASS_TYPE_VARIANT)) { | |
5cd6d0e5 PP |
51 | struct bt_field_class_named_field_class_container *container_fc = |
52 | (void *) fc; | |
44c440bc PP |
53 | uint64_t i; |
54 | ||
5cd6d0e5 PP |
55 | for (i = 0; i < container_fc->named_fcs->len; i++) { |
56 | struct bt_named_field_class *named_fc = | |
45c51519 | 57 | container_fc->named_fcs->pdata[i]; |
66ddcddf PP |
58 | struct bt_field_path_item item = { |
59 | .type = BT_FIELD_PATH_ITEM_TYPE_INDEX, | |
60 | .index = i, | |
61 | }; | |
44c440bc | 62 | |
66ddcddf | 63 | bt_field_path_append_item(field_path, &item); |
5cd6d0e5 PP |
64 | found = find_field_class_recursive(named_fc->fc, |
65 | tgt_fc, field_path); | |
44c440bc PP |
66 | if (found) { |
67 | goto end; | |
68 | } | |
69 | ||
66ddcddf | 70 | bt_field_path_remove_last_item(field_path); |
44c440bc | 71 | } |
ebdb6693 | 72 | } else if (bt_field_class_type_is(fc->type, BT_FIELD_CLASS_TYPE_ARRAY)) { |
5cd6d0e5 | 73 | struct bt_field_class_array *array_fc = (void *) fc; |
66ddcddf PP |
74 | struct bt_field_path_item item = { |
75 | .type = BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT, | |
76 | .index = UINT64_C(-1), | |
77 | }; | |
44c440bc | 78 | |
66ddcddf | 79 | bt_field_path_append_item(field_path, &item); |
5cd6d0e5 PP |
80 | found = find_field_class_recursive(array_fc->element_fc, |
81 | tgt_fc, field_path); | |
66ddcddf PP |
82 | if (found) { |
83 | goto end; | |
84 | } | |
85 | ||
86 | bt_field_path_remove_last_item(field_path); | |
44c440bc PP |
87 | } |
88 | ||
89 | end: | |
90 | return found; | |
91 | } | |
92 | ||
93 | static | |
5cd6d0e5 | 94 | int find_field_class(struct bt_field_class *root_fc, |
e7ceb9df | 95 | enum bt_field_path_scope root_scope, struct bt_field_class *tgt_fc, |
44c440bc PP |
96 | struct bt_field_path **ret_field_path) |
97 | { | |
98 | int ret = 0; | |
99 | struct bt_field_path *field_path = NULL; | |
100 | ||
5cd6d0e5 | 101 | if (!root_fc) { |
44c440bc PP |
102 | goto end; |
103 | } | |
104 | ||
105 | field_path = bt_field_path_create(); | |
106 | if (!field_path) { | |
107 | ret = -1; | |
108 | goto end; | |
109 | } | |
110 | ||
111 | field_path->root = root_scope; | |
5cd6d0e5 | 112 | if (!find_field_class_recursive(root_fc, tgt_fc, field_path)) { |
44c440bc | 113 | /* Not found here */ |
65300d60 | 114 | BT_OBJECT_PUT_REF_AND_RESET(field_path); |
44c440bc PP |
115 | } |
116 | ||
117 | end: | |
118 | *ret_field_path = field_path; | |
119 | return ret; | |
120 | } | |
121 | ||
122 | static | |
5cd6d0e5 | 123 | struct bt_field_path *find_field_class_in_ctx(struct bt_field_class *fc, |
44c440bc PP |
124 | struct bt_resolve_field_path_context *ctx) |
125 | { | |
126 | struct bt_field_path *field_path = NULL; | |
127 | int ret; | |
128 | ||
e7ceb9df | 129 | ret = find_field_class(ctx->packet_context, BT_FIELD_PATH_SCOPE_PACKET_CONTEXT, |
5cd6d0e5 | 130 | fc, &field_path); |
44c440bc PP |
131 | if (ret || field_path) { |
132 | goto end; | |
133 | } | |
134 | ||
5cd6d0e5 | 135 | ret = find_field_class(ctx->event_common_context, |
e7ceb9df | 136 | BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT, fc, &field_path); |
44c440bc PP |
137 | if (ret || field_path) { |
138 | goto end; | |
139 | } | |
140 | ||
5cd6d0e5 | 141 | ret = find_field_class(ctx->event_specific_context, |
e7ceb9df | 142 | BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT, fc, &field_path); |
44c440bc PP |
143 | if (ret || field_path) { |
144 | goto end; | |
145 | } | |
146 | ||
e7ceb9df | 147 | ret = find_field_class(ctx->event_payload, BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD, |
5cd6d0e5 | 148 | fc, &field_path); |
44c440bc PP |
149 | if (ret || field_path) { |
150 | goto end; | |
151 | } | |
152 | ||
153 | end: | |
154 | return field_path; | |
155 | } | |
156 | ||
d98421f2 | 157 | BT_ASSERT_COND_DEV_FUNC |
44c440bc PP |
158 | static inline |
159 | bool target_is_before_source(struct bt_field_path *src_field_path, | |
160 | struct bt_field_path *tgt_field_path) | |
161 | { | |
162 | bool is_valid = true; | |
163 | uint64_t src_i = 0, tgt_i = 0; | |
164 | ||
165 | if (tgt_field_path->root < src_field_path->root) { | |
166 | goto end; | |
167 | } | |
168 | ||
169 | if (tgt_field_path->root > src_field_path->root) { | |
170 | is_valid = false; | |
171 | goto end; | |
172 | } | |
173 | ||
174 | BT_ASSERT(tgt_field_path->root == src_field_path->root); | |
175 | ||
66ddcddf PP |
176 | for (src_i = 0, tgt_i = 0; src_i < src_field_path->items->len && |
177 | tgt_i < tgt_field_path->items->len; src_i++, tgt_i++) { | |
178 | struct bt_field_path_item *src_fp_item = | |
179 | bt_field_path_borrow_item_by_index_inline( | |
180 | src_field_path, src_i); | |
181 | struct bt_field_path_item *tgt_fp_item = | |
182 | bt_field_path_borrow_item_by_index_inline( | |
183 | tgt_field_path, tgt_i); | |
184 | ||
185 | if (src_fp_item->type == BT_FIELD_PATH_ITEM_TYPE_INDEX && | |
186 | tgt_fp_item->type == BT_FIELD_PATH_ITEM_TYPE_INDEX) { | |
187 | if (tgt_fp_item->index > src_fp_item->index) { | |
188 | is_valid = false; | |
189 | goto end; | |
190 | } | |
44c440bc PP |
191 | } |
192 | ||
193 | src_i++; | |
194 | tgt_i++; | |
195 | } | |
196 | ||
197 | end: | |
198 | return is_valid; | |
199 | } | |
200 | ||
d98421f2 | 201 | BT_ASSERT_COND_DEV_FUNC |
44c440bc | 202 | static inline |
5cd6d0e5 | 203 | struct bt_field_class *borrow_root_field_class( |
e7ceb9df | 204 | struct bt_resolve_field_path_context *ctx, enum bt_field_path_scope scope) |
44c440bc PP |
205 | { |
206 | switch (scope) { | |
e7ceb9df | 207 | case BT_FIELD_PATH_SCOPE_PACKET_CONTEXT: |
44c440bc | 208 | return ctx->packet_context; |
e7ceb9df | 209 | case BT_FIELD_PATH_SCOPE_EVENT_COMMON_CONTEXT: |
44c440bc | 210 | return ctx->event_common_context; |
e7ceb9df | 211 | case BT_FIELD_PATH_SCOPE_EVENT_SPECIFIC_CONTEXT: |
44c440bc | 212 | return ctx->event_specific_context; |
e7ceb9df | 213 | case BT_FIELD_PATH_SCOPE_EVENT_PAYLOAD: |
44c440bc PP |
214 | return ctx->event_payload; |
215 | default: | |
498e7994 | 216 | bt_common_abort(); |
44c440bc PP |
217 | } |
218 | ||
219 | return NULL; | |
220 | } | |
221 | ||
d98421f2 | 222 | BT_ASSERT_COND_DEV_FUNC |
44c440bc | 223 | static inline |
66ddcddf PP |
224 | struct bt_field_class *borrow_child_field_class( |
225 | struct bt_field_class *parent_fc, | |
226 | struct bt_field_path_item *fp_item) | |
44c440bc | 227 | { |
5cd6d0e5 | 228 | struct bt_field_class *child_fc = NULL; |
44c440bc | 229 | |
ebdb6693 PP |
230 | if (bt_field_class_type_is(parent_fc->type, |
231 | BT_FIELD_CLASS_TYPE_OPTION)) { | |
b38aea74 PP |
232 | struct bt_field_class_option *opt_fc = (void *) parent_fc; |
233 | ||
234 | BT_ASSERT(fp_item->type == | |
235 | BT_FIELD_PATH_ITEM_TYPE_CURRENT_OPTION_CONTENT); | |
236 | child_fc = opt_fc->content_fc; | |
ebdb6693 PP |
237 | } else if (parent_fc->type == BT_FIELD_CLASS_TYPE_STRUCTURE || |
238 | bt_field_class_type_is(parent_fc->type, | |
239 | BT_FIELD_CLASS_TYPE_VARIANT)) { | |
45c51519 PP |
240 | struct bt_field_class_named_field_class_container *container_fc = |
241 | (void *) parent_fc; | |
66ddcddf | 242 | struct bt_named_field_class *named_fc; |
44c440bc | 243 | |
66ddcddf | 244 | BT_ASSERT(fp_item->type == BT_FIELD_PATH_ITEM_TYPE_INDEX); |
45c51519 | 245 | named_fc = container_fc->named_fcs->pdata[fp_item->index]; |
5cd6d0e5 | 246 | child_fc = named_fc->fc; |
ebdb6693 PP |
247 | } else if (bt_field_class_type_is(parent_fc->type, |
248 | BT_FIELD_CLASS_TYPE_ARRAY)) { | |
5cd6d0e5 | 249 | struct bt_field_class_array *array_fc = (void *) parent_fc; |
44c440bc | 250 | |
66ddcddf PP |
251 | BT_ASSERT(fp_item->type == |
252 | BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT); | |
5cd6d0e5 | 253 | child_fc = array_fc->element_fc; |
44c440bc PP |
254 | } |
255 | ||
5cd6d0e5 | 256 | return child_fc; |
44c440bc PP |
257 | } |
258 | ||
d98421f2 | 259 | BT_ASSERT_COND_DEV_FUNC |
44c440bc | 260 | static inline |
5cd6d0e5 | 261 | bool target_field_path_in_different_scope_has_struct_fc_only( |
44c440bc PP |
262 | struct bt_field_path *src_field_path, |
263 | struct bt_field_path *tgt_field_path, | |
264 | struct bt_resolve_field_path_context *ctx) | |
265 | { | |
266 | bool is_valid = true; | |
267 | uint64_t i = 0; | |
5cd6d0e5 | 268 | struct bt_field_class *fc; |
44c440bc PP |
269 | |
270 | if (src_field_path->root == tgt_field_path->root) { | |
271 | goto end; | |
272 | } | |
273 | ||
5cd6d0e5 | 274 | fc = borrow_root_field_class(ctx, tgt_field_path->root); |
44c440bc | 275 | |
66ddcddf PP |
276 | for (i = 0; i < tgt_field_path->items->len; i++) { |
277 | struct bt_field_path_item *fp_item = | |
278 | bt_field_path_borrow_item_by_index_inline( | |
279 | tgt_field_path, i); | |
44c440bc | 280 | |
ebdb6693 PP |
281 | if (bt_field_class_type_is(fc->type, |
282 | BT_FIELD_CLASS_TYPE_ARRAY) || | |
283 | bt_field_class_type_is(fc->type, | |
284 | BT_FIELD_CLASS_TYPE_OPTION) || | |
285 | bt_field_class_type_is(fc->type, | |
286 | BT_FIELD_CLASS_TYPE_VARIANT)) { | |
44c440bc PP |
287 | is_valid = false; |
288 | goto end; | |
289 | } | |
290 | ||
66ddcddf PP |
291 | BT_ASSERT(fp_item->type == BT_FIELD_PATH_ITEM_TYPE_INDEX); |
292 | fc = borrow_child_field_class(fc, fp_item); | |
44c440bc PP |
293 | } |
294 | ||
295 | end: | |
296 | return is_valid; | |
297 | } | |
298 | ||
d98421f2 | 299 | BT_ASSERT_COND_DEV_FUNC |
44c440bc | 300 | static inline |
5cd6d0e5 | 301 | bool lca_is_structure_field_class(struct bt_field_path *src_field_path, |
44c440bc PP |
302 | struct bt_field_path *tgt_field_path, |
303 | struct bt_resolve_field_path_context *ctx) | |
304 | { | |
305 | bool is_valid = true; | |
5cd6d0e5 PP |
306 | struct bt_field_class *src_fc; |
307 | struct bt_field_class *tgt_fc; | |
308 | struct bt_field_class *prev_fc = NULL; | |
44c440bc PP |
309 | uint64_t src_i = 0, tgt_i = 0; |
310 | ||
311 | if (src_field_path->root != tgt_field_path->root) { | |
312 | goto end; | |
313 | } | |
314 | ||
5cd6d0e5 PP |
315 | src_fc = borrow_root_field_class(ctx, src_field_path->root); |
316 | tgt_fc = borrow_root_field_class(ctx, tgt_field_path->root); | |
317 | BT_ASSERT(src_fc); | |
318 | BT_ASSERT(tgt_fc); | |
44c440bc | 319 | |
66ddcddf PP |
320 | for (src_i = 0, tgt_i = 0; src_i < src_field_path->items->len && |
321 | tgt_i < tgt_field_path->items->len; src_i++, tgt_i++) { | |
322 | struct bt_field_path_item *src_fp_item = | |
323 | bt_field_path_borrow_item_by_index_inline( | |
324 | src_field_path, src_i); | |
325 | struct bt_field_path_item *tgt_fp_item = | |
326 | bt_field_path_borrow_item_by_index_inline( | |
327 | tgt_field_path, tgt_i); | |
44c440bc | 328 | |
5cd6d0e5 PP |
329 | if (src_fc != tgt_fc) { |
330 | if (!prev_fc) { | |
44c440bc PP |
331 | /* |
332 | * This is correct: the LCA is the root | |
e6276565 PP |
333 | * scope field class, which must be a |
334 | * structure field class. | |
44c440bc PP |
335 | */ |
336 | break; | |
337 | } | |
338 | ||
864cad70 | 339 | if (prev_fc->type != BT_FIELD_CLASS_TYPE_STRUCTURE) { |
44c440bc PP |
340 | is_valid = false; |
341 | } | |
342 | ||
343 | break; | |
344 | } | |
345 | ||
5cd6d0e5 | 346 | prev_fc = src_fc; |
66ddcddf PP |
347 | src_fc = borrow_child_field_class(src_fc, src_fp_item); |
348 | tgt_fc = borrow_child_field_class(tgt_fc, tgt_fp_item); | |
44c440bc PP |
349 | } |
350 | ||
351 | end: | |
352 | return is_valid; | |
353 | } | |
354 | ||
d98421f2 | 355 | BT_ASSERT_COND_DEV_FUNC |
44c440bc | 356 | static inline |
5cd6d0e5 | 357 | bool lca_to_target_has_struct_fc_only(struct bt_field_path *src_field_path, |
44c440bc PP |
358 | struct bt_field_path *tgt_field_path, |
359 | struct bt_resolve_field_path_context *ctx) | |
360 | { | |
361 | bool is_valid = true; | |
5cd6d0e5 PP |
362 | struct bt_field_class *src_fc; |
363 | struct bt_field_class *tgt_fc; | |
44c440bc PP |
364 | uint64_t src_i = 0, tgt_i = 0; |
365 | ||
366 | if (src_field_path->root != tgt_field_path->root) { | |
367 | goto end; | |
368 | } | |
369 | ||
5cd6d0e5 PP |
370 | src_fc = borrow_root_field_class(ctx, src_field_path->root); |
371 | tgt_fc = borrow_root_field_class(ctx, tgt_field_path->root); | |
372 | BT_ASSERT(src_fc); | |
373 | BT_ASSERT(tgt_fc); | |
374 | BT_ASSERT(src_fc == tgt_fc); | |
44c440bc PP |
375 | |
376 | /* Find LCA */ | |
66ddcddf PP |
377 | for (src_i = 0, tgt_i = 0; src_i < src_field_path->items->len && |
378 | tgt_i < tgt_field_path->items->len; src_i++, tgt_i++) { | |
379 | struct bt_field_path_item *src_fp_item = | |
380 | bt_field_path_borrow_item_by_index_inline( | |
381 | src_field_path, src_i); | |
382 | struct bt_field_path_item *tgt_fp_item = | |
383 | bt_field_path_borrow_item_by_index_inline( | |
384 | tgt_field_path, tgt_i); | |
44c440bc PP |
385 | |
386 | if (src_i != tgt_i) { | |
5cd6d0e5 | 387 | /* Next field class is different: LCA is `tgt_fc` */ |
44c440bc PP |
388 | break; |
389 | } | |
390 | ||
66ddcddf PP |
391 | src_fc = borrow_child_field_class(src_fc, src_fp_item); |
392 | tgt_fc = borrow_child_field_class(tgt_fc, tgt_fp_item); | |
44c440bc PP |
393 | } |
394 | ||
5cd6d0e5 | 395 | /* Only structure field classes to the target */ |
66ddcddf PP |
396 | for (; tgt_i < tgt_field_path->items->len; tgt_i++) { |
397 | struct bt_field_path_item *tgt_fp_item = | |
398 | bt_field_path_borrow_item_by_index_inline( | |
399 | tgt_field_path, tgt_i); | |
44c440bc | 400 | |
ebdb6693 PP |
401 | if (bt_field_class_type_is(tgt_fc->type, |
402 | BT_FIELD_CLASS_TYPE_ARRAY) || | |
403 | bt_field_class_type_is(tgt_fc->type, | |
404 | BT_FIELD_CLASS_TYPE_OPTION) || | |
405 | bt_field_class_type_is(tgt_fc->type, | |
406 | BT_FIELD_CLASS_TYPE_VARIANT)) { | |
44c440bc PP |
407 | is_valid = false; |
408 | goto end; | |
409 | } | |
410 | ||
66ddcddf | 411 | tgt_fc = borrow_child_field_class(tgt_fc, tgt_fp_item); |
44c440bc PP |
412 | } |
413 | ||
414 | end: | |
415 | return is_valid; | |
416 | } | |
417 | ||
d98421f2 | 418 | BT_ASSERT_COND_DEV_FUNC |
44c440bc | 419 | static inline |
5cd6d0e5 PP |
420 | bool field_path_is_valid(struct bt_field_class *src_fc, |
421 | struct bt_field_class *tgt_fc, | |
44c440bc PP |
422 | struct bt_resolve_field_path_context *ctx) |
423 | { | |
424 | bool is_valid = true; | |
5cd6d0e5 PP |
425 | struct bt_field_path *src_field_path = find_field_class_in_ctx( |
426 | src_fc, ctx); | |
427 | struct bt_field_path *tgt_field_path = find_field_class_in_ctx( | |
428 | tgt_fc, ctx); | |
44c440bc PP |
429 | |
430 | if (!src_field_path) { | |
d98421f2 | 431 | BT_ASSERT_COND_DEV_MSG("Cannot find requesting field class in " |
5cd6d0e5 | 432 | "resolving context: %!+F", src_fc); |
44c440bc PP |
433 | is_valid = false; |
434 | goto end; | |
435 | } | |
436 | ||
437 | if (!tgt_field_path) { | |
d98421f2 | 438 | BT_ASSERT_COND_DEV_MSG("Cannot find target field class in " |
5cd6d0e5 | 439 | "resolving context: %!+F", tgt_fc); |
44c440bc PP |
440 | is_valid = false; |
441 | goto end; | |
442 | } | |
443 | ||
444 | /* Target must be before source */ | |
445 | if (!target_is_before_source(src_field_path, tgt_field_path)) { | |
d98421f2 | 446 | BT_ASSERT_COND_DEV_MSG("Target field class is located after " |
e6276565 | 447 | "requesting field class: %![req-fc-]+F, %![tgt-fc-]+F", |
5cd6d0e5 | 448 | src_fc, tgt_fc); |
44c440bc PP |
449 | is_valid = false; |
450 | goto end; | |
451 | } | |
452 | ||
453 | /* | |
454 | * If target is in a different scope than source, there are no | |
5cd6d0e5 | 455 | * array or variant field classes on the way to the target. |
44c440bc | 456 | */ |
5cd6d0e5 | 457 | if (!target_field_path_in_different_scope_has_struct_fc_only( |
44c440bc | 458 | src_field_path, tgt_field_path, ctx)) { |
d98421f2 | 459 | BT_ASSERT_COND_DEV_MSG("Target field class is located in a " |
e6276565 PP |
460 | "different scope than requesting field class, " |
461 | "but within an array or a variant field class: " | |
5cd6d0e5 PP |
462 | "%![req-fc-]+F, %![tgt-fc-]+F", |
463 | src_fc, tgt_fc); | |
44c440bc PP |
464 | is_valid = false; |
465 | goto end; | |
466 | } | |
467 | ||
e6276565 | 468 | /* Same scope: LCA must be a structure field class */ |
5cd6d0e5 | 469 | if (!lca_is_structure_field_class(src_field_path, tgt_field_path, ctx)) { |
d98421f2 | 470 | BT_ASSERT_COND_DEV_MSG("Lowest common ancestor of target and " |
e6276565 | 471 | "requesting field classes is not a structure field class: " |
5cd6d0e5 PP |
472 | "%![req-fc-]+F, %![tgt-fc-]+F", |
473 | src_fc, tgt_fc); | |
44c440bc PP |
474 | is_valid = false; |
475 | goto end; | |
476 | } | |
477 | ||
478 | /* Same scope: path from LCA to target has no array/variant FTs */ | |
5cd6d0e5 | 479 | if (!lca_to_target_has_struct_fc_only(src_field_path, tgt_field_path, |
44c440bc | 480 | ctx)) { |
d98421f2 | 481 | BT_ASSERT_COND_DEV_MSG("Path from lowest common ancestor of target " |
e6276565 PP |
482 | "and requesting field classes to target field class " |
483 | "contains an array or a variant field class: " | |
5cd6d0e5 | 484 | "%![req-fc-]+F, %![tgt-fc-]+F", src_fc, tgt_fc); |
44c440bc PP |
485 | is_valid = false; |
486 | goto end; | |
487 | } | |
488 | ||
489 | end: | |
65300d60 PP |
490 | bt_object_put_ref(src_field_path); |
491 | bt_object_put_ref(tgt_field_path); | |
44c440bc PP |
492 | return is_valid; |
493 | } | |
494 | ||
495 | static | |
5cd6d0e5 PP |
496 | struct bt_field_path *resolve_field_path(struct bt_field_class *src_fc, |
497 | struct bt_field_class *tgt_fc, | |
1778c2a4 PP |
498 | struct bt_resolve_field_path_context *ctx, |
499 | const char *api_func) | |
44c440bc | 500 | { |
1778c2a4 PP |
501 | BT_ASSERT_PRE_DEV_FROM_FUNC(api_func, "valid-field-class", |
502 | field_path_is_valid(src_fc, tgt_fc, ctx), | |
e6276565 | 503 | "Invalid target field class: %![req-fc-]+F, %![tgt-fc-]+F", |
5cd6d0e5 PP |
504 | src_fc, tgt_fc); |
505 | return find_field_class_in_ctx(tgt_fc, ctx); | |
44c440bc PP |
506 | } |
507 | ||
5cd6d0e5 | 508 | int bt_resolve_field_paths(struct bt_field_class *fc, |
1778c2a4 PP |
509 | struct bt_resolve_field_path_context *ctx, |
510 | const char *api_func) | |
44c440bc PP |
511 | { |
512 | int ret = 0; | |
513 | ||
5cd6d0e5 | 514 | BT_ASSERT(fc); |
44c440bc | 515 | |
5cd6d0e5 | 516 | /* Resolving part for dynamic array and variant field classes */ |
ebdb6693 PP |
517 | if (bt_field_class_type_is(fc->type, |
518 | BT_FIELD_CLASS_TYPE_OPTION_WITH_SELECTOR_FIELD)) { | |
de821fe5 | 519 | struct bt_field_class_option_with_selector_field *opt_fc = (void *) fc; |
b38aea74 | 520 | |
81b8fa44 PP |
521 | BT_ASSERT(opt_fc->selector_fc); |
522 | BT_ASSERT(!opt_fc->selector_field_path); | |
523 | opt_fc->selector_field_path = resolve_field_path( | |
1778c2a4 | 524 | fc, opt_fc->selector_fc, ctx, __func__); |
81b8fa44 PP |
525 | if (!opt_fc->selector_field_path) { |
526 | ret = -1; | |
527 | goto end; | |
b38aea74 | 528 | } |
ebdb6693 | 529 | } else if (fc->type == BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD) { |
9c08c816 | 530 | struct bt_field_class_array_dynamic *dyn_array_fc = (void *) fc; |
44c440bc | 531 | |
81b8fa44 PP |
532 | BT_ASSERT(dyn_array_fc->length_fc); |
533 | BT_ASSERT(!dyn_array_fc->length_field_path); | |
534 | dyn_array_fc->length_field_path = resolve_field_path( | |
1778c2a4 | 535 | fc, dyn_array_fc->length_fc, ctx, __func__); |
81b8fa44 PP |
536 | if (!dyn_array_fc->length_field_path) { |
537 | ret = -1; | |
538 | goto end; | |
44c440bc | 539 | } |
ebdb6693 PP |
540 | } else if (bt_field_class_type_is(fc->type, |
541 | BT_FIELD_CLASS_TYPE_VARIANT_WITH_SELECTOR_FIELD)) { | |
de821fe5 | 542 | struct bt_field_class_variant_with_selector_field *var_fc = |
45c51519 | 543 | (void *) fc; |
5cd6d0e5 PP |
544 | |
545 | if (var_fc->selector_fc) { | |
546 | BT_ASSERT(!var_fc->selector_field_path); | |
547 | var_fc->selector_field_path = | |
548 | resolve_field_path(fc, | |
1778c2a4 PP |
549 | (void *) var_fc->selector_fc, ctx, |
550 | __func__); | |
5cd6d0e5 | 551 | if (!var_fc->selector_field_path) { |
44c440bc PP |
552 | ret = -1; |
553 | goto end; | |
554 | } | |
555 | } | |
556 | } | |
44c440bc PP |
557 | |
558 | /* Recursive part */ | |
ebdb6693 | 559 | if (bt_field_class_type_is(fc->type, BT_FIELD_CLASS_TYPE_OPTION)) { |
b38aea74 PP |
560 | struct bt_field_class_option *opt_fc = (void *) fc; |
561 | ||
1778c2a4 | 562 | ret = bt_resolve_field_paths(opt_fc->content_fc, ctx, api_func); |
ebdb6693 PP |
563 | } else if (fc->type == BT_FIELD_CLASS_TYPE_STRUCTURE || |
564 | bt_field_class_type_is(fc->type, | |
565 | BT_FIELD_CLASS_TYPE_VARIANT)) { | |
5cd6d0e5 PP |
566 | struct bt_field_class_named_field_class_container *container_fc = |
567 | (void *) fc; | |
44c440bc PP |
568 | uint64_t i; |
569 | ||
5cd6d0e5 PP |
570 | for (i = 0; i < container_fc->named_fcs->len; i++) { |
571 | struct bt_named_field_class *named_fc = | |
45c51519 | 572 | container_fc->named_fcs->pdata[i]; |
44c440bc | 573 | |
1778c2a4 PP |
574 | ret = bt_resolve_field_paths(named_fc->fc, ctx, |
575 | api_func); | |
44c440bc PP |
576 | if (ret) { |
577 | goto end; | |
578 | } | |
579 | } | |
ebdb6693 PP |
580 | } else if (bt_field_class_type_is(fc->type, |
581 | BT_FIELD_CLASS_TYPE_ARRAY)) { | |
5cd6d0e5 | 582 | struct bt_field_class_array *array_fc = (void *) fc; |
44c440bc | 583 | |
1778c2a4 PP |
584 | ret = bt_resolve_field_paths(array_fc->element_fc, ctx, |
585 | api_func); | |
44c440bc PP |
586 | } |
587 | ||
588 | end: | |
589 | return ret; | |
590 | } |