From: William Lee Irwin III The program counter calculation from pt_regs is the only portion of profile accounting that differs across various architectures. This is usually instruction_pointer(regs), but to handle the few arches where it isn't, introduce profile_pc(). Signed-off-by: Andrew Morton --- 25-akpm/arch/ia64/kernel/time.c | 6 +-- 25-akpm/arch/sh/kernel/time.c | 5 -- 25-akpm/arch/sparc/kernel/time.c | 36 +++++++++++--------- 25-akpm/arch/sparc64/kernel/time.c | 52 +++++++++++++---------------- 25-akpm/include/asm-alpha/ptrace.h | 1 25-akpm/include/asm-arm/ptrace.h | 1 25-akpm/include/asm-arm26/ptrace.h | 1 25-akpm/include/asm-cris/arch-v10/ptrace.h | 1 25-akpm/include/asm-h8300/ptrace.h | 1 25-akpm/include/asm-i386/ptrace.h | 1 25-akpm/include/asm-ia64/ptrace.h | 9 +++++ 25-akpm/include/asm-m68k/ptrace.h | 1 25-akpm/include/asm-m68knommu/ptrace.h | 1 25-akpm/include/asm-mips/ptrace.h | 1 25-akpm/include/asm-parisc/ptrace.h | 1 25-akpm/include/asm-ppc/ptrace.h | 1 25-akpm/include/asm-ppc64/ptrace.h | 1 25-akpm/include/asm-s390/ptrace.h | 1 25-akpm/include/asm-sh/ptrace.h | 9 +++++ 25-akpm/include/asm-sh64/ptrace.h | 1 25-akpm/include/asm-sparc/ptrace.h | 1 25-akpm/include/asm-sparc64/ptrace.h | 1 25-akpm/include/asm-v850/ptrace.h | 1 25-akpm/include/asm-x86_64/ptrace.h | 1 24 files changed, 84 insertions(+), 51 deletions(-) diff -puN arch/ia64/kernel/time.c~profile_pc arch/ia64/kernel/time.c --- 25/arch/ia64/kernel/time.c~profile_pc Mon Aug 2 16:02:24 2004 +++ 25-akpm/arch/ia64/kernel/time.c Mon Aug 2 16:02:24 2004 @@ -195,7 +195,7 @@ EXPORT_SYMBOL(do_gettimeofday); static inline void ia64_do_profile (struct pt_regs * regs) { - unsigned long ip, slot; + unsigned long ip; profile_hook(regs); @@ -205,12 +205,10 @@ ia64_do_profile (struct pt_regs * regs) if (!prof_buffer) return; - ip = instruction_pointer(regs); /* Conserve space in histogram by encoding slot bits in address * bits 2 and 3 rather than bits 0 and 1. */ - slot = ip & 3; - ip = (ip & ~3UL) + 4*slot; + ip = profile_pc(regs); /* * Only measure the CPUs specified by /proc/irq/prof_cpu_mask. diff -puN arch/sh/kernel/time.c~profile_pc arch/sh/kernel/time.c --- 25/arch/sh/kernel/time.c~profile_pc Mon Aug 2 16:02:24 2004 +++ 25-akpm/arch/sh/kernel/time.c Mon Aug 2 16:02:24 2004 @@ -262,9 +262,6 @@ static inline void sh_do_profile(unsigne if (!prof_buffer || !current->pid) return; - if (pc >= 0xa0000000UL && pc < 0xc0000000UL) - pc -= 0x20000000; - pc -= (unsigned long)&_stext; pc >>= prof_shift; @@ -288,7 +285,7 @@ static inline void do_timer_interrupt(in do_timer(regs); if (!user_mode(regs)) - sh_do_profile(regs->pc); + sh_do_profile(profile_pc(regs)); #ifdef CONFIG_HEARTBEAT if (sh_mv.mv_heartbeat != NULL) diff -puN arch/sparc64/kernel/time.c~profile_pc arch/sparc64/kernel/time.c --- 25/arch/sparc64/kernel/time.c~profile_pc Mon Aug 2 16:02:24 2004 +++ 25-akpm/arch/sparc64/kernel/time.c Mon Aug 2 16:02:24 2004 @@ -441,11 +441,31 @@ static __inline__ void timer_check_rtc(v } } -void sparc64_do_profile(struct pt_regs *regs) +unsigned long profile_pc(struct pt_regs *regs) { + extern int rwlock_impl_begin, rwlock_impl_end; + extern int atomic_impl_begin, atomic_impl_end; + extern int __memcpy_begin, __memcpy_end; + extern int __bzero_begin, __bzero_end; + extern int __bitops_begin, __bitops_end; unsigned long pc = regs->tpc; - unsigned long o7 = regs->u_regs[UREG_RETPC]; + if ((pc >= (unsigned long) &atomic_impl_begin && + pc < (unsigned long) &atomic_impl_end) || + (pc >= (unsigned long) &rwlock_impl_begin && + pc < (unsigned long) &rwlock_impl_end) || + (pc >= (unsigned long) &__memcpy_begin && + pc < (unsigned long) &__memcpy_end) || + (pc >= (unsigned long) &__bzero_begin && + pc < (unsigned long) &__bzero_end) || + (pc >= (unsigned long) &__bitops_begin && + pc < (unsigned long) &__bitops_end)) + pc = regs->u_regs[UREG_RETPC]; /* o7/ + return pc; +} + +void sparc64_do_profile(struct pt_regs *regs) +{ profile_hook(regs); if (user_mode(regs)) @@ -454,32 +474,8 @@ void sparc64_do_profile(struct pt_regs * if (!prof_buffer) return; - { - extern int rwlock_impl_begin, rwlock_impl_end; - extern int atomic_impl_begin, atomic_impl_end; - extern int __memcpy_begin, __memcpy_end; - extern int __bzero_begin, __bzero_end; - extern int __bitops_begin, __bitops_end; - - if ((pc >= (unsigned long) &atomic_impl_begin && - pc < (unsigned long) &atomic_impl_end) || - (pc >= (unsigned long) &rwlock_impl_begin && - pc < (unsigned long) &rwlock_impl_end) || - (pc >= (unsigned long) &__memcpy_begin && - pc < (unsigned long) &__memcpy_end) || - (pc >= (unsigned long) &__bzero_begin && - pc < (unsigned long) &__bzero_end) || - (pc >= (unsigned long) &__bitops_begin && - pc < (unsigned long) &__bitops_end)) - pc = o7; - - pc -= (unsigned long) _stext; - pc >>= prof_shift; - - if(pc >= prof_len) - pc = prof_len - 1; - atomic_inc((atomic_t *)&prof_buffer[pc]); - } + pc = (profile_pc(regs) - (unsigned long)_stext) >> prof_shift; + atomic_inc((atomic_t *)&prof_buffer[min(pc, prof_len-1)]); } static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) diff -puN arch/sparc/kernel/time.c~profile_pc arch/sparc/kernel/time.c --- 25/arch/sparc/kernel/time.c~profile_pc Mon Aug 2 16:02:24 2004 +++ 25-akpm/arch/sparc/kernel/time.c Mon Aug 2 16:02:24 2004 @@ -79,6 +79,26 @@ struct intersil *intersil_clock; #endif +unsigned long profile_pc(struct pt_regs *regs) +{ + extern int __copy_user_begin, __copy_user_end; + extern int __atomic_begin, __atomic_end; + extern int __bzero_begin, __bzero_end; + extern int __bitops_begin, __bitops_end; + unsigned long pc = regs->pc; + + if ((pc >= (unsigned long) &__copy_user_begin && + pc < (unsigned long) &__copy_user_end) || + (pc >= (unsigned long) &__atomic_begin && + pc < (unsigned long) &__atomic_end) || + (pc >= (unsigned long) &__bzero_begin && + pc < (unsigned long) &__bzero_end) || + (pc >= (unsigned long) &__bitops_begin && + pc < (unsigned long) &__bitops_end)) + pc = regs->u_regs[UREG_RETPC]; + return pc; +} + static spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED; /* 32-bit Sparc specific profiling function. */ @@ -86,20 +106,6 @@ void sparc_do_profile(unsigned long pc, { if(prof_buffer && current->pid) { extern int _stext; - extern int __copy_user_begin, __copy_user_end; - extern int __atomic_begin, __atomic_end; - extern int __bzero_begin, __bzero_end; - extern int __bitops_begin, __bitops_end; - - if ((pc >= (unsigned long) &__copy_user_begin && - pc < (unsigned long) &__copy_user_end) || - (pc >= (unsigned long) &__atomic_begin && - pc < (unsigned long) &__atomic_end) || - (pc >= (unsigned long) &__bzero_begin && - pc < (unsigned long) &__bzero_end) || - (pc >= (unsigned long) &__bitops_begin && - pc < (unsigned long) &__bitops_end)) - pc = o7; pc -= (unsigned long) &_stext; pc >>= prof_shift; @@ -130,7 +136,7 @@ irqreturn_t timer_interrupt(int irq, voi #ifndef CONFIG_SMP if(!user_mode(regs)) - sparc_do_profile(regs->pc, regs->u_regs[UREG_RETPC]); + sparc_do_profile(profile_pc(regs)); #endif /* Protect counter clear so that do_gettimeoffset works */ diff -puN include/asm-alpha/ptrace.h~profile_pc include/asm-alpha/ptrace.h --- 25/include/asm-alpha/ptrace.h~profile_pc Mon Aug 2 16:02:24 2004 +++ 25-akpm/include/asm-alpha/ptrace.h Mon Aug 2 16:02:24 2004 @@ -69,6 +69,7 @@ struct switch_stack { #ifdef __KERNEL__ #define user_mode(regs) (((regs)->ps & 8) != 0) #define instruction_pointer(regs) ((regs)->pc) +#define profile_pc(regs) instruction_pointer(regs) extern void show_regs(struct pt_regs *); #define alpha_task_regs(task) \ diff -puN include/asm-arm26/ptrace.h~profile_pc include/asm-arm26/ptrace.h --- 25/include/asm-arm26/ptrace.h~profile_pc Mon Aug 2 16:02:24 2004 +++ 25-akpm/include/asm-arm26/ptrace.h Mon Aug 2 16:02:24 2004 @@ -30,6 +30,7 @@ #define pc_pointer(v) ((v) & ~PCMASK) /* convert v to pc type address */ #define instruction_pointer(regs) (pc_pointer((regs)->ARM_pc)) /* get pc */ +#define profile_pc(regs) instruction_pointer(regs) /* this struct defines the way the registers are stored on the stack during a system call. */ diff -puN include/asm-arm/ptrace.h~profile_pc include/asm-arm/ptrace.h --- 25/include/asm-arm/ptrace.h~profile_pc Mon Aug 2 16:02:24 2004 +++ 25-akpm/include/asm-arm/ptrace.h Mon Aug 2 16:02:24 2004 @@ -130,6 +130,7 @@ static inline int valid_user_regs(struct #define instruction_pointer(regs) \ (pc_pointer((regs)->ARM_pc)) +#define profile_pc(regs) instruction_pointer(regs) #ifdef __KERNEL__ extern void show_regs(struct pt_regs *); diff -puN include/asm-cris/arch-v10/ptrace.h~profile_pc include/asm-cris/arch-v10/ptrace.h --- 25/include/asm-cris/arch-v10/ptrace.h~profile_pc Mon Aug 2 16:02:24 2004 +++ 25-akpm/include/asm-cris/arch-v10/ptrace.h Mon Aug 2 16:02:24 2004 @@ -109,6 +109,7 @@ struct switch_stack { /* bit 8 is user-mode flag */ #define user_mode(regs) (((regs)->dccr & 0x100) != 0) #define instruction_pointer(regs) ((regs)->irp) +#define profile_pc(regs) instruction_pointer(regs) extern void show_regs(struct pt_regs *); #endif diff -puN include/asm-h8300/ptrace.h~profile_pc include/asm-h8300/ptrace.h --- 25/include/asm-h8300/ptrace.h~profile_pc Mon Aug 2 16:02:24 2004 +++ 25-akpm/include/asm-h8300/ptrace.h Mon Aug 2 16:02:24 2004 @@ -57,6 +57,7 @@ struct pt_regs { #define user_mode(regs) (!((regs)->ccr & PS_S)) #define instruction_pointer(regs) ((regs)->pc) +#define profile_pc(regs) instruction_pointer(regs) extern void show_regs(struct pt_regs *); #endif /* __KERNEL__ */ #endif /* __ASSEMBLY__ */ diff -puN include/asm-i386/ptrace.h~profile_pc include/asm-i386/ptrace.h --- 25/include/asm-i386/ptrace.h~profile_pc Mon Aug 2 16:02:24 2004 +++ 25-akpm/include/asm-i386/ptrace.h Mon Aug 2 16:02:24 2004 @@ -57,6 +57,7 @@ struct pt_regs { #ifdef __KERNEL__ #define user_mode(regs) ((VM_MASK & (regs)->eflags) || (3 & (regs)->xcs)) #define instruction_pointer(regs) ((regs)->eip) +#define profile_pc(regs) instruction_pointer(regs) #endif #endif diff -puN include/asm-ia64/ptrace.h~profile_pc include/asm-ia64/ptrace.h --- 25/include/asm-ia64/ptrace.h~profile_pc Mon Aug 2 16:02:24 2004 +++ 25-akpm/include/asm-ia64/ptrace.h Mon Aug 2 16:02:24 2004 @@ -229,6 +229,15 @@ struct switch_stack { * the canonical representation by adding to instruction pointer. */ # define instruction_pointer(regs) ((regs)->cr_iip + ia64_psr(regs)->ri) +/* Conserve space in histogram by encoding slot bits in address + * bits 2 and 3 rather than bits 0 and 1. + */ +static inline unsigned long profile_pc(struct pt_regs *regs) +{ + unsigned long ip = instruction_pointer(regs); + return (ip & ~3UL) + ((ip & 3UL) << 2); +} + /* given a pointer to a task_struct, return the user's pt_regs */ # define ia64_task_regs(t) (((struct pt_regs *) ((char *) (t) + IA64_STK_OFFSET)) - 1) # define ia64_psr(regs) ((struct ia64_psr *) &(regs)->cr_ipsr) diff -puN include/asm-m68knommu/ptrace.h~profile_pc include/asm-m68knommu/ptrace.h --- 25/include/asm-m68knommu/ptrace.h~profile_pc Mon Aug 2 16:02:24 2004 +++ 25-akpm/include/asm-m68knommu/ptrace.h Mon Aug 2 16:02:24 2004 @@ -84,6 +84,7 @@ struct switch_stack { #define user_mode(regs) (!((regs)->sr & PS_S)) #define instruction_pointer(regs) ((regs)->pc) +#define profile_pc(regs) instruction_pointer(regs) extern void show_regs(struct pt_regs *); #endif /* __KERNEL__ */ #endif /* __ASSEMBLY__ */ diff -puN include/asm-m68k/ptrace.h~profile_pc include/asm-m68k/ptrace.h --- 25/include/asm-m68k/ptrace.h~profile_pc Mon Aug 2 16:02:24 2004 +++ 25-akpm/include/asm-m68k/ptrace.h Mon Aug 2 16:02:24 2004 @@ -73,6 +73,7 @@ struct switch_stack { #define user_mode(regs) (!((regs)->sr & PS_S)) #define instruction_pointer(regs) ((regs)->pc) +#define profile_pc(regs) instruction_pointer(regs) extern void show_regs(struct pt_regs *); #endif /* __KERNEL__ */ #endif /* __ASSEMBLY__ */ diff -puN include/asm-mips/ptrace.h~profile_pc include/asm-mips/ptrace.h --- 25/include/asm-mips/ptrace.h~profile_pc Mon Aug 2 16:02:24 2004 +++ 25-akpm/include/asm-mips/ptrace.h Mon Aug 2 16:02:24 2004 @@ -66,6 +66,7 @@ struct pt_regs { #define user_mode(regs) (((regs)->cp0_status & KU_MASK) == KU_USER) #define instruction_pointer(regs) ((regs)->cp0_epc) +#define profile_pc(regs) instruction_pointer(regs) extern void show_regs(struct pt_regs *); diff -puN include/asm-parisc/ptrace.h~profile_pc include/asm-parisc/ptrace.h --- 25/include/asm-parisc/ptrace.h~profile_pc Mon Aug 2 16:02:24 2004 +++ 25-akpm/include/asm-parisc/ptrace.h Mon Aug 2 16:02:24 2004 @@ -48,6 +48,7 @@ struct pt_regs { /* XXX should we use iaoq[1] or iaoq[0] ? */ #define user_mode(regs) (((regs)->iaoq[0] & 3) ? 1 : 0) #define instruction_pointer(regs) ((regs)->iaoq[0] & ~3) +#define profile_pc(regs) instruction_pointer(regs) extern void show_regs(struct pt_regs *); #endif diff -puN include/asm-ppc64/ptrace.h~profile_pc include/asm-ppc64/ptrace.h --- 25/include/asm-ppc64/ptrace.h~profile_pc Mon Aug 2 16:02:24 2004 +++ 25-akpm/include/asm-ppc64/ptrace.h Mon Aug 2 16:02:24 2004 @@ -69,6 +69,7 @@ struct pt_regs32 { #define __SIGNAL_FRAMESIZE32 64 #define instruction_pointer(regs) ((regs)->nip) +#define profile_pc(regs) instruction_pointer(regs) #define user_mode(regs) ((((regs)->msr) >> MSR_PR_LG) & 0x1) #define force_successful_syscall_return() \ diff -puN include/asm-ppc/ptrace.h~profile_pc include/asm-ppc/ptrace.h --- 25/include/asm-ppc/ptrace.h~profile_pc Mon Aug 2 16:02:24 2004 +++ 25-akpm/include/asm-ppc/ptrace.h Mon Aug 2 16:02:24 2004 @@ -47,6 +47,7 @@ struct pt_regs { #ifndef __ASSEMBLY__ #define instruction_pointer(regs) ((regs)->nip) +#define profile_pc(regs) instruction_pointer(regs) #define user_mode(regs) (((regs)->msr & MSR_PR) != 0) #define force_successful_syscall_return() \ diff -puN include/asm-s390/ptrace.h~profile_pc include/asm-s390/ptrace.h --- 25/include/asm-s390/ptrace.h~profile_pc Mon Aug 2 16:02:24 2004 +++ 25-akpm/include/asm-s390/ptrace.h Mon Aug 2 16:02:24 2004 @@ -466,6 +466,7 @@ struct user_regs_struct #ifdef __KERNEL__ #define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0) #define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN) +#define profile_pc(regs) instruction_pointer(regs) extern void show_regs(struct pt_regs * regs); #endif diff -puN include/asm-sh64/ptrace.h~profile_pc include/asm-sh64/ptrace.h --- 25/include/asm-sh64/ptrace.h~profile_pc Mon Aug 2 16:02:24 2004 +++ 25-akpm/include/asm-sh64/ptrace.h Mon Aug 2 16:02:24 2004 @@ -28,6 +28,7 @@ struct pt_regs { #ifdef __KERNEL__ #define user_mode(regs) (((regs)->sr & 0x40000000)==0) #define instruction_pointer(regs) ((regs)->pc) +#define profile_pc(regs) instruction_pointer(regs) extern void show_regs(struct pt_regs *); #endif diff -puN include/asm-sh/ptrace.h~profile_pc include/asm-sh/ptrace.h --- 25/include/asm-sh/ptrace.h~profile_pc Mon Aug 2 16:02:24 2004 +++ 25-akpm/include/asm-sh/ptrace.h Mon Aug 2 16:02:24 2004 @@ -90,6 +90,15 @@ struct pt_dspregs { #define user_mode(regs) (((regs)->sr & 0x40000000)==0) #define instruction_pointer(regs) ((regs)->pc) extern void show_regs(struct pt_regs *); + +static inline unsigned long profile_pc(struct pt_regs *regs) +{ + unsigned long pc = instruction_pointer(regs); + + if (pc >= 0xa0000000UL && pc < 0xc0000000UL) + pc -= 0x20000000; + return pc; +} #endif #endif /* __ASM_SH_PTRACE_H */ diff -puN include/asm-sparc64/ptrace.h~profile_pc include/asm-sparc64/ptrace.h --- 25/include/asm-sparc64/ptrace.h~profile_pc Mon Aug 2 16:02:24 2004 +++ 25-akpm/include/asm-sparc64/ptrace.h Mon Aug 2 16:02:24 2004 @@ -98,6 +98,7 @@ struct sparc_trapf { set_thread_flag(TIF_SYSCALL_SUCCESS) #define user_mode(regs) (!((regs)->tstate & TSTATE_PRIV)) #define instruction_pointer(regs) ((regs)->tpc) +unsigned long profile_pc(struct pt_regs *); extern void show_regs(struct pt_regs *); #endif diff -puN include/asm-sparc/ptrace.h~profile_pc include/asm-sparc/ptrace.h --- 25/include/asm-sparc/ptrace.h~profile_pc Mon Aug 2 16:02:24 2004 +++ 25-akpm/include/asm-sparc/ptrace.h Mon Aug 2 16:02:24 2004 @@ -62,6 +62,7 @@ struct sparc_stackf { #ifdef __KERNEL__ #define user_mode(regs) (!((regs)->psr & PSR_PS)) #define instruction_pointer(regs) ((regs)->pc) +unsigned long profile_pc(struct pt_regs *); extern void show_regs(struct pt_regs *); #endif diff -puN include/asm-v850/ptrace.h~profile_pc include/asm-v850/ptrace.h --- 25/include/asm-v850/ptrace.h~profile_pc Mon Aug 2 16:02:24 2004 +++ 25-akpm/include/asm-v850/ptrace.h Mon Aug 2 16:02:24 2004 @@ -76,6 +76,7 @@ struct pt_regs #define instruction_pointer(regs) ((regs)->pc) +#define profile_pc(regs) instruction_pointer(regs) #define user_mode(regs) (!(regs)->kernel_mode) /* When a struct pt_regs is used to save user state for a system call in diff -puN include/asm-x86_64/ptrace.h~profile_pc include/asm-x86_64/ptrace.h --- 25/include/asm-x86_64/ptrace.h~profile_pc Mon Aug 2 16:02:24 2004 +++ 25-akpm/include/asm-x86_64/ptrace.h Mon Aug 2 16:02:24 2004 @@ -83,6 +83,7 @@ struct pt_regs { #if defined(__KERNEL__) && !defined(__ASSEMBLY__) #define user_mode(regs) (!!((regs)->cs & 3)) #define instruction_pointer(regs) ((regs)->rip) +#define profile_pc(regs) instruction_pointer(regs) void signal_fault(struct pt_regs *regs, void __user *frame, char *where); enum { _