···506506 return randomize_range(mm->brk, range_end, 0) ? : mm->brk;507507}508508509509+/*510510+ * Called from fs/proc with a reference on @p to find the function511511+ * which called into schedule(). This needs to be done carefully512512+ * because the task might wake up and we might look at a stack513513+ * changing under us.514514+ */515515+unsigned long get_wchan(struct task_struct *p)516516+{517517+ unsigned long start, bottom, top, sp, fp, ip;518518+ int count = 0;519519+520520+ if (!p || p == current || p->state == TASK_RUNNING)521521+ return 0;522522+523523+ start = (unsigned long)task_stack_page(p);524524+ if (!start)525525+ return 0;526526+527527+ /*528528+ * Layout of the stack page:529529+ *530530+ * ----------- topmax = start + THREAD_SIZE - sizeof(unsigned long)531531+ * PADDING532532+ * ----------- top = topmax - TOP_OF_KERNEL_STACK_PADDING533533+ * stack534534+ * ----------- bottom = start + sizeof(thread_info)535535+ * thread_info536536+ * ----------- start537537+ *538538+ * The tasks stack pointer points at the location where the539539+ * framepointer is stored. The data on the stack is:540540+ * ... IP FP ... IP FP541541+ *542542+ * We need to read FP and IP, so we need to adjust the upper543543+ * bound by another unsigned long.544544+ */545545+ top = start + THREAD_SIZE - TOP_OF_KERNEL_STACK_PADDING;546546+ top -= 2 * sizeof(unsigned long);547547+ bottom = start + sizeof(struct thread_info);548548+549549+ sp = READ_ONCE(p->thread.sp);550550+ if (sp < bottom || sp > top)551551+ return 0;552552+553553+ fp = READ_ONCE(*(unsigned long *)sp);554554+ do {555555+ if (fp < bottom || fp > top)556556+ return 0;557557+ ip = READ_ONCE(*(unsigned long *)(fp + sizeof(unsigned long)));558558+ if (!in_sched_functions(ip))559559+ return ip;560560+ fp = READ_ONCE(*(unsigned long *)fp);561561+ } while (count++ < 16 && p->state != TASK_RUNNING);562562+ return 0;563563+}
-28
arch/x86/kernel/process_32.c
···324324325325 return prev_p;326326}327327-328328-#define top_esp (THREAD_SIZE - sizeof(unsigned long))329329-#define top_ebp (THREAD_SIZE - 2*sizeof(unsigned long))330330-331331-unsigned long get_wchan(struct task_struct *p)332332-{333333- unsigned long bp, sp, ip;334334- unsigned long stack_page;335335- int count = 0;336336- if (!p || p == current || p->state == TASK_RUNNING)337337- return 0;338338- stack_page = (unsigned long)task_stack_page(p);339339- sp = p->thread.sp;340340- if (!stack_page || sp < stack_page || sp > top_esp+stack_page)341341- return 0;342342- /* include/asm-i386/system.h:switch_to() pushes bp last. */343343- bp = *(unsigned long *) sp;344344- do {345345- if (bp < stack_page || bp > top_ebp+stack_page)346346- return 0;347347- ip = *(unsigned long *) (bp+4);348348- if (!in_sched_functions(ip))349349- return ip;350350- bp = *(unsigned long *) bp;351351- } while (count++ < 16);352352- return 0;353353-}354354-
-24
arch/x86/kernel/process_64.c
···499499}500500EXPORT_SYMBOL_GPL(set_personality_ia32);501501502502-unsigned long get_wchan(struct task_struct *p)503503-{504504- unsigned long stack;505505- u64 fp, ip;506506- int count = 0;507507-508508- if (!p || p == current || p->state == TASK_RUNNING)509509- return 0;510510- stack = (unsigned long)task_stack_page(p);511511- if (p->thread.sp < stack || p->thread.sp >= stack+THREAD_SIZE)512512- return 0;513513- fp = *(u64 *)(p->thread.sp);514514- do {515515- if (fp < (unsigned long)stack ||516516- fp >= (unsigned long)stack+THREAD_SIZE)517517- return 0;518518- ip = *(u64 *)(fp+8);519519- if (!in_sched_functions(ip))520520- return ip;521521- fp = *(u64 *)fp;522522- } while (count++ < 16);523523- return 0;524524-}525525-526502long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)527503{528504 int ret = 0;