LCOV - code coverage report
Current view: top level - strace - qualify.c (source / functions) Hit Total Coverage
Test: strace-4.18.0.129.97bbb Code Coverage Lines: 270 271 99.6 %
Date: 2017-07-31 03:46:08 Functions: 29 29 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 236 240 98.3 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
       3                 :            :  * Copyright (c) 2016-2017 The strace developers.
       4                 :            :  * All rights reserved.
       5                 :            :  *
       6                 :            :  * Redistribution and use in source and binary forms, with or without
       7                 :            :  * modification, are permitted provided that the following conditions
       8                 :            :  * are met:
       9                 :            :  * 1. Redistributions of source code must retain the above copyright
      10                 :            :  *    notice, this list of conditions and the following disclaimer.
      11                 :            :  * 2. Redistributions in binary form must reproduce the above copyright
      12                 :            :  *    notice, this list of conditions and the following disclaimer in the
      13                 :            :  *    documentation and/or other materials provided with the distribution.
      14                 :            :  * 3. The name of the author may not be used to endorse or promote products
      15                 :            :  *    derived from this software without specific prior written permission.
      16                 :            :  *
      17                 :            :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
      18                 :            :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      19                 :            :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      20                 :            :  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
      21                 :            :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      22                 :            :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      23                 :            :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      24                 :            :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      25                 :            :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      26                 :            :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      27                 :            :  */
      28                 :            : 
      29                 :            : #include "defs.h"
      30                 :            : #include "nsig.h"
      31                 :            : #include <regex.h>
      32                 :            : 
      33                 :            : const struct syscall_class syscall_classes[] = {
      34                 :            :         { "desc",     TRACE_DESC      },
      35                 :            :         { "file",     TRACE_FILE      },
      36                 :            :         { "memory",   TRACE_MEMORY    },
      37                 :            :         { "process",  TRACE_PROCESS   },
      38                 :            :         { "signal",   TRACE_SIGNAL    },
      39                 :            :         { "ipc",      TRACE_IPC       },
      40                 :            :         { "network",  TRACE_NETWORK   },
      41                 :            :         { "%desc",    TRACE_DESC      },
      42                 :            :         { "%file",    TRACE_FILE      },
      43                 :            :         { "%memory",  TRACE_MEMORY    },
      44                 :            :         { "%process", TRACE_PROCESS   },
      45                 :            :         { "%signal",  TRACE_SIGNAL    },
      46                 :            :         { "%ipc",     TRACE_IPC       },
      47                 :            :         { "%network", TRACE_NETWORK   },
      48                 :            :         { "%stat",    TRACE_STAT      },
      49                 :            :         { "%lstat",   TRACE_LSTAT     },
      50                 :            :         { "%fstat",   TRACE_FSTAT     },
      51                 :            :         { "%%stat",   TRACE_STAT_LIKE },
      52                 :            :         { "%statfs",  TRACE_STATFS    },
      53                 :            :         { "%fstatfs", TRACE_FSTATFS   },
      54                 :            :         { "%%statfs", TRACE_STATFS_LIKE       },
      55                 :            :         {}
      56                 :            : };
      57                 :            : 
      58                 :            : typedef unsigned int number_slot_t;
      59                 :            : #define BITS_PER_SLOT (sizeof(number_slot_t) * 8)
      60                 :            : 
      61                 :            : struct number_set {
      62                 :            :         number_slot_t *vec;
      63                 :            :         unsigned int nslots;
      64                 :            :         bool not;
      65                 :            : };
      66                 :            : 
      67                 :            : struct number_set read_set;
      68                 :            : struct number_set write_set;
      69                 :            : struct number_set signal_set;
      70                 :            : 
      71                 :            : static struct number_set abbrev_set[SUPPORTED_PERSONALITIES];
      72                 :            : static struct number_set inject_set[SUPPORTED_PERSONALITIES];
      73                 :            : static struct number_set raw_set[SUPPORTED_PERSONALITIES];
      74                 :            : static struct number_set trace_set[SUPPORTED_PERSONALITIES];
      75                 :            : static struct number_set verbose_set[SUPPORTED_PERSONALITIES];
      76                 :            : #ifdef USE_LUAJIT
      77                 :            : static struct number_set hook_entry_set[SUPPORTED_PERSONALITIES];
      78                 :            : static struct number_set hook_exit_set[SUPPORTED_PERSONALITIES];
      79                 :            : #endif
      80                 :            : 
      81                 :            : static void
      82                 :            : number_setbit(const unsigned int i, number_slot_t *const vec)
      83                 :            : {
      84                 :     561396 :         vec[i / BITS_PER_SLOT] |= (number_slot_t) 1 << (i % BITS_PER_SLOT);
      85                 :            : }
      86                 :            : 
      87                 :            : static bool
      88                 :            : number_isset(const unsigned int i, const number_slot_t *const vec)
      89                 :            : {
      90                 :   41447958 :         return vec[i / BITS_PER_SLOT] & ((number_slot_t) 1 << (i % BITS_PER_SLOT));
      91                 :            : }
      92                 :            : 
      93                 :            : static void
      94                 :     561396 : reallocate_number_set(struct number_set *const set, const unsigned int new_nslots)
      95                 :            : {
      96         [ +  + ]:     561396 :         if (new_nslots <= set->nslots)
      97                 :     561396 :                 return;
      98                 :     105449 :         set->vec = xreallocarray(set->vec, new_nslots, sizeof(*set->vec));
      99                 :     105449 :         memset(set->vec + set->nslots, 0,
     100                 :     105449 :                sizeof(*set->vec) * (new_nslots - set->nslots));
     101                 :     105449 :         set->nslots = new_nslots;
     102                 :            : }
     103                 :            : 
     104                 :            : static void
     105                 :     561396 : add_number_to_set(const unsigned int number, struct number_set *const set)
     106                 :            : {
     107                 :     561396 :         reallocate_number_set(set, number / BITS_PER_SLOT + 1);
     108                 :     561396 :         number_setbit(number, set->vec);
     109                 :     561396 : }
     110                 :            : 
     111                 :            : bool
     112                 :     509459 : is_number_in_set(const unsigned int number, const struct number_set *const set)
     113                 :            : {
     114                 :  301143936 :         return ((number / BITS_PER_SLOT < set->nslots)
     115 [ +  + ][ +  + ]:  226077625 :                 && number_isset(number, set->vec)) ^ set->not;
         [ +  + ][ +  + ]
         [ +  + ][ +  + ]
         [ +  + ][ +  + ]
         [ +  + ][ +  + ]
         [ +  + ][ +  + ]
         [ +  + ][ +  + ]
         [ +  + ][ +  + ]
         [ +  + ][ +  + ]
     116                 :            : }
     117                 :            : 
     118                 :            : typedef int (*string_to_uint_func)(const char *);
     119                 :            : 
     120                 :            : /*
     121                 :            :  * Add numbers to SET according to STR specification.
     122                 :            :  */
     123                 :            : static void
     124                 :      17980 : qualify_tokens(const char *const str, struct number_set *const set,
     125                 :            :                string_to_uint_func func, const char *const name)
     126                 :            : {
     127                 :            :         /* Clear the set. */
     128         [ +  + ]:      17980 :         if (set->nslots)
     129                 :          4 :                 memset(set->vec, 0, sizeof(*set->vec) * set->nslots);
     130                 :      17980 :         set->not = false;
     131                 :            : 
     132                 :            :         /*
     133                 :            :          * Each leading ! character means inversion
     134                 :            :          * of the remaining specification.
     135                 :            :          */
     136                 :      17980 :         const char *s = str;
     137                 :            : handle_inversion:
     138         [ +  + ]:      39741 :         while (*s == '!') {
     139                 :      10945 :                 set->not = !set->not;
     140                 :      21761 :                 ++s;
     141                 :            :         }
     142                 :            : 
     143         [ +  + ]:      28796 :         if (strcmp(s, "none") == 0) {
     144                 :            :                 /*
     145                 :            :                  * No numbers are added to the set.
     146                 :            :                  * Subsequent is_number_in_set invocations will return set->not.
     147                 :            :                  */
     148                 :      17944 :                 return;
     149 [ +  + ][ +  - ]:      11089 :         } else if (strcmp(s, "all") == 0) {
         [ +  + ][ +  + ]
     150                 :            :                 s = "!none";
     151                 :            :                 goto handle_inversion;
     152                 :            :         }
     153                 :            : 
     154                 :            :         /*
     155                 :            :          * Split the string into comma separated tokens.
     156                 :            :          * For each token, find out the corresponding number
     157                 :            :          * by calling FUNC, and add that number to the set.
     158                 :            :          * The absence of tokens or a negative answer
     159                 :            :          * from FUNC is a fatal error.
     160                 :            :          */
     161                 :        273 :         char *copy = xstrdup(s);
     162                 :        273 :         char *saveptr = NULL;
     163                 :            :         const char *token;
     164                 :        273 :         int number = -1;
     165                 :            : 
     166         [ +  + ]:       4816 :         for (token = strtok_r(copy, ",", &saveptr); token;
     167                 :       4543 :              token = strtok_r(NULL, ",", &saveptr)) {
     168                 :       4571 :                 number = func(token);
     169         [ +  + ]:       4571 :                 if (number < 0) {
     170                 :         28 :                         error_msg_and_die("invalid %s '%s'", name, token);
     171                 :            :                 }
     172                 :            : 
     173                 :       4543 :                 add_number_to_set(number, set);
     174                 :            :         }
     175                 :            : 
     176                 :        245 :         free(copy);
     177                 :            : 
     178         [ +  + ]:        245 :         if (number < 0) {
     179                 :          8 :                 error_msg_and_die("invalid %s '%s'", name, str);
     180                 :            :         }
     181                 :            : }
     182                 :            : 
     183                 :            : static int
     184                 :        399 : sigstr_to_uint(const char *s)
     185                 :            : {
     186                 :            :         int i;
     187                 :            : 
     188         [ +  + ]:        399 :         if (*s >= '0' && *s <= '9')
     189                 :        154 :                 return string_to_uint_upto(s, 255);
     190                 :            : 
     191         [ +  + ]:        245 :         if (strncasecmp(s, "SIG", 3) == 0)
     192                 :        116 :                 s += 3;
     193                 :            : 
     194         [ +  + ]:       5535 :         for (i = 0; i <= 255; ++i) {
     195                 :       5525 :                 const char *name = signame(i);
     196                 :            : 
     197         [ +  + ]:       5525 :                 if (strncasecmp(name, "SIG", 3) != 0)
     198                 :       1910 :                         continue;
     199                 :            : 
     200                 :       3615 :                 name += 3;
     201                 :            : 
     202         [ +  + ]:       3615 :                 if (strcasecmp(name, s) != 0)
     203                 :       3380 :                         continue;
     204                 :            : 
     205                 :        235 :                 return i;
     206                 :            :         }
     207                 :            : 
     208                 :            :         return -1;
     209                 :            : }
     210                 :            : 
     211                 :            : static bool
     212                 :        718 : qualify_syscall_number(const char *s, struct number_set *set)
     213                 :            : {
     214                 :        718 :         int n = string_to_uint(s);
     215         [ +  + ]:        718 :         if (n < 0)
     216                 :            :                 return false;
     217                 :            : 
     218                 :            :         unsigned int p;
     219                 :            :         bool done = false;
     220                 :            : 
     221         [ +  + ]:       2848 :         for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
     222         [ +  + ]:       2136 :                 if ((unsigned) n >= nsyscall_vec[p]) {
     223                 :         24 :                         continue;
     224                 :            :                 }
     225                 :       2112 :                 add_number_to_set(n, &set[p]);
     226                 :       2112 :                 done = true;
     227                 :            :         }
     228                 :            : 
     229                 :        712 :         return done;
     230                 :            : }
     231                 :            : 
     232                 :            : static void
     233                 :         10 : regerror_msg_and_die(int errcode, const regex_t *preg,
     234                 :            :                      const char *str, const char *pattern)
     235                 :            : {
     236                 :            :         char buf[512];
     237                 :            : 
     238                 :         10 :         regerror(errcode, preg, buf, sizeof(buf));
     239                 :         10 :         error_msg_and_die("%s: %s: %s", str, pattern, buf);
     240                 :            : }
     241                 :            : 
     242                 :            : static bool
     243                 :       2520 : qualify_syscall_regex(const char *s, struct number_set *set)
     244                 :            : {
     245                 :            :         regex_t preg;
     246                 :            :         int rc;
     247                 :            : 
     248         [ +  + ]:       2520 :         if ((rc = regcomp(&preg, s, REG_EXTENDED | REG_NOSUB)) != 0)
     249                 :         10 :                 regerror_msg_and_die(rc, &preg, "regcomp", s);
     250                 :            : 
     251                 :            :         unsigned int p;
     252                 :            :         bool found = false;
     253         [ +  + ]:      10040 :         for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
     254                 :            :                 unsigned int i;
     255                 :            : 
     256         [ +  + ]:    3338300 :                 for (i = 0; i < nsyscall_vec[p]; ++i) {
     257         [ +  + ]:    3330770 :                         if (!sysent_vec[p][i].sys_name)
     258                 :     532120 :                                 continue;
     259                 :    2798650 :                         rc = regexec(&preg, sysent_vec[p][i].sys_name,
     260                 :            :                                      0, NULL, 0);
     261         [ +  + ]:    2798650 :                         if (rc == REG_NOMATCH)
     262                 :    2749806 :                                 continue;
     263         [ -  + ]:      48844 :                         else if (rc)
     264                 :          0 :                                 regerror_msg_and_die(rc, &preg, "regexec", s);
     265                 :      48844 :                         add_number_to_set(i, &set[p]);
     266                 :      48844 :                         found = true;
     267                 :            :                 }
     268                 :            :         }
     269                 :            : 
     270                 :       2510 :         regfree(&preg);
     271                 :       2510 :         return found;
     272                 :            : }
     273                 :            : 
     274                 :            : static unsigned int
     275                 :       9222 : lookup_class(const char *s)
     276                 :            : {
     277                 :            :         const struct syscall_class *c;
     278         [ +  + ]:     168803 :         for (c = syscall_classes; c->name; ++c) {
     279         [ +  + ]:     164779 :                 if (strcmp(s, c->name) == 0) {
     280                 :       5198 :                         return c->value;
     281                 :            :                 }
     282                 :            :         }
     283                 :            : 
     284                 :            :         return 0;
     285                 :            : }
     286                 :            : 
     287                 :            : static bool
     288                 :       9222 : qualify_syscall_class(const char *s, struct number_set *set)
     289                 :            : {
     290                 :       9222 :         const unsigned int n = lookup_class(s);
     291         [ +  + ]:       9222 :         if (!n)
     292                 :            :                 return false;
     293                 :            : 
     294                 :            :         unsigned int p;
     295         [ +  + ]:      20792 :         for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
     296                 :            :                 unsigned int i;
     297                 :            : 
     298         [ +  + ]:    6913340 :                 for (i = 0; i < nsyscall_vec[p]; ++i) {
     299         [ +  + ]:    6897746 :                         if (!sysent_vec[p][i].sys_name
     300         [ +  + ]:    5795770 :                             || (sysent_vec[p][i].sys_flags & n) != n) {
     301                 :    6636630 :                                 continue;
     302                 :            :                         }
     303                 :     261116 :                         add_number_to_set(i, &set[p]);
     304                 :            :                 }
     305                 :            :         }
     306                 :            : 
     307                 :            :         return true;
     308                 :            : }
     309                 :            : 
     310                 :            : static bool
     311                 :       4024 : qualify_syscall_name(const char *s, struct number_set *set)
     312                 :            : {
     313                 :            :         unsigned int p;
     314                 :       4024 :         bool found = false;
     315                 :            : 
     316         [ +  + ]:      16096 :         for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
     317                 :            :                 unsigned int i;
     318                 :            : 
     319         [ +  + ]:    5351920 :                 for (i = 0; i < nsyscall_vec[p]; ++i) {
     320         [ +  + ]:    5339848 :                         if (!sysent_vec[p][i].sys_name
     321         [ +  + ]:    4486760 :                             || strcmp(s, sysent_vec[p][i].sys_name)) {
     322                 :    5329782 :                                 continue;
     323                 :            :                         }
     324                 :      10066 :                         add_number_to_set(i, &set[p]);
     325                 :      10066 :                         found = true;
     326                 :            :                 }
     327                 :            :         }
     328                 :            : 
     329                 :       4024 :         return found;
     330                 :            : }
     331                 :            : 
     332                 :            : static bool
     333                 :      12460 : qualify_syscall(const char *token, struct number_set *set)
     334                 :            : {
     335                 :      12460 :         bool ignore_fail = false;
     336                 :            : 
     337         [ +  + ]:      13712 :         while (*token == '?') {
     338                 :       1252 :                 token++;
     339                 :       1252 :                 ignore_fail = true;
     340                 :            :         }
     341         [ +  + ]:      12460 :         if (*token >= '0' && *token <= '9')
     342 [ +  + ][ +  - ]:        718 :                 return qualify_syscall_number(token, set) || ignore_fail;
     343         [ +  + ]:      11742 :         if (*token == '/')
     344 [ +  + ][ +  - ]:       2520 :                 return qualify_syscall_regex(token + 1, set) || ignore_fail;
     345                 :      18444 :         return qualify_syscall_class(token, set)
     346         [ +  + ]:       4024 :                || qualify_syscall_name(token, set)
     347 [ +  + ][ +  + ]:       9884 :                || ignore_fail;
     348                 :            : }
     349                 :            : 
     350                 :            : /*
     351                 :            :  * Add syscall numbers to SETs for each supported personality
     352                 :            :  * according to STR specification.
     353                 :            :  */
     354                 :            : static void
     355                 :      46483 : qualify_syscall_tokens(const char *const str, struct number_set *const set,
     356                 :            :                        const char *const name)
     357                 :            : {
     358                 :            :         /* Clear all sets. */
     359                 :            :         unsigned int p;
     360         [ +  + ]:     185932 :         for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
     361         [ +  + ]:     139449 :                 if (set[p].nslots)
     362                 :          6 :                         memset(set[p].vec, 0,
     363                 :            :                                sizeof(*set[p].vec) * set[p].nslots);
     364                 :     139449 :                 set[p].not = false;
     365                 :            :         }
     366                 :            : 
     367                 :            :         /*
     368                 :            :          * Each leading ! character means inversion
     369                 :            :          * of the remaining specification.
     370                 :            :          */
     371                 :            :         const char *s = str;
     372                 :            : handle_inversion:
     373         [ +  + ]:     112143 :         while (*s == '!') {
     374         [ +  + ]:     131496 :                 for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
     375                 :      98622 :                         set[p].not = !set[p].not;
     376                 :            :                 }
     377                 :      65660 :                 ++s;
     378                 :            :         }
     379                 :            : 
     380         [ +  + ]:      79269 :         if (strcmp(s, "none") == 0) {
     381                 :            :                 /*
     382                 :            :                  * No syscall numbers are added to sets.
     383                 :            :                  * Subsequent is_number_in_set invocations
     384                 :            :                  * will return set[p]->not.
     385                 :            :                  */
     386                 :      46409 :                 return;
     387 [ +  + ][ +  + ]:      43664 :         } else if (strcmp(s, "all") == 0) {
         [ +  + ][ +  + ]
     388                 :            :                 s = "!none";
     389                 :            :                 goto handle_inversion;
     390                 :            :         }
     391                 :            : 
     392                 :            :         /*
     393                 :            :          * Split the string into comma separated tokens.
     394                 :            :          * For each token, call qualify_syscall that will take care
     395                 :            :          * if adding appropriate syscall numbers to sets.
     396                 :            :          * The absence of tokens or a negative return code
     397                 :            :          * from qualify_syscall is a fatal error.
     398                 :            :          */
     399                 :      10878 :         char *copy = xstrdup(s);
     400                 :      10878 :         char *saveptr = NULL;
     401                 :            :         const char *token;
     402                 :      10878 :         bool done = false;
     403                 :            : 
     404         [ +  + ]:      23276 :         for (token = strtok_r(copy, ",", &saveptr); token;
     405                 :      12398 :              token = strtok_r(NULL, ",", &saveptr)) {
     406                 :      12460 :                 done = qualify_syscall(token, set);
     407         [ +  + ]:      12450 :                 if (!done) {
     408                 :         52 :                         error_msg_and_die("invalid %s '%s'", name, token);
     409                 :            :                 }
     410                 :            :         }
     411                 :            : 
     412                 :      10816 :         free(copy);
     413                 :            : 
     414         [ +  + ]:      10816 :         if (!done) {
     415                 :         12 :                 error_msg_and_die("invalid %s '%s'", name, str);
     416                 :            :         }
     417                 :            : }
     418                 :            : 
     419                 :            : static int
     420                 :        750 : find_errno_by_name(const char *name)
     421                 :            : {
     422                 :            :         unsigned int i;
     423                 :            : 
     424         [ +  + ]:      48508 :         for (i = 1; i < nerrnos; ++i) {
     425 [ +  + ][ +  + ]:      48456 :                 if (errnoent[i] && (strcasecmp(name, errnoent[i]) == 0))
     426                 :        698 :                         return i;
     427                 :            :         }
     428                 :            : 
     429                 :            :         return -1;
     430                 :            : }
     431                 :            : 
     432                 :            : static bool
     433                 :       2634 : parse_inject_token(const char *const token, struct inject_opts *const fopts,
     434                 :            :                    const bool fault_tokens_only)
     435                 :            : {
     436                 :            :         const char *val;
     437                 :            :         int intval;
     438                 :            : 
     439         [ +  + ]:       2634 :         if ((val = STR_STRIP_PREFIX(token, "when=")) != token) {
     440                 :            :                 /*
     441                 :            :                  *      == 1+1
     442                 :            :                  * F    == F+0
     443                 :            :                  * F+   == F+1
     444                 :            :                  * F+S
     445                 :            :                  */
     446                 :            :                 char *end;
     447                 :       1470 :                 intval = string_to_uint_ex(val, &end, 0xffff, "+");
     448         [ +  + ]:       1470 :                 if (intval < 1)
     449                 :        104 :                         return false;
     450                 :            : 
     451                 :       1414 :                 fopts->first = intval;
     452                 :            : 
     453         [ +  + ]:       1414 :                 if (*end) {
     454                 :       1298 :                         val = end + 1;
     455         [ +  + ]:       1298 :                         if (*val) {
     456                 :            :                                 /* F+S */
     457                 :       1200 :                                 intval = string_to_uint_upto(val, 0xffff);
     458         [ +  + ]:       1200 :                                 if (intval < 1)
     459                 :            :                                         return false;
     460                 :       1152 :                                 fopts->step = intval;
     461                 :            :                         } else {
     462                 :            :                                 /* F+ == F+1 */
     463                 :         98 :                                 fopts->step = 1;
     464                 :            :                         }
     465                 :            :                 } else {
     466                 :            :                         /* F == F+0 */
     467                 :       1366 :                         fopts->step = 0;
     468                 :            :                 }
     469         [ +  + ]:       1164 :         } else if ((val = STR_STRIP_PREFIX(token, "error=")) != token) {
     470         [ +  + ]:       1114 :                 if (fopts->rval != INJECT_OPTS_RVAL_DEFAULT)
     471                 :            :                         return false;
     472                 :       1106 :                 intval = string_to_uint_upto(val, MAX_ERRNO_VALUE);
     473         [ +  + ]:       1106 :                 if (intval < 0)
     474                 :        750 :                         intval = find_errno_by_name(val);
     475         [ +  + ]:       1106 :                 if (intval < 1)
     476                 :            :                         return false;
     477                 :       1054 :                 fopts->rval = -intval;
     478         [ +  + ]:         50 :         } else if (!fault_tokens_only
     479         [ +  + ]:         36 :                    && (val = STR_STRIP_PREFIX(token, "retval=")) != token) {
     480         [ +  + ]:         16 :                 if (fopts->rval != INJECT_OPTS_RVAL_DEFAULT)
     481                 :            :                         return false;
     482                 :         12 :                 intval = string_to_uint(val);
     483         [ +  + ]:         12 :                 if (intval < 0)
     484                 :            :                         return false;
     485                 :         10 :                 fopts->rval = intval;
     486         [ +  + ]:         34 :         } else if (!fault_tokens_only
     487         [ +  + ]:         20 :                    && (val = STR_STRIP_PREFIX(token, "signal=")) != token) {
     488                 :         10 :                 intval = sigstr_to_uint(val);
     489         [ +  + ]:         10 :                 if (intval < 1 || intval > NSIG_BYTES * 8)
     490                 :            :                         return false;
     491                 :          6 :                 fopts->signo = intval;
     492                 :            :         } else {
     493                 :            :                 return false;
     494                 :            :         }
     495                 :            : 
     496                 :            :         return true;
     497                 :            : }
     498                 :            : 
     499                 :            : static char *
     500                 :       1752 : parse_inject_expression(const char *const s, char **buf,
     501                 :            :                         struct inject_opts *const fopts,
     502                 :            :                         const bool fault_tokens_only)
     503                 :            : {
     504                 :       1752 :         char *saveptr = NULL;
     505                 :       1752 :         char *name = NULL;
     506                 :            :         char *token;
     507                 :            : 
     508                 :       1752 :         *buf = xstrdup(s);
     509         [ +  + ]:       5924 :         for (token = strtok_r(*buf, ":", &saveptr); token;
     510                 :       4172 :              token = strtok_r(NULL, ":", &saveptr)) {
     511         [ +  + ]:       4370 :                 if (!name)
     512                 :            :                         name = token;
     513         [ +  + ]:       2634 :                 else if (!parse_inject_token(token, fopts, fault_tokens_only))
     514                 :            :                         goto parse_error;
     515                 :            :         }
     516                 :            : 
     517         [ +  + ]:       1554 :         if (name)
     518                 :       1538 :                 return name;
     519                 :            : 
     520                 :            : parse_error:
     521                 :        214 :         free(*buf);
     522                 :        214 :         return *buf = NULL;
     523                 :            : }
     524                 :            : 
     525                 :            : static void
     526                 :         47 : qualify_read(const char *const str)
     527                 :            : {
     528                 :         47 :         qualify_tokens(str, &read_set, string_to_uint, "descriptor");
     529                 :         37 : }
     530                 :            : 
     531                 :            : static void
     532                 :         49 : qualify_write(const char *const str)
     533                 :            : {
     534                 :         49 :         qualify_tokens(str, &write_set, string_to_uint, "descriptor");
     535                 :         39 : }
     536                 :            : 
     537                 :            : static void
     538                 :      17884 : qualify_signals(const char *const str)
     539                 :            : {
     540                 :      17884 :         qualify_tokens(str, &signal_set, sigstr_to_uint, "signal");
     541                 :      17868 : }
     542                 :            : 
     543                 :            : static void
     544                 :      20304 : qualify_trace(const char *const str)
     545                 :            : {
     546                 :      20304 :         qualify_syscall_tokens(str, trace_set, "system call");
     547                 :      20274 : }
     548                 :            : 
     549                 :            : static void
     550                 :      13425 : qualify_abbrev(const char *const str)
     551                 :            : {
     552                 :      13425 :         qualify_syscall_tokens(str, abbrev_set, "system call");
     553                 :      13425 : }
     554                 :            : 
     555                 :            : static void
     556                 :      10860 : qualify_verbose(const char *const str)
     557                 :            : {
     558                 :      10860 :         qualify_syscall_tokens(str, verbose_set, "system call");
     559                 :      10860 : }
     560                 :            : 
     561                 :            : static void
     562                 :        404 : qualify_raw(const char *const str)
     563                 :            : {
     564                 :        404 :         qualify_syscall_tokens(str, raw_set, "system call");
     565                 :        404 : }
     566                 :            : 
     567                 :            : static void
     568                 :       1752 : qualify_inject_common(const char *const str,
     569                 :            :                       const bool fault_tokens_only,
     570                 :            :                       const char *const description)
     571                 :            : {
     572                 :       1752 :         struct inject_opts opts = {
     573                 :            :                 .first = 1,
     574                 :            :                 .step = 1,
     575                 :            :                 .rval = INJECT_OPTS_RVAL_DEFAULT,
     576                 :            :                 .signo = 0
     577                 :            :         };
     578                 :       1752 :         char *buf = NULL;
     579                 :       1752 :         char *name = parse_inject_expression(str, &buf, &opts, fault_tokens_only);
     580         [ +  + ]:       1752 :         if (!name) {
     581                 :        214 :                 error_msg_and_die("invalid %s '%s'", description, str);
     582                 :            :         }
     583                 :            : 
     584                 :            :         /* If neither of retval, error, or signal is specified, then ... */
     585 [ +  + ][ +  + ]:       1538 :         if (opts.rval == INJECT_OPTS_RVAL_DEFAULT && !opts.signo) {
     586         [ +  + ]:        484 :                 if (fault_tokens_only) {
     587                 :            :                         /* in fault= syntax the default error code is ENOSYS. */
     588                 :        436 :                         opts.rval = -ENOSYS;
     589                 :            :                 } else {
     590                 :            :                         /* in inject= syntax this is not allowed. */
     591                 :         48 :                         error_msg_and_die("invalid %s '%s'", description, str);
     592                 :            :                 }
     593                 :            :         }
     594                 :            : 
     595                 :            :         struct number_set tmp_set[SUPPORTED_PERSONALITIES];
     596                 :       1490 :         memset(tmp_set, 0, sizeof(tmp_set));
     597                 :       1490 :         qualify_syscall_tokens(name, tmp_set, description);
     598                 :            : 
     599                 :       1446 :         free(buf);
     600                 :            : 
     601                 :            :         /*
     602                 :            :          * Initialize inject_vec accourding to tmp_set.
     603                 :            :          * Merge tmp_set into inject_set.
     604                 :            :          */
     605                 :            :         unsigned int p;
     606         [ +  + ]:       5784 :         for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
     607 [ +  + ][ +  + ]:       4338 :                 if (!tmp_set[p].nslots && !tmp_set[p].not) {
     608                 :         48 :                         continue;
     609                 :            :                 }
     610                 :            : 
     611         [ +  + ]:       4290 :                 if (!inject_vec[p]) {
     612                 :       4290 :                         inject_vec[p] = xcalloc(nsyscall_vec[p],
     613                 :            :                                                sizeof(*inject_vec[p]));
     614                 :            :                 }
     615                 :            : 
     616                 :            :                 unsigned int i;
     617         [ +  + ]:    1901900 :                 for (i = 0; i < nsyscall_vec[p]; ++i) {
     618         [ +  + ]:    1897610 :                         if (is_number_in_set(i, &tmp_set[p])) {
     619                 :     221276 :                                 add_number_to_set(i, &inject_set[p]);
     620                 :     221276 :                                 inject_vec[p][i] = opts;
     621                 :            :                         }
     622                 :            :                 }
     623                 :            : 
     624                 :       4290 :                 free(tmp_set[p].vec);
     625                 :            :         }
     626                 :       1446 : }
     627                 :            : 
     628                 :            : static void
     629                 :       1584 : qualify_fault(const char *const str)
     630                 :            : {
     631                 :       1584 :         qualify_inject_common(str, true, "fault argument");
     632                 :       1438 : }
     633                 :            : 
     634                 :            : static void
     635                 :        168 : qualify_inject(const char *const str)
     636                 :            : {
     637                 :        168 :         qualify_inject_common(str, false, "inject argument");
     638                 :          8 : }
     639                 :            : 
     640                 :            : static const struct qual_options {
     641                 :            :         const char *name;
     642                 :            :         void (*qualify)(const char *);
     643                 :            : } qual_options[] = {
     644                 :            :         { "trace",    qualify_trace   },
     645                 :            :         { "t",                qualify_trace   },
     646                 :            :         { "abbrev",   qualify_abbrev  },
     647                 :            :         { "a",                qualify_abbrev  },
     648                 :            :         { "verbose",  qualify_verbose },
     649                 :            :         { "v",                qualify_verbose },
     650                 :            :         { "raw",      qualify_raw     },
     651                 :            :         { "x",                qualify_raw     },
     652                 :            :         { "signal",   qualify_signals },
     653                 :            :         { "signals",  qualify_signals },
     654                 :            :         { "s",                qualify_signals },
     655                 :            :         { "read",     qualify_read    },
     656                 :            :         { "reads",    qualify_read    },
     657                 :            :         { "r",                qualify_read    },
     658                 :            :         { "write",    qualify_write   },
     659                 :            :         { "writes",   qualify_write   },
     660                 :            :         { "w",                qualify_write   },
     661                 :            :         { "fault",    qualify_fault   },
     662                 :            :         { "inject",   qualify_inject  },
     663                 :            : };
     664                 :            : 
     665                 :            : void
     666                 :      64725 : qualify(const char *str)
     667                 :            : {
     668                 :      64725 :         const struct qual_options *opt = qual_options;
     669                 :            :         unsigned int i;
     670                 :            : 
     671         [ +  + ]:     438472 :         for (i = 0; i < ARRAY_SIZE(qual_options); ++i) {
     672                 :     431798 :                 const char *name = qual_options[i].name;
     673                 :     431798 :                 const size_t len = strlen(name);
     674                 :     431798 :                 const char *val = str_strip_prefix_len(str, name, len);
     675                 :            : 
     676 [ +  + ][ +  + ]:     431798 :                 if (val == str || *val != '=')
     677                 :     373747 :                         continue;
     678                 :      58051 :                 str = val + 1;
     679                 :      58051 :                 opt = &qual_options[i];
     680                 :      58051 :                 break;
     681                 :            :         }
     682                 :            : 
     683                 :      64725 :         opt->qualify(str);
     684                 :      64353 : }
     685                 :            : 
     686                 :            : unsigned int
     687                 :   37278426 : qual_flags(const unsigned int scno)
     688                 :            : {
     689                 :   74556852 :         return  (is_number_in_set(scno, &trace_set[current_personality])
     690                 :   37278426 :                    ? QUAL_TRACE : 0)
     691                 :   74556852 :                 | (is_number_in_set(scno, &abbrev_set[current_personality])
     692         [ +  + ]:   37278426 :                    ? QUAL_ABBREV : 0)
     693                 :   74556852 :                 | (is_number_in_set(scno, &verbose_set[current_personality])
     694         [ +  + ]:   37278426 :                    ? QUAL_VERBOSE : 0)
     695                 :   74556852 :                 | (is_number_in_set(scno, &raw_set[current_personality])
     696         [ +  + ]:   37278426 :                    ? QUAL_RAW : 0)
     697                 :   74556852 :                 | (is_number_in_set(scno, &inject_set[current_personality])
     698         [ +  + ]:   37278426 :                    ? QUAL_INJECT : 0)
     699                 :            : #ifdef USE_LUAJIT
     700                 :   74556852 :                 | (is_number_in_set(scno, &hook_entry_set[current_personality])
     701         [ +  + ]:   37278426 :                    ? QUAL_HOOK_ENTRY : 0)
     702                 :   74556852 :                 | (is_number_in_set(scno, &hook_exit_set[current_personality])
     703         [ +  + ]:   37278426 :                    ? QUAL_HOOK_EXIT : 0)
     704                 :            : #endif
     705                 :            :                 ;
     706                 :            : }
     707                 :            : 
     708                 :            : #ifdef USE_LUAJIT
     709                 :            : void
     710                 :      13439 : set_hook_qual(unsigned int scno, unsigned int pers, bool entry_hook, bool exit_hook)
     711                 :            : {
     712         [ +  + ]:      13439 :         if (entry_hook)
     713                 :      13397 :                 add_number_to_set(scno, &hook_entry_set[pers]);
     714         [ +  + ]:      13439 :         if (exit_hook)
     715                 :         42 :                 add_number_to_set(scno, &hook_exit_set[pers]);
     716                 :      13439 : }
     717                 :            : #endif

Generated by: LCOV version 1.11