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