Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Stack trace management functions
0003  *
0004  *  Copyright (C) 2006-2009 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
0005  */
0006 #include <linux/sched.h>
0007 #include <linux/sched/debug.h>
0008 #include <linux/sched/task_stack.h>
0009 #include <linux/stacktrace.h>
0010 #include <linux/export.h>
0011 #include <linux/uaccess.h>
0012 #include <asm/stacktrace.h>
0013 #include <asm/unwind.h>
0014 
0015 void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie,
0016              struct task_struct *task, struct pt_regs *regs)
0017 {
0018     struct unwind_state state;
0019     unsigned long addr;
0020 
0021     if (regs && !consume_entry(cookie, regs->ip))
0022         return;
0023 
0024     for (unwind_start(&state, task, regs, NULL); !unwind_done(&state);
0025          unwind_next_frame(&state)) {
0026         addr = unwind_get_return_address(&state);
0027         if (!addr || !consume_entry(cookie, addr))
0028             break;
0029     }
0030 }
0031 
0032 int arch_stack_walk_reliable(stack_trace_consume_fn consume_entry,
0033                  void *cookie, struct task_struct *task)
0034 {
0035     struct unwind_state state;
0036     struct pt_regs *regs;
0037     unsigned long addr;
0038 
0039     for (unwind_start(&state, task, NULL, NULL);
0040          !unwind_done(&state) && !unwind_error(&state);
0041          unwind_next_frame(&state)) {
0042 
0043         regs = unwind_get_entry_regs(&state, NULL);
0044         if (regs) {
0045             /* Success path for user tasks */
0046             if (user_mode(regs))
0047                 return 0;
0048 
0049             /*
0050              * Kernel mode registers on the stack indicate an
0051              * in-kernel interrupt or exception (e.g., preemption
0052              * or a page fault), which can make frame pointers
0053              * unreliable.
0054              */
0055             if (IS_ENABLED(CONFIG_FRAME_POINTER))
0056                 return -EINVAL;
0057         }
0058 
0059         addr = unwind_get_return_address(&state);
0060 
0061         /*
0062          * A NULL or invalid return address probably means there's some
0063          * generated code which __kernel_text_address() doesn't know
0064          * about.
0065          */
0066         if (!addr)
0067             return -EINVAL;
0068 
0069         if (!consume_entry(cookie, addr))
0070             return -EINVAL;
0071     }
0072 
0073     /* Check for stack corruption */
0074     if (unwind_error(&state))
0075         return -EINVAL;
0076 
0077     return 0;
0078 }
0079 
0080 /* Userspace stacktrace - based on kernel/trace/trace_sysprof.c */
0081 
0082 struct stack_frame_user {
0083     const void __user   *next_fp;
0084     unsigned long       ret_addr;
0085 };
0086 
0087 static int
0088 copy_stack_frame(const struct stack_frame_user __user *fp,
0089          struct stack_frame_user *frame)
0090 {
0091     int ret;
0092 
0093     if (!__access_ok(fp, sizeof(*frame)))
0094         return 0;
0095 
0096     ret = 1;
0097     pagefault_disable();
0098     if (__get_user(frame->next_fp, &fp->next_fp) ||
0099         __get_user(frame->ret_addr, &fp->ret_addr))
0100         ret = 0;
0101     pagefault_enable();
0102 
0103     return ret;
0104 }
0105 
0106 void arch_stack_walk_user(stack_trace_consume_fn consume_entry, void *cookie,
0107               const struct pt_regs *regs)
0108 {
0109     const void __user *fp = (const void __user *)regs->bp;
0110 
0111     if (!consume_entry(cookie, regs->ip))
0112         return;
0113 
0114     while (1) {
0115         struct stack_frame_user frame;
0116 
0117         frame.next_fp = NULL;
0118         frame.ret_addr = 0;
0119         if (!copy_stack_frame(fp, &frame))
0120             break;
0121         if ((unsigned long)fp < regs->sp)
0122             break;
0123         if (!frame.ret_addr)
0124             break;
0125         if (!consume_entry(cookie, frame.ret_addr))
0126             break;
0127         fp = frame.next_fp;
0128     }
0129 }
0130