]> git.hungrycats.org Git - linux/commitdiff
[PATCH] x86_64: fix profile_pc
authorAndi Kleen <ak@muc.de>
Wed, 6 Oct 2004 01:13:42 +0000 (18:13 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Wed, 6 Oct 2004 01:13:42 +0000 (18:13 -0700)
This fixes profile_pc to work properly on x86-64 and not crash.

It does now a simple backtrace to the caller of the spin lock without
requiring a frame pointer for this.

Frame pointer support has been dropped because it never worked.

There is still a small race window, but the only way to avoid it would be
to rewrite kernel/spinlock.c in assembler again.  The race will account a
profile tick the the parent of the spinlock caller.

Signed-off-by: Andi Kleen <ak@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
arch/x86_64/kernel/time.c
include/asm-x86_64/ptrace.h

index e7b11d23c4cd03785a6de32f97a782cd69f07708..9b0d22d53cfee194ef0ed72f3f9c25069f3d145e 100644 (file)
@@ -32,6 +32,7 @@
 #include <asm/timex.h>
 #include <asm/proto.h>
 #include <asm/hpet.h>
+#include <asm/sections.h>
 #include <linux/cpufreq.h>
 #ifdef CONFIG_X86_LOCAL_APIC
 #include <asm/apic.h>
@@ -179,17 +180,27 @@ int do_settimeofday(struct timespec *tv)
 
 EXPORT_SYMBOL(do_settimeofday);
 
-#if defined(CONFIG_SMP) && defined(CONFIG_FRAME_POINTER)
 unsigned long profile_pc(struct pt_regs *regs)
 {
        unsigned long pc = instruction_pointer(regs);
 
-       if (in_lock_functions(pc))
-               return *(unsigned long *)regs->rbp;
+       /* Assume the lock function has either no stack frame or only a single word.
+          This checks if the address on the stack looks like a kernel text address.
+          There is a small window for false hits, but in that case the tick
+          is just accounted to the spinlock function.
+          Better would be to write these functions in assembler again
+          and check exactly. */
+       if (in_lock_functions(pc)) {
+               char *v = *(char **)regs->rsp;
+               if ((v >= _stext && v <= _etext) ||
+                       (v >= _sinittext && v <= _einittext) ||
+                       (v >= (char *)MODULES_VADDR  && v <= (char *)MODULES_END))
+                       return (unsigned long)v;
+               return ((unsigned long *)regs->rsp)[1];
+       }
        return pc;
 }
 EXPORT_SYMBOL(profile_pc);
-#endif
 
 /*
  * In order to set the CMOS clock precisely, set_rtc_mmss has to be called 500
index 86489292359e1ab32f16c935e62429f6bcd807b1..c7865cfedc1fd7b44943ef30a423a27eb1b6f515 100644 (file)
@@ -83,11 +83,7 @@ struct pt_regs {
 #if defined(__KERNEL__) && !defined(__ASSEMBLY__) 
 #define user_mode(regs) (!!((regs)->cs & 3))
 #define instruction_pointer(regs) ((regs)->rip)
-#if defined(CONFIG_SMP) && defined(CONFIG_FRAME_POINTER)
 extern unsigned long profile_pc(struct pt_regs *regs);
-#else
-#define profile_pc(regs) instruction_pointer(regs)
-#endif
 void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
 
 enum {