Print this page
12166 resync smatch to 0.6.1-rc1-il-3

Split Close
Expand all
Collapse all
          --- old/usr/src/tools/smatch/src/check_locking.c
          +++ new/usr/src/tools/smatch/src/check_locking.c
   1    1  /*
   2    2   * Copyright (C) 2009 Dan Carpenter.
        3 + * Copyright (C) 2019 Oracle.
   3    4   *
   4    5   * This program is free software; you can redistribute it and/or
   5    6   * modify it under the terms of the GNU General Public License
   6    7   * as published by the Free Software Foundation; either version 2
   7    8   * of the License, or (at your option) any later version.
   8    9   *
   9   10   * This program is distributed in the hope that it will be useful,
  10   11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11   12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12   13   * GNU General Public License for more details.
  13   14   *
  14   15   * You should have received a copy of the GNU General Public License
  15   16   * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
  16   17   */
  17   18  
  18      -/*
  19      - * This test checks that locks are held the same across all returns.
  20      - *
  21      - * Of course, some functions are designed to only hold the locks on success.
  22      - * Oh well... We can rewrite it later if we want.
  23      - *
  24      - * The list of wine locking functions came from an earlier script written
  25      - * by Michael Stefaniuc.
  26      - *
  27      - */
  28      -
       19 +#include <ctype.h>
  29   20  #include "parse.h"
  30   21  #include "smatch.h"
  31   22  #include "smatch_extra.h"
  32   23  #include "smatch_slist.h"
  33   24  
  34   25  static int my_id;
  35   26  
  36      -static int func_has_transition;
  37      -
  38   27  STATE(locked);
       28 +STATE(half_locked);
  39   29  STATE(start_state);
  40   30  STATE(unlocked);
  41   31  STATE(impossible);
       32 +STATE(restore);
  42   33  
  43   34  enum action {
  44   35          LOCK,
  45   36          UNLOCK,
       37 +        RESTORE,
  46   38  };
  47   39  
       40 +enum lock_type {
       41 +        spin_lock,
       42 +        read_lock,
       43 +        write_lock,
       44 +        mutex,
       45 +        bottom_half,
       46 +        irq,
       47 +        sem,
       48 +        prepare_lock,
       49 +        enable_lock,
       50 +};
       51 +
       52 +const char *get_lock_name(enum lock_type type)
       53 +{
       54 +        static const char *names[] = {
       55 +                [spin_lock] = "spin_lock",
       56 +                [read_lock] = "read_lock",
       57 +                [write_lock] = "write_lock",
       58 +                [mutex] = "mutex",
       59 +                [bottom_half] = "bottom_half",
       60 +                [irq] = "irq",
       61 +                [sem] = "sem",
       62 +                [prepare_lock] = "prepare_lock",
       63 +                [enable_lock] = "enable_lock",
       64 +        };
       65 +
       66 +        return names[type];
       67 +}
       68 +
  48   69  enum return_type {
  49   70          ret_any,
  50      -        ret_non_zero,
  51   71          ret_zero,
  52   72          ret_one,
  53   73          ret_negative,
  54   74          ret_positive,
       75 +        ret_valid_ptr,
  55   76  };
  56   77  
  57   78  #define RETURN_VAL -1
  58   79  #define NO_ARG -2
  59   80  
  60   81  struct lock_info {
  61   82          const char *function;
  62   83          enum action action;
  63      -        const char *name;
       84 +        enum lock_type type;
  64   85          int arg;
  65   86          enum return_type return_type;
  66   87  };
  67   88  
  68      -static struct lock_info wine_lock_table[] = {
  69      -        {"create_window_handle", LOCK, "create_window_handle", RETURN_VAL, ret_non_zero},
  70      -        {"WIN_GetPtr", LOCK, "create_window_handle", RETURN_VAL, ret_non_zero},
  71      -        {"WIN_ReleasePtr", UNLOCK, "create_window_handle", 0, ret_any},
  72      -        {"EnterCriticalSection", LOCK, "CriticalSection", 0, ret_any},
  73      -        {"LeaveCriticalSection", UNLOCK, "CriticalSection", 0, ret_any},
  74      -        {"RtlEnterCriticalSection", LOCK, "RtlCriticalSection", 0, ret_any},
  75      -        {"RtlLeaveCriticalSection", UNLOCK, "RtlCriticalSection", 0, ret_any},
  76      -        {"GDI_GetObjPtr", LOCK, "GDI_Get", 0, ret_non_zero},
  77      -        {"GDI_ReleaseObj", UNLOCK, "GDI_Get", 0, ret_any},
  78      -        {"LdrLockLoaderLock", LOCK, "LdrLockLoaderLock", 2, ret_any},
  79      -        {"LdrUnlockLoaderLock", UNLOCK, "LdrLockLoaderLock", 1, ret_any},
  80      -        {"_lock", LOCK, "_lock", 0, ret_any},
  81      -        {"_unlock", UNLOCK, "_lock", 0, ret_any},
  82      -        {"msiobj_lock", LOCK, "msiobj_lock", 0, ret_any},
  83      -        {"msiobj_unlock", UNLOCK, "msiobj_lock", 0, ret_any},
  84      -        {"RtlAcquirePebLock", LOCK, "PebLock", NO_ARG, ret_any},
  85      -        {"RtlReleasePebLock", UNLOCK, "PebLock", NO_ARG, ret_any},
  86      -        {"server_enter_uninterrupted_section", LOCK, "server_uninterrupted_section", 0, ret_any},
  87      -        {"server_leave_uninterrupted_section", UNLOCK, "server_uninterrupted_section", 0, ret_any},
  88      -        {"RtlLockHeap", LOCK, "RtlLockHeap", 0, ret_any},
  89      -        {"RtlUnlockHeap", UNLOCK, "RtlLockHeap", 0, ret_any},
  90      -        {"_EnterSysLevel", LOCK, "SysLevel", 0, ret_any},
  91      -        {"_LeaveSysLevel", UNLOCK, "SysLevel", 0, ret_any},
  92      -        {"USER_Lock", LOCK, "USER_Lock", NO_ARG, ret_any},
  93      -        {"USER_Unlock", UNLOCK, "USER_Lock", NO_ARG, ret_any},
  94      -        {"wine_tsx11_lock", LOCK, "wine_tsx11_lock", NO_ARG, ret_any},
  95      -        {"wine_tsx11_unlock", UNLOCK, "wine_tsx11_lock", NO_ARG, ret_any},
  96      -        {"wine_tsx11_lock_ptr", LOCK, "wine_tsx11_lock_ptr", NO_ARG, ret_any},
  97      -        {"wine_tsx11_unlock_ptr", UNLOCK, "wine_tsx11_lock_ptr", NO_ARG, ret_any},
  98      -        {"wined3d_mutex_lock", LOCK, "wined3d_mutex_lock", NO_ARG, ret_any},
  99      -        {"wined3d_mutex_unlock", UNLOCK, "wined3d_mutex_lock", NO_ARG, ret_any},
 100      -        {"X11DRV_DIB_Lock", LOCK, "X11DRV_DIB_Lock", 0, ret_any},
 101      -        {"X11DRV_DIB_Unlock", UNLOCK, "X11DRV_DIB_Lock", 0, ret_any},
 102      -};
       89 +static struct lock_info lock_table[] = {
       90 +        {"spin_lock",                  LOCK,   spin_lock, 0, ret_any},
       91 +        {"spin_unlock",                UNLOCK, spin_lock, 0, ret_any},
       92 +        {"spin_lock_nested",           LOCK,   spin_lock, 0, ret_any},
       93 +        {"_spin_lock",                 LOCK,   spin_lock, 0, ret_any},
       94 +        {"_spin_unlock",               UNLOCK, spin_lock, 0, ret_any},
       95 +        {"_spin_lock_nested",          LOCK,   spin_lock, 0, ret_any},
       96 +        {"__spin_lock",                LOCK,   spin_lock, 0, ret_any},
       97 +        {"__spin_unlock",              UNLOCK, spin_lock, 0, ret_any},
       98 +        {"__spin_lock_nested",         LOCK,   spin_lock, 0, ret_any},
       99 +        {"raw_spin_lock",              LOCK,   spin_lock, 0, ret_any},
      100 +        {"raw_spin_unlock",            UNLOCK, spin_lock, 0, ret_any},
      101 +        {"_raw_spin_lock",             LOCK,   spin_lock, 0, ret_any},
      102 +        {"_raw_spin_lock_nested",      LOCK,   spin_lock, 0, ret_any},
      103 +        {"_raw_spin_unlock",           UNLOCK, spin_lock, 0, ret_any},
      104 +        {"__raw_spin_lock",            LOCK,   spin_lock, 0, ret_any},
      105 +        {"__raw_spin_unlock",          UNLOCK, spin_lock, 0, ret_any},
 103  106  
 104      -static struct lock_info kernel_lock_table[] = {
 105      -        {"lock_kernel",   LOCK,   "BKL", NO_ARG, ret_any},
 106      -        {"unlock_kernel", UNLOCK, "BKL", NO_ARG, ret_any},
      107 +        {"spin_lock_irq",                 LOCK,   spin_lock, 0, ret_any},
      108 +        {"spin_unlock_irq",               UNLOCK, spin_lock, 0, ret_any},
      109 +        {"_spin_lock_irq",                LOCK,   spin_lock, 0, ret_any},
      110 +        {"_spin_unlock_irq",              UNLOCK, spin_lock, 0, ret_any},
      111 +        {"__spin_lock_irq",               LOCK,   spin_lock, 0, ret_any},
      112 +        {"__spin_unlock_irq",             UNLOCK, spin_lock, 0, ret_any},
      113 +        {"_raw_spin_lock_irq",            LOCK,   spin_lock, 0, ret_any},
      114 +        {"_raw_spin_unlock_irq",          UNLOCK, spin_lock, 0, ret_any},
      115 +        {"__raw_spin_unlock_irq",         UNLOCK, spin_lock, 0, ret_any},
      116 +        {"spin_lock_irqsave",             LOCK,   spin_lock, 0, ret_any},
      117 +        {"spin_unlock_irqrestore",        UNLOCK, spin_lock, 0, ret_any},
      118 +        {"_spin_lock_irqsave",            LOCK,   spin_lock, 0, ret_any},
      119 +        {"_spin_unlock_irqrestore",       UNLOCK, spin_lock, 0, ret_any},
      120 +        {"__spin_lock_irqsave",           LOCK,   spin_lock, 0, ret_any},
      121 +        {"__spin_unlock_irqrestore",      UNLOCK, spin_lock, 0, ret_any},
      122 +        {"_raw_spin_lock_irqsave",        LOCK,   spin_lock, 0, ret_any},
      123 +        {"_raw_spin_unlock_irqrestore",   UNLOCK, spin_lock, 0, ret_any},
      124 +        {"__raw_spin_lock_irqsave",       LOCK,   spin_lock, 0, ret_any},
      125 +        {"__raw_spin_unlock_irqrestore",  UNLOCK, spin_lock, 0, ret_any},
      126 +        {"spin_lock_irqsave_nested",      LOCK,   spin_lock, 0, ret_any},
      127 +        {"_spin_lock_irqsave_nested",     LOCK,   spin_lock, 0, ret_any},
      128 +        {"__spin_lock_irqsave_nested",    LOCK,   spin_lock, 0, ret_any},
      129 +        {"_raw_spin_lock_irqsave_nested", LOCK,   spin_lock, 0, ret_any},
      130 +        {"spin_lock_bh",                  LOCK,   spin_lock, 0, ret_any},
      131 +        {"spin_unlock_bh",                UNLOCK, spin_lock, 0, ret_any},
      132 +        {"_spin_lock_bh",                 LOCK,   spin_lock, 0, ret_any},
      133 +        {"_spin_unlock_bh",               UNLOCK, spin_lock, 0, ret_any},
      134 +        {"__spin_lock_bh",                LOCK,   spin_lock, 0, ret_any},
      135 +        {"__spin_unlock_bh",              UNLOCK, spin_lock, 0, ret_any},
 107  136  
 108      -        {"spin_lock",                  LOCK,   "spin_lock", 0, ret_any},
 109      -        {"spin_unlock",                UNLOCK, "spin_lock", 0, ret_any},
 110      -        {"spin_lock_nested",           LOCK,   "spin_lock", 0, ret_any},
 111      -        {"_spin_lock",                 LOCK,   "spin_lock", 0, ret_any},
 112      -        {"_spin_unlock",               UNLOCK, "spin_lock", 0, ret_any},
 113      -        {"_spin_lock_nested",          LOCK,   "spin_lock", 0, ret_any},
 114      -        {"__spin_lock",                LOCK,   "spin_lock", 0, ret_any},
 115      -        {"__spin_unlock",              UNLOCK, "spin_lock", 0, ret_any},
 116      -        {"__spin_lock_nested",         LOCK,   "spin_lock", 0, ret_any},
 117      -        {"raw_spin_lock",              LOCK,   "spin_lock", 0, ret_any},
 118      -        {"raw_spin_unlock",            UNLOCK, "spin_lock", 0, ret_any},
 119      -        {"_raw_spin_lock",             LOCK,   "spin_lock", 0, ret_any},
 120      -        {"_raw_spin_lock_nested",      LOCK,   "spin_lock", 0, ret_any},
 121      -        {"_raw_spin_unlock",           UNLOCK, "spin_lock", 0, ret_any},
 122      -        {"__raw_spin_lock",            LOCK,   "spin_lock", 0, ret_any},
 123      -        {"__raw_spin_unlock",          UNLOCK, "spin_lock", 0, ret_any},
      137 +        {"spin_trylock",               LOCK,   spin_lock, 0, ret_one},
      138 +        {"_spin_trylock",              LOCK,   spin_lock, 0, ret_one},
      139 +        {"__spin_trylock",             LOCK,   spin_lock, 0, ret_one},
      140 +        {"raw_spin_trylock",           LOCK,   spin_lock, 0, ret_one},
      141 +        {"_raw_spin_trylock",          LOCK,   spin_lock, 0, ret_one},
      142 +        {"spin_trylock_irq",           LOCK,   spin_lock, 0, ret_one},
      143 +        {"spin_trylock_irqsave",       LOCK,   spin_lock, 0, ret_one},
      144 +        {"spin_trylock_bh",            LOCK,   spin_lock, 0, ret_one},
      145 +        {"_spin_trylock_bh",           LOCK,   spin_lock, 0, ret_one},
      146 +        {"__spin_trylock_bh",          LOCK,   spin_lock, 0, ret_one},
      147 +        {"__raw_spin_trylock",         LOCK,   spin_lock, 0, ret_one},
      148 +        {"_atomic_dec_and_lock",       LOCK,   spin_lock, 1, ret_one},
 124  149  
 125      -        {"spin_lock_irq",              LOCK,   "spin_lock", 0, ret_any},
 126      -        {"spin_unlock_irq",            UNLOCK, "spin_lock", 0, ret_any},
 127      -        {"_spin_lock_irq",             LOCK,   "spin_lock", 0, ret_any},
 128      -        {"_spin_unlock_irq",           UNLOCK, "spin_lock", 0, ret_any},
 129      -        {"__spin_lock_irq",            LOCK,   "spin_lock", 0, ret_any},
 130      -        {"__spin_unlock_irq",          UNLOCK, "spin_lock", 0, ret_any},
 131      -        {"_raw_spin_lock_irq",         LOCK,   "spin_lock", 0, ret_any},
 132      -        {"_raw_spin_unlock_irq",       UNLOCK, "spin_lock", 0, ret_any},
 133      -        {"__raw_spin_unlock_irq",      UNLOCK, "spin_lock", 0, ret_any},
 134      -        {"spin_lock_irqsave",          LOCK,   "spin_lock", 0, ret_any},
 135      -        {"spin_unlock_irqrestore",     UNLOCK, "spin_lock", 0, ret_any},
 136      -        {"_spin_lock_irqsave",         LOCK,   "spin_lock", 0, ret_any},
 137      -        {"_spin_unlock_irqrestore",    UNLOCK, "spin_lock", 0, ret_any},
 138      -        {"__spin_lock_irqsave",        LOCK,   "spin_lock", 0, ret_any},
 139      -        {"__spin_unlock_irqrestore",   UNLOCK, "spin_lock", 0, ret_any},
 140      -        {"_raw_spin_lock_irqsave",     LOCK,   "spin_lock", 0, ret_any},
 141      -        {"_raw_spin_unlock_irqrestore", UNLOCK, "spin_lock", 0, ret_any},
 142      -        {"__raw_spin_lock_irqsave",    LOCK,   "spin_lock", 0, ret_any},
 143      -        {"__raw_spin_unlock_irqrestore", UNLOCK, "spin_lock", 0, ret_any},
 144      -        {"spin_lock_irqsave_nested",   LOCK,   "spin_lock", 0, ret_any},
 145      -        {"_spin_lock_irqsave_nested",  LOCK,   "spin_lock", 0, ret_any},
 146      -        {"__spin_lock_irqsave_nested", LOCK,   "spin_lock", 0, ret_any},
 147      -        {"_raw_spin_lock_irqsave_nested", LOCK, "spin_lock", 0, ret_any},
 148      -        {"spin_lock_bh",               LOCK,   "spin_lock", 0, ret_any},
 149      -        {"spin_unlock_bh",             UNLOCK, "spin_lock", 0, ret_any},
 150      -        {"_spin_lock_bh",              LOCK,   "spin_lock", 0, ret_any},
 151      -        {"_spin_unlock_bh",            UNLOCK, "spin_lock", 0, ret_any},
 152      -        {"__spin_lock_bh",             LOCK,   "spin_lock", 0, ret_any},
 153      -        {"__spin_unlock_bh",           UNLOCK, "spin_lock", 0, ret_any},
      150 +        {"read_lock",                 LOCK,   read_lock, 0, ret_any},
      151 +        {"down_read",                 LOCK,   read_lock, 0, ret_any},
      152 +        {"down_read_nested",          LOCK,   read_lock, 0, ret_any},
      153 +        {"down_read_trylock",         LOCK,   read_lock, 0, ret_one},
      154 +        {"up_read",                   UNLOCK, read_lock, 0, ret_any},
      155 +        {"read_unlock",               UNLOCK, read_lock, 0, ret_any},
      156 +        {"_read_lock",                LOCK,   read_lock, 0, ret_any},
      157 +        {"_read_unlock",              UNLOCK, read_lock, 0, ret_any},
      158 +        {"__read_lock",               LOCK,   read_lock, 0, ret_any},
      159 +        {"__read_unlock",             UNLOCK, read_lock, 0, ret_any},
      160 +        {"_raw_read_lock",            LOCK,   read_lock, 0, ret_any},
      161 +        {"_raw_read_unlock",          UNLOCK, read_lock, 0, ret_any},
      162 +        {"__raw_read_lock",           LOCK,   read_lock, 0, ret_any},
      163 +        {"__raw_read_unlock",         UNLOCK, read_lock, 0, ret_any},
      164 +        {"read_lock_irq",             LOCK,   read_lock, 0, ret_any},
      165 +        {"read_unlock_irq" ,          UNLOCK, read_lock, 0, ret_any},
      166 +        {"_read_lock_irq",            LOCK,   read_lock, 0, ret_any},
      167 +        {"_read_unlock_irq",          UNLOCK, read_lock, 0, ret_any},
      168 +        {"__read_lock_irq",           LOCK,   read_lock, 0, ret_any},
      169 +        {"__read_unlock_irq",         UNLOCK, read_lock, 0, ret_any},
      170 +        {"_raw_read_unlock_irq",      UNLOCK, read_lock, 0, ret_any},
      171 +        {"_raw_read_lock_irq",        LOCK,   read_lock, 0, ret_any},
      172 +        {"_raw_read_lock_bh",         LOCK,   read_lock, 0, ret_any},
      173 +        {"_raw_read_unlock_bh",       UNLOCK, read_lock, 0, ret_any},
      174 +        {"read_lock_irqsave",         LOCK,   read_lock, 0, ret_any},
      175 +        {"read_unlock_irqrestore",    UNLOCK, read_lock, 0, ret_any},
      176 +        {"_read_lock_irqsave",        LOCK,   read_lock, 0, ret_any},
      177 +        {"_read_unlock_irqrestore",   UNLOCK, read_lock, 0, ret_any},
      178 +        {"__read_lock_irqsave",       LOCK,   read_lock, 0, ret_any},
      179 +        {"__read_unlock_irqrestore",  UNLOCK, read_lock, 0, ret_any},
      180 +        {"read_lock_bh",              LOCK,   read_lock, 0, ret_any},
      181 +        {"read_unlock_bh",            UNLOCK, read_lock, 0, ret_any},
      182 +        {"_read_lock_bh",             LOCK,   read_lock, 0, ret_any},
      183 +        {"_read_unlock_bh",           UNLOCK, read_lock, 0, ret_any},
      184 +        {"__read_lock_bh",            LOCK,   read_lock, 0, ret_any},
      185 +        {"__read_unlock_bh",          UNLOCK, read_lock, 0, ret_any},
      186 +        {"__raw_read_lock_bh",        LOCK,   read_lock, 0, ret_any},
      187 +        {"__raw_read_unlock_bh",      UNLOCK, read_lock, 0, ret_any},
 154  188  
 155      -        {"spin_trylock",               LOCK,   "spin_lock", 0, ret_one},
 156      -        {"_spin_trylock",              LOCK,   "spin_lock", 0, ret_one},
 157      -        {"__spin_trylock",             LOCK,   "spin_lock", 0, ret_one},
 158      -        {"raw_spin_trylock",           LOCK,   "spin_lock", 0, ret_one},
 159      -        {"_raw_spin_trylock",          LOCK,   "spin_lock", 0, ret_one},
 160      -        {"spin_trylock_irq",           LOCK,   "spin_lock", 0, ret_one},
 161      -        {"spin_trylock_irqsave",       LOCK,   "spin_lock", 0, ret_one},
 162      -        {"spin_trylock_bh",            LOCK,   "spin_lock", 0, ret_one},
 163      -        {"_spin_trylock_bh",           LOCK,   "spin_lock", 0, ret_one},
 164      -        {"__spin_trylock_bh",          LOCK,   "spin_lock", 0, ret_one},
 165      -        {"__raw_spin_trylock",         LOCK,   "spin_lock", 0, ret_one},
 166      -        {"_atomic_dec_and_lock",       LOCK,   "spin_lock", 1, ret_one},
      189 +        {"_raw_read_lock_irqsave",        LOCK,    read_lock,   0,          ret_any},
      190 +        {"_raw_read_lock_irqsave",        LOCK,    irq,         RETURN_VAL, ret_any},
      191 +        {"_raw_read_unlock_irqrestore",   UNLOCK,  read_lock,   0,          ret_any},
      192 +        {"_raw_read_unlock_irqrestore",   RESTORE, irq,         1,          ret_any},
      193 +        {"_raw_spin_lock_bh",             LOCK,    read_lock,   0,          ret_any},
      194 +        {"_raw_spin_lock_bh",             LOCK,    bottom_half, NO_ARG,     ret_any},
      195 +        {"_raw_spin_lock_nest_lock",      LOCK,    read_lock,   0,          ret_any},
      196 +        {"_raw_spin_unlock_bh",           UNLOCK,  read_lock,   0,          ret_any},
      197 +        {"_raw_spin_unlock_bh",           UNLOCK,  bottom_half, NO_ARG,     ret_any},
      198 +        {"_raw_write_lock_irqsave",       LOCK,    write_lock,  0,          ret_any},
      199 +        {"_raw_write_lock_irqsave",       LOCK,    irq,         RETURN_VAL, ret_any},
      200 +        {"_raw_write_unlock_irqrestore",  UNLOCK,  write_lock,  0,          ret_any},
      201 +        {"_raw_write_unlock_irqrestore",  RESTORE, irq,         1,          ret_any},
      202 +        {"__raw_write_unlock_irqrestore", UNLOCK,  write_lock,  0,          ret_any},
      203 +        {"__raw_write_unlock_irqrestore", RESTORE, irq,         1,          ret_any},
 167  204  
 168      -        {"read_lock",                 LOCK,   "read_lock", 0, ret_any},
 169      -        {"read_unlock",               UNLOCK, "read_lock", 0, ret_any},
 170      -        {"_read_lock",                LOCK,   "read_lock", 0, ret_any},
 171      -        {"_read_unlock",              UNLOCK, "read_lock", 0, ret_any},
 172      -        {"__read_lock",               LOCK,   "read_lock", 0, ret_any},
 173      -        {"__read_unlock",             UNLOCK, "read_lock", 0, ret_any},
 174      -        {"_raw_read_lock",            LOCK,   "read_lock", 0, ret_any},
 175      -        {"_raw_read_unlock",          UNLOCK, "read_lock", 0, ret_any},
 176      -        {"__raw_read_lock",           LOCK,   "read_lock", 0, ret_any},
 177      -        {"__raw_read_unlock",         UNLOCK, "read_lock", 0, ret_any},
 178      -        {"read_lock_irq",             LOCK,   "read_lock", 0, ret_any},
 179      -        {"read_unlock_irq" ,          UNLOCK, "read_lock", 0, ret_any},
 180      -        {"_read_lock_irq",            LOCK,   "read_lock", 0, ret_any},
 181      -        {"_read_unlock_irq",          UNLOCK, "read_lock", 0, ret_any},
 182      -        {"__read_lock_irq",           LOCK,   "read_lock", 0, ret_any},
 183      -        {"__read_unlock_irq",         UNLOCK, "read_lock", 0, ret_any},
 184      -        {"read_lock_irqsave",         LOCK,   "read_lock", 0, ret_any},
 185      -        {"read_unlock_irqrestore",    UNLOCK, "read_lock", 0, ret_any},
 186      -        {"_read_lock_irqsave",        LOCK,   "read_lock", 0, ret_any},
 187      -        {"_read_unlock_irqrestore",   UNLOCK, "read_lock", 0, ret_any},
 188      -        {"__read_lock_irqsave",       LOCK,   "read_lock", 0, ret_any},
 189      -        {"__read_unlock_irqrestore",  UNLOCK, "read_lock", 0, ret_any},
 190      -        {"read_lock_bh",              LOCK,   "read_lock", 0, ret_any},
 191      -        {"read_unlock_bh",            UNLOCK, "read_lock", 0, ret_any},
 192      -        {"_read_lock_bh",             LOCK,   "read_lock", 0, ret_any},
 193      -        {"_read_unlock_bh",           UNLOCK, "read_lock", 0, ret_any},
 194      -        {"__read_lock_bh",            LOCK,   "read_lock", 0, ret_any},
 195      -        {"__read_unlock_bh",          UNLOCK, "read_lock", 0, ret_any},
 196      -        {"_raw_read_lock_bh",         LOCK,   "read_lock", 0, ret_any},
 197      -        {"_raw_read_unlock_bh",       UNLOCK, "read_lock", 0, ret_any},
 198      -        {"__raw_read_lock_bh",        LOCK,   "read_lock", 0, ret_any},
 199      -        {"__raw_read_unlock_bh",      UNLOCK, "read_lock", 0, ret_any},
      205 +        {"generic__raw_read_trylock", LOCK,   read_lock, 0, ret_one},
      206 +        {"read_trylock",              LOCK,   read_lock, 0, ret_one},
      207 +        {"_read_trylock",             LOCK,   read_lock, 0, ret_one},
      208 +        {"raw_read_trylock",          LOCK,   read_lock, 0, ret_one},
      209 +        {"_raw_read_trylock",         LOCK,   read_lock, 0, ret_one},
      210 +        {"__raw_read_trylock",        LOCK,   read_lock, 0, ret_one},
      211 +        {"__read_trylock",            LOCK,   read_lock, 0, ret_one},
 200  212  
 201      -        {"generic__raw_read_trylock", LOCK,   "read_lock", 0, ret_one},
 202      -        {"read_trylock",              LOCK,   "read_lock", 0, ret_one},
 203      -        {"_read_trylock",             LOCK,   "read_lock", 0, ret_one},
 204      -        {"raw_read_trylock",          LOCK,   "read_lock", 0, ret_one},
 205      -        {"_raw_read_trylock",         LOCK,   "read_lock", 0, ret_one},
 206      -        {"__raw_read_trylock",        LOCK,   "read_lock", 0, ret_one},
 207      -        {"__read_trylock",            LOCK,   "read_lock", 0, ret_one},
      213 +        {"write_lock",                LOCK,   write_lock, 0, ret_any},
      214 +        {"down_write",                LOCK,   write_lock, 0, ret_any},
      215 +        {"down_write_nested",         LOCK,   write_lock, 0, ret_any},
      216 +        {"up_write",                  UNLOCK, write_lock, 0, ret_any},
      217 +        {"write_unlock",              UNLOCK, write_lock, 0, ret_any},
      218 +        {"_write_lock",               LOCK,   write_lock, 0, ret_any},
      219 +        {"_write_unlock",             UNLOCK, write_lock, 0, ret_any},
      220 +        {"__write_lock",              LOCK,   write_lock, 0, ret_any},
      221 +        {"__write_unlock",            UNLOCK, write_lock, 0, ret_any},
      222 +        {"write_lock_irq",            LOCK,   write_lock, 0, ret_any},
      223 +        {"write_unlock_irq",          UNLOCK, write_lock, 0, ret_any},
      224 +        {"_write_lock_irq",           LOCK,   write_lock, 0, ret_any},
      225 +        {"_write_unlock_irq",         UNLOCK, write_lock, 0, ret_any},
      226 +        {"__write_lock_irq",          LOCK,   write_lock, 0, ret_any},
      227 +        {"__write_unlock_irq",        UNLOCK, write_lock, 0, ret_any},
      228 +        {"_raw_write_unlock_irq",     UNLOCK, write_lock, 0, ret_any},
      229 +        {"write_lock_irqsave",        LOCK,   write_lock, 0, ret_any},
      230 +        {"write_unlock_irqrestore",   UNLOCK, write_lock, 0, ret_any},
      231 +        {"_write_lock_irqsave",       LOCK,   write_lock, 0, ret_any},
      232 +        {"_write_unlock_irqrestore",  UNLOCK, write_lock, 0, ret_any},
      233 +        {"__write_lock_irqsave",      LOCK,   write_lock, 0, ret_any},
      234 +        {"__write_unlock_irqrestore", UNLOCK, write_lock, 0, ret_any},
      235 +        {"write_lock_bh",             LOCK,   write_lock, 0, ret_any},
      236 +        {"write_unlock_bh",           UNLOCK, write_lock, 0, ret_any},
      237 +        {"_write_lock_bh",            LOCK,   write_lock, 0, ret_any},
      238 +        {"_write_unlock_bh",          UNLOCK, write_lock, 0, ret_any},
      239 +        {"__write_lock_bh",           LOCK,   write_lock, 0, ret_any},
      240 +        {"__write_unlock_bh",         UNLOCK, write_lock, 0, ret_any},
      241 +        {"_raw_write_lock",           LOCK,   write_lock, 0, ret_any},
      242 +        {"__raw_write_lock",          LOCK,   write_lock, 0, ret_any},
      243 +        {"_raw_write_unlock",         UNLOCK, write_lock, 0, ret_any},
      244 +        {"__raw_write_unlock",        UNLOCK, write_lock, 0, ret_any},
      245 +        {"_raw_write_lock_bh",        LOCK,   write_lock, 0, ret_any},
      246 +        {"_raw_write_unlock_bh",      UNLOCK, write_lock, 0, ret_any},
      247 +        {"_raw_write_lock_irq",       LOCK,   write_lock, 0, ret_any},
 208  248  
 209      -        {"write_lock",                LOCK,   "write_lock", 0, ret_any},
 210      -        {"write_unlock",              UNLOCK, "write_lock", 0, ret_any},
 211      -        {"_write_lock",               LOCK,   "write_lock", 0, ret_any},
 212      -        {"_write_unlock",             UNLOCK, "write_lock", 0, ret_any},
 213      -        {"__write_lock",              LOCK,   "write_lock", 0, ret_any},
 214      -        {"__write_unlock",            UNLOCK, "write_lock", 0, ret_any},
 215      -        {"write_lock_irq",            LOCK,   "write_lock", 0, ret_any},
 216      -        {"write_unlock_irq",          UNLOCK, "write_lock", 0, ret_any},
 217      -        {"_write_lock_irq",           LOCK,   "write_lock", 0, ret_any},
 218      -        {"_write_unlock_irq",         UNLOCK, "write_lock", 0, ret_any},
 219      -        {"__write_lock_irq",          LOCK,   "write_lock", 0, ret_any},
 220      -        {"__write_unlock_irq",        UNLOCK, "write_lock", 0, ret_any},
 221      -        {"write_lock_irqsave",        LOCK,   "write_lock", 0, ret_any},
 222      -        {"write_unlock_irqrestore",   UNLOCK, "write_lock", 0, ret_any},
 223      -        {"_write_lock_irqsave",       LOCK,   "write_lock", 0, ret_any},
 224      -        {"_write_unlock_irqrestore",  UNLOCK, "write_lock", 0, ret_any},
 225      -        {"__write_lock_irqsave",      LOCK,   "write_lock", 0, ret_any},
 226      -        {"__write_unlock_irqrestore", UNLOCK, "write_lock", 0, ret_any},
 227      -        {"write_lock_bh",             LOCK,   "write_lock", 0, ret_any},
 228      -        {"write_unlock_bh",           UNLOCK, "write_lock", 0, ret_any},
 229      -        {"_write_lock_bh",            LOCK,   "write_lock", 0, ret_any},
 230      -        {"_write_unlock_bh",          UNLOCK, "write_lock", 0, ret_any},
 231      -        {"__write_lock_bh",           LOCK,   "write_lock", 0, ret_any},
 232      -        {"__write_unlock_bh",         UNLOCK, "write_lock", 0, ret_any},
 233      -        {"_raw_write_lock",           LOCK,   "write_lock", 0, ret_any},
 234      -        {"__raw_write_lock",          LOCK,   "write_lock", 0, ret_any},
 235      -        {"_raw_write_unlock",         UNLOCK, "write_lock", 0, ret_any},
 236      -        {"__raw_write_unlock",        UNLOCK, "write_lock", 0, ret_any},
      249 +        {"write_trylock",             LOCK,   write_lock, 0, ret_one},
      250 +        {"_write_trylock",            LOCK,   write_lock, 0, ret_one},
      251 +        {"raw_write_trylock",         LOCK,   write_lock, 0, ret_one},
      252 +        {"_raw_write_trylock",        LOCK,   write_lock, 0, ret_one},
      253 +        {"__write_trylock",           LOCK,   write_lock, 0, ret_one},
      254 +        {"__raw_write_trylock",       LOCK,   write_lock, 0, ret_one},
      255 +        {"down_write_trylock",        LOCK,   write_lock, 0, ret_one},
      256 +        {"down_write_killable",       LOCK,   write_lock, 0, ret_zero},
 237  257  
 238      -        {"write_trylock",             LOCK,   "write_lock", 0, ret_one},
 239      -        {"_write_trylock",            LOCK,   "write_lock", 0, ret_one},
 240      -        {"raw_write_trylock",         LOCK,   "write_lock", 0, ret_one},
 241      -        {"_raw_write_trylock",        LOCK,   "write_lock", 0, ret_one},
 242      -        {"__write_trylock",           LOCK,   "write_lock", 0, ret_one},
 243      -        {"__raw_write_trylock",       LOCK,   "write_lock", 0, ret_one},
      258 +        {"down",               LOCK,   sem, 0, ret_any},
      259 +        {"up",                 UNLOCK, sem, 0, ret_any},
      260 +        {"down_trylock",       LOCK,   sem, 0, ret_zero},
      261 +        {"down_timeout",       LOCK,   sem, 0, ret_zero},
      262 +        {"down_interruptible", LOCK,   sem, 0, ret_zero},
      263 +        {"down_killable",      LOCK,   sem, 0, ret_zero},
 244  264  
 245      -        {"down",               LOCK,   "sem", 0, ret_any},
 246      -        {"up",                 UNLOCK, "sem", 0, ret_any},
 247      -        {"down_trylock",       LOCK,   "sem", 0, ret_zero},
 248      -        {"down_timeout",       LOCK,   "sem", 0, ret_zero},
 249      -        {"down_interruptible", LOCK,   "sem", 0, ret_zero},
 250  265  
      266 +        {"mutex_lock",                      LOCK,   mutex, 0, ret_any},
      267 +        {"mutex_unlock",                    UNLOCK, mutex, 0, ret_any},
      268 +        {"mutex_lock_nested",               LOCK,   mutex, 0, ret_any},
      269 +        {"mutex_lock_io",                   LOCK,   mutex, 0, ret_any},
      270 +        {"mutex_lock_io_nested",            LOCK,   mutex, 0, ret_any},
 251  271  
 252      -        {"down_write",          LOCK,   "rw_sem", 0, ret_any},
 253      -        {"downgrade_write",     UNLOCK, "rw_sem", 0, ret_any},
 254      -        {"downgrade_write",     LOCK,   "read_sem", 0, ret_any},
 255      -        {"up_write",            UNLOCK, "rw_sem", 0, ret_any},
 256      -        {"down_write_trylock",  LOCK,   "rw_sem", 0, ret_one},
 257      -        {"down_write_killable", LOCK,   "rw_sem", 0, ret_zero},
 258      -        {"down_read",           LOCK,   "read_sem", 0, ret_any},
 259      -        {"down_read_trylock",   LOCK,   "read_sem", 0, ret_one},
 260      -        {"down_read_killable",  LOCK,   "read_sem", 0, ret_zero},
 261      -        {"up_read",             UNLOCK, "read_sem", 0, ret_any},
      272 +        {"mutex_lock_interruptible",        LOCK,   mutex, 0, ret_zero},
      273 +        {"mutex_lock_interruptible_nested", LOCK,   mutex, 0, ret_zero},
      274 +        {"mutex_lock_killable",             LOCK,   mutex, 0, ret_zero},
      275 +        {"mutex_lock_killable_nested",      LOCK,   mutex, 0, ret_zero},
 262  276  
 263      -        {"mutex_lock",                      LOCK,   "mutex", 0, ret_any},
 264      -        {"mutex_lock_io",                   LOCK,   "mutex", 0, ret_any},
 265      -        {"mutex_unlock",                    UNLOCK, "mutex", 0, ret_any},
 266      -        {"mutex_lock_nested",               LOCK,   "mutex", 0, ret_any},
 267      -        {"mutex_lock_io_nested",            LOCK,   "mutex", 0, ret_any},
      277 +        {"mutex_trylock",                   LOCK,   mutex, 0, ret_one},
 268  278  
 269      -        {"mutex_lock_interruptible",        LOCK,   "mutex", 0, ret_zero},
 270      -        {"mutex_lock_interruptible_nested", LOCK,   "mutex", 0, ret_zero},
 271      -        {"mutex_lock_killable",             LOCK,   "mutex", 0, ret_zero},
 272      -        {"mutex_lock_killable_nested",      LOCK,   "mutex", 0, ret_zero},
      279 +        {"ww_mutex_lock",               LOCK,   mutex, 0, ret_any},
      280 +        {"__ww_mutex_lock",             LOCK,   mutex, 0, ret_any},
      281 +        {"ww_mutex_lock_interruptible", LOCK,   mutex, 0, ret_zero},
      282 +        {"ww_mutex_unlock",             UNLOCK, mutex, 0, ret_any},
 273  283  
 274      -        {"mutex_trylock",                   LOCK,   "mutex", 0, ret_one},
      284 +        {"raw_local_irq_disable", LOCK,   irq, NO_ARG, ret_any},
      285 +        {"raw_local_irq_enable",  UNLOCK, irq, NO_ARG, ret_any},
      286 +        {"spin_lock_irq",         LOCK,   irq, NO_ARG, ret_any},
      287 +        {"spin_unlock_irq",       UNLOCK, irq, NO_ARG, ret_any},
      288 +        {"_spin_lock_irq",        LOCK,   irq, NO_ARG, ret_any},
      289 +        {"_spin_unlock_irq",      UNLOCK, irq, NO_ARG, ret_any},
      290 +        {"__spin_lock_irq",       LOCK,   irq, NO_ARG, ret_any},
      291 +        {"__spin_unlock_irq",     UNLOCK, irq, NO_ARG, ret_any},
      292 +        {"_raw_spin_lock_irq",    LOCK,   irq, NO_ARG, ret_any},
      293 +        {"_raw_spin_unlock_irq",  UNLOCK, irq, NO_ARG, ret_any},
      294 +        {"__raw_spin_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
      295 +        {"spin_trylock_irq",      LOCK,   irq, NO_ARG, ret_one},
      296 +        {"read_lock_irq",         LOCK,   irq, NO_ARG, ret_any},
      297 +        {"read_unlock_irq",       UNLOCK, irq, NO_ARG, ret_any},
      298 +        {"_read_lock_irq",        LOCK,   irq, NO_ARG, ret_any},
      299 +        {"_read_unlock_irq",      UNLOCK, irq, NO_ARG, ret_any},
      300 +        {"__read_lock_irq",       LOCK,   irq, NO_ARG, ret_any},
      301 +        {"_raw_read_lock_irq",    LOCK,   irq, NO_ARG, ret_any},
      302 +        {"__read_unlock_irq",     UNLOCK, irq, NO_ARG, ret_any},
      303 +        {"_raw_read_unlock_irq",  UNLOCK, irq, NO_ARG, ret_any},
      304 +        {"write_lock_irq",        LOCK,   irq, NO_ARG, ret_any},
      305 +        {"write_unlock_irq",      UNLOCK, irq, NO_ARG, ret_any},
      306 +        {"_write_lock_irq",       LOCK,   irq, NO_ARG, ret_any},
      307 +        {"_write_unlock_irq",     UNLOCK, irq, NO_ARG, ret_any},
      308 +        {"__write_lock_irq",      LOCK,   irq, NO_ARG, ret_any},
      309 +        {"__write_unlock_irq",    UNLOCK, irq, NO_ARG, ret_any},
      310 +        {"_raw_write_lock_irq",   LOCK,   irq, NO_ARG, ret_any},
      311 +        {"_raw_write_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
 275  312  
 276      -        {"raw_local_irq_disable", LOCK,   "irq", NO_ARG, ret_any},
 277      -        {"raw_local_irq_enable",  UNLOCK, "irq", NO_ARG, ret_any},
 278      -        {"spin_lock_irq",         LOCK,   "irq", NO_ARG, ret_any},
 279      -        {"spin_unlock_irq",       UNLOCK, "irq", NO_ARG, ret_any},
 280      -        {"_spin_lock_irq",        LOCK,   "irq", NO_ARG, ret_any},
 281      -        {"_spin_unlock_irq",      UNLOCK, "irq", NO_ARG, ret_any},
 282      -        {"__spin_lock_irq",       LOCK,   "irq", NO_ARG, ret_any},
 283      -        {"__spin_unlock_irq",     UNLOCK, "irq", NO_ARG, ret_any},
 284      -        {"_raw_spin_lock_irq",    LOCK,   "irq", NO_ARG, ret_any},
 285      -        {"_raw_spin_unlock_irq",  UNLOCK, "irq", NO_ARG, ret_any},
 286      -        {"__raw_spin_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
 287      -        {"spin_trylock_irq",      LOCK,   "irq", NO_ARG, ret_one},
 288      -        {"read_lock_irq",         LOCK,   "irq", NO_ARG, ret_any},
 289      -        {"read_unlock_irq",       UNLOCK, "irq", NO_ARG, ret_any},
 290      -        {"_read_lock_irq",        LOCK,   "irq", NO_ARG, ret_any},
 291      -        {"_read_unlock_irq",      UNLOCK, "irq", NO_ARG, ret_any},
 292      -        {"__read_lock_irq",       LOCK,   "irq", NO_ARG, ret_any},
 293      -        {"__read_unlock_irq",     UNLOCK, "irq", NO_ARG, ret_any},
 294      -        {"write_lock_irq",        LOCK,   "irq", NO_ARG, ret_any},
 295      -        {"write_unlock_irq",      UNLOCK, "irq", NO_ARG, ret_any},
 296      -        {"_write_lock_irq",       LOCK,   "irq", NO_ARG, ret_any},
 297      -        {"_write_unlock_irq",     UNLOCK, "irq", NO_ARG, ret_any},
 298      -        {"__write_lock_irq",      LOCK,   "irq", NO_ARG, ret_any},
 299      -        {"__write_unlock_irq",    UNLOCK, "irq", NO_ARG, ret_any},
      313 +        {"arch_local_irq_save",        LOCK,      irq, RETURN_VAL, ret_any},
      314 +        {"arch_local_irq_restore",     RESTORE,   irq, 0,          ret_any},
      315 +        {"__raw_local_irq_save",       LOCK,      irq, RETURN_VAL, ret_any},
      316 +        {"raw_local_irq_restore",      RESTORE,   irq, 0,          ret_any},
      317 +        {"spin_lock_irqsave_nested",   LOCK,      irq, RETURN_VAL, ret_any},
      318 +        {"spin_lock_irqsave",          LOCK,      irq, 1,          ret_any},
      319 +        {"spin_unlock_irqrestore",     RESTORE,   irq, 1,          ret_any},
      320 +        {"_spin_lock_irqsave_nested",  LOCK,      irq, RETURN_VAL, ret_any},
      321 +        {"_spin_lock_irqsave",         LOCK,      irq, RETURN_VAL, ret_any},
      322 +        {"_spin_lock_irqsave",         LOCK,      irq, 1,          ret_any},
      323 +        {"_spin_unlock_irqrestore",    RESTORE,   irq, 1,          ret_any},
      324 +        {"__spin_lock_irqsave_nested", LOCK,      irq, 1,          ret_any},
      325 +        {"__spin_lock_irqsave",        LOCK,      irq, 1,          ret_any},
      326 +        {"__spin_unlock_irqrestore",   RESTORE,   irq, 1,          ret_any},
      327 +        {"_raw_spin_lock_irqsave",     LOCK,      irq, RETURN_VAL, ret_any},
      328 +        {"_raw_spin_lock_irqsave",     LOCK,      irq, 1,          ret_any},
      329 +        {"_raw_spin_unlock_irqrestore", RESTORE,  irq, 1,          ret_any},
      330 +        {"__raw_spin_lock_irqsave",    LOCK,      irq, RETURN_VAL, ret_any},
      331 +        {"__raw_spin_unlock_irqrestore", RESTORE, irq, 1,          ret_any},
      332 +        {"_raw_spin_lock_irqsave_nested", LOCK,   irq, RETURN_VAL, ret_any},
      333 +        {"spin_trylock_irqsave",       LOCK,      irq, 1,          ret_one},
      334 +        {"read_lock_irqsave",          LOCK,      irq, RETURN_VAL, ret_any},
      335 +        {"read_lock_irqsave",          LOCK,      irq, 1,          ret_any},
      336 +        {"read_unlock_irqrestore",     RESTORE,   irq, 1,          ret_any},
      337 +        {"_read_lock_irqsave",         LOCK,      irq, RETURN_VAL, ret_any},
      338 +        {"_read_lock_irqsave",         LOCK,      irq, 1,          ret_any},
      339 +        {"_read_unlock_irqrestore",    RESTORE,   irq, 1,          ret_any},
      340 +        {"__read_lock_irqsave",        LOCK,      irq, RETURN_VAL, ret_any},
      341 +        {"__read_unlock_irqrestore",   RESTORE,   irq, 1,          ret_any},
      342 +        {"write_lock_irqsave",         LOCK,      irq, RETURN_VAL, ret_any},
      343 +        {"write_lock_irqsave",         LOCK,      irq, 1,          ret_any},
      344 +        {"write_unlock_irqrestore",    RESTORE,   irq, 1,          ret_any},
      345 +        {"_write_lock_irqsave",        LOCK,      irq, RETURN_VAL, ret_any},
      346 +        {"_write_lock_irqsave",        LOCK,      irq, 1,          ret_any},
      347 +        {"_write_unlock_irqrestore",   RESTORE,   irq, 1,          ret_any},
      348 +        {"__write_lock_irqsave",       LOCK,      irq, RETURN_VAL, ret_any},
      349 +        {"__write_unlock_irqrestore",  RESTORE,   irq, 1,          ret_any},
 300  350  
 301      -        {"arch_local_irq_save",        LOCK,   "irqsave", RETURN_VAL, ret_any},
 302      -        {"arch_local_irq_restore",     UNLOCK, "irqsave", 0, ret_any},
 303      -        {"__raw_local_irq_save",       LOCK,   "irqsave", RETURN_VAL, ret_any},
 304      -        {"raw_local_irq_restore",      UNLOCK, "irqsave", 0, ret_any},
 305      -        {"spin_lock_irqsave_nested",   LOCK,   "irqsave", RETURN_VAL, ret_any},
 306      -        {"spin_lock_irqsave",          LOCK,   "irqsave", RETURN_VAL, ret_any},
 307      -        {"spin_lock_irqsave",          LOCK,   "irqsave", 1, ret_any},
 308      -        {"spin_unlock_irqrestore",     UNLOCK, "irqsave", 1, ret_any},
 309      -        {"_spin_lock_irqsave_nested",  LOCK,   "irqsave", RETURN_VAL, ret_any},
 310      -        {"_spin_lock_irqsave",         LOCK,   "irqsave", RETURN_VAL, ret_any},
 311      -        {"_spin_lock_irqsave",         LOCK,   "irqsave", 1, ret_any},
 312      -        {"_spin_unlock_irqrestore",    UNLOCK, "irqsave", 1, ret_any},
 313      -        {"__spin_lock_irqsave_nested", LOCK,   "irqsave", 1, ret_any},
 314      -        {"__spin_lock_irqsave",        LOCK,   "irqsave", 1, ret_any},
 315      -        {"__spin_unlock_irqrestore",   UNLOCK, "irqsave", 1, ret_any},
 316      -        {"_raw_spin_lock_irqsave",     LOCK,   "irqsave", RETURN_VAL, ret_any},
 317      -        {"_raw_spin_lock_irqsave",     LOCK,   "irqsave", 1, ret_any},
 318      -        {"_raw_spin_unlock_irqrestore",UNLOCK, "irqsave", 1, ret_any},
 319      -        {"__raw_spin_lock_irqsave",    LOCK,   "irqsave", RETURN_VAL, ret_any},
 320      -        {"__raw_spin_unlock_irqrestore",UNLOCK, "irqsave", 1, ret_any},
 321      -        {"_raw_spin_lock_irqsave_nested", LOCK, "irqsave", RETURN_VAL, ret_any},
 322      -        {"spin_trylock_irqsave",       LOCK,   "irqsave", 1, ret_one},
 323      -        {"read_lock_irqsave",          LOCK,   "irqsave", RETURN_VAL, ret_any},
 324      -        {"read_lock_irqsave",          LOCK,   "irqsave", 1, ret_any},
 325      -        {"read_unlock_irqrestore",     UNLOCK, "irqsave", 1, ret_any},
 326      -        {"_read_lock_irqsave",         LOCK,   "irqsave", RETURN_VAL, ret_any},
 327      -        {"_read_lock_irqsave",         LOCK,   "irqsave", 1, ret_any},
 328      -        {"_read_unlock_irqrestore",    UNLOCK, "irqsave", 1, ret_any},
 329      -        {"__read_lock_irqsave",        LOCK,   "irqsave", RETURN_VAL, ret_any},
 330      -        {"__read_unlock_irqrestore",   UNLOCK, "irqsave", 1, ret_any},
 331      -        {"write_lock_irqsave",         LOCK,   "irqsave", RETURN_VAL, ret_any},
 332      -        {"write_lock_irqsave",         LOCK,   "irqsave", 1, ret_any},
 333      -        {"write_unlock_irqrestore",    UNLOCK, "irqsave", 1, ret_any},
 334      -        {"_write_lock_irqsave",        LOCK,   "irqsave", RETURN_VAL, ret_any},
 335      -        {"_write_lock_irqsave",        LOCK,   "irqsave", 1, ret_any},
 336      -        {"_write_unlock_irqrestore",   UNLOCK, "irqsave", 1, ret_any},
 337      -        {"__write_lock_irqsave",       LOCK,   "irqsave", RETURN_VAL, ret_any},
 338      -        {"__write_unlock_irqrestore",  UNLOCK, "irqsave", 1, ret_any},
      351 +        {"local_bh_disable",    LOCK,   bottom_half, NO_ARG, ret_any},
      352 +        {"_local_bh_disable",   LOCK,   bottom_half, NO_ARG, ret_any},
      353 +        {"__local_bh_disable",  LOCK,   bottom_half, NO_ARG, ret_any},
      354 +        {"local_bh_enable",     UNLOCK, bottom_half, NO_ARG, ret_any},
      355 +        {"_local_bh_enable",    UNLOCK, bottom_half, NO_ARG, ret_any},
      356 +        {"__local_bh_enable",   UNLOCK, bottom_half, NO_ARG, ret_any},
      357 +        {"spin_lock_bh",        LOCK,   bottom_half, NO_ARG, ret_any},
      358 +        {"spin_unlock_bh",      UNLOCK, bottom_half, NO_ARG, ret_any},
      359 +        {"_spin_lock_bh",       LOCK,   bottom_half, NO_ARG, ret_any},
      360 +        {"_spin_unlock_bh",     UNLOCK, bottom_half, NO_ARG, ret_any},
      361 +        {"__spin_lock_bh",      LOCK,   bottom_half, NO_ARG, ret_any},
      362 +        {"__spin_unlock_bh",    UNLOCK, bottom_half, NO_ARG, ret_any},
      363 +        {"read_lock_bh",        LOCK,   bottom_half, NO_ARG, ret_any},
      364 +        {"read_unlock_bh",      UNLOCK, bottom_half, NO_ARG, ret_any},
      365 +        {"_read_lock_bh",       LOCK,   bottom_half, NO_ARG, ret_any},
      366 +        {"_read_unlock_bh",     UNLOCK, bottom_half, NO_ARG, ret_any},
      367 +        {"__read_lock_bh",      LOCK,   bottom_half, NO_ARG, ret_any},
      368 +        {"__read_unlock_bh",    UNLOCK, bottom_half, NO_ARG, ret_any},
      369 +        {"_raw_read_lock_bh",   LOCK,   bottom_half, NO_ARG, ret_any},
      370 +        {"_raw_read_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
      371 +        {"write_lock_bh",       LOCK,   bottom_half, NO_ARG, ret_any},
      372 +        {"write_unlock_bh",     UNLOCK, bottom_half, NO_ARG, ret_any},
      373 +        {"_write_lock_bh",      LOCK,   bottom_half, NO_ARG, ret_any},
      374 +        {"_write_unlock_bh",    UNLOCK, bottom_half, NO_ARG, ret_any},
      375 +        {"__write_lock_bh",     LOCK,   bottom_half, NO_ARG, ret_any},
      376 +        {"__write_unlock_bh",   UNLOCK, bottom_half, NO_ARG, ret_any},
      377 +        {"_raw_write_lock_bh",  LOCK,   bottom_half, NO_ARG, ret_any},
      378 +        {"_raw_write_unlock_bh",UNLOCK, bottom_half, NO_ARG, ret_any},
      379 +        {"spin_trylock_bh",     LOCK,   bottom_half, NO_ARG, ret_one},
      380 +        {"_spin_trylock_bh",    LOCK,   bottom_half, NO_ARG, ret_one},
      381 +        {"__spin_trylock_bh",   LOCK,   bottom_half, NO_ARG, ret_one},
 339  382  
 340      -        {"local_bh_disable",    LOCK,   "bottom_half", NO_ARG, ret_any},
 341      -        {"_local_bh_disable",   LOCK,   "bottom_half", NO_ARG, ret_any},
 342      -        {"__local_bh_disable",  LOCK,   "bottom_half", NO_ARG, ret_any},
 343      -        {"local_bh_enable",     UNLOCK, "bottom_half", NO_ARG, ret_any},
 344      -        {"_local_bh_enable",    UNLOCK, "bottom_half", NO_ARG, ret_any},
 345      -        {"__local_bh_enable",   UNLOCK, "bottom_half", NO_ARG, ret_any},
 346      -        {"spin_lock_bh",        LOCK,   "bottom_half", NO_ARG, ret_any},
 347      -        {"spin_unlock_bh",      UNLOCK, "bottom_half", NO_ARG, ret_any},
 348      -        {"_spin_lock_bh",       LOCK,   "bottom_half", NO_ARG, ret_any},
 349      -        {"_spin_unlock_bh",     UNLOCK, "bottom_half", NO_ARG, ret_any},
 350      -        {"__spin_lock_bh",      LOCK,   "bottom_half", NO_ARG, ret_any},
 351      -        {"__spin_unlock_bh",    UNLOCK, "bottom_half", NO_ARG, ret_any},
 352      -        {"read_lock_bh",        LOCK,   "bottom_half", NO_ARG, ret_any},
 353      -        {"read_unlock_bh",      UNLOCK, "bottom_half", NO_ARG, ret_any},
 354      -        {"_read_lock_bh",       LOCK,   "bottom_half", NO_ARG, ret_any},
 355      -        {"_read_unlock_bh",     UNLOCK, "bottom_half", NO_ARG, ret_any},
 356      -        {"__read_lock_bh",      LOCK,   "bottom_half", NO_ARG, ret_any},
 357      -        {"__read_unlock_bh",    UNLOCK, "bottom_half", NO_ARG, ret_any},
 358      -        {"_raw_read_lock_bh",   LOCK,   "bottom_half", NO_ARG, ret_any},
 359      -        {"_raw_read_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
 360      -        {"write_lock_bh",       LOCK,   "bottom_half", NO_ARG, ret_any},
 361      -        {"write_unlock_bh",     UNLOCK, "bottom_half", NO_ARG, ret_any},
 362      -        {"_write_lock_bh",      LOCK,   "bottom_half", NO_ARG, ret_any},
 363      -        {"_write_unlock_bh",    UNLOCK, "bottom_half", NO_ARG, ret_any},
 364      -        {"__write_lock_bh",     LOCK,   "bottom_half", NO_ARG, ret_any},
 365      -        {"__write_unlock_bh",   UNLOCK, "bottom_half", NO_ARG, ret_any},
 366      -        {"spin_trylock_bh",     LOCK,   "bottom_half", NO_ARG, ret_one},
 367      -        {"_spin_trylock_bh",    LOCK,   "bottom_half", NO_ARG, ret_one},
 368      -        {"__spin_trylock_bh",   LOCK,   "bottom_half", NO_ARG, ret_one},
      383 +        {"ffs_mutex_lock",      LOCK,   mutex, 0, ret_zero},
 369  384  
 370      -        {"ffs_mutex_lock",        LOCK,   "mutex", 0, ret_zero},
      385 +        {"clk_prepare_lock",    LOCK,   prepare_lock, NO_ARG, ret_any},
      386 +        {"clk_prepare_unlock",  UNLOCK, prepare_lock, NO_ARG, ret_any},
      387 +        {"clk_enable_lock",     LOCK,   enable_lock, -1, ret_any},
      388 +        {"clk_enable_unlock",   UNLOCK, enable_lock,  0, ret_any},
      389 +
      390 +        {"dma_resv_lock",               LOCK,   mutex, 0, ret_zero},
      391 +        {"dma_resv_trylock",            LOCK,   mutex, 0, ret_one},
      392 +        {"dma_resv_lock_interruptible", LOCK,   mutex, 0, ret_zero},
      393 +        {"dma_resv_unlock",             UNLOCK, mutex, 0, ret_any},
      394 +
      395 +        {"modeset_lock",                          LOCK,   mutex, 0, ret_zero},
      396 +        {"drm_ modeset_lock",                     LOCK,   mutex, 0, ret_zero},
      397 +        {"drm_modeset_lock_single_interruptible", LOCK,   mutex, 0, ret_zero},
      398 +        {"modeset_unlock",                        UNLOCK, mutex, 0, ret_any},
      399 +
      400 +        {"reiserfs_write_lock_nested",   LOCK,   mutex, 0, ret_any},
      401 +        {"reiserfs_write_unlock_nested", UNLOCK, mutex, 0, ret_any},
      402 +
      403 +        {"rw_lock",                LOCK,   write_lock, 1, ret_any},
      404 +        {"rw_unlock",              UNLOCK, write_lock, 1, ret_any},
      405 +
      406 +        {"sem_lock",               LOCK,   mutex, 0, ret_any},
      407 +        {"sem_unlock",             UNLOCK, mutex, 0, ret_any},
      408 +
      409 +        {},
 371  410  };
 372  411  
 373      -static struct lock_info *lock_table;
      412 +struct macro_info {
      413 +        const char *macro;
      414 +        enum action action;
      415 +        int param;
      416 +};
 374  417  
 375      -static struct tracker_list *starts_locked;
 376      -static struct tracker_list *starts_unlocked;
      418 +static struct macro_info macro_table[] = {
      419 +        {"genpd_lock",               LOCK,   0},
      420 +        {"genpd_lock_nested",        LOCK,   0},
      421 +        {"genpd_lock_interruptible", LOCK,   0},
      422 +        {"genpd_unlock",             UNLOCK, 0},
      423 +};
 377  424  
 378      -struct locks_on_return {
 379      -        int line;
 380      -        struct tracker_list *locked;
 381      -        struct tracker_list *unlocked;
 382      -        struct tracker_list *impossible;
 383      -        struct range_list *return_values;
      425 +static const char *false_positives[][2] = {
      426 +        {"fs/jffs2/", "->alloc_sem"},
      427 +        {"fs/xfs/", "->b_sema"},
      428 +        {"mm/", "pvmw->ptl"},
 384  429  };
 385      -DECLARE_PTR_LIST(return_list, struct locks_on_return);
 386      -static struct return_list *all_returns;
 387  430  
 388      -static char *make_full_name(const char *lock, const char *var)
 389      -{
 390      -        static char tmp_buf[512];
      431 +static struct stree *start_states;
      432 +static struct stree_stack *saved_stack;
 391  433  
 392      -        snprintf(tmp_buf, sizeof(tmp_buf), "%s:%s", lock, var);
 393      -        remove_parens(tmp_buf);
 394      -        return alloc_string(tmp_buf);
      434 +static struct tracker_list *locks;
      435 +
      436 +static void reset(struct sm_state *sm, struct expression *mod_expr)
      437 +{
      438 +        set_state(my_id, sm->name, sm->sym, &start_state);
 395  439  }
 396  440  
 397  441  static struct expression *remove_spinlock_check(struct expression *expr)
 398  442  {
 399  443          if (expr->type != EXPR_CALL)
 400  444                  return expr;
 401  445          if (expr->fn->type != EXPR_SYMBOL)
 402  446                  return expr;
 403  447          if (strcmp(expr->fn->symbol_name->name, "spinlock_check"))
 404  448                  return expr;
 405  449          expr = get_argument_from_call_expr(expr->args, 0);
 406  450          return expr;
 407  451  }
 408  452  
 409      -static char *get_full_name(struct expression *expr, int index)
      453 +static struct expression *filter_kernel_args(struct expression *arg)
 410  454  {
 411      -        struct expression *arg;
 412      -        char *name = NULL;
 413      -        char *full_name = NULL;
      455 +        if (arg->type == EXPR_PREOP && arg->op == '&')
      456 +                return strip_expr(arg->unop);
      457 +        if (!is_pointer(arg))
      458 +                return arg;
      459 +        return deref_expression(strip_expr(arg));
      460 +}
      461 +
      462 +static char *lock_to_name_sym(struct expression *expr, struct symbol **sym)
      463 +{
      464 +        expr = remove_spinlock_check(expr);
      465 +        expr = filter_kernel_args(expr);
      466 +        return expr_to_str_sym(expr, sym);
      467 +}
      468 +
      469 +static char *get_full_name(struct expression *expr, int index, struct symbol **sym)
      470 +{
 414  471          struct lock_info *lock = &lock_table[index];
      472 +        struct expression *arg;
 415  473  
      474 +        *sym = NULL;
 416  475          if (lock->arg == RETURN_VAL) {
 417      -                name = expr_to_var(expr->left);
 418      -                full_name = make_full_name(lock->name, name);
      476 +                return expr_to_var_sym(strip_expr(expr->left), sym);
 419  477          } else if (lock->arg == NO_ARG) {
 420      -                full_name = make_full_name(lock->name, "");
      478 +                return alloc_string(get_lock_name(lock->type));
 421  479          } else {
 422  480                  arg = get_argument_from_call_expr(expr->args, lock->arg);
 423  481                  if (!arg)
 424      -                        goto free;
 425      -                arg = remove_spinlock_check(arg);
 426      -                name = expr_to_str(arg);
 427      -                if (!name)
 428      -                        goto free;
 429      -                full_name = make_full_name(lock->name, name);
      482 +                        return NULL;
      483 +                return lock_to_name_sym(arg, sym);
 430  484          }
 431      -free:
 432      -        free_string(name);
 433      -        return full_name;
 434  485  }
 435  486  
 436      -static struct smatch_state *get_start_state(struct sm_state *sm)
      487 +static struct smatch_state *unmatched_state(struct sm_state *sm)
 437  488  {
 438      -        int is_locked = 0;
 439      -        int is_unlocked = 0;
      489 +        return &start_state;
      490 +}
 440  491  
 441      -        if (in_tracker_list(starts_locked, my_id, sm->name, sm->sym))
 442      -                is_locked = 1;
 443      -        if (in_tracker_list(starts_unlocked, my_id, sm->name, sm->sym))
 444      -                is_unlocked = 1;
 445      -        if (is_locked && is_unlocked)
 446      -                return &undefined;
 447      -        if (is_locked)
      492 +static void pre_merge_hook(struct sm_state *cur, struct sm_state *other)
      493 +{
      494 +        if (is_impossible_path())
      495 +                set_state(my_id, cur->name, cur->sym, &impossible);
      496 +}
      497 +
      498 +static struct smatch_state *merge_func(struct smatch_state *s1, struct smatch_state *s2)
      499 +{
      500 +        if (s1 == &impossible)
      501 +                return s2;
      502 +        if (s2 == &impossible)
      503 +                return s1;
      504 +        return &merged;
      505 +}
      506 +
      507 +static struct smatch_state *action_to_state(enum action lock_unlock)
      508 +{
      509 +        switch (lock_unlock) {
      510 +        case LOCK:
 448  511                  return &locked;
 449      -        if (is_unlocked)
      512 +        case UNLOCK:
 450  513                  return &unlocked;
 451      -        return &undefined;
      514 +        case RESTORE:
      515 +                return &restore;
      516 +        }
      517 +        return NULL;
 452  518  }
 453  519  
 454      -static struct smatch_state *unmatched_state(struct sm_state *sm)
      520 +static struct sm_state *get_best_match(const char *key, enum action lock_unlock)
 455  521  {
 456      -        return &start_state;
      522 +        struct sm_state *sm;
      523 +        struct sm_state *match;
      524 +        int cnt = 0;
      525 +        int start_pos, state_len, key_len, chunks, i;
      526 +
      527 +        if (strncmp(key, "$->", 3) == 0)
      528 +                key += 3;
      529 +
      530 +        key_len = strlen(key);
      531 +        chunks = 0;
      532 +        for (i = key_len - 1; i > 0; i--) {
      533 +                if (key[i] == '>' || key[i] == '.')
      534 +                        chunks++;
      535 +                if (chunks == 2) {
      536 +                        key += (i + 1);
      537 +                        key_len = strlen(key);
      538 +                        break;
      539 +                }
      540 +        }
      541 +
      542 +        FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
      543 +                if (((lock_unlock == UNLOCK || lock_unlock == RESTORE) &&
      544 +                     sm->state != &locked) ||
      545 +                    (lock_unlock == LOCK && sm->state != &unlocked))
      546 +                        continue;
      547 +                state_len = strlen(sm->name);
      548 +                if (state_len < key_len)
      549 +                        continue;
      550 +                start_pos = state_len - key_len;
      551 +                if ((start_pos == 0 || !isalnum(sm->name[start_pos - 1])) &&
      552 +                    strcmp(sm->name + start_pos, key) == 0) {
      553 +                        cnt++;
      554 +                        match = sm;
      555 +                }
      556 +        } END_FOR_EACH_SM(sm);
      557 +
      558 +        if (cnt == 1)
      559 +                return match;
      560 +        return NULL;
 457  561  }
 458  562  
 459      -static void pre_merge_hook(struct sm_state *cur, struct sm_state *other)
      563 +static void use_best_match(char *key, enum action lock_unlock)
 460  564  {
 461      -        if (is_impossible_path())
 462      -                set_state(my_id, cur->name, cur->sym, &impossible);
      565 +        struct sm_state *match;
      566 +
      567 +        match = get_best_match(key, lock_unlock);
      568 +        if (match)
      569 +                set_state(my_id, match->name, match->sym, action_to_state(lock_unlock));
      570 +        else
      571 +                set_state(my_id, key, NULL, action_to_state(lock_unlock));
 463  572  }
 464  573  
 465      -static bool nestable(const char *name)
      574 +static void set_start_state(const char *name, struct symbol *sym, struct smatch_state *start)
 466  575  {
 467      -        if (strstr(name, "read_sem:"))
 468      -                return true;
 469      -        if (strcmp(name, "bottom_half:") == 0)
 470      -                return true;
      576 +        struct smatch_state *orig;
      577 +
      578 +        orig = get_state_stree(start_states, my_id, name, sym);
      579 +        if (!orig)
      580 +                set_state_stree(&start_states, my_id, name, sym, start);
      581 +        else if (orig != start)
      582 +                set_state_stree(&start_states, my_id, name, sym, &undefined);
      583 +}
      584 +
      585 +static bool common_false_positive(const char *name)
      586 +{
      587 +        const char *path, *lname;
      588 +        int i, len_total, len_path, len_name, skip;
      589 +
      590 +        if (!get_filename())
      591 +                return false;
      592 +
      593 +        len_total = strlen(name);
      594 +        for (i = 0; i < ARRAY_SIZE(false_positives); i++) {
      595 +                path = false_positives[i][0];
      596 +                lname = false_positives[i][1];
      597 +
      598 +                len_path = strlen(path);
      599 +                len_name = strlen(lname);
      600 +
      601 +                if (len_name > len_total)
      602 +                        continue;
      603 +                skip = len_total - len_name;
      604 +
      605 +                if (strncmp(get_filename(), path, len_path) == 0 &&
      606 +                    strcmp(name + skip, lname) == 0)
      607 +                        return true;
      608 +        }
      609 +
 471  610          return false;
 472  611  }
 473  612  
 474      -static void do_lock(const char *name)
      613 +static void warn_on_double(struct sm_state *sm, struct smatch_state *state)
 475  614  {
 476      -        struct sm_state *sm;
      615 +        struct sm_state *tmp;
 477  616  
 478      -        if (__inline_fn)
      617 +        if (!sm)
 479  618                  return;
 480  619  
 481      -        sm = get_sm_state(my_id, name, NULL);
 482      -        if (!sm)
 483      -                add_tracker(&starts_unlocked, my_id, name, NULL);
 484      -        if (sm && slist_has_state(sm->possible, &locked) && !nestable(name))
 485      -                sm_error("double lock '%s'", name);
 486      -        if (sm)
 487      -                func_has_transition = TRUE;
 488      -        set_state(my_id, name, NULL, &locked);
      620 +        FOR_EACH_PTR(sm->possible, tmp) {
      621 +                if (tmp->state == state)
      622 +                        goto found;
      623 +        } END_FOR_EACH_PTR(tmp);
      624 +
      625 +        return;
      626 +found:
      627 +        if (strcmp(sm->name, "bottom_half") == 0)
      628 +                return;
      629 +        if (common_false_positive(sm->name))
      630 +                return;
      631 +        sm_msg("error: double %s '%s' (orig line %u)",
      632 +               state->name, sm->name, tmp->line);
 489  633  }
 490  634  
 491      -static void do_lock_failed(const char *name)
      635 +static bool handle_macro_lock_unlock(void)
 492  636  {
      637 +        struct expression *expr, *arg;
      638 +        struct macro_info *info;
 493  639          struct sm_state *sm;
      640 +        struct symbol *sym;
      641 +        const char *macro;
      642 +        char *name;
      643 +        bool ret = false;
      644 +        int i;
 494  645  
 495      -        if (__inline_fn)
      646 +        expr = last_ptr_list((struct ptr_list *)big_expression_stack);
      647 +        while (expr && expr->type == EXPR_ASSIGNMENT)
      648 +                expr = strip_expr(expr->right);
      649 +        if (!expr || expr->type != EXPR_CALL)
      650 +                return false;
      651 +
      652 +        macro = get_macro_name(expr->pos);
      653 +        if (!macro)
      654 +                return false;
      655 +
      656 +        for (i = 0; i < ARRAY_SIZE(macro_table); i++) {
      657 +                info = &macro_table[i];
      658 +
      659 +                if (strcmp(macro, info->macro) != 0)
      660 +                        continue;
      661 +                arg = get_argument_from_call_expr(expr->args, info->param);
      662 +                name = expr_to_str_sym(arg, &sym);
      663 +                if (!name || !sym)
      664 +                        goto free;
      665 +                sm = get_sm_state(my_id, name, sym);
      666 +
      667 +                if (info->action == LOCK) {
      668 +                        if (!sm)
      669 +                                set_start_state(name, sym, &unlocked);
      670 +                        if (sm && sm->line != expr->pos.line)
      671 +                                warn_on_double(sm, &locked);
      672 +                        set_state(my_id, name, sym, &locked);
      673 +                } else {
      674 +                        if (!sm)
      675 +                                set_start_state(name, sym, &locked);
      676 +                        if (sm && sm->line != expr->pos.line)
      677 +                                warn_on_double(sm, &unlocked);
      678 +                        set_state(my_id, name, sym, &unlocked);
      679 +                }
      680 +                ret = true;
      681 +free:
      682 +                free_string(name);
      683 +                return ret;
      684 +        }
      685 +        return false;
      686 +}
      687 +
      688 +static void do_lock(const char *name, struct symbol *sym, struct lock_info *info)
      689 +{
      690 +        struct sm_state *sm;
      691 +
      692 +        if (handle_macro_lock_unlock())
 496  693                  return;
 497  694  
 498      -        sm = get_sm_state(my_id, name, NULL);
      695 +        add_tracker(&locks, my_id, name, sym);
      696 +
      697 +        sm = get_sm_state(my_id, name, sym);
 499  698          if (!sm)
 500      -                add_tracker(&starts_unlocked, my_id, name, NULL);
 501      -        set_state(my_id, name, NULL, &unlocked);
      699 +                set_start_state(name, sym, &unlocked);
      700 +        warn_on_double(sm, &locked);
      701 +        set_state(my_id, name, sym, &locked);
 502  702  }
 503  703  
 504      -static void do_unlock(const char *name)
      704 +static void do_lock_failed(const char *name, struct symbol *sym)
 505  705  {
      706 +        add_tracker(&locks, my_id, name, sym);
      707 +        set_state(my_id, name, sym, &unlocked);
      708 +}
      709 +
      710 +static void do_unlock(const char *name, struct symbol *sym, struct lock_info *info)
      711 +{
 506  712          struct sm_state *sm;
 507  713  
 508      -        if (__inline_fn)
 509      -                return;
 510  714          if (__path_is_null())
 511  715                  return;
 512      -        sm = get_sm_state(my_id, name, NULL);
      716 +
      717 +        if (handle_macro_lock_unlock())
      718 +                return;
      719 +
      720 +        add_tracker(&locks, my_id, name, sym);
      721 +        sm = get_sm_state(my_id, name, sym);
      722 +        if (!sm) {
      723 +                sm = get_best_match(name, UNLOCK);
      724 +                if (sm) {
      725 +                        name = sm->name;
      726 +                        sym = sm->sym;
      727 +                }
      728 +        }
 513  729          if (!sm)
 514      -                add_tracker(&starts_locked, my_id, name, NULL);
 515      -        if (sm && slist_has_state(sm->possible, &unlocked) &&
 516      -                        strcmp(name, "bottom_half:") != 0)
 517      -                sm_error("double unlock '%s'", name);
 518      -        if (sm)
 519      -                func_has_transition = TRUE;
 520      -        set_state(my_id, name, NULL, &unlocked);
      730 +                set_start_state(name, sym, &locked);
      731 +        warn_on_double(sm, &unlocked);
      732 +        set_state(my_id, name, sym, &unlocked);
 521  733  }
 522  734  
      735 +static void do_restore(const char *name, struct symbol *sym, struct lock_info *info)
      736 +{
      737 +        if (__path_is_null())
      738 +                return;
      739 +
      740 +        if (!get_state(my_id, name, sym))
      741 +                set_start_state(name, sym, &locked);
      742 +
      743 +        add_tracker(&locks, my_id, name, sym);
      744 +        set_state(my_id, name, sym, &restore);
      745 +}
      746 +
 523  747  static void match_lock_held(const char *fn, struct expression *call_expr,
 524      -                        struct expression *assign_expr, void *_index)
      748 +                            struct expression *assign_expr, void *_index)
 525  749  {
 526  750          int index = PTR_INT(_index);
 527      -        char *lock_name;
 528  751          struct lock_info *lock = &lock_table[index];
      752 +        char *lock_name;
      753 +        struct symbol *sym;
 529  754  
 530  755          if (lock->arg == NO_ARG) {
 531      -                lock_name = get_full_name(NULL, index);
      756 +                lock_name = get_full_name(NULL, index, &sym);
 532  757          } else if (lock->arg == RETURN_VAL) {
 533  758                  if (!assign_expr)
 534  759                          return;
 535      -                lock_name = get_full_name(assign_expr, index);
      760 +                lock_name = get_full_name(assign_expr, index, &sym);
 536  761          } else {
 537      -                lock_name = get_full_name(call_expr, index);
      762 +                lock_name = get_full_name(call_expr, index, &sym);
 538  763          }
 539  764          if (!lock_name)
 540  765                  return;
 541      -        do_lock(lock_name);
      766 +        do_lock(lock_name, sym, lock);
 542  767          free_string(lock_name);
 543  768  }
 544  769  
 545  770  static void match_lock_failed(const char *fn, struct expression *call_expr,
 546  771                          struct expression *assign_expr, void *_index)
 547  772  {
 548  773          int index = PTR_INT(_index);
 549      -        char *lock_name;
 550  774          struct lock_info *lock = &lock_table[index];
      775 +        char *lock_name;
      776 +        struct symbol *sym;
 551  777  
 552  778          if (lock->arg == NO_ARG) {
 553      -                lock_name = get_full_name(NULL, index);
      779 +                lock_name = get_full_name(NULL, index, &sym);
 554  780          } else if (lock->arg == RETURN_VAL) {
 555  781                  if (!assign_expr)
 556  782                          return;
 557      -                lock_name = get_full_name(assign_expr, index);
      783 +                lock_name = get_full_name(assign_expr, index, &sym);
 558  784          } else {
 559      -                lock_name = get_full_name(call_expr, index);
      785 +                lock_name = get_full_name(call_expr, index, &sym);
 560  786          }
 561  787          if (!lock_name)
 562  788                  return;
 563      -        do_lock_failed(lock_name);
      789 +        do_lock_failed(lock_name, sym);
 564  790          free_string(lock_name);
 565  791  }
 566  792  
 567  793  static void match_returns_locked(const char *fn, struct expression *expr,
 568  794                                        void *_index)
 569  795  {
 570      -        char *full_name = NULL;
 571  796          int index = PTR_INT(_index);
 572  797          struct lock_info *lock = &lock_table[index];
      798 +        char *full_name;
      799 +        struct symbol *sym;
 573  800  
 574  801          if (lock->arg != RETURN_VAL)
 575  802                  return;
 576      -        full_name = get_full_name(expr, index);
 577      -        do_lock(full_name);
      803 +        full_name = get_full_name(expr, index, &sym);
      804 +        if (!full_name)
      805 +                return;
      806 +        do_lock(full_name, sym, lock);
 578  807  }
 579  808  
 580  809  static void match_lock_unlock(const char *fn, struct expression *expr, void *_index)
 581  810  {
 582      -        char *full_name = NULL;
 583  811          int index = PTR_INT(_index);
 584  812          struct lock_info *lock = &lock_table[index];
      813 +        char *full_name;
      814 +        struct symbol *sym;
 585  815  
 586      -        if (__inline_fn)
 587      -                return;
 588      -
 589      -        full_name = get_full_name(expr, index);
      816 +        full_name = get_full_name(expr, index, &sym);
 590  817          if (!full_name)
 591  818                  return;
 592      -        if (lock->action == LOCK)
 593      -                do_lock(full_name);
 594      -        else
 595      -                do_unlock(full_name);
      819 +        switch (lock->action) {
      820 +        case LOCK:
      821 +                do_lock(full_name, sym, lock);
      822 +                break;
      823 +        case UNLOCK:
      824 +                do_unlock(full_name, sym, lock);
      825 +                break;
      826 +        case RESTORE:
      827 +                do_restore(full_name, sym, lock);
      828 +                break;
      829 +        }
 596  830          free_string(full_name);
 597  831  }
 598  832  
 599      -static struct locks_on_return *alloc_return(struct expression *expr)
      833 +static struct smatch_state *get_start_state(struct sm_state *sm)
 600  834  {
 601      -        struct locks_on_return *ret;
      835 +        struct smatch_state *orig;
 602  836  
 603      -        ret = malloc(sizeof(*ret));
 604      -        if (!get_implied_rl(expr, &ret->return_values))
 605      -                ret->return_values = NULL;
 606      -        ret->line = get_lineno();
 607      -        ret->locked = NULL;
 608      -        ret->unlocked = NULL;
 609      -        ret->impossible = NULL;
 610      -        return ret;
      837 +        orig = get_state_stree(start_states, my_id, sm->name, sm->sym);
      838 +        if (orig)
      839 +                return orig;
      840 +        return &undefined;
 611  841  }
 612  842  
 613      -static int check_possible(struct sm_state *sm)
      843 +static int get_param_lock_name(struct sm_state *sm, struct expression *expr,
      844 +                               const char **name)
 614  845  {
 615      -        struct sm_state *tmp;
 616      -        int islocked = 0;
 617      -        int isunlocked = 0;
 618      -        int undef = 0;
      846 +        char *other_name;
      847 +        struct symbol *other_sym;
      848 +        const char *param_name;
      849 +        int param;
 619  850  
 620      -        if (!option_spammy)
 621      -                return 0;
      851 +        *name = sm->name;
 622  852  
 623      -        FOR_EACH_PTR(sm->possible, tmp) {
 624      -                if (tmp->state == &locked)
 625      -                        islocked = 1;
 626      -                if (tmp->state == &unlocked)
 627      -                        isunlocked = 1;
 628      -                if (tmp->state == &start_state) {
 629      -                        struct smatch_state *s;
      853 +        param = get_param_num_from_sym(sm->sym);
      854 +        if (param >= 0) {
      855 +                param_name = get_param_name(sm);
      856 +                if (param_name)
      857 +                        *name = param_name;
      858 +                return param;
      859 +        }
 630  860  
 631      -                        s = get_start_state(tmp);
 632      -                        if (s == &locked)
 633      -                                islocked = 1;
 634      -                        else if (s == &unlocked)
 635      -                                isunlocked = 1;
 636      -                        else
 637      -                                undef = 1;
      861 +        if (expr) {
      862 +                struct symbol *ret_sym;
      863 +                char *ret_str;
      864 +
      865 +                ret_str = expr_to_str_sym(expr, &ret_sym);
      866 +                if (ret_str && ret_sym == sm->sym) {
      867 +                        param_name = state_name_to_param_name(sm->name, ret_str);
      868 +                        if (param_name) {
      869 +                                free_string(ret_str);
      870 +                                *name = param_name;
      871 +                                return -1;
      872 +                        }
 638  873                  }
 639      -                if (tmp->state == &undefined)
 640      -                        undef = 1;  // i don't think this is possible any more.
 641      -        } END_FOR_EACH_PTR(tmp);
 642      -        if ((islocked && isunlocked) || undef) {
 643      -                sm_warning("'%s' is sometimes locked here and sometimes unlocked.", sm->name);
 644      -                return 1;
      874 +                free_string(ret_str);
 645  875          }
 646      -        return 0;
      876 +
      877 +        other_name = get_other_name_sym(sm->name, sm->sym, &other_sym);
      878 +        if (!other_name)
      879 +                return -2;
      880 +        param = get_param_num_from_sym(other_sym);
      881 +        if (param < 0)
      882 +                return -2;
      883 +
      884 +        param_name = get_param_name_var_sym(other_name, other_sym);
      885 +        free_string(other_name);
      886 +        if (param_name)
      887 +                *name = param_name;
      888 +        return param;
 647  889  }
 648  890  
 649      -static struct position warned_pos;
      891 +static int get_db_type(struct sm_state *sm)
      892 +{
      893 +        if (sm->state == get_start_state(sm)) {
      894 +                if (sm->state == &locked)
      895 +                        return KNOWN_LOCKED;
      896 +                if (sm->state == &unlocked)
      897 +                        return KNOWN_UNLOCKED;
      898 +        }
 650  899  
 651      -static void match_return(int return_id, char *return_ranges, struct expression *expr)
      900 +        if (sm->state == &locked)
      901 +                return LOCKED;
      902 +        if (sm->state == &unlocked)
      903 +                return UNLOCKED;
      904 +        if (sm->state == &restore)
      905 +                return LOCK_RESTORED;
      906 +        return LOCKED;
      907 +}
      908 +
      909 +static void match_return_info(int return_id, char *return_ranges, struct expression *expr)
 652  910  {
 653      -        struct locks_on_return *ret;
 654      -        struct stree *stree;
 655      -        struct sm_state *tmp;
      911 +        struct sm_state *sm;
      912 +        const char *param_name;
      913 +        int param;
 656  914  
 657      -        if (!final_pass)
 658      -                return;
 659      -        if (__inline_fn)
 660      -                return;
      915 +        FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
      916 +                if (sm->state != &locked &&
      917 +                    sm->state != &unlocked &&
      918 +                    sm->state != &restore)
      919 +                        continue;
 661  920  
 662      -        if (expr && cmp_pos(expr->pos, warned_pos) == 0)
 663      -                return;
      921 +                param = get_param_lock_name(sm, expr, &param_name);
      922 +                sql_insert_return_states(return_id, return_ranges,
      923 +                                         get_db_type(sm),
      924 +                                         param, param_name, "");
      925 +        } END_FOR_EACH_SM(sm);
      926 +}
 664  927  
 665      -        ret = alloc_return(expr);
      928 +enum {
      929 +        ERR_PTR, VALID_PTR, NEGATIVE, ZERO, POSITIVE, NUM_BUCKETS,
      930 +};
 666  931  
 667      -        stree = __get_cur_stree();
 668      -        FOR_EACH_MY_SM(my_id, stree, tmp) {
 669      -                if (tmp->state == &locked) {
 670      -                        add_tracker(&ret->locked, tmp->owner, tmp->name,
 671      -                                tmp->sym);
 672      -                } else if (tmp->state == &unlocked) {
 673      -                        add_tracker(&ret->unlocked, tmp->owner, tmp->name,
 674      -                                tmp->sym);
 675      -                } else if (tmp->state == &start_state) {
 676      -                        struct smatch_state *s;
      932 +static bool is_EINTR(struct range_list *rl)
      933 +{
      934 +        sval_t sval;
 677  935  
 678      -                        s = get_start_state(tmp);
 679      -                        if (s == &locked)
 680      -                                add_tracker(&ret->locked, tmp->owner, tmp->name, 
 681      -                                            tmp->sym);
 682      -                        if (s == &unlocked)
 683      -                                add_tracker(&ret->unlocked, tmp->owner,tmp->name,
 684      -                                             tmp->sym);
 685      -                } else if (tmp->state == &impossible) {
 686      -                        add_tracker(&ret->impossible, tmp->owner, tmp->name,
 687      -                                    tmp->sym);
 688      -                } else {
 689      -                        if (check_possible(tmp)) {
 690      -                                if (expr)
 691      -                                        warned_pos = expr->pos;
 692      -                        }
 693      -                }
 694      -        } END_FOR_EACH_SM(tmp);
 695      -        add_ptr_list(&all_returns, ret);
      936 +        if (!rl_to_sval(rl, &sval))
      937 +                return false;
      938 +        return sval.value == -4;
 696  939  }
 697  940  
 698      -static void add_line(struct range_list **rl, int line)
      941 +static int success_fail_positive(struct range_list *rl)
 699  942  {
 700      -        sval_t sval = sval_type_val(&int_ctype, line);
      943 +        /* void returns are the same as success (zero in the kernel) */
      944 +        if (!rl)
      945 +                return ZERO;
 701  946  
 702      -        add_range(rl, sval, sval);
      947 +        if (rl_type(rl)->type != SYM_PTR && sval_is_negative(rl_min(rl)))
      948 +                return NEGATIVE;
      949 +
      950 +        if (rl_min(rl).value == 0 && rl_max(rl).value == 0)
      951 +                return ZERO;
      952 +
      953 +        if (is_err_ptr(rl_min(rl)) &&
      954 +            is_err_ptr(rl_max(rl)))
      955 +                return ERR_PTR;
      956 +
      957 +        /*
      958 +         * Trying to match ERR_PTR(ret) but without the expression struct.
      959 +         * Ugly...
      960 +         */
      961 +        if (type_bits(&long_ctype) == 64 &&
      962 +            rl_type(rl)->type == SYM_PTR &&
      963 +            rl_min(rl).value == INT_MIN)
      964 +                return ERR_PTR;
      965 +
      966 +        return POSITIVE;
 703  967  }
 704  968  
 705      -static int line_printed(struct range_list *rl, int line)
      969 +static bool sym_in_lock_table(struct symbol *sym)
 706  970  {
 707      -        sval_t sval = sval_type_val(&int_ctype, line);
      971 +        int i;
 708  972  
 709      -        return rl_has_sval(rl, sval);
      973 +        if (!sym || !sym->ident)
      974 +                return false;
      975 +
      976 +        for (i = 0; lock_table[i].function != NULL; i++) {
      977 +                if (strcmp(lock_table[i].function, sym->ident->name) == 0)
      978 +                        return true;
      979 +        }
      980 +        return false;
 710  981  }
 711  982  
 712      -static void print_inconsistent_returns(struct tracker *lock,
 713      -                                struct smatch_state *start)
      983 +static bool func_in_lock_table(struct expression *expr)
 714  984  {
 715      -        struct locks_on_return *tmp;
 716      -        struct range_list *printed = NULL;
      985 +        if (expr->type != EXPR_SYMBOL)
      986 +                return false;
      987 +        return sym_in_lock_table(expr->symbol);
      988 +}
      989 +
      990 +static void check_lock(char *name, struct symbol *sym)
      991 +{
      992 +        struct range_list *locked_lines = NULL;
      993 +        struct range_list *unlocked_lines = NULL;
      994 +        int locked_buckets[NUM_BUCKETS] = {};
      995 +        int unlocked_buckets[NUM_BUCKETS] = {};
      996 +        struct stree *stree, *orig;
      997 +        struct sm_state *return_sm;
      998 +        struct sm_state *sm;
      999 +        sval_t line = sval_type_val(&int_ctype, 0);
     1000 +        int bucket;
 717 1001          int i;
 718 1002  
 719      -        sm_warning("inconsistent returns '%s'.", lock->name);
 720      -        sm_printf("  Locked on:   ");
     1003 +        if (sym_in_lock_table(cur_func_sym))
     1004 +                return;
 721 1005  
 722      -        i = 0;
 723      -        FOR_EACH_PTR(all_returns, tmp) {
 724      -                if (line_printed(printed, tmp->line))
 725      -                        continue;
 726      -                if (in_tracker_list(tmp->unlocked, lock->owner, lock->name, lock->sym))
 727      -                        continue;
 728      -                if (in_tracker_list(tmp->locked, lock->owner, lock->name, lock->sym)) {
 729      -                        if (i++)
 730      -                                sm_printf("               ");
 731      -                        sm_printf("line %d\n", tmp->line);
 732      -                        add_line(&printed, tmp->line);
 733      -                        continue;
 734      -                }
 735      -                if (start == &locked) {
 736      -                        if (i++)
 737      -                                sm_printf("               ");
 738      -                        sm_printf("line %d\n", tmp->line);
 739      -                        add_line(&printed, tmp->line);
 740      -                }
 741      -        } END_FOR_EACH_PTR(tmp);
     1006 +        FOR_EACH_PTR(get_all_return_strees(), stree) {
     1007 +                orig = __swap_cur_stree(stree);
 742 1008  
 743      -        sm_printf("  Unlocked on: ");
 744      -        printed = NULL;
 745      -        i = 0;
 746      -        FOR_EACH_PTR(all_returns, tmp) {
 747      -                if (line_printed(printed, tmp->line))
 748      -                        continue;
 749      -                if (in_tracker_list(tmp->unlocked, lock->owner, lock->name, lock->sym)) {
 750      -                        if (i++)
 751      -                                sm_printf("               ");
 752      -                        sm_printf("line %d\n", tmp->line);
 753      -                        add_line(&printed, tmp->line);
 754      -                        continue;
     1009 +                if (is_impossible_path())
     1010 +                        goto swap_stree;
     1011 +
     1012 +                return_sm = get_sm_state(RETURN_ID, "return_ranges", NULL);
     1013 +                if (!return_sm)
     1014 +                        goto swap_stree;
     1015 +                line.value = return_sm->line;
     1016 +
     1017 +                sm = get_sm_state(my_id, name, sym);
     1018 +                if (!sm)
     1019 +                        goto swap_stree;
     1020 +
     1021 +                if (parent_is_gone_var_sym(sm->name, sm->sym))
     1022 +                        goto swap_stree;
     1023 +
     1024 +                if (sm->state != &locked && sm->state != &unlocked)
     1025 +                        goto swap_stree;
     1026 +
     1027 +                if (sm->state == &unlocked && is_EINTR(estate_rl(return_sm->state)))
     1028 +                        goto swap_stree;
     1029 +
     1030 +                bucket = success_fail_positive(estate_rl(return_sm->state));
     1031 +                if (sm->state == &locked) {
     1032 +                        add_range(&locked_lines, line, line);
     1033 +                        locked_buckets[bucket] = true;
 755 1034                  }
 756      -                if (in_tracker_list(tmp->locked, lock->owner, lock->name, lock->sym))
 757      -                        continue;
 758      -                if (start == &unlocked) {
 759      -                        if (i++)
 760      -                                sm_printf("               ");
 761      -                        sm_printf("line %d\n", tmp->line);
 762      -                        add_line(&printed, tmp->line);
     1035 +                if (sm->state == &unlocked) {
     1036 +                        add_range(&unlocked_lines, line, line);
     1037 +                        unlocked_buckets[bucket] = true;
 763 1038                  }
 764      -        } END_FOR_EACH_PTR(tmp);
 765      -}
     1039 +swap_stree:
     1040 +                __swap_cur_stree(orig);
     1041 +        } END_FOR_EACH_PTR(stree);
 766 1042  
 767      -static int matches_return_type(struct range_list *rl, enum return_type type)
 768      -{
 769      -        sval_t zero_sval = ll_to_sval(0);
 770      -        sval_t one_sval = ll_to_sval(1);
 771 1043  
 772      -        /* All these double negatives are super ugly!  */
     1044 +        if (!locked_lines || !unlocked_lines)
     1045 +                return;
 773 1046  
 774      -        switch (type) {
 775      -        case ret_zero:
 776      -                return !possibly_true_rl(rl, SPECIAL_NOTEQUAL, alloc_rl(zero_sval, zero_sval));
 777      -        case ret_one:
 778      -                return !possibly_true_rl(rl, SPECIAL_NOTEQUAL, alloc_rl(one_sval, one_sval));
 779      -        case ret_non_zero:
 780      -                return !possibly_true_rl(rl, SPECIAL_EQUAL, alloc_rl(zero_sval, zero_sval));
 781      -        case ret_negative:
 782      -                return !possibly_true_rl(rl, SPECIAL_GTE, alloc_rl(zero_sval, zero_sval));
 783      -        case ret_positive:
 784      -                return !possibly_true_rl(rl, '<', alloc_rl(zero_sval, zero_sval));
 785      -        case ret_any:
 786      -        default:
 787      -                return 1;
     1047 +        for (i = 0; i < NUM_BUCKETS; i++) {
     1048 +                if (locked_buckets[i] && unlocked_buckets[i])
     1049 +                        goto complain;
 788 1050          }
 789      -}
     1051 +        if (locked_buckets[NEGATIVE] &&
     1052 +            (unlocked_buckets[ZERO] || unlocked_buckets[POSITIVE]))
     1053 +                goto complain;
 790 1054  
 791      -static int match_held(struct tracker *lock, struct locks_on_return *this_return, struct smatch_state *start)
 792      -{
 793      -        if (in_tracker_list(this_return->impossible, lock->owner, lock->name, lock->sym))
 794      -                return 0;
 795      -        if (in_tracker_list(this_return->unlocked, lock->owner, lock->name, lock->sym))
 796      -                return 0;
 797      -        if (in_tracker_list(this_return->locked, lock->owner, lock->name, lock->sym))
 798      -                return 1;
 799      -        if (start == &unlocked)
 800      -                return 0;
 801      -        return 1;
     1055 +        if (locked_buckets[ERR_PTR])
     1056 +                goto complain;
     1057 +
     1058 +        return;
     1059 +
     1060 +complain:
     1061 +        sm_msg("warn: inconsistent returns '%s'.", name);
     1062 +        sm_printf("  Locked on  : %s\n", show_rl(locked_lines));
     1063 +        sm_printf("  Unlocked on: %s\n", show_rl(unlocked_lines));
 802 1064  }
 803 1065  
 804      -static int match_released(struct tracker *lock, struct locks_on_return *this_return, struct smatch_state *start)
     1066 +static void match_func_end(struct symbol *sym)
 805 1067  {
 806      -        if (in_tracker_list(this_return->impossible, lock->owner, lock->name, lock->sym))
 807      -                return 0;
 808      -        if (in_tracker_list(this_return->unlocked, lock->owner, lock->name, lock->sym))
 809      -                return 1;
 810      -        if (in_tracker_list(this_return->locked, lock->owner, lock->name, lock->sym))
 811      -                return 0;
 812      -        if (start == &unlocked)
 813      -                return 1;
 814      -        return 0;
     1068 +        struct tracker *tracker;
     1069 +
     1070 +        FOR_EACH_PTR(locks, tracker) {
     1071 +                check_lock(tracker->name, tracker->sym);
     1072 +        } END_FOR_EACH_PTR(tracker);
 815 1073  }
 816 1074  
 817      -static int held_on_return(struct tracker *lock, struct smatch_state *start, enum return_type type)
     1075 +static void register_lock(int index)
 818 1076  {
 819      -        struct locks_on_return *tmp;
     1077 +        struct lock_info *lock = &lock_table[index];
     1078 +        void *idx = INT_PTR(index);
 820 1079  
 821      -        FOR_EACH_PTR(all_returns, tmp) {
 822      -                if (!matches_return_type(tmp->return_values, type))
 823      -                        continue;
 824      -                if (match_held(lock, tmp, start))
 825      -                        return 1;
 826      -        } END_FOR_EACH_PTR(tmp);
 827      -        return 0;
     1080 +        if (lock->return_type == ret_one) {
     1081 +                return_implies_state(lock->function, 1, 1, &match_lock_held, idx);
     1082 +                return_implies_state(lock->function, 0, 0, &match_lock_failed, idx);
     1083 +        } else if (lock->return_type == ret_any && lock->arg == RETURN_VAL) {
     1084 +                add_function_assign_hook(lock->function, &match_returns_locked, idx);
     1085 +        } else if (lock->return_type == ret_any) {
     1086 +                add_function_hook(lock->function, &match_lock_unlock, idx);
     1087 +        } else if (lock->return_type == ret_zero) {
     1088 +                return_implies_state(lock->function, 0, 0, &match_lock_held, idx);
     1089 +                return_implies_state(lock->function, -4095, -1, &match_lock_failed, idx);
     1090 +        } else if (lock->return_type == ret_valid_ptr) {
     1091 +                return_implies_state_sval(lock->function, valid_ptr_min_sval, valid_ptr_max_sval, &match_lock_held, idx);
     1092 +        }
 828 1093  }
 829 1094  
 830      -static int released_on_return(struct tracker *lock, struct smatch_state *start, enum return_type type)
     1095 +static void load_table(struct lock_info *lock_table)
 831 1096  {
 832      -        struct locks_on_return *tmp;
     1097 +        int i;
 833 1098  
 834      -        FOR_EACH_PTR(all_returns, tmp) {
 835      -                if (!matches_return_type(tmp->return_values, type))
 836      -                        continue;
 837      -                if (match_released(lock, tmp, start))
 838      -                        return 1;
 839      -        } END_FOR_EACH_PTR(tmp);
 840      -        return 0;
     1099 +        for (i = 0; lock_table[i].function != NULL; i++) {
     1100 +                if (lock_table[i].action == LOCK)
     1101 +                        register_lock(i);
     1102 +                else
     1103 +                        add_function_hook(lock_table[i].function, &match_lock_unlock, INT_PTR(i));
     1104 +        }
 841 1105  }
 842 1106  
 843      -static void check_returns_consistently(struct tracker *lock,
 844      -                                struct smatch_state *start)
     1107 +static void db_param_locked_unlocked(struct expression *expr, int param, char *key, char *value, enum action lock_unlock)
 845 1108  {
 846      -        struct symbol *type;
     1109 +        struct expression *call, *arg;
     1110 +        char *name;
     1111 +        struct symbol *sym;
 847 1112  
 848      -        if (!held_on_return(lock, start, ret_any) ||
 849      -            !released_on_return(lock, start, ret_any))
     1113 +        call = expr;
     1114 +        while (call->type == EXPR_ASSIGNMENT)
     1115 +                call = strip_expr(call->right);
     1116 +        if (call->type != EXPR_CALL)
 850 1117                  return;
 851 1118  
 852      -        if (held_on_return(lock, start, ret_zero) &&
 853      -            !held_on_return(lock, start, ret_non_zero))
     1119 +        if (func_in_lock_table(call->fn))
 854 1120                  return;
 855 1121  
 856      -        if (held_on_return(lock, start, ret_positive) &&
 857      -            !held_on_return(lock, start, ret_zero))
     1122 +        if (param == -2) {
     1123 +                use_best_match(key, lock_unlock);
 858 1124                  return;
     1125 +        }
 859 1126  
 860      -        if (held_on_return(lock, start, ret_positive) &&
 861      -            !held_on_return(lock, start, ret_negative))
 862      -                return;
 863      -
 864      -        type = cur_func_return_type();
 865      -        if (type && type->type == SYM_PTR) {
 866      -                if (held_on_return(lock, start, ret_non_zero) &&
 867      -                    !held_on_return(lock, start, ret_zero))
     1127 +        if (param == -1) {
     1128 +                if (expr->type != EXPR_ASSIGNMENT)
 868 1129                          return;
     1130 +                name = get_variable_from_key(expr->left, key, &sym);
     1131 +        } else {
     1132 +                arg = get_argument_from_call_expr(call->args, param);
     1133 +                if (!arg)
     1134 +                        return;
     1135 +
     1136 +                name = get_variable_from_key(arg, key, &sym);
 869 1137          }
     1138 +        if (!name || !sym)
     1139 +                goto free;
 870 1140  
 871      -        print_inconsistent_returns(lock, start);
     1141 +        if (lock_unlock == LOCK)
     1142 +                do_lock(name, sym, NULL);
     1143 +        else if (lock_unlock == UNLOCK)
     1144 +                do_unlock(name, sym, NULL);
     1145 +        else if (lock_unlock == RESTORE)
     1146 +                do_restore(name, sym, NULL);
     1147 +
     1148 +free:
     1149 +        free_string(name);
 872 1150  }
 873 1151  
 874      -static void check_consistency(struct symbol *sym)
     1152 +static void db_param_locked(struct expression *expr, int param, char *key, char *value)
 875 1153  {
 876      -        struct tracker *tmp;
     1154 +        db_param_locked_unlocked(expr, param, key, value, LOCK);
     1155 +}
 877 1156  
 878      -        FOR_EACH_PTR(starts_locked, tmp) {
 879      -                if (in_tracker_list(starts_unlocked, tmp->owner, tmp->name,
 880      -                                        tmp->sym))
 881      -                        sm_error("locking inconsistency.  We assume "
 882      -                                   "'%s' is both locked and unlocked at the "
 883      -                                   "start.",
 884      -                                tmp->name);
 885      -        } END_FOR_EACH_PTR(tmp);
     1157 +static void db_param_unlocked(struct expression *expr, int param, char *key, char *value)
     1158 +{
     1159 +        db_param_locked_unlocked(expr, param, key, value, UNLOCK);
     1160 +}
 886 1161  
 887      -        FOR_EACH_PTR(starts_locked, tmp) {
 888      -                check_returns_consistently(tmp, &locked);
 889      -        } END_FOR_EACH_PTR(tmp);
 890      -
 891      -        FOR_EACH_PTR(starts_unlocked, tmp) {
 892      -                check_returns_consistently(tmp, &unlocked);
 893      -        } END_FOR_EACH_PTR(tmp);
     1162 +static void db_param_restore(struct expression *expr, int param, char *key, char *value)
     1163 +{
     1164 +        db_param_locked_unlocked(expr, param, key, value, RESTORE);
 894 1165  }
 895 1166  
 896      -static void clear_lists(void)
     1167 +static int get_caller_param_lock_name(struct expression *call, struct sm_state *sm, const char **name)
 897 1168  {
 898      -        struct locks_on_return *tmp;
     1169 +        struct expression *arg;
     1170 +        char *arg_name;
     1171 +        int param;
 899 1172  
 900      -        func_has_transition = FALSE;
     1173 +        param = 0;
     1174 +        FOR_EACH_PTR(call->args, arg) {
     1175 +                arg_name = sm_to_arg_name(arg, sm);
     1176 +                if (arg_name) {
     1177 +                        *name = arg_name;
     1178 +                        return param;
     1179 +                }
     1180 +                param++;
     1181 +        } END_FOR_EACH_PTR(arg);
 901 1182  
 902      -        free_trackers_and_list(&starts_locked);
 903      -        free_trackers_and_list(&starts_unlocked);
 904      -
 905      -        FOR_EACH_PTR(all_returns, tmp) {
 906      -                free_trackers_and_list(&tmp->locked);
 907      -                free_trackers_and_list(&tmp->unlocked);
 908      -                free(tmp);
 909      -        } END_FOR_EACH_PTR(tmp);
 910      -        __free_ptr_list((struct ptr_list **)&all_returns);
     1183 +        *name = sm->name;
     1184 +        return -2;
 911 1185  }
 912 1186  
 913      -static void match_func_end(struct symbol *sym)
     1187 +static void match_call_info(struct expression *expr)
 914 1188  {
 915      -        if (__inline_fn)
 916      -                return;
     1189 +        struct sm_state *sm;
     1190 +        const char *param_name;
     1191 +        int locked_type;
     1192 +        int param;
 917 1193  
 918      -        if (func_has_transition)
 919      -                check_consistency(sym);
     1194 +        FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
     1195 +                param = get_caller_param_lock_name(expr, sm, &param_name);
     1196 +                if (sm->state == &locked)
     1197 +                        locked_type = LOCKED;
     1198 +                else if (sm->state == &half_locked ||
     1199 +                         slist_has_state(sm->possible, &locked))
     1200 +                        locked_type = HALF_LOCKED;
     1201 +                else
     1202 +                        continue;
     1203 +                sql_insert_caller_info(expr, locked_type, param, param_name, "xxx type");
     1204 +
     1205 +        } END_FOR_EACH_SM(sm);
 920 1206  }
 921 1207  
 922      -static void match_after_func(struct symbol *sym)
     1208 +static void match_save_states(struct expression *expr)
 923 1209  {
 924      -        if (__inline_fn)
 925      -                return;
 926      -        clear_lists();
     1210 +        push_stree(&saved_stack, start_states);
     1211 +        start_states = NULL;
 927 1212  }
 928 1213  
 929      -static void register_lock(int index)
     1214 +static void match_restore_states(struct expression *expr)
 930 1215  {
 931      -        struct lock_info *lock = &lock_table[index];
 932      -        void *idx = INT_PTR(index);
     1216 +        start_states = pop_stree(&saved_stack);
     1217 +}
 933 1218  
 934      -        if (lock->return_type == ret_non_zero) {
 935      -                return_implies_state(lock->function, 1, INT_MAX, &match_lock_held, idx);
 936      -                return_implies_state(lock->function, 0, 0, &match_lock_failed, idx);
 937      -        } else if (lock->return_type == ret_any && lock->arg == RETURN_VAL) {
 938      -                add_function_assign_hook(lock->function, &match_returns_locked, idx);
 939      -        } else if (lock->return_type == ret_any) {
 940      -                add_function_hook(lock->function, &match_lock_unlock, idx);
 941      -        } else if (lock->return_type == ret_zero) {
 942      -                return_implies_state(lock->function, 0, 0, &match_lock_held, idx);
 943      -                return_implies_state(lock->function, -4095, -1, &match_lock_failed, idx);
 944      -        } else if (lock->return_type == ret_one) {
 945      -                return_implies_state(lock->function, 1, 1, &match_lock_held, idx);
 946      -                return_implies_state(lock->function, 0, 0, &match_lock_failed, idx);
 947      -        }
     1219 +static void match_after_func(struct symbol *sym)
     1220 +{
     1221 +        free_stree(&start_states);
 948 1222  }
 949 1223  
 950      -static void load_table(struct lock_info *_lock_table, int size)
     1224 +static void match_dma_resv_lock_NULL(const char *fn, struct expression *call_expr,
     1225 +                                     struct expression *assign_expr, void *_index)
 951 1226  {
 952      -        int i;
     1227 +        struct expression *lock, *ctx;
     1228 +        char *lock_name;
     1229 +        struct symbol *sym;
 953 1230  
 954      -        lock_table = _lock_table;
     1231 +        lock = get_argument_from_call_expr(call_expr->args, 0);
     1232 +        ctx = get_argument_from_call_expr(call_expr->args, 1);
     1233 +        if (!expr_is_zero(ctx))
     1234 +                return;
 955 1235  
 956      -        for (i = 0; i < size; i++) {
 957      -                if (lock_table[i].action == LOCK)
 958      -                        register_lock(i);
 959      -                else
 960      -                        add_function_hook(lock_table[i].function, &match_lock_unlock, INT_PTR(i));
 961      -        }
     1236 +        lock_name = lock_to_name_sym(lock, &sym);
     1237 +        if (!lock_name || !sym)
     1238 +                goto free;
     1239 +        do_lock(lock_name, sym, NULL);
     1240 +free:
     1241 +        free_string(lock_name);
 962 1242  }
 963 1243  
 964 1244  /* print_held_locks() is used in check_call_tree.c */
 965 1245  void print_held_locks(void)
 966 1246  {
 967 1247          struct stree *stree;
 968 1248          struct sm_state *sm;
 969 1249          int i = 0;
 970 1250  
 971 1251          stree = __get_cur_stree();
↓ open down ↓ 3 lines elided ↑ open up ↑
 975 1255                  if (i++)
 976 1256                          sm_printf(" ");
 977 1257                  sm_printf("'%s'", sm->name);
 978 1258          } END_FOR_EACH_SM(sm);
 979 1259  }
 980 1260  
 981 1261  void check_locking(int id)
 982 1262  {
 983 1263          my_id = id;
 984 1264  
 985      -        if (option_project == PROJ_WINE)
 986      -                load_table(wine_lock_table, ARRAY_SIZE(wine_lock_table));
 987      -        else if (option_project == PROJ_KERNEL)
 988      -                load_table(kernel_lock_table, ARRAY_SIZE(kernel_lock_table));
 989      -        else
     1265 +        if (option_project != PROJ_KERNEL)
 990 1266                  return;
 991 1267  
     1268 +        load_table(lock_table);
     1269 +
     1270 +        set_dynamic_states(my_id);
 992 1271          add_unmatched_state_hook(my_id, &unmatched_state);
 993 1272          add_pre_merge_hook(my_id, &pre_merge_hook);
 994      -        add_split_return_callback(match_return);
     1273 +        add_merge_hook(my_id, &merge_func);
     1274 +        add_modification_hook(my_id, &reset);
     1275 +
 995 1276          add_hook(&match_func_end, END_FUNC_HOOK);
     1277 +
 996 1278          add_hook(&match_after_func, AFTER_FUNC_HOOK);
     1279 +        add_hook(&match_save_states, INLINE_FN_START);
     1280 +        add_hook(&match_restore_states, INLINE_FN_END);
 997 1281  
     1282 +        add_hook(&match_call_info, FUNCTION_CALL_HOOK);
     1283 +
     1284 +        add_split_return_callback(match_return_info);
     1285 +        select_return_states_hook(LOCKED, &db_param_locked);
     1286 +        select_return_states_hook(UNLOCKED, &db_param_unlocked);
     1287 +        select_return_states_hook(LOCK_RESTORED, &db_param_restore);
     1288 +
     1289 +        return_implies_state("dma_resv_lock", -4095, -1, &match_dma_resv_lock_NULL, 0);
 998 1290  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX