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