Commit b2123b2a authored by Andi Kleen's avatar Andi Kleen Committed by Linus Torvalds

[PATCH] x86_64: fix profile_pc

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: default avatarAndi Kleen <ak@suse.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 523e7f28
......@@ -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
......
......@@ -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 {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment