aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2015-09-30 04:38:23 -0400
committerThomas Gleixner <tglx@linutronix.de>2015-09-30 15:51:34 -0400
commit7ba78053aacb89998a052843e3c56983c31d57f0 (patch)
treede45a4545a91a08613ed1bc0fb4659241fba34d0 /arch
parenteddd3826a1a0190e5235703d1e666affa4d13b96 (diff)
x86/process: Unify 32bit and 64bit implementations of get_wchan()
The stack layout and the functionality is identical. Use the 64bit version for all of x86. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Borislav Petkov <bp@alien8.de> Reviewed-by: Dmitry Vyukov <dvyukov@google.com> Cc: Andrey Ryabinin <ryabinin.a.a@gmail.com> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Andrey Konovalov <andreyknvl@google.com> Cc: Kostya Serebryany <kcc@google.com> Cc: Alexander Potapenko <glider@google.com> Cc: kasan-dev <kasan-dev@googlegroups.com> Cc: Denys Vlasenko <dvlasenk@redhat.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: Sasha Levin <sasha.levin@oracle.com> Cc: Wolfram Gloger <wmglo@dent.med.uni-muenchen.de> Link: http://lkml.kernel.org/r/20150930083302.779694618@linutronix.de Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/kernel/process.c55
-rw-r--r--arch/x86/kernel/process_32.c28
-rw-r--r--arch/x86/kernel/process_64.c56
3 files changed, 55 insertions, 84 deletions
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 6d0e62ae8516..39e585a554b7 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -506,3 +506,58 @@ unsigned long arch_randomize_brk(struct mm_struct *mm)
506 return randomize_range(mm->brk, range_end, 0) ? : mm->brk; 506 return randomize_range(mm->brk, range_end, 0) ? : mm->brk;
507} 507}
508 508
509/*
510 * Called from fs/proc with a reference on @p to find the function
511 * which called into schedule(). This needs to be done carefully
512 * because the task might wake up and we might look at a stack
513 * changing under us.
514 */
515unsigned long get_wchan(struct task_struct *p)
516{
517 unsigned long start, bottom, top, sp, fp, ip;
518 int count = 0;
519
520 if (!p || p == current || p->state == TASK_RUNNING)
521 return 0;
522
523 start = (unsigned long)task_stack_page(p);
524 if (!start)
525 return 0;
526
527 /*
528 * Layout of the stack page:
529 *
530 * ----------- topmax = start + THREAD_SIZE - sizeof(unsigned long)
531 * PADDING
532 * ----------- top = topmax - TOP_OF_KERNEL_STACK_PADDING
533 * stack
534 * ----------- bottom = start + sizeof(thread_info)
535 * thread_info
536 * ----------- start
537 *
538 * The tasks stack pointer points at the location where the
539 * framepointer is stored. The data on the stack is:
540 * ... IP FP ... IP FP
541 *
542 * We need to read FP and IP, so we need to adjust the upper
543 * bound by another unsigned long.
544 */
545 top = start + THREAD_SIZE - TOP_OF_KERNEL_STACK_PADDING;
546 top -= 2 * sizeof(unsigned long);
547 bottom = start + sizeof(struct thread_info);
548
549 sp = READ_ONCE(p->thread.sp);
550 if (sp < bottom || sp > top)
551 return 0;
552
553 fp = READ_ONCE(*(unsigned long *)sp);
554 do {
555 if (fp < bottom || fp > top)
556 return 0;
557 ip = READ_ONCE(*(unsigned long *)(fp + sizeof(unsigned long)));
558 if (!in_sched_functions(ip))
559 return ip;
560 fp = READ_ONCE(*(unsigned long *)fp);
561 } while (count++ < 16 && p->state != TASK_RUNNING);
562 return 0;
563}
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index c13df2c735f8..737527b40e5b 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -324,31 +324,3 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
324 324
325 return prev_p; 325 return prev_p;
326} 326}
327
328#define top_esp (THREAD_SIZE - sizeof(unsigned long))
329#define top_ebp (THREAD_SIZE - 2*sizeof(unsigned long))
330
331unsigned long get_wchan(struct task_struct *p)
332{
333 unsigned long bp, sp, ip;
334 unsigned long stack_page;
335 int count = 0;
336 if (!p || p == current || p->state == TASK_RUNNING)
337 return 0;
338 stack_page = (unsigned long)task_stack_page(p);
339 sp = p->thread.sp;
340 if (!stack_page || sp < stack_page || sp > top_esp+stack_page)
341 return 0;
342 /* include/asm-i386/system.h:switch_to() pushes bp last. */
343 bp = *(unsigned long *) sp;
344 do {
345 if (bp < stack_page || bp > top_ebp+stack_page)
346 return 0;
347 ip = *(unsigned long *) (bp+4);
348 if (!in_sched_functions(ip))
349 return ip;
350 bp = *(unsigned long *) bp;
351 } while (count++ < 16);
352 return 0;
353}
354
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index f1fd0889e8af..b35921a670b2 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -499,62 +499,6 @@ void set_personality_ia32(bool x32)
499} 499}
500EXPORT_SYMBOL_GPL(set_personality_ia32); 500EXPORT_SYMBOL_GPL(set_personality_ia32);
501 501
502/*
503 * Called from fs/proc with a reference on @p to find the function
504 * which called into schedule(). This needs to be done carefully
505 * because the task might wake up and we might look at a stack
506 * changing under us.
507 */
508unsigned long get_wchan(struct task_struct *p)
509{
510 unsigned long start, bottom, top, sp, fp, ip;
511 int count = 0;
512
513 if (!p || p == current || p->state == TASK_RUNNING)
514 return 0;
515
516 start = (unsigned long)task_stack_page(p);
517 if (!start)
518 return 0;
519
520 /*
521 * Layout of the stack page:
522 *
523 * ----------- topmax = start + THREAD_SIZE - sizeof(unsigned long)
524 * PADDING
525 * ----------- top = topmax - TOP_OF_KERNEL_STACK_PADDING
526 * stack
527 * ----------- bottom = start + sizeof(thread_info)
528 * thread_info
529 * ----------- start
530 *
531 * The tasks stack pointer points at the location where the
532 * framepointer is stored. The data on the stack is:
533 * ... IP FP ... IP FP
534 *
535 * We need to read FP and IP, so we need to adjust the upper
536 * bound by another unsigned long.
537 */
538 top = start + THREAD_SIZE - TOP_OF_KERNEL_STACK_PADDING;
539 top -= 2 * sizeof(unsigned long);
540 bottom = start + sizeof(struct thread_info);
541
542 sp = READ_ONCE(p->thread.sp);
543 if (sp < bottom || sp > top)
544 return 0;
545
546 fp = READ_ONCE(*(unsigned long *)sp);
547 do {
548 if (fp < bottom || fp > top)
549 return 0;
550 ip = READ_ONCE(*(unsigned long *)(fp + sizeof(unsigned long)));
551 if (!in_sched_functions(ip))
552 return ip;
553 fp = READ_ONCE(*(unsigned long *)fp);
554 } while (count++ < 16 && p->state != TASK_RUNNING);
555 return 0;
556}
557
558long do_arch_prctl(struct task_struct *task, int code, unsigned long addr) 502long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
559{ 503{
560 int ret = 0; 504 int ret = 0;