LCOV - code coverage report
Current view: top level - arch/x86/kernel - stacktrace.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 8 46 17.4 %
Date: 2022-03-28 15:32:58 Functions: 1 4 25.0 %
Branches: 6 52 11.5 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Stack trace management functions
       3                 :            :  *
       4                 :            :  *  Copyright (C) 2006-2009 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
       5                 :            :  */
       6                 :            : #include <linux/sched.h>
       7                 :            : #include <linux/sched/debug.h>
       8                 :            : #include <linux/sched/task_stack.h>
       9                 :            : #include <linux/stacktrace.h>
      10                 :            : #include <linux/export.h>
      11                 :            : #include <linux/uaccess.h>
      12                 :            : #include <asm/stacktrace.h>
      13                 :            : #include <asm/unwind.h>
      14                 :            : 
      15                 :     121475 : void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie,
      16                 :            :                      struct task_struct *task, struct pt_regs *regs)
      17                 :            : {
      18                 :     121475 :         struct unwind_state state;
      19                 :     121475 :         unsigned long addr;
      20                 :            : 
      21   [ -  +  -  - ]:     121475 :         if (regs && !consume_entry(cookie, regs->ip, false))
      22                 :          0 :                 return;
      23                 :            : 
      24   [ -  +  +  - ]:     971800 :         for (unwind_start(&state, task, regs, NULL); !unwind_done(&state);
      25                 :     728850 :              unwind_next_frame(&state)) {
      26                 :     850325 :                 addr = unwind_get_return_address(&state);
      27   [ +  -  +  + ]:     850325 :                 if (!addr || !consume_entry(cookie, addr, false))
      28                 :            :                         break;
      29                 :            :         }
      30                 :            : }
      31                 :            : 
      32                 :            : /*
      33                 :            :  * This function returns an error if it detects any unreliable features of the
      34                 :            :  * stack.  Otherwise it guarantees that the stack trace is reliable.
      35                 :            :  *
      36                 :            :  * If the task is not 'current', the caller *must* ensure the task is inactive.
      37                 :            :  */
      38                 :          0 : int arch_stack_walk_reliable(stack_trace_consume_fn consume_entry,
      39                 :            :                              void *cookie, struct task_struct *task)
      40                 :            : {
      41                 :          0 :         struct unwind_state state;
      42                 :          0 :         struct pt_regs *regs;
      43                 :          0 :         unsigned long addr;
      44                 :            : 
      45   [ #  #  #  # ]:          0 :         for (unwind_start(&state, task, NULL, NULL);
      46   [ #  #  #  # ]:          0 :              !unwind_done(&state) && !unwind_error(&state);
      47                 :          0 :              unwind_next_frame(&state)) {
      48                 :            : 
      49         [ #  # ]:          0 :                 regs = unwind_get_entry_regs(&state, NULL);
      50         [ #  # ]:          0 :                 if (regs) {
      51                 :            :                         /* Success path for user tasks */
      52         [ #  # ]:          0 :                         if (user_mode(regs))
      53                 :            :                                 return 0;
      54                 :            : 
      55                 :            :                         /*
      56                 :            :                          * Kernel mode registers on the stack indicate an
      57                 :            :                          * in-kernel interrupt or exception (e.g., preemption
      58                 :            :                          * or a page fault), which can make frame pointers
      59                 :            :                          * unreliable.
      60                 :            :                          */
      61                 :            : 
      62                 :            :                         if (IS_ENABLED(CONFIG_FRAME_POINTER))
      63                 :            :                                 return -EINVAL;
      64                 :            :                 }
      65                 :            : 
      66                 :          0 :                 addr = unwind_get_return_address(&state);
      67                 :            : 
      68                 :            :                 /*
      69                 :            :                  * A NULL or invalid return address probably means there's some
      70                 :            :                  * generated code which __kernel_text_address() doesn't know
      71                 :            :                  * about.
      72                 :            :                  */
      73         [ #  # ]:          0 :                 if (!addr)
      74                 :            :                         return -EINVAL;
      75                 :            : 
      76         [ #  # ]:          0 :                 if (!consume_entry(cookie, addr, false))
      77                 :            :                         return -EINVAL;
      78                 :            :         }
      79                 :            : 
      80                 :            :         /* Check for stack corruption */
      81         [ #  # ]:          0 :         if (unwind_error(&state))
      82                 :            :                 return -EINVAL;
      83                 :            : 
      84                 :            :         /* Success path for non-user tasks, i.e. kthreads and idle tasks */
      85         [ #  # ]:          0 :         if (!(task->flags & (PF_KTHREAD | PF_IDLE)))
      86                 :          0 :                 return -EINVAL;
      87                 :            : 
      88                 :            :         return 0;
      89                 :            : }
      90                 :            : 
      91                 :            : /* Userspace stacktrace - based on kernel/trace/trace_sysprof.c */
      92                 :            : 
      93                 :            : struct stack_frame_user {
      94                 :            :         const void __user       *next_fp;
      95                 :            :         unsigned long           ret_addr;
      96                 :            : };
      97                 :            : 
      98                 :            : static int
      99                 :          0 : copy_stack_frame(const void __user *fp, struct stack_frame_user *frame)
     100                 :            : {
     101                 :          0 :         int ret;
     102                 :            : 
     103   [ #  #  #  #  :          0 :         if (__range_not_ok(fp, sizeof(*frame), TASK_SIZE))
                   #  # ]
     104                 :            :                 return 0;
     105                 :            : 
     106                 :          0 :         ret = 1;
     107                 :          0 :         pagefault_disable();
     108         [ #  # ]:          0 :         if (__copy_from_user_inatomic(frame, fp, sizeof(*frame)))
     109                 :          0 :                 ret = 0;
     110                 :          0 :         pagefault_enable();
     111                 :            : 
     112                 :          0 :         return ret;
     113                 :            : }
     114                 :            : 
     115                 :          0 : void arch_stack_walk_user(stack_trace_consume_fn consume_entry, void *cookie,
     116                 :            :                           const struct pt_regs *regs)
     117                 :            : {
     118                 :          0 :         const void __user *fp = (const void __user *)regs->bp;
     119                 :            : 
     120         [ #  # ]:          0 :         if (!consume_entry(cookie, regs->ip, false))
     121                 :            :                 return;
     122                 :            : 
     123                 :          0 :         while (1) {
     124                 :          0 :                 struct stack_frame_user frame;
     125                 :            : 
     126                 :          0 :                 frame.next_fp = NULL;
     127                 :          0 :                 frame.ret_addr = 0;
     128         [ #  # ]:          0 :                 if (!copy_stack_frame(fp, &frame))
     129                 :            :                         break;
     130         [ #  # ]:          0 :                 if ((unsigned long)fp < regs->sp)
     131                 :            :                         break;
     132         [ #  # ]:          0 :                 if (!frame.ret_addr)
     133                 :            :                         break;
     134         [ #  # ]:          0 :                 if (!consume_entry(cookie, frame.ret_addr, false))
     135                 :            :                         break;
     136                 :          0 :                 fp = frame.next_fp;
     137                 :            :         }
     138                 :            : }
     139                 :            : 

Generated by: LCOV version 1.14