diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2015-09-30 04:38:23 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2015-09-30 15:51:34 -0400 |
commit | 7ba78053aacb89998a052843e3c56983c31d57f0 (patch) | |
tree | de45a4545a91a08613ed1bc0fb4659241fba34d0 /arch | |
parent | eddd3826a1a0190e5235703d1e666affa4d13b96 (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.c | 55 | ||||
-rw-r--r-- | arch/x86/kernel/process_32.c | 28 | ||||
-rw-r--r-- | arch/x86/kernel/process_64.c | 56 |
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 | */ | ||
515 | unsigned 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 | |||
331 | unsigned 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 | } |
500 | EXPORT_SYMBOL_GPL(set_personality_ia32); | 500 | EXPORT_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 | */ | ||
508 | unsigned 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 | |||
558 | long do_arch_prctl(struct task_struct *task, int code, unsigned long addr) | 502 | long do_arch_prctl(struct task_struct *task, int code, unsigned long addr) |
559 | { | 503 | { |
560 | int ret = 0; | 504 | int ret = 0; |