Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2025 Huawei Technologies Co., Ltd
3 : : */
4 : :
5 : : #include "bpf_impl.h"
6 : : #include "bpf_validate.h"
7 : : #include "bpf_validate_debug.h"
8 : :
9 : : #include <eal_export.h>
10 : : #include <rte_bpf_validate_debug.h>
11 : : #include <rte_errno.h>
12 : : #include <rte_per_lcore.h>
13 : :
14 : : #include <errno.h>
15 : : #include <stddef.h>
16 : : #include <stdlib.h>
17 : :
18 : : #ifndef LIST_FOREACH_SAFE
19 : : /* We need this macro which neither Linux nor EAL for Linux include yet. */
20 : : #define LIST_FOREACH_SAFE(var, head, field, tvar) \
21 : : for ((var) = LIST_FIRST((head)); \
22 : : (var) && ((tvar) = LIST_NEXT((var), field), 1); \
23 : : (var) = (tvar))
24 : : #endif
25 : :
26 : : #define EVENT_ARRAY_LENGTH RTE_BPF_VALIDATE_DEBUG_EVENT_END
27 : :
28 : : struct rte_bpf_validate_debug_point {
29 : : LIST_ENTRY(rte_bpf_validate_debug_point) list;
30 : : struct rte_bpf_validate_debug_callback callback;
31 : : uint32_t pc;
32 : : };
33 : :
34 : : LIST_HEAD(point_list, rte_bpf_validate_debug_point);
35 : :
36 : : struct rte_bpf_validate_debug {
37 : : /* Accessible immediately after object creation. */
38 : : struct point_list pending_breakpoints;
39 : : struct point_list *catchpoint_lists;
40 : : struct rte_bpf_validate_debug_callback step_callback;
41 : :
42 : : /* Accessible only after evaluate start. */
43 : : const struct bpf_verifier *verifier;
44 : : const struct rte_bpf_prm_ex *bpf_prm;
45 : : struct point_list *breakpoint_lists;
46 : : struct rte_bpf_validate_debug_point *last_point;
47 : : uint32_t pc;
48 : : /* Evaluate stage (only tracking `evaluate` part at the moment). */
49 : : bool evaluate_started;
50 : : bool evaluate_finished;
51 : : int evaluate_result; /* Only valid if `evaluate_finished` is true. */
52 : : };
53 : :
54 : : /* Point lists functions. */
55 : :
56 : : /* Destroy all points in the list. */
57 : : static void
58 : : point_list_destroy(struct point_list *point_list)
59 : : {
60 : : struct rte_bpf_validate_debug_point *point, *next;
61 : :
62 [ + + + + ]: 5706 : LIST_FOREACH_SAFE(point, point_list, list, next)
63 : 1566 : rte_bpf_validate_debug_point_destroy(point);
64 : :
65 : : RTE_ASSERT(LIST_EMPTY(point_list));
66 : : }
67 : :
68 : : /* Destroy all points in all lists in the array and free the array. */
69 : : static void
70 : 414 : point_lists_destroy(struct point_list *point_lists, uint32_t length)
71 : : {
72 [ + - ]: 414 : if (point_lists == NULL)
73 : : return;
74 : :
75 [ + + ]: 4140 : for (uint32_t pli = 0; pli != length; ++pli)
76 : 3726 : point_list_destroy(&point_lists[pli]);
77 : :
78 : 414 : free(point_lists);
79 : : }
80 : :
81 : : /* Dynamically allocate and initialize an array of point lists. */
82 : : static struct point_list *
83 : 828 : point_lists_create(uint32_t length)
84 : : {
85 : : /* Allocate at least one element to avoid calloc(0, ...) shenanigans. */
86 : : struct point_list *const array =
87 : 828 : calloc(RTE_MAX(1u, length), sizeof(*array));
88 [ + - ]: 828 : if (array == NULL)
89 : : return NULL;
90 : :
91 [ + + ]: 9935 : for (uint32_t pli = 0; pli != length; ++pli)
92 : 9107 : LIST_INIT(&array[pli]);
93 : :
94 : : return array;
95 : : }
96 : :
97 : : /* Move point to a different list. */
98 : : static inline void
99 : : point_move(struct rte_bpf_validate_debug_point *point,
100 : : struct point_list *destination)
101 : : {
102 : 2214 : LIST_REMOVE(point, list);
103 [ + + + + : 4608 : LIST_INSERT_HEAD(destination, point, list);
+ + - + ]
104 : : }
105 : :
106 : : /* Move all points between lists (the order is inverted). */
107 : : static void
108 : : points_move(struct point_list *source, struct point_list *destination)
109 : : {
110 : : struct rte_bpf_validate_debug_point *point, *next;
111 : :
112 [ + + - + : 9665 : LIST_FOREACH_SAFE(point, source, list, next)
+ + + + +
+ + + ]
113 : : point_move(point, destination);
114 : : RTE_ASSERT(LIST_EMPTY(source));
115 : : }
116 : :
117 : : /* Pending breakpoints. */
118 : :
119 : : /* Return true if all pending breakpoints have pc less than nb_ins. */
120 : : static bool
121 : : debug_pending_breakpoints_are_valid(const struct rte_bpf_validate_debug *debug,
122 : : uint32_t nb_ins)
123 : : {
124 : : const struct rte_bpf_validate_debug_point *breakpoint;
125 : :
126 [ + + ]: 1566 : LIST_FOREACH(breakpoint, &debug->pending_breakpoints, list)
127 [ + - ]: 1152 : if (breakpoint->pc >= nb_ins)
128 : : return false;
129 : :
130 : : return true;
131 : : }
132 : :
133 : : /* Move all pending breakpoints to correct per-pc lists. */
134 : : static void
135 : 414 : debug_pending_breakpoints_restore(struct rte_bpf_validate_debug *debug)
136 : : {
137 : : struct rte_bpf_validate_debug_point *breakpoint, *next;
138 : : struct point_list breakpoints;
139 : :
140 : : /* Invert the list first to preserve point order when we move them. */
141 : 414 : LIST_INIT(&breakpoints);
142 : : points_move(&debug->pending_breakpoints, &breakpoints);
143 : :
144 [ + + ]: 1566 : LIST_FOREACH_SAFE(breakpoint, &breakpoints, list, next)
145 [ + + ]: 1152 : point_move(breakpoint, &debug->breakpoint_lists[breakpoint->pc]);
146 : : RTE_ASSERT(LIST_EMPTY(&breakpoints));
147 : 414 : }
148 : :
149 : : /* Move all breakpoints from per-pc lists to the pending one. */
150 : : static void
151 : 414 : debug_pending_breakpoints_save(struct rte_bpf_validate_debug *debug)
152 : : {
153 : : struct point_list breakpoints;
154 : :
155 : 414 : LIST_INIT(&breakpoints);
156 [ + + ]: 5795 : for (uint32_t pc = 0; pc != debug->bpf_prm->raw.nb_ins; ++pc)
157 : 5381 : points_move(&debug->breakpoint_lists[pc], &breakpoints);
158 : :
159 : : /* Invert the list to restore point order after we moved them. */
160 : : RTE_ASSERT(LIST_EMPTY(&debug->pending_breakpoints));
161 : : points_move(&breakpoints, &debug->pending_breakpoints);
162 : 414 : }
163 : :
164 : : /* Debug instance creation and destruction. */
165 : :
166 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_bpf_validate_debug_destroy, 26.07)
167 : : void
168 : 414 : rte_bpf_validate_debug_destroy(struct rte_bpf_validate_debug *debug)
169 : : {
170 [ + - ]: 414 : if (debug == NULL)
171 : : return;
172 : :
173 : : /* Cannot destroy the instance during validation. */
174 : : RTE_ASSERT(!debug->evaluate_started);
175 : :
176 : 414 : point_lists_destroy(debug->catchpoint_lists, EVENT_ARRAY_LENGTH);
177 : : point_list_destroy(&debug->pending_breakpoints);
178 : 414 : free(debug);
179 : : }
180 : :
181 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_bpf_validate_debug_create, 26.07)
182 : : struct rte_bpf_validate_debug *
183 : 414 : rte_bpf_validate_debug_create(void)
184 : : {
185 : 414 : struct rte_bpf_validate_debug *const debug = calloc(1, sizeof(*debug));
186 [ - + ]: 414 : if (debug == NULL) {
187 : 0 : rte_errno = ENOMEM;
188 : 0 : return NULL;
189 : : }
190 : :
191 : : LIST_INIT(&debug->pending_breakpoints);
192 : :
193 : 414 : debug->catchpoint_lists = point_lists_create(EVENT_ARRAY_LENGTH);
194 [ - + ]: 414 : if (debug->catchpoint_lists == NULL) {
195 : 0 : free(debug);
196 : 0 : rte_errno = ENOMEM;
197 : 0 : return NULL;
198 : : }
199 : :
200 : : return debug;
201 : : }
202 : :
203 : : /* Managing callbacks. */
204 : :
205 : : /* Call back the user function with correct arguments for a point. */
206 : : static inline int
207 : : debug_point_call_back(struct rte_bpf_validate_debug *debug,
208 : : struct rte_bpf_validate_debug_point *point)
209 : : {
210 : 6150 : debug->last_point = point;
211 : 6150 : return point->callback.fn(debug, point->callback.ctx);
212 : : }
213 : :
214 : : /* Call back all points in point_list. */
215 : : static int
216 : : debug_points_call_back(struct rte_bpf_validate_debug *debug,
217 : : const struct point_list *point_list)
218 : : {
219 : : struct rte_bpf_validate_debug_point *point, *next;
220 : : int rc = 0;
221 : :
222 [ + + - + : 37148 : LIST_FOREACH_SAFE(point, point_list, list, next)
+ + - + -
+ ]
223 [ + - - - : 6150 : rc = rc < 0 ? rc : debug_point_call_back(debug, point);
+ - - - -
- ]
224 : :
225 : : return rc;
226 : : }
227 : :
228 : : /* Call back all catchpoints for the specified event. */
229 : : static int
230 : : debug_send_event(struct rte_bpf_validate_debug *debug, debug_event_t event)
231 : : {
232 : 23519 : return debug_points_call_back(debug, &debug->catchpoint_lists[event]);
233 : : }
234 : :
235 : : /* Create new point and insert it into the specified list. */
236 : : static struct rte_bpf_validate_debug_point *
237 : 1566 : point_list_insert(struct point_list *point_list,
238 : : const struct rte_bpf_validate_debug_callback *callback, uint32_t pc)
239 : : {
240 : : struct rte_bpf_validate_debug_point *const point =
241 : 1566 : malloc(sizeof(*point));
242 [ - + ]: 1566 : if (point == NULL) {
243 : 0 : rte_errno = ENOMEM;
244 : 0 : return NULL;
245 : : }
246 : :
247 [ + + ]: 1566 : LIST_INSERT_HEAD(point_list, point, list);
248 : 1566 : point->callback = *callback;
249 : 1566 : point->pc = pc;
250 : 1566 : return point;
251 : : }
252 : :
253 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_bpf_validate_debug_break, 26.07)
254 : : struct rte_bpf_validate_debug_point *
255 : 1152 : rte_bpf_validate_debug_break(struct rte_bpf_validate_debug *debug, uint32_t pc,
256 : : const struct rte_bpf_validate_debug_callback *callback)
257 : : {
258 [ + - - + ]: 1152 : if (debug == NULL || callback == NULL || callback->fn == NULL) {
259 : 0 : rte_errno = EINVAL;
260 : 0 : return NULL;
261 : : }
262 : :
263 [ + - ]: 1152 : if (!debug->evaluate_started)
264 : 1152 : return point_list_insert(&debug->pending_breakpoints,
265 : : callback, pc);
266 : :
267 [ # # ]: 0 : if (pc >= debug->bpf_prm->raw.nb_ins) {
268 : 0 : rte_errno = ENOENT;
269 : 0 : return NULL;
270 : : }
271 : :
272 : 0 : return point_list_insert(&debug->breakpoint_lists[pc], callback, pc);
273 : : }
274 : :
275 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_bpf_validate_debug_catch, 26.07)
276 : : struct rte_bpf_validate_debug_point *
277 : 414 : rte_bpf_validate_debug_catch(struct rte_bpf_validate_debug *debug,
278 : : debug_event_t event, const struct rte_bpf_validate_debug_callback *callback)
279 : : {
280 [ + - + - ]: 414 : if (debug == NULL || callback == NULL || callback->fn == NULL ||
281 [ - + ]: 414 : event < 0 || event >= RTE_BPF_VALIDATE_DEBUG_EVENT_END) {
282 : 0 : rte_errno = EINVAL;
283 : 0 : return NULL;
284 : : }
285 : :
286 : 414 : return point_list_insert(&debug->catchpoint_lists[event], callback, 0);
287 : : }
288 : :
289 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_bpf_validate_debug_point_destroy, 26.07)
290 : : void
291 : 1566 : rte_bpf_validate_debug_point_destroy(struct rte_bpf_validate_debug_point *point)
292 : : {
293 [ + - ]: 1566 : if (point == NULL)
294 : : return;
295 : :
296 [ + + ]: 1566 : LIST_REMOVE(point, list);
297 : 1566 : free(point);
298 : : }
299 : :
300 : : /* Querying execution state. */
301 : :
302 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_bpf_validate_debug_get_bpf_param, 26.07)
303 : : const struct rte_bpf_prm_ex *
304 : 0 : rte_bpf_validate_debug_get_bpf_param(const struct rte_bpf_validate_debug *debug)
305 : : {
306 [ # # ]: 0 : if (debug == NULL) {
307 : 0 : rte_errno = EINVAL;
308 : 0 : return NULL;
309 : : }
310 : :
311 [ # # ]: 0 : if (!debug->evaluate_started) {
312 : 0 : rte_errno = ECHILD;
313 : 0 : return NULL;
314 : : }
315 : :
316 : 0 : return debug->bpf_prm;
317 : : }
318 : :
319 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_bpf_validate_debug_get_ins, 26.07)
320 : : int
321 : 0 : rte_bpf_validate_debug_get_ins(const struct rte_bpf_validate_debug *debug,
322 : : const struct ebpf_insn **ins, uint32_t *nb_ins)
323 : : {
324 [ # # ]: 0 : if (debug == NULL)
325 : : return -EINVAL;
326 : :
327 [ # # ]: 0 : if (!debug->evaluate_started)
328 : : return -ECHILD;
329 : :
330 [ # # ]: 0 : if (debug->bpf_prm->origin != RTE_BPF_ORIGIN_RAW)
331 : : return -ENOTSUP;
332 : :
333 : 0 : *ins = debug->bpf_prm->raw.ins;
334 : 0 : *nb_ins = debug->bpf_prm->raw.nb_ins;
335 : 0 : return 0;
336 : : }
337 : :
338 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_bpf_validate_debug_get_last_point, 26.07)
339 : : struct rte_bpf_validate_debug_point *
340 : 0 : rte_bpf_validate_debug_get_last_point(const struct rte_bpf_validate_debug *debug)
341 : : {
342 [ # # ]: 0 : if (debug == NULL) {
343 : 0 : rte_errno = EINVAL;
344 : 0 : return NULL;
345 : : }
346 : :
347 : 0 : return debug->last_point;
348 : : }
349 : :
350 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_bpf_validate_debug_get_pc, 26.07)
351 : : uint32_t
352 : 6150 : rte_bpf_validate_debug_get_pc(const struct rte_bpf_validate_debug *debug)
353 : : {
354 [ + - + - ]: 6150 : if (debug == NULL || !debug->evaluate_started)
355 : : return UINT32_MAX;
356 : :
357 : 6150 : return debug->pc;
358 : : }
359 : :
360 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_bpf_validate_debug_get_validation_result, 26.07)
361 : : int
362 : 0 : rte_bpf_validate_debug_get_validation_result(const struct rte_bpf_validate_debug *debug,
363 : : int *result)
364 : : {
365 [ # # ]: 0 : if (debug == NULL)
366 : : return -EINVAL;
367 : :
368 [ # # ]: 0 : if (!debug->evaluate_finished)
369 : : return -EAGAIN;
370 : :
371 : 0 : *result = debug->evaluate_result;
372 : :
373 : 0 : return 0;
374 : : }
375 : :
376 : : /* Querying VM state. */
377 : :
378 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_bpf_validate_debug_can_access, 26.07)
379 : : int
380 : 96 : rte_bpf_validate_debug_can_access(const struct rte_bpf_validate_debug *debug,
381 : : const struct ebpf_insn *access, uint64_t off64)
382 : : {
383 [ + - ]: 96 : if (debug == NULL || access == NULL)
384 : : return -EINVAL;
385 : :
386 [ + - ]: 96 : if (!debug->evaluate_started)
387 : : return -ECHILD;
388 : :
389 : 96 : return __rte_bpf_validate_can_access(debug->verifier, access, off64);
390 : : }
391 : :
392 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_bpf_validate_debug_may_jump, 26.07)
393 : : int
394 : 14608 : rte_bpf_validate_debug_may_jump(const struct rte_bpf_validate_debug *debug,
395 : : const struct ebpf_insn *jump, uint64_t imm64)
396 : : {
397 [ + - ]: 14608 : if (debug == NULL || jump == NULL)
398 : : return -EINVAL;
399 : :
400 [ + - ]: 14608 : if (!debug->evaluate_started)
401 : : return -ECHILD;
402 : :
403 : 14608 : return __rte_bpf_validate_may_jump(debug->verifier, jump, imm64);
404 : : }
405 : :
406 : : /* Formatting VM state for user. */
407 : :
408 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_bpf_validate_debug_format_register_info, 26.07)
409 : : int
410 : 1833 : rte_bpf_validate_debug_format_register_info(const struct rte_bpf_validate_debug *debug,
411 : : char *buffer, size_t bufsz, uint8_t reg)
412 : : {
413 [ + - ]: 1833 : if (debug == NULL)
414 : : return -EINVAL;
415 : :
416 [ + - ]: 1833 : if (!debug->evaluate_started)
417 : : return -ECHILD;
418 : :
419 : 1833 : return __rte_bpf_validate_format_register_info(debug->verifier, buffer,
420 : : bufsz, reg);
421 : : }
422 : :
423 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_bpf_validate_debug_format_frame_info, 26.07)
424 : : int
425 : 0 : rte_bpf_validate_debug_format_frame_info(const struct rte_bpf_validate_debug *debug,
426 : : char *buffer, size_t bufsz, int32_t offset)
427 : : {
428 [ # # ]: 0 : if (debug == NULL)
429 : : return -EINVAL;
430 : :
431 [ # # ]: 0 : if (!debug->evaluate_started)
432 : : return -ECHILD;
433 : :
434 : 0 : return __rte_bpf_validate_format_frame_info(debug->verifier, buffer,
435 : : bufsz, offset);
436 : : }
437 : :
438 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_bpf_validate_debug_get_frame_size, 26.07)
439 : : int32_t
440 : 0 : rte_bpf_validate_debug_get_frame_size(const struct rte_bpf_validate_debug *debug)
441 : : {
442 [ # # ]: 0 : if (debug == NULL)
443 : : return -EINVAL;
444 : :
445 [ # # ]: 0 : if (!debug->evaluate_started)
446 : : return -ECHILD;
447 : :
448 : 0 : return __rte_bpf_validate_get_frame_size(debug->verifier);
449 : : }
450 : :
451 : : /* Courtesy formatting functions for user-supplied values. */
452 : :
453 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_bpf_validate_debug_format_value, 26.07)
454 : : int
455 : 3838 : rte_bpf_validate_debug_format_value(char *buffer, size_t bufsz, char format,
456 : : uint64_t value)
457 : : {
458 : : static const struct {
459 : : uint64_t value;
460 : : const char *name;
461 : : } constants[] = {
462 : : { .value = INT64_MIN, .name = "INT64_MIN" },
463 : : { .value = INT32_MIN, .name = "INT32_MIN" },
464 : : { .value = INT16_MIN, .name = "INT16_MIN" },
465 : : { .value = INT8_MIN, .name = "INT8_MIN" },
466 : : { .value = INT8_MAX, .name = "INT8_MAX" },
467 : : { .value = UINT8_MAX, .name = "UINT8_MAX" },
468 : : { .value = INT16_MAX, .name = "INT16_MAX" },
469 : : { .value = UINT16_MAX, .name = "UINT16_MAX" },
470 : : { .value = INT32_MAX, .name = "INT32_MAX" },
471 : : { .value = UINT32_MAX, .name = "UINT32_MAX" },
472 : : { .value = INT64_MAX, .name = "INT64_MAX" },
473 : : /* UINT64_MAX omitted on purpose, it looks better as -1 */
474 : : };
475 : :
476 [ + + - ]: 3838 : switch (format) {
477 : : case 'd':
478 [ + + ]: 36407 : for (int ci = 0; ci != RTE_DIM(constants); ++ci)
479 [ + + ]: 33400 : if (constants[ci].value == value)
480 : 73 : return snprintf(buffer, bufsz, "%s", constants[ci].name);
481 : : /*
482 : : * Special case numbers close to int32_t or int64_t range ends,
483 : : * since they are hard to recognize in decimal otherwise.
484 : : */
485 [ + + ]: 3007 : if (value - INT64_MIN < 1000000)
486 : 7 : return snprintf(buffer, bufsz, "INT64_MIN+%" PRId64,
487 : : value - INT64_MIN);
488 [ + + ]: 3000 : if (INT64_MAX - value < 1000000)
489 : 6 : return snprintf(buffer, bufsz, "INT64_MAX-%" PRId64,
490 : : INT64_MAX - value);
491 [ - + ]: 2994 : if (value - INT32_MIN < 1000)
492 : 0 : return snprintf(buffer, bufsz, "INT32_MIN+%" PRId64,
493 : : value - INT32_MIN);
494 [ - + ]: 2994 : if (INT32_MAX - value < 1000)
495 : 0 : return snprintf(buffer, bufsz, "INT32_MAX-%" PRId64,
496 : : INT32_MAX - value);
497 : 2994 : return snprintf(buffer, bufsz, "%" PRId64, value);
498 : 758 : case 'x':
499 : : /* Special case only the common case of UINT64_MAX. */
500 [ + + ]: 758 : if (value == UINT64_MAX)
501 : 24 : return snprintf(buffer, bufsz, "%s", "UINT64_MAX");
502 : 734 : return snprintf(buffer, bufsz, "%#" PRIx64, value);
503 : : default:
504 : : return -EINVAL;
505 : : }
506 : : }
507 : :
508 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_bpf_validate_debug_format_interval, 26.07)
509 : : int
510 : 2166 : rte_bpf_validate_debug_format_interval(char *buffer, size_t bufsz, char format,
511 : : uint64_t min, uint64_t max)
512 : : {
513 : : char min_buffer[32], max_buffer[32];
514 : : int rc;
515 : :
516 [ + + ]: 2166 : if (min == max)
517 : 494 : return rte_bpf_validate_debug_format_value(buffer, bufsz, format, min);
518 : :
519 : 1672 : rc = rte_bpf_validate_debug_format_value(min_buffer, sizeof(min_buffer), format, min);
520 [ + - ]: 1672 : if (rc < 0)
521 : : return rc;
522 : :
523 : 1672 : rc = rte_bpf_validate_debug_format_value(max_buffer, sizeof(max_buffer), format, max);
524 [ + - ]: 1672 : if (rc < 0)
525 : : return rc;
526 : :
527 : 1672 : return snprintf(buffer, bufsz, "%s..%s", min_buffer, max_buffer);
528 : : }
529 : :
530 : : /* Evaluation start and finish. */
531 : :
532 : : /* Free all resources associated with current evaluation. */
533 : : static void
534 : : debug_evaluate_close(struct rte_bpf_validate_debug *debug)
535 : : {
536 : : RTE_ASSERT(debug->evaluate_started);
537 : 414 : debug_pending_breakpoints_save(debug);
538 : 414 : free(debug->breakpoint_lists);
539 : 414 : debug->breakpoint_lists = NULL;
540 : 414 : debug->evaluate_started = false;
541 : : }
542 : :
543 : : int
544 : 834 : __rte_bpf_validate_debug_evaluate_start(struct rte_bpf_validate_debug *debug,
545 : : const struct bpf_verifier *verifier, const struct rte_bpf_prm_ex *bpf_prm)
546 : : {
547 [ + + ]: 834 : if (debug == NULL)
548 : : return 0;
549 : :
550 [ + - ]: 414 : if (verifier == NULL || bpf_prm == NULL ||
551 [ + - ]: 414 : bpf_prm->origin != RTE_BPF_ORIGIN_RAW)
552 : : return -EINVAL;
553 : :
554 [ - + ]: 414 : if (debug->evaluate_started) {
555 : 0 : RTE_BPF_LOG_FUNC_LINE(ERR, "already started");
556 : 0 : return -EEXIST;
557 : : }
558 : :
559 [ + - ]: 828 : if (!debug_pending_breakpoints_are_valid(debug, bpf_prm->raw.nb_ins))
560 : : return -ENOENT;
561 : :
562 : 414 : debug->verifier = verifier;
563 : 414 : debug->bpf_prm = bpf_prm;
564 : 414 : debug->breakpoint_lists = point_lists_create(bpf_prm->raw.nb_ins);
565 [ + - ]: 414 : if (debug->breakpoint_lists == NULL)
566 : : return -ENOMEM;
567 : 414 : debug_pending_breakpoints_restore(debug);
568 : 414 : debug->last_point = NULL;
569 : 414 : debug->pc = 0;
570 : 414 : debug->evaluate_started = true;
571 : :
572 : : const int rc = debug_send_event(debug,
573 : : RTE_BPF_VALIDATE_DEBUG_EVENT_VALIDATION_START);
574 [ - + ]: 414 : if (rc < 0) {
575 : : debug_evaluate_close(debug);
576 : 0 : return rc;
577 : : }
578 : :
579 : 414 : RTE_BPF_LOG_FUNC_LINE(DEBUG, "evaluate started");
580 : 414 : return 0;
581 : : }
582 : :
583 : : int
584 : 15333 : __rte_bpf_validate_debug_evaluate_step(struct rte_bpf_validate_debug *debug,
585 : : uint32_t pc, debug_event_t event)
586 : : {
587 : : int rc;
588 : :
589 [ + + ]: 15333 : if (debug == NULL)
590 : : return 0;
591 : :
592 [ - + ]: 10343 : if (!debug->evaluate_started) {
593 : 0 : RTE_BPF_LOG_FUNC_LINE(ERR, "not started");
594 : 0 : return -ECHILD;
595 : : }
596 : :
597 [ + - + - ]: 10343 : if (pc > debug->bpf_prm->raw.nb_ins || event < 0 ||
598 : : event >= RTE_BPF_VALIDATE_DEBUG_EVENT_END)
599 : : return -EINVAL;
600 : :
601 : 10343 : debug->pc = pc;
602 : :
603 : 10343 : rc = __rte_bpf_validate_state_is_valid(debug->verifier);
604 [ + + ]: 10343 : if (rc == 0)
605 : : rc = debug_send_event(debug,
606 : : RTE_BPF_VALIDATE_DEBUG_EVENT_INVALID_STATE);
607 : :
608 [ + + ]: 10343 : if (event != RTE_BPF_VALIDATE_DEBUG_EVENT_STEP)
609 [ + - ]: 8016 : rc = rc < 0 ? rc : debug_send_event(debug, event);
610 : :
611 : 10343 : if (event == RTE_BPF_VALIDATE_DEBUG_EVENT_STEP ||
612 [ + + ]: 10343 : event == RTE_BPF_VALIDATE_DEBUG_EVENT_BRANCH_ENTER)
613 : : /* Stepping into a real instruction to execute. */
614 [ + - ]: 7065 : rc = rc < 0 ? rc : debug_points_call_back(debug,
615 : 7065 : &debug->breakpoint_lists[pc]);
616 : :
617 [ + - ]: 10343 : rc = rc < 0 ? rc : debug_send_event(debug,
618 : : RTE_BPF_VALIDATE_DEBUG_EVENT_STEP);
619 : :
620 : : return rc;
621 : : }
622 : :
623 : : int
624 : 834 : __rte_bpf_validate_debug_evaluate_finish(struct rte_bpf_validate_debug *debug,
625 : : int result)
626 : : {
627 : : int rc = 0;
628 : : uint32_t pc;
629 : : debug_event_t event;
630 : :
631 [ + + ]: 834 : if (debug == NULL)
632 : : return 0;
633 : :
634 [ - + ]: 414 : if (!debug->evaluate_started) {
635 : 0 : RTE_BPF_LOG_FUNC_LINE(ERR, "not started");
636 : 0 : return -ECHILD;
637 : : }
638 : :
639 : 414 : debug->evaluate_finished = true;
640 : 414 : debug->evaluate_result = result;
641 : :
642 [ + - ]: 414 : if (result != -ECANCELED) {
643 [ - + ]: 414 : if (result < 0) {
644 : : /* Last known pc is the place we failed. */
645 : 0 : pc = debug->pc;
646 : : event = RTE_BPF_VALIDATE_DEBUG_EVENT_VALIDATION_FAILURE;
647 : : } else {
648 : : /* Show program end, not particular instruction. */
649 : 414 : pc = debug->bpf_prm->raw.nb_ins;
650 : : event = RTE_BPF_VALIDATE_DEBUG_EVENT_VALIDATION_SUCCESS;
651 : : }
652 : :
653 : 414 : rc = __rte_bpf_validate_debug_evaluate_step(debug, pc, event);
654 : : }
655 : :
656 : : debug_evaluate_close(debug);
657 : :
658 : 414 : return rc;
659 : : }
|