LCOV - code coverage report
Current view: top level - lib/bpf - bpf_validate_debug.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 144 202 71.3 %
Date: 2026-08-01 17:54:00 Functions: 19 25 76.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 114 195 58.5 %

           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                 :            : }

Generated by: LCOV version 1.14