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