diff options
-rw-r--r-- | arch/x86_64/kernel/time.c | 21 |
1 files changed, 8 insertions, 13 deletions
diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c index 560ed944dc0e..ea00915d393a 100644 --- a/arch/x86_64/kernel/time.c +++ b/arch/x86_64/kernel/time.c | |||
@@ -189,20 +189,15 @@ unsigned long profile_pc(struct pt_regs *regs) | |||
189 | { | 189 | { |
190 | unsigned long pc = instruction_pointer(regs); | 190 | unsigned long pc = instruction_pointer(regs); |
191 | 191 | ||
192 | /* Assume the lock function has either no stack frame or only a single | 192 | /* Assume the lock function has either no stack frame or a copy |
193 | word. This checks if the address on the stack looks like a kernel | 193 | of eflags from PUSHF |
194 | text address. | 194 | Eflags always has bits 22 and up cleared unlike kernel addresses. */ |
195 | There is a small window for false hits, but in that case the tick | ||
196 | is just accounted to the spinlock function. | ||
197 | Better would be to write these functions in assembler again | ||
198 | and check exactly. */ | ||
199 | if (!user_mode(regs) && in_lock_functions(pc)) { | 195 | if (!user_mode(regs) && in_lock_functions(pc)) { |
200 | char *v = *(char **)regs->rsp; | 196 | unsigned long *sp = (unsigned long *)regs->rsp; |
201 | if ((v >= _stext && v <= _etext) || | 197 | if (sp[0] >> 22) |
202 | (v >= _sinittext && v <= _einittext) || | 198 | return sp[0]; |
203 | (v >= (char *)MODULES_VADDR && v <= (char *)MODULES_END)) | 199 | if (sp[1] >> 22) |
204 | return (unsigned long)v; | 200 | return sp[1]; |
205 | return ((unsigned long *)regs->rsp)[1]; | ||
206 | } | 201 | } |
207 | return pc; | 202 | return pc; |
208 | } | 203 | } |