LCOV - code coverage report
Current view: top level - kernel - kcov.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 161 377 42.7 %
Date: 2022-03-28 16:04:14 Functions: 10 17 58.8 %
Branches: 39 197 19.8 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : #define pr_fmt(fmt) "kcov: " fmt
       3                 :            : 
       4                 :            : #define DISABLE_BRANCH_PROFILING
       5                 :            : #include <linux/atomic.h>
       6                 :            : #include <linux/compiler.h>
       7                 :            : #include <linux/errno.h>
       8                 :            : #include <linux/export.h>
       9                 :            : #include <linux/types.h>
      10                 :            : #include <linux/file.h>
      11                 :            : #include <linux/fs.h>
      12                 :            : #include <linux/hashtable.h>
      13                 :            : #include <linux/init.h>
      14                 :            : #include <linux/mm.h>
      15                 :            : #include <linux/preempt.h>
      16                 :            : #include <linux/printk.h>
      17                 :            : #include <linux/sched.h>
      18                 :            : #include <linux/slab.h>
      19                 :            : #include <linux/spinlock.h>
      20                 :            : #include <linux/vmalloc.h>
      21                 :            : #include <linux/debugfs.h>
      22                 :            : #include <linux/uaccess.h>
      23                 :            : #include <linux/kcov.h>
      24                 :            : #include <linux/refcount.h>
      25                 :            : #include <linux/log2.h>
      26                 :            : #include <asm/setup.h>
      27                 :            : 
      28                 :            : #define kcov_debug(fmt, ...) pr_debug("%s: " fmt, __func__, ##__VA_ARGS__)
      29                 :            : 
      30                 :            : /* Number of 64-bit words written per one comparison: */
      31                 :            : #define KCOV_WORDS_PER_CMP 4
      32                 :            : 
      33                 :            : /*
      34                 :            :  * kcov descriptor (one per opened debugfs file).
      35                 :            :  * State transitions of the descriptor:
      36                 :            :  *  - initial state after open()
      37                 :            :  *  - then there must be a single ioctl(KCOV_INIT_TRACE) call
      38                 :            :  *  - then, mmap() call (several calls are allowed but not useful)
      39                 :            :  *  - then, ioctl(KCOV_ENABLE, arg), where arg is
      40                 :            :  *      KCOV_TRACE_PC - to trace only the PCs
      41                 :            :  *      or
      42                 :            :  *      KCOV_TRACE_CMP - to trace only the comparison operands
      43                 :            :  *  - then, ioctl(KCOV_DISABLE) to disable the task.
      44                 :            :  * Enabling/disabling ioctls can be repeated (only one task a time allowed).
      45                 :            :  */
      46                 :            : struct kcov {
      47                 :            :         /*
      48                 :            :          * Reference counter. We keep one for:
      49                 :            :          *  - opened file descriptor
      50                 :            :          *  - task with enabled coverage (we can't unwire it from another task)
      51                 :            :          *  - each code section for remote coverage collection
      52                 :            :          */
      53                 :            :         refcount_t              refcount;
      54                 :            :         /* The lock protects mode, size, area and t. */
      55                 :            :         spinlock_t              lock;
      56                 :            :         enum kcov_mode          mode;
      57                 :            :         /* Size of arena (in long's). */
      58                 :            :         unsigned int            size;
      59                 :            :         /* Coverage buffer shared with user space. */
      60                 :            :         void                    *area;
      61                 :            :         /* Task for which we collect coverage, or NULL. */
      62                 :            :         struct task_struct      *t;
      63                 :            :         /* Collecting coverage from remote (background) threads. */
      64                 :            :         bool                    remote;
      65                 :            :         /* Size of remote area (in long's). */
      66                 :            :         unsigned int            remote_size;
      67                 :            :         /*
      68                 :            :          * Sequence is incremented each time kcov is reenabled, used by
      69                 :            :          * kcov_remote_stop(), see the comment there.
      70                 :            :          */
      71                 :            :         int                     sequence;
      72                 :            : };
      73                 :            : 
      74                 :            : struct kcov_remote_area {
      75                 :            :         struct list_head        list;
      76                 :            :         unsigned int            size;
      77                 :            : };
      78                 :            : 
      79                 :            : struct kcov_remote {
      80                 :            :         u64                     handle;
      81                 :            :         struct kcov             *kcov;
      82                 :            :         struct hlist_node       hnode;
      83                 :            : };
      84                 :            : 
      85                 :            : static DEFINE_SPINLOCK(kcov_remote_lock);
      86                 :            : static DEFINE_HASHTABLE(kcov_remote_map, 4);
      87                 :            : static struct list_head kcov_remote_areas = LIST_HEAD_INIT(kcov_remote_areas);
      88                 :            : 
      89                 :            : 
      90                 :            : /* Size of the kcov_area: */
      91                 :            : static unsigned int                     _kcov_size = 0;
      92                 :            : /* Buffer for coverage collection: */
      93                 :            : static void                                     *_kcov_area = NULL;
      94                 :            : /* Task struct where kcov is enabled */
      95                 :            : static struct task_struct       *_t = NULL;
      96                 :            : 
      97                 :            : /* Must be called with kcov_remote_lock locked. */
      98                 :          0 : static struct kcov_remote *kcov_remote_find(u64 handle)
      99                 :            : {
     100                 :          0 :         struct kcov_remote *remote;
     101                 :            : 
     102   [ #  #  #  #  :          0 :         hash_for_each_possible(kcov_remote_map, remote, hnode, handle) {
             #  #  #  # ]
     103   [ #  #  #  # ]:          0 :                 if (remote->handle == handle)
     104                 :            :                         return remote;
     105                 :            :         }
     106                 :            :         return NULL;
     107                 :            : }
     108                 :            : 
     109                 :          0 : static struct kcov_remote *kcov_remote_add(struct kcov *kcov, u64 handle)
     110                 :            : {
     111                 :          0 :         struct kcov_remote *remote;
     112                 :            : 
     113   [ #  #  #  # ]:          0 :         if (kcov_remote_find(handle))
     114                 :            :                 return ERR_PTR(-EEXIST);
     115                 :          0 :         remote = kmalloc(sizeof(*remote), GFP_ATOMIC);
     116         [ #  # ]:          0 :         if (!remote)
     117                 :            :                 return ERR_PTR(-ENOMEM);
     118                 :          0 :         remote->handle = handle;
     119                 :          0 :         remote->kcov = kcov;
     120         [ #  # ]:          0 :         hash_add(kcov_remote_map, &remote->hnode, handle);
     121                 :          0 :         return remote;
     122                 :            : }
     123                 :            : 
     124                 :            : /* Must be called with kcov_remote_lock locked. */
     125                 :          0 : static struct kcov_remote_area *kcov_remote_area_get(unsigned int size)
     126                 :            : {
     127                 :          0 :         struct kcov_remote_area *area;
     128                 :          0 :         struct list_head *pos;
     129                 :            : 
     130                 :          0 :         kcov_debug("size = %u\n", size);
     131         [ #  # ]:          0 :         list_for_each(pos, &kcov_remote_areas) {
     132                 :          0 :                 area = list_entry(pos, struct kcov_remote_area, list);
     133         [ #  # ]:          0 :                 if (area->size == size) {
     134                 :          0 :                         list_del(&area->list);
     135                 :          0 :                         kcov_debug("rv = %px\n", area);
     136                 :          0 :                         return area;
     137                 :            :                 }
     138                 :            :         }
     139                 :            :         kcov_debug("rv = NULL\n");
     140                 :            :         return NULL;
     141                 :            : }
     142                 :            : 
     143                 :            : /* Must be called with kcov_remote_lock locked. */
     144                 :          0 : static void kcov_remote_area_put(struct kcov_remote_area *area,
     145                 :            :                                         unsigned int size)
     146                 :            : {
     147                 :          0 :         kcov_debug("area = %px, size = %u\n", area, size);
     148                 :          0 :         INIT_LIST_HEAD(&area->list);
     149                 :          0 :         area->size = size;
     150                 :          0 :         list_add(&area->list, &kcov_remote_areas);
     151                 :            : }
     152                 :            : 
     153                 :            : static notrace bool check_kcov_mode(enum kcov_mode needed_mode, struct task_struct *t)
     154                 :            : {
     155                 :            :         unsigned int mode;
     156                 :            : 
     157                 :            :         /*
     158                 :            :          * We are interested in code coverage as a function of a syscall inputs,
     159                 :            :          * so we ignore code executed in interrupts.
     160                 :            :          */
     161                 :            :         if (!in_task())
     162                 :            :                 return false;
     163                 :            :         mode = READ_ONCE(t->kcov_mode);
     164                 :            :         /*
     165                 :            :          * There is some code that runs in interrupts but for which
     166                 :            :          * in_interrupt() returns false (e.g. preempt_schedule_irq()).
     167                 :            :          * READ_ONCE()/barrier() effectively provides load-acquire wrt
     168                 :            :          * interrupts, there are paired barrier()/WRITE_ONCE() in
     169                 :            :          * kcov_start().
     170                 :            :          */
     171                 :            :         barrier();
     172                 :            :         return mode == needed_mode;
     173                 :            : }
     174                 :            : 
     175                 :     331544 : static notrace unsigned long canonicalize_ip(unsigned long ip)
     176                 :            : {
     177                 :            : #ifdef CONFIG_RANDOMIZE_BASE
     178                 :            :         ip -= kaslr_offset();
     179                 :            : #endif
     180                 :     331544 :         return ip;
     181                 :            : }
     182                 :            : 
     183                 :     661996 : static inline uint64_t mix_bits(uint64_t v) {
     184                 :     661996 :     v ^= (v >> 31);
     185                 :     661996 :     v *= 0x7fb5d329728ea185;
     186                 :     661996 :     v ^= (v >> 27);
     187                 :     661996 :     v *= 0x81dadef4bc2dd44d;
     188                 :     661996 :     v ^= (v >> 33);
     189                 :     661996 :     return v;
     190                 :            : }
     191                 :            : 
     192                 :            : /*
     193                 :            :  * Entry point from instrumented code.
     194                 :            :  * This is called once per basic-block/edge.
     195                 :            :  */
     196                 :     331544 : void notrace __sanitizer_cov_trace_pc(void)
     197                 :            : {
     198                 :     331544 :         struct task_struct *t;
     199                 :     331544 :         unsigned char *area;
     200                 :     331544 :         unsigned long ip = canonicalize_ip(_RET_IP_);
     201                 :     331544 :         unsigned int size;
     202                 :     331544 :         unsigned long addr;
     203         [ +  + ]:     331544 :         t = current;
     204                 :            :         /* Drifuzz */
     205         [ +  + ]:     331544 :         if (!_kcov_area) 
     206                 :            :                 return;
     207                 :     330998 :         area = _kcov_area;
     208                 :     330998 :         size = _kcov_size;
     209                 :            :         // if (!check_kcov_mode(KCOV_MODE_TRACE_PC, t))
     210                 :            :         //      return;
     211                 :            : 
     212                 :            :         // area = t->kcov_area;
     213                 :            :         // kcov_size = t->kcov_size;
     214                 :            :         /* The first 64-bit word is the number of subsequent PCs. */
     215                 :            :         // pos = READ_ONCE(area[0]) + 1;
     216                 :            :         // if (likely(pos < size)) {
     217                 :            :         //      area[pos] = ip;
     218                 :            :         //      WRITE_ONCE(area[0], pos);
     219                 :            :         // }
     220                 :     330998 :         addr = mix_bits(ip) % size;
     221                 :     330998 :         addr = (addr ^ (t->kcov_last >> 1)) % size;
     222                 :            : 
     223         [ +  + ]:     330998 :         if (likely(area[addr] != 0))
     224                 :     117227 :                 area[addr] --;
     225                 :            :         
     226                 :     330998 :         t->kcov_last = mix_bits(ip) % size;
     227                 :            :         
     228                 :            : }
     229                 :            : EXPORT_SYMBOL(__sanitizer_cov_trace_pc);
     230                 :            : 
     231                 :            : #ifdef CONFIG_KCOV_ENABLE_COMPARISONS
     232                 :            : static void notrace write_comp_data(u64 type, u64 arg1, u64 arg2, u64 ip)
     233                 :            : {
     234                 :            :         struct task_struct *t;
     235                 :            :         u64 *area;
     236                 :            :         u64 count, start_index, end_pos, max_pos;
     237                 :            : 
     238                 :            :         t = current;
     239                 :            :         if (!check_kcov_mode(KCOV_MODE_TRACE_CMP, t))
     240                 :            :                 return;
     241                 :            : 
     242                 :            :         ip = canonicalize_ip(ip);
     243                 :            : 
     244                 :            :         /*
     245                 :            :          * We write all comparison arguments and types as u64.
     246                 :            :          * The buffer was allocated for t->kcov_size unsigned longs.
     247                 :            :          */
     248                 :            :         area = (u64 *)t->kcov_area;
     249                 :            :         max_pos = t->kcov_size * sizeof(unsigned long);
     250                 :            : 
     251                 :            :         count = READ_ONCE(area[0]);
     252                 :            : 
     253                 :            :         /* Every record is KCOV_WORDS_PER_CMP 64-bit words. */
     254                 :            :         start_index = 1 + count * KCOV_WORDS_PER_CMP;
     255                 :            :         end_pos = (start_index + KCOV_WORDS_PER_CMP) * sizeof(u64);
     256                 :            :         if (likely(end_pos <= max_pos)) {
     257                 :            :                 area[start_index] = type;
     258                 :            :                 area[start_index + 1] = arg1;
     259                 :            :                 area[start_index + 2] = arg2;
     260                 :            :                 area[start_index + 3] = ip;
     261                 :            :                 WRITE_ONCE(area[0], count + 1);
     262                 :            :         }
     263                 :            : }
     264                 :            : 
     265                 :            : void notrace __sanitizer_cov_trace_cmp1(u8 arg1, u8 arg2)
     266                 :            : {
     267                 :            :         write_comp_data(KCOV_CMP_SIZE(0), arg1, arg2, _RET_IP_);
     268                 :            : }
     269                 :            : EXPORT_SYMBOL(__sanitizer_cov_trace_cmp1);
     270                 :            : 
     271                 :            : void notrace __sanitizer_cov_trace_cmp2(u16 arg1, u16 arg2)
     272                 :            : {
     273                 :            :         write_comp_data(KCOV_CMP_SIZE(1), arg1, arg2, _RET_IP_);
     274                 :            : }
     275                 :            : EXPORT_SYMBOL(__sanitizer_cov_trace_cmp2);
     276                 :            : 
     277                 :            : void notrace __sanitizer_cov_trace_cmp4(u32 arg1, u32 arg2)
     278                 :            : {
     279                 :            :         write_comp_data(KCOV_CMP_SIZE(2), arg1, arg2, _RET_IP_);
     280                 :            : }
     281                 :            : EXPORT_SYMBOL(__sanitizer_cov_trace_cmp4);
     282                 :            : 
     283                 :            : void notrace __sanitizer_cov_trace_cmp8(u64 arg1, u64 arg2)
     284                 :            : {
     285                 :            :         write_comp_data(KCOV_CMP_SIZE(3), arg1, arg2, _RET_IP_);
     286                 :            : }
     287                 :            : EXPORT_SYMBOL(__sanitizer_cov_trace_cmp8);
     288                 :            : 
     289                 :            : void notrace __sanitizer_cov_trace_const_cmp1(u8 arg1, u8 arg2)
     290                 :            : {
     291                 :            :         write_comp_data(KCOV_CMP_SIZE(0) | KCOV_CMP_CONST, arg1, arg2,
     292                 :            :                         _RET_IP_);
     293                 :            : }
     294                 :            : EXPORT_SYMBOL(__sanitizer_cov_trace_const_cmp1);
     295                 :            : 
     296                 :            : void notrace __sanitizer_cov_trace_const_cmp2(u16 arg1, u16 arg2)
     297                 :            : {
     298                 :            :         write_comp_data(KCOV_CMP_SIZE(1) | KCOV_CMP_CONST, arg1, arg2,
     299                 :            :                         _RET_IP_);
     300                 :            : }
     301                 :            : EXPORT_SYMBOL(__sanitizer_cov_trace_const_cmp2);
     302                 :            : 
     303                 :            : void notrace __sanitizer_cov_trace_const_cmp4(u32 arg1, u32 arg2)
     304                 :            : {
     305                 :            :         write_comp_data(KCOV_CMP_SIZE(2) | KCOV_CMP_CONST, arg1, arg2,
     306                 :            :                         _RET_IP_);
     307                 :            : }
     308                 :            : EXPORT_SYMBOL(__sanitizer_cov_trace_const_cmp4);
     309                 :            : 
     310                 :            : void notrace __sanitizer_cov_trace_const_cmp8(u64 arg1, u64 arg2)
     311                 :            : {
     312                 :            :         write_comp_data(KCOV_CMP_SIZE(3) | KCOV_CMP_CONST, arg1, arg2,
     313                 :            :                         _RET_IP_);
     314                 :            : }
     315                 :            : EXPORT_SYMBOL(__sanitizer_cov_trace_const_cmp8);
     316                 :            : 
     317                 :            : void notrace __sanitizer_cov_trace_switch(u64 val, u64 *cases)
     318                 :            : {
     319                 :            :         u64 i;
     320                 :            :         u64 count = cases[0];
     321                 :            :         u64 size = cases[1];
     322                 :            :         u64 type = KCOV_CMP_CONST;
     323                 :            : 
     324                 :            :         switch (size) {
     325                 :            :         case 8:
     326                 :            :                 type |= KCOV_CMP_SIZE(0);
     327                 :            :                 break;
     328                 :            :         case 16:
     329                 :            :                 type |= KCOV_CMP_SIZE(1);
     330                 :            :                 break;
     331                 :            :         case 32:
     332                 :            :                 type |= KCOV_CMP_SIZE(2);
     333                 :            :                 break;
     334                 :            :         case 64:
     335                 :            :                 type |= KCOV_CMP_SIZE(3);
     336                 :            :                 break;
     337                 :            :         default:
     338                 :            :                 return;
     339                 :            :         }
     340                 :            :         for (i = 0; i < count; i++)
     341                 :            :                 write_comp_data(type, cases[i + 2], val, _RET_IP_);
     342                 :            : }
     343                 :            : EXPORT_SYMBOL(__sanitizer_cov_trace_switch);
     344                 :            : #endif /* ifdef CONFIG_KCOV_ENABLE_COMPARISONS */
     345                 :            : 
     346                 :         13 : static void kcov_start(struct task_struct *t, unsigned int size,
     347                 :            :                         void *area, enum kcov_mode mode, int sequence)
     348                 :            : {
     349                 :         13 :         kcov_debug("t = %px, size = %u, area = %px\n", t, size, area);
     350                 :            :         /* Cache in task struct for performance. */
     351                 :         13 :         t->kcov_size = size;
     352                 :         13 :         t->kcov_area = area;
     353                 :            :         /* Driffuzz */
     354                 :         13 :         _kcov_size = size * sizeof(unsigned long);
     355                 :         13 :         _kcov_area = area;
     356                 :         13 :         _t = t;
     357                 :            :         /* See comment in check_kcov_mode(). */
     358                 :         13 :         barrier();
     359                 :         13 :         WRITE_ONCE(t->kcov_mode, mode);
     360                 :         13 :         t->kcov_sequence = sequence;
     361                 :          0 : }
     362                 :            : 
     363                 :      10281 : static void kcov_stop(struct task_struct *t)
     364                 :            : {
     365                 :      10281 :         WRITE_ONCE(t->kcov_mode, KCOV_MODE_DISABLED);
     366                 :      10281 :         barrier();
     367                 :            :         /* Driffuzz */
     368   [ -  -  +  -  :      10281 :         if (t ==_t) {
                   -  + ]
     369                 :         13 :                 _kcov_size = 0;
     370                 :         13 :                 _kcov_area = NULL;
     371                 :         13 :                 _t = NULL;
     372                 :            :         }
     373                 :      10281 :         t->kcov_size = 0;
     374                 :      10281 :         t->kcov_area = NULL;
     375                 :            : }
     376                 :            : 
     377                 :      10281 : static void kcov_task_reset(struct task_struct *t)
     378                 :            : {
     379                 :      10281 :         kcov_stop(t);
     380                 :      10281 :         t->kcov = NULL;
     381                 :      10281 :         t->kcov_sequence = 0;
     382                 :      10281 :         t->kcov_handle = 0;
     383                 :            : }
     384                 :            : 
     385                 :      10268 : void kcov_task_init(struct task_struct *t)
     386                 :            : {
     387                 :      10268 :         kcov_task_reset(t);
     388                 :      10268 :         t->kcov_handle = current->kcov_handle;
     389                 :      10268 : }
     390                 :            : 
     391                 :         13 : static void kcov_reset(struct kcov *kcov)
     392                 :            : {
     393                 :         13 :         kcov->t = NULL;
     394                 :         13 :         kcov->mode = KCOV_MODE_INIT;
     395                 :         13 :         kcov->remote = false;
     396                 :         13 :         kcov->remote_size = 0;
     397                 :         13 :         kcov->sequence++;
     398                 :         13 : }
     399                 :            : 
     400                 :          0 : static void kcov_remote_reset(struct kcov *kcov)
     401                 :            : {
     402                 :          0 :         int bkt;
     403                 :          0 :         struct kcov_remote *remote;
     404                 :          0 :         struct hlist_node *tmp;
     405                 :            : 
     406                 :          0 :         spin_lock(&kcov_remote_lock);
     407   [ #  #  #  #  :          0 :         hash_for_each_safe(kcov_remote_map, bkt, tmp, remote, hnode) {
             #  #  #  # ]
     408         [ #  # ]:          0 :                 if (remote->kcov != kcov)
     409                 :          0 :                         continue;
     410                 :          0 :                 kcov_debug("removing handle %llx\n", remote->handle);
     411         [ #  # ]:          0 :                 hash_del(&remote->hnode);
     412                 :          0 :                 kfree(remote);
     413                 :            :         }
     414                 :            :         /* Do reset before unlock to prevent races with kcov_remote_start(). */
     415                 :          0 :         kcov_reset(kcov);
     416                 :          0 :         spin_unlock(&kcov_remote_lock);
     417                 :          0 : }
     418                 :            : 
     419                 :         13 : static void kcov_disable(struct task_struct *t, struct kcov *kcov)
     420                 :            : {
     421                 :         13 :         kcov_task_reset(t);
     422         [ -  + ]:         13 :         if (kcov->remote)
     423                 :          0 :                 kcov_remote_reset(kcov);
     424                 :            :         else
     425                 :         13 :                 kcov_reset(kcov);
     426                 :         13 : }
     427                 :            : 
     428                 :         13 : static void kcov_get(struct kcov *kcov)
     429                 :            : {
     430                 :         13 :         refcount_inc(&kcov->refcount);
     431                 :            : }
     432                 :            : 
     433                 :         13 : static void kcov_put(struct kcov *kcov)
     434                 :            : {
     435         [ -  + ]:         13 :         if (refcount_dec_and_test(&kcov->refcount)) {
     436                 :          0 :                 kcov_remote_reset(kcov);
     437                 :          0 :                 vfree(kcov->area);
     438                 :          0 :                 kfree(kcov);
     439                 :            :         }
     440                 :         13 : }
     441                 :            : 
     442                 :       9334 : void kcov_task_exit(struct task_struct *t)
     443                 :            : {
     444                 :       9334 :         struct kcov *kcov;
     445                 :            : 
     446                 :       9334 :         kcov = t->kcov;
     447         [ -  + ]:       9334 :         if (kcov == NULL)
     448                 :            :                 return;
     449                 :            : 
     450                 :          0 :         spin_lock(&kcov->lock);
     451                 :          0 :         kcov_debug("t = %px, kcov->t = %px\n", t, kcov->t);
     452                 :            :         /*
     453                 :            :          * For KCOV_ENABLE devices we want to make sure that t->kcov->t == t,
     454                 :            :          * which comes down to:
     455                 :            :          *        WARN_ON(!kcov->remote && kcov->t != t);
     456                 :            :          *
     457                 :            :          * For KCOV_REMOTE_ENABLE devices, the exiting task is either:
     458                 :            :          * 2. A remote task between kcov_remote_start() and kcov_remote_stop().
     459                 :            :          *    In this case we should print a warning right away, since a task
     460                 :            :          *    shouldn't be exiting when it's in a kcov coverage collection
     461                 :            :          *    section. Here t points to the task that is collecting remote
     462                 :            :          *    coverage, and t->kcov->t points to the thread that created the
     463                 :            :          *    kcov device. Which means that to detect this case we need to
     464                 :            :          *    check that t != t->kcov->t, and this gives us the following:
     465                 :            :          *        WARN_ON(kcov->remote && kcov->t != t);
     466                 :            :          *
     467                 :            :          * 2. The task that created kcov exiting without calling KCOV_DISABLE,
     468                 :            :          *    and then again we can make sure that t->kcov->t == t:
     469                 :            :          *        WARN_ON(kcov->remote && kcov->t != t);
     470                 :            :          *
     471                 :            :          * By combining all three checks into one we get:
     472                 :            :          */
     473   [ #  #  #  # ]:          0 :         if (WARN_ON(kcov->t != t)) {
     474                 :          0 :                 spin_unlock(&kcov->lock);
     475                 :          0 :                 return;
     476                 :            :         }
     477                 :            :         /* Just to not leave dangling references behind. */
     478                 :          0 :         kcov_disable(t, kcov);
     479                 :          0 :         spin_unlock(&kcov->lock);
     480                 :          0 :         kcov_put(kcov);
     481                 :            : }
     482                 :            : #ifndef page_to_phys
     483                 :            : #define page_to_phys(page)      ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT)
     484                 :            : #endif
     485                 :            : void handle_submit_kcov_trace(uint64_t address, uint64_t size);
     486                 :         13 : static int kcov_mmap(struct file *filep, struct vm_area_struct *vma)
     487                 :            : {
     488                 :         13 :         int res = 0;
     489                 :         13 :         void *area;
     490                 :         13 :         struct kcov *kcov = vma->vm_file->private_data;
     491                 :         13 :         unsigned long size, off;
     492                 :         13 :         struct page *page;
     493                 :            : 
     494                 :         13 :         area = vmalloc_user(vma->vm_end - vma->vm_start);
     495         [ +  - ]:         13 :         if (!area)
     496                 :            :                 return -ENOMEM;
     497                 :            : 
     498                 :         13 :         spin_lock(&kcov->lock);
     499                 :         13 :         size = kcov->size * sizeof(unsigned long);
     500   [ +  -  +  - ]:         13 :         if (kcov->mode != KCOV_MODE_INIT || vma->vm_pgoff != 0 ||
     501         [ -  + ]:         13 :             vma->vm_end - vma->vm_start != size) {
     502                 :          0 :                 res = -EINVAL;
     503                 :          0 :                 goto exit;
     504                 :            :         }
     505         [ +  - ]:         13 :         if (!kcov->area) {
     506                 :         13 :                 kcov->area = area;
     507                 :         13 :                 vma->vm_flags |= VM_DONTEXPAND;
     508                 :         13 :                 spin_unlock(&kcov->lock);
     509         [ +  + ]:        234 :                 for (off = 0; off < size; off += PAGE_SIZE) {
     510                 :        208 :                         page = vmalloc_to_page(kcov->area + off);
     511                 :        208 :                         handle_submit_kcov_trace(page_to_phys(page), PAGE_SIZE);
     512         [ -  + ]:        208 :                         if (vm_insert_page(vma, vma->vm_start + off, page))
     513         [ #  # ]:          0 :                                 WARN_ONCE(1, "vm_insert_page() failed");
     514                 :            :                 }
     515                 :            :                 return 0;
     516                 :            :         }
     517                 :          0 : exit:
     518                 :          0 :         spin_unlock(&kcov->lock);
     519                 :          0 :         vfree(area);
     520                 :          0 :         return res;
     521                 :            : }
     522                 :            : 
     523                 :         13 : static int kcov_open(struct inode *inode, struct file *filep)
     524                 :            : {
     525                 :         13 :         struct kcov *kcov;
     526                 :            : 
     527                 :         13 :         kcov = kzalloc(sizeof(*kcov), GFP_KERNEL);
     528         [ +  - ]:         13 :         if (!kcov)
     529                 :            :                 return -ENOMEM;
     530                 :         13 :         kcov->mode = KCOV_MODE_DISABLED;
     531                 :         13 :         kcov->sequence = 1;
     532                 :         13 :         refcount_set(&kcov->refcount, 1);
     533                 :         13 :         spin_lock_init(&kcov->lock);
     534                 :         13 :         filep->private_data = kcov;
     535                 :         13 :         return nonseekable_open(inode, filep);
     536                 :            : }
     537                 :            : 
     538                 :          0 : static int kcov_close(struct inode *inode, struct file *filep)
     539                 :            : {
     540                 :          0 :         kcov_put(filep->private_data);
     541                 :          0 :         return 0;
     542                 :            : }
     543                 :            : 
     544                 :         13 : static int kcov_get_mode(unsigned long arg)
     545                 :            : {
     546                 :         13 :         if (arg == KCOV_TRACE_PC)
     547                 :            :                 return KCOV_MODE_TRACE_PC;
     548   [ #  #  #  # ]:          0 :         else if (arg == KCOV_TRACE_CMP)
     549                 :            : #ifdef CONFIG_KCOV_ENABLE_COMPARISONS
     550                 :            :                 return KCOV_MODE_TRACE_CMP;
     551                 :            : #else
     552                 :            :                 return -ENOTSUPP;
     553                 :            : #endif
     554                 :            :         else
     555                 :            :                 return -EINVAL;
     556                 :            : }
     557                 :            : 
     558                 :            : /*
     559                 :            :  * Fault in a lazily-faulted vmalloc area before it can be used by
     560                 :            :  * __santizer_cov_trace_pc(), to avoid recursion issues if any code on the
     561                 :            :  * vmalloc fault handling path is instrumented.
     562                 :            :  */
     563                 :         13 : static void kcov_fault_in_area(struct kcov *kcov)
     564                 :            : {
     565                 :         13 :         unsigned long stride = PAGE_SIZE / sizeof(unsigned long);
     566                 :         13 :         unsigned long *area = kcov->area;
     567                 :         13 :         unsigned long offset;
     568                 :            : 
     569         [ +  + ]:        221 :         for (offset = 0; offset < kcov->size; offset += stride)
     570                 :        208 :                 READ_ONCE(area[offset]);
     571                 :            : }
     572                 :            : 
     573                 :          0 : static inline bool kcov_check_handle(u64 handle, bool common_valid,
     574                 :            :                                 bool uncommon_valid, bool zero_valid)
     575                 :            : {
     576                 :          0 :         if (handle & ~(KCOV_SUBSYSTEM_MASK | KCOV_INSTANCE_MASK))
     577                 :            :                 return false;
     578   [ #  #  #  #  :          0 :         switch (handle & KCOV_SUBSYSTEM_MASK) {
                   #  # ]
     579                 :          0 :         case KCOV_SUBSYSTEM_COMMON:
     580                 :          0 :                 return (handle & KCOV_INSTANCE_MASK) ?
     581         [ #  # ]:          0 :                         common_valid : zero_valid;
     582                 :            :         case KCOV_SUBSYSTEM_USB:
     583                 :            :                 return uncommon_valid;
     584                 :          0 :         default:
     585                 :          0 :                 return false;
     586                 :            :         }
     587                 :            :         return false;
     588                 :            : }
     589                 :            : 
     590                 :         39 : static int kcov_ioctl_locked(struct kcov *kcov, unsigned int cmd,
     591                 :            :                              unsigned long arg)
     592                 :            : {
     593                 :         39 :         struct task_struct *t;
     594                 :         39 :         unsigned long size, unused;
     595                 :         39 :         int mode, i;
     596                 :         39 :         struct kcov_remote_arg *remote_arg;
     597                 :         39 :         struct kcov_remote *remote;
     598                 :            : 
     599   [ +  +  +  -  :         39 :         switch (cmd) {
                      - ]
     600                 :            :         case KCOV_INIT_TRACE:
     601                 :         13 :                 kcov_debug("KCOV_INIT_TRACE\n");
     602                 :            :                 /*
     603                 :            :                  * Enable kcov in trace mode and setup buffer size.
     604                 :            :                  * Must happen before anything else.
     605                 :            :                  */
     606         [ +  - ]:         13 :                 if (kcov->mode != KCOV_MODE_DISABLED)
     607                 :            :                         return -EBUSY;
     608                 :            :                 /*
     609                 :            :                  * Size must be at least 2 to hold current position and one PC.
     610                 :            :                  * Later we allocate size * sizeof(unsigned long) memory,
     611                 :            :                  * that must not overflow.
     612                 :            :                  */
     613                 :         13 :                 size = arg;
     614         [ +  - ]:         13 :                 if (size < 2 || size > INT_MAX / sizeof(unsigned long))
     615                 :            :                         return -EINVAL;
     616                 :         13 :                 kcov->size = size;
     617                 :         13 :                 kcov->mode = KCOV_MODE_INIT;
     618                 :         13 :                 return 0;
     619                 :            :         case KCOV_ENABLE:
     620                 :         13 :                 kcov_debug("KCOV_ENABLE\n");
     621                 :            :                 /*
     622                 :            :                  * Enable coverage for the current task.
     623                 :            :                  * At this point user must have been enabled trace mode,
     624                 :            :                  * and mmapped the file. Coverage collection is disabled only
     625                 :            :                  * at task exit or voluntary by KCOV_DISABLE. After that it can
     626                 :            :                  * be enabled for another task.
     627                 :            :                  */
     628   [ +  -  +  - ]:         13 :                 if (kcov->mode != KCOV_MODE_INIT || !kcov->area)
     629                 :            :                         return -EINVAL;
     630         [ +  - ]:         13 :                 t = current;
     631   [ +  -  +  - ]:         13 :                 if (kcov->t != NULL || t->kcov != NULL)
     632                 :            :                         return -EBUSY;
     633         [ +  - ]:         13 :                 mode = kcov_get_mode(arg);
     634                 :          0 :                 if (mode < 0)
     635                 :          0 :                         return mode;
     636                 :         13 :                 kcov_fault_in_area(kcov);
     637                 :         13 :                 kcov->mode = mode;
     638                 :         13 :                 kcov_start(t, kcov->size, kcov->area, kcov->mode,
     639                 :            :                                 kcov->sequence);
     640                 :         13 :                 t->kcov = kcov;
     641                 :         13 :                 kcov->t = t;
     642                 :            :                 /* Put either in kcov_task_exit() or in KCOV_DISABLE. */
     643                 :         13 :                 kcov_get(kcov);
     644                 :         13 :                 return 0;
     645                 :            :         case KCOV_DISABLE:
     646                 :         13 :                 kcov_debug("KCOV_DISABLE\n");
     647                 :            :                 /* Disable coverage for the current task. */
     648                 :         13 :                 unused = arg;
     649   [ +  -  +  - ]:         13 :                 if (unused != 0 || current->kcov != kcov)
     650                 :            :                         return -EINVAL;
     651         [ -  + ]:         13 :                 t = current;
     652   [ -  +  +  - ]:         13 :                 if (WARN_ON(kcov->t != t))
     653                 :            :                         return -EINVAL;
     654                 :         13 :                 kcov_disable(t, kcov);
     655                 :         13 :                 kcov_put(kcov);
     656                 :         13 :                 return 0;
     657                 :            :         case KCOV_REMOTE_ENABLE:
     658                 :          0 :                 kcov_debug("KCOV_REMOTE_ENABLE\n");
     659   [ #  #  #  # ]:          0 :                 if (kcov->mode != KCOV_MODE_INIT || !kcov->area)
     660                 :            :                         return -EINVAL;
     661         [ #  # ]:          0 :                 t = current;
     662   [ #  #  #  # ]:          0 :                 if (kcov->t != NULL || t->kcov != NULL)
     663                 :            :                         return -EBUSY;
     664                 :          0 :                 remote_arg = (struct kcov_remote_arg *)arg;
     665         [ #  # ]:          0 :                 mode = kcov_get_mode(remote_arg->trace_mode);
     666                 :          0 :                 if (mode < 0)
     667                 :          0 :                         return mode;
     668                 :          0 :                 if (remote_arg->area_size > LONG_MAX / sizeof(unsigned long))
     669                 :            :                         return -EINVAL;
     670                 :          0 :                 kcov->mode = mode;
     671                 :          0 :                 t->kcov = kcov;
     672                 :          0 :                 kcov->t = t;
     673                 :          0 :                 kcov->remote = true;
     674                 :          0 :                 kcov->remote_size = remote_arg->area_size;
     675                 :          0 :                 spin_lock(&kcov_remote_lock);
     676         [ #  # ]:          0 :                 for (i = 0; i < remote_arg->num_handles; i++) {
     677                 :          0 :                         kcov_debug("handle %llx\n", remote_arg->handles[i]);
     678         [ #  # ]:          0 :                         if (!kcov_check_handle(remote_arg->handles[i],
     679                 :            :                                                 false, true, false)) {
     680                 :          0 :                                 spin_unlock(&kcov_remote_lock);
     681                 :          0 :                                 kcov_disable(t, kcov);
     682                 :          0 :                                 return -EINVAL;
     683                 :            :                         }
     684                 :          0 :                         remote = kcov_remote_add(kcov, remote_arg->handles[i]);
     685         [ #  # ]:          0 :                         if (IS_ERR(remote)) {
     686                 :          0 :                                 spin_unlock(&kcov_remote_lock);
     687                 :          0 :                                 kcov_disable(t, kcov);
     688                 :          0 :                                 return PTR_ERR(remote);
     689                 :            :                         }
     690                 :            :                 }
     691         [ #  # ]:          0 :                 if (remote_arg->common_handle) {
     692                 :          0 :                         kcov_debug("common handle %llx\n",
     693                 :            :                                         remote_arg->common_handle);
     694         [ #  # ]:          0 :                         if (!kcov_check_handle(remote_arg->common_handle,
     695                 :            :                                                 true, false, false)) {
     696                 :          0 :                                 spin_unlock(&kcov_remote_lock);
     697                 :          0 :                                 kcov_disable(t, kcov);
     698                 :          0 :                                 return -EINVAL;
     699                 :            :                         }
     700                 :          0 :                         remote = kcov_remote_add(kcov,
     701                 :            :                                         remote_arg->common_handle);
     702         [ #  # ]:          0 :                         if (IS_ERR(remote)) {
     703                 :          0 :                                 spin_unlock(&kcov_remote_lock);
     704                 :          0 :                                 kcov_disable(t, kcov);
     705                 :          0 :                                 return PTR_ERR(remote);
     706                 :            :                         }
     707                 :          0 :                         t->kcov_handle = remote_arg->common_handle;
     708                 :            :                 }
     709                 :          0 :                 spin_unlock(&kcov_remote_lock);
     710                 :            :                 /* Put either in kcov_task_exit() or in KCOV_DISABLE. */
     711                 :          0 :                 kcov_get(kcov);
     712                 :          0 :                 return 0;
     713                 :            :         default:
     714                 :            :                 return -ENOTTY;
     715                 :            :         }
     716                 :            : }
     717                 :            : 
     718                 :         39 : static long kcov_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
     719                 :            : {
     720                 :         39 :         struct kcov *kcov;
     721                 :         39 :         int res;
     722                 :         39 :         struct kcov_remote_arg *remote_arg = NULL;
     723                 :         39 :         unsigned int remote_num_handles;
     724                 :         39 :         unsigned long remote_arg_size;
     725                 :            : 
     726         [ -  + ]:         39 :         if (cmd == KCOV_REMOTE_ENABLE) {
     727         [ #  # ]:          0 :                 if (get_user(remote_num_handles, (unsigned __user *)(arg +
     728                 :            :                                 offsetof(struct kcov_remote_arg, num_handles))))
     729                 :            :                         return -EFAULT;
     730         [ #  # ]:          0 :                 if (remote_num_handles > KCOV_REMOTE_MAX_HANDLES)
     731                 :            :                         return -EINVAL;
     732         [ #  # ]:          0 :                 remote_arg_size = struct_size(remote_arg, handles,
     733                 :            :                                         remote_num_handles);
     734                 :          0 :                 remote_arg = memdup_user((void __user *)arg, remote_arg_size);
     735         [ #  # ]:          0 :                 if (IS_ERR(remote_arg))
     736                 :          0 :                         return PTR_ERR(remote_arg);
     737         [ #  # ]:          0 :                 if (remote_arg->num_handles != remote_num_handles) {
     738                 :          0 :                         kfree(remote_arg);
     739                 :          0 :                         return -EINVAL;
     740                 :            :                 }
     741                 :            :                 arg = (unsigned long)remote_arg;
     742                 :            :         }
     743                 :            : 
     744                 :         39 :         kcov = filep->private_data;
     745                 :         39 :         spin_lock(&kcov->lock);
     746                 :         39 :         res = kcov_ioctl_locked(kcov, cmd, arg);
     747                 :         39 :         spin_unlock(&kcov->lock);
     748                 :            : 
     749                 :         39 :         kfree(remote_arg);
     750                 :            : 
     751                 :         39 :         return res;
     752                 :            : }
     753                 :            : 
     754                 :            : static const struct file_operations kcov_fops = {
     755                 :            :         .open           = kcov_open,
     756                 :            :         .unlocked_ioctl = kcov_ioctl,
     757                 :            :         .compat_ioctl   = kcov_ioctl,
     758                 :            :         .mmap           = kcov_mmap,
     759                 :            :         .release        = kcov_close,
     760                 :            : };
     761                 :            : 
     762                 :            : /*
     763                 :            :  * kcov_remote_start() and kcov_remote_stop() can be used to annotate a section
     764                 :            :  * of code in a kernel background thread to allow kcov to be used to collect
     765                 :            :  * coverage from that part of code.
     766                 :            :  *
     767                 :            :  * The handle argument of kcov_remote_start() identifies a code section that is
     768                 :            :  * used for coverage collection. A userspace process passes this handle to
     769                 :            :  * KCOV_REMOTE_ENABLE ioctl to make the used kcov device start collecting
     770                 :            :  * coverage for the code section identified by this handle.
     771                 :            :  *
     772                 :            :  * The usage of these annotations in the kernel code is different depending on
     773                 :            :  * the type of the kernel thread whose code is being annotated.
     774                 :            :  *
     775                 :            :  * For global kernel threads that are spawned in a limited number of instances
     776                 :            :  * (e.g. one USB hub_event() worker thread is spawned per USB HCD), each
     777                 :            :  * instance must be assigned a unique 4-byte instance id. The instance id is
     778                 :            :  * then combined with a 1-byte subsystem id to get a handle via
     779                 :            :  * kcov_remote_handle(subsystem_id, instance_id).
     780                 :            :  *
     781                 :            :  * For local kernel threads that are spawned from system calls handler when a
     782                 :            :  * user interacts with some kernel interface (e.g. vhost workers), a handle is
     783                 :            :  * passed from a userspace process as the common_handle field of the
     784                 :            :  * kcov_remote_arg struct (note, that the user must generate a handle by using
     785                 :            :  * kcov_remote_handle() with KCOV_SUBSYSTEM_COMMON as the subsystem id and an
     786                 :            :  * arbitrary 4-byte non-zero number as the instance id). This common handle
     787                 :            :  * then gets saved into the task_struct of the process that issued the
     788                 :            :  * KCOV_REMOTE_ENABLE ioctl. When this proccess issues system calls that spawn
     789                 :            :  * kernel threads, the common handle must be retrived via kcov_common_handle()
     790                 :            :  * and passed to the spawned threads via custom annotations. Those kernel
     791                 :            :  * threads must in turn be annotated with kcov_remote_start(common_handle) and
     792                 :            :  * kcov_remote_stop(). All of the threads that are spawned by the same process
     793                 :            :  * obtain the same handle, hence the name "common".
     794                 :            :  *
     795                 :            :  * See Documentation/dev-tools/kcov.rst for more details.
     796                 :            :  *
     797                 :            :  * Internally, this function looks up the kcov device associated with the
     798                 :            :  * provided handle, allocates an area for coverage collection, and saves the
     799                 :            :  * pointers to kcov and area into the current task_struct to allow coverage to
     800                 :            :  * be collected via __sanitizer_cov_trace_pc()
     801                 :            :  * In turns kcov_remote_stop() clears those pointers from task_struct to stop
     802                 :            :  * collecting coverage and copies all collected coverage into the kcov area.
     803                 :            :  */
     804                 :          0 : void kcov_remote_start(u64 handle)
     805                 :            : {
     806                 :          0 :         struct kcov_remote *remote;
     807                 :          0 :         void *area;
     808                 :          0 :         struct task_struct *t;
     809                 :          0 :         unsigned int size;
     810                 :          0 :         enum kcov_mode mode;
     811                 :          0 :         int sequence;
     812                 :            : 
     813   [ #  #  #  #  :          0 :         if (WARN_ON(!kcov_check_handle(handle, true, true, true)))
                   #  # ]
     814                 :            :                 return;
     815   [ #  #  #  # ]:          0 :         if (WARN_ON(!in_task()))
     816                 :            :                 return;
     817         [ #  # ]:          0 :         t = current;
     818                 :            :         /*
     819                 :            :          * Check that kcov_remote_start is not called twice
     820                 :            :          * nor called by user tasks (with enabled kcov).
     821                 :            :          */
     822   [ #  #  #  # ]:          0 :         if (WARN_ON(t->kcov))
     823                 :            :                 return;
     824                 :            : 
     825                 :          0 :         kcov_debug("handle = %llx\n", handle);
     826                 :            : 
     827                 :          0 :         spin_lock(&kcov_remote_lock);
     828         [ #  # ]:          0 :         remote = kcov_remote_find(handle);
     829         [ #  # ]:          0 :         if (!remote) {
     830                 :          0 :                 kcov_debug("no remote found");
     831                 :          0 :                 spin_unlock(&kcov_remote_lock);
     832                 :          0 :                 return;
     833                 :            :         }
     834                 :            :         /* Put in kcov_remote_stop(). */
     835                 :          0 :         kcov_get(remote->kcov);
     836                 :          0 :         t->kcov = remote->kcov;
     837                 :            :         /*
     838                 :            :          * Read kcov fields before unlock to prevent races with
     839                 :            :          * KCOV_DISABLE / kcov_remote_reset().
     840                 :            :          */
     841                 :          0 :         size = remote->kcov->remote_size;
     842                 :          0 :         mode = remote->kcov->mode;
     843                 :          0 :         sequence = remote->kcov->sequence;
     844                 :          0 :         area = kcov_remote_area_get(size);
     845                 :          0 :         spin_unlock(&kcov_remote_lock);
     846                 :            : 
     847         [ #  # ]:          0 :         if (!area) {
     848                 :          0 :                 area = vmalloc(size * sizeof(unsigned long));
     849         [ #  # ]:          0 :                 if (!area) {
     850                 :          0 :                         t->kcov = NULL;
     851                 :          0 :                         kcov_put(remote->kcov);
     852                 :          0 :                         return;
     853                 :            :                 }
     854                 :            :         }
     855                 :            :         /* Reset coverage size. */
     856                 :          0 :         *(u64 *)area = 0;
     857                 :            : 
     858                 :          0 :         kcov_debug("area = %px, size = %u", area, size);
     859                 :            : 
     860                 :          0 :         kcov_start(t, size, area, mode, sequence);
     861                 :            : 
     862                 :            : }
     863                 :            : EXPORT_SYMBOL(kcov_remote_start);
     864                 :            : 
     865                 :          0 : static void kcov_move_area(enum kcov_mode mode, void *dst_area,
     866                 :            :                                 unsigned int dst_area_size, void *src_area)
     867                 :            : {
     868                 :          0 :         u64 word_size = sizeof(unsigned long);
     869                 :          0 :         u64 count_size, entry_size_log;
     870                 :          0 :         u64 dst_len, src_len;
     871                 :          0 :         void *dst_entries, *src_entries;
     872                 :          0 :         u64 dst_occupied, dst_free, bytes_to_move, entries_moved;
     873                 :            : 
     874                 :          0 :         kcov_debug("%px %u <= %px %lu\n",
     875                 :            :                 dst_area, dst_area_size, src_area, *(unsigned long *)src_area);
     876                 :            : 
     877      [ #  #  # ]:          0 :         switch (mode) {
     878                 :            :         case KCOV_MODE_TRACE_PC:
     879                 :          0 :                 dst_len = READ_ONCE(*(unsigned long *)dst_area);
     880                 :          0 :                 src_len = *(unsigned long *)src_area;
     881                 :          0 :                 count_size = sizeof(unsigned long);
     882                 :          0 :                 entry_size_log = __ilog2_u64(sizeof(unsigned long));
     883                 :          0 :                 break;
     884                 :            :         case KCOV_MODE_TRACE_CMP:
     885                 :          0 :                 dst_len = READ_ONCE(*(u64 *)dst_area);
     886                 :          0 :                 src_len = *(u64 *)src_area;
     887                 :          0 :                 count_size = sizeof(u64);
     888                 :          0 :                 BUILD_BUG_ON(!is_power_of_2(KCOV_WORDS_PER_CMP));
     889                 :          0 :                 entry_size_log = __ilog2_u64(sizeof(u64) * KCOV_WORDS_PER_CMP);
     890                 :          0 :                 break;
     891                 :            :         default:
     892                 :          0 :                 WARN_ON(1);
     893                 :          0 :                 return;
     894                 :            :         }
     895                 :            : 
     896                 :            :         /* As arm can't divide u64 integers use log of entry size. */
     897         [ #  # ]:          0 :         if (dst_len > ((dst_area_size * word_size - count_size) >>
     898                 :            :                                 entry_size_log))
     899                 :            :                 return;
     900                 :          0 :         dst_occupied = count_size + (dst_len << entry_size_log);
     901                 :          0 :         dst_free = dst_area_size * word_size - dst_occupied;
     902                 :          0 :         bytes_to_move = min(dst_free, src_len << entry_size_log);
     903                 :          0 :         dst_entries = dst_area + dst_occupied;
     904                 :          0 :         src_entries = src_area + count_size;
     905                 :          0 :         memcpy(dst_entries, src_entries, bytes_to_move);
     906                 :          0 :         entries_moved = bytes_to_move >> entry_size_log;
     907                 :            : 
     908      [ #  #  # ]:          0 :         switch (mode) {
     909                 :          0 :         case KCOV_MODE_TRACE_PC:
     910                 :          0 :                 WRITE_ONCE(*(unsigned long *)dst_area, dst_len + entries_moved);
     911                 :          0 :                 break;
     912                 :          0 :         case KCOV_MODE_TRACE_CMP:
     913                 :          0 :                 WRITE_ONCE(*(u64 *)dst_area, dst_len + entries_moved);
     914                 :          0 :                 break;
     915                 :            :         default:
     916                 :            :                 break;
     917                 :            :         }
     918                 :            : }
     919                 :            : 
     920                 :            : /* See the comment before kcov_remote_start() for usage details. */
     921                 :          0 : void kcov_remote_stop(void)
     922                 :            : {
     923         [ #  # ]:          0 :         struct task_struct *t = current;
     924                 :          0 :         struct kcov *kcov = t->kcov;
     925                 :          0 :         void *area = t->kcov_area;
     926                 :          0 :         unsigned int size = t->kcov_size;
     927                 :          0 :         int sequence = t->kcov_sequence;
     928                 :            : 
     929         [ #  # ]:          0 :         if (!kcov) {
     930                 :            :                 kcov_debug("no kcov found\n");
     931                 :            :                 return;
     932                 :            :         }
     933                 :            : 
     934                 :          0 :         kcov_stop(t);
     935                 :          0 :         t->kcov = NULL;
     936                 :            : 
     937                 :          0 :         spin_lock(&kcov->lock);
     938                 :            :         /*
     939                 :            :          * KCOV_DISABLE could have been called between kcov_remote_start()
     940                 :            :          * and kcov_remote_stop(), hence the check.
     941                 :            :          */
     942                 :          0 :         kcov_debug("move if: %d == %d && %d\n",
     943                 :            :                 sequence, kcov->sequence, (int)kcov->remote);
     944   [ #  #  #  # ]:          0 :         if (sequence == kcov->sequence && kcov->remote)
     945                 :          0 :                 kcov_move_area(kcov->mode, kcov->area, kcov->size, area);
     946                 :          0 :         spin_unlock(&kcov->lock);
     947                 :            : 
     948                 :          0 :         spin_lock(&kcov_remote_lock);
     949                 :          0 :         kcov_remote_area_put(area, size);
     950                 :          0 :         spin_unlock(&kcov_remote_lock);
     951                 :            : 
     952                 :          0 :         kcov_put(kcov);
     953                 :            : }
     954                 :            : EXPORT_SYMBOL(kcov_remote_stop);
     955                 :            : 
     956                 :            : /* See the comment before kcov_remote_start() for usage details. */
     957                 :          0 : u64 kcov_common_handle(void)
     958                 :            : {
     959                 :          0 :         return current->kcov_handle;
     960                 :            : }
     961                 :            : EXPORT_SYMBOL(kcov_common_handle);
     962                 :            : 
     963                 :         13 : static int __init kcov_init(void)
     964                 :            : {
     965                 :            :         /*
     966                 :            :          * The kcov debugfs file won't ever get removed and thus,
     967                 :            :          * there is no need to protect it against removal races. The
     968                 :            :          * use of debugfs_create_file_unsafe() is actually safe here.
     969                 :            :          */
     970                 :         13 :         debugfs_create_file_unsafe("kcov", 0600, NULL, NULL, &kcov_fops);
     971                 :            : 
     972                 :         13 :         return 0;
     973                 :            : }
     974                 :            : 
     975                 :            : device_initcall(kcov_init);

Generated by: LCOV version 1.14