sh: Trivial trace_mark() instrumentation for core events.
This implements a few trace points across events that are deemed interesting. This implements a number of trace points: - The page fault handler / TLB miss - IPC calls - Kernel thread creation The original LTTng patch had the slow-path instrumented, which fails to account for the vast majority of events. In general placing this in the fast-path is not a huge performance hit, as we don't take page faults for kernel addresses. The other bits of interest are some of the other trap handlers, as well as the syscall entry/exit (which is better off being handled through the tracehook API). Most of the other trap handlers are corner cases where alternate means of notification exist, so there is little value in placing extra trace points in these locations. Based on top of the points provided both by the LTTng instrumentation patch as well as the patch shipping in the ST-Linux tree, albeit in a stripped down form. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
This commit is contained in:
Родитель
8f2baee280
Коммит
3d58695edb
|
@ -169,6 +169,7 @@ __asm__(".align 5\n"
|
||||||
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
|
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
|
||||||
{
|
{
|
||||||
struct pt_regs regs;
|
struct pt_regs regs;
|
||||||
|
int pid;
|
||||||
|
|
||||||
memset(®s, 0, sizeof(regs));
|
memset(®s, 0, sizeof(regs));
|
||||||
regs.regs[4] = (unsigned long)arg;
|
regs.regs[4] = (unsigned long)arg;
|
||||||
|
@ -178,8 +179,12 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
|
||||||
regs.sr = (1 << 30);
|
regs.sr = (1 << 30);
|
||||||
|
|
||||||
/* Ok, create the new process.. */
|
/* Ok, create the new process.. */
|
||||||
return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
|
pid = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
|
||||||
®s, 0, NULL, NULL);
|
®s, 0, NULL, NULL);
|
||||||
|
|
||||||
|
trace_mark(kernel_arch_kthread_create, "pid %d fn %p", pid, fn);
|
||||||
|
|
||||||
|
return pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -396,6 +396,7 @@ ATTRIB_NORET void kernel_thread_helper(void *arg, int (*fn)(void *))
|
||||||
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
|
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
|
||||||
{
|
{
|
||||||
struct pt_regs regs;
|
struct pt_regs regs;
|
||||||
|
int pid;
|
||||||
|
|
||||||
memset(®s, 0, sizeof(regs));
|
memset(®s, 0, sizeof(regs));
|
||||||
regs.regs[2] = (unsigned long)arg;
|
regs.regs[2] = (unsigned long)arg;
|
||||||
|
@ -404,8 +405,13 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
|
||||||
regs.pc = (unsigned long)kernel_thread_helper;
|
regs.pc = (unsigned long)kernel_thread_helper;
|
||||||
regs.sr = (1 << 30);
|
regs.sr = (1 << 30);
|
||||||
|
|
||||||
return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
|
/* Ok, create the new process.. */
|
||||||
®s, 0, NULL, NULL);
|
pid = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
|
||||||
|
®s, 0, NULL, NULL);
|
||||||
|
|
||||||
|
trace_mark(kernel_arch_kthread_create, "pid %d fn %p", pid, fn);
|
||||||
|
|
||||||
|
return pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -171,6 +171,8 @@ asmlinkage int sys_ipc(uint call, int first, int second,
|
||||||
version = call >> 16; /* hack for backward compatibility */
|
version = call >> 16; /* hack for backward compatibility */
|
||||||
call &= 0xffff;
|
call &= 0xffff;
|
||||||
|
|
||||||
|
trace_mark(kernel_arch_ipc_call, "call %u first %d", call, first);
|
||||||
|
|
||||||
if (call <= SEMTIMEDOP)
|
if (call <= SEMTIMEDOP)
|
||||||
switch (call) {
|
switch (call) {
|
||||||
case SEMOP:
|
case SEMOP:
|
||||||
|
|
|
@ -15,28 +15,13 @@
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/hardirq.h>
|
#include <linux/hardirq.h>
|
||||||
#include <linux/kprobes.h>
|
#include <linux/kprobes.h>
|
||||||
|
#include <linux/marker.h>
|
||||||
#include <asm/io_trapped.h>
|
#include <asm/io_trapped.h>
|
||||||
#include <asm/system.h>
|
#include <asm/system.h>
|
||||||
#include <asm/mmu_context.h>
|
#include <asm/mmu_context.h>
|
||||||
#include <asm/tlbflush.h>
|
#include <asm/tlbflush.h>
|
||||||
#include <asm/kgdb.h>
|
#include <asm/kgdb.h>
|
||||||
|
|
||||||
static inline int notify_page_fault(struct pt_regs *regs, int trap)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
#ifdef CONFIG_KPROBES
|
|
||||||
if (!user_mode(regs)) {
|
|
||||||
preempt_disable();
|
|
||||||
if (kprobe_running() && kprobe_fault_handler(regs, trap))
|
|
||||||
ret = 1;
|
|
||||||
preempt_enable();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This routine handles page faults. It determines the address,
|
* This routine handles page faults. It determines the address,
|
||||||
* and the problem, and then passes it off to one of the appropriate
|
* and the problem, and then passes it off to one of the appropriate
|
||||||
|
@ -261,6 +246,25 @@ do_sigbus:
|
||||||
goto no_context;
|
goto no_context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int notify_page_fault(struct pt_regs *regs, int trap)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
trace_mark(kernel_arch_trap_entry, "trap_id %d ip #p%ld",
|
||||||
|
trap >> 5, instruction_pointer(regs));
|
||||||
|
|
||||||
|
#ifdef CONFIG_KPROBES
|
||||||
|
if (!user_mode(regs)) {
|
||||||
|
preempt_disable();
|
||||||
|
if (kprobe_running() && kprobe_fault_handler(regs, trap))
|
||||||
|
ret = 1;
|
||||||
|
preempt_enable();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_SH_STORE_QUEUES
|
#ifdef CONFIG_SH_STORE_QUEUES
|
||||||
/*
|
/*
|
||||||
* This is a special case for the SH-4 store queues, as pages for this
|
* This is a special case for the SH-4 store queues, as pages for this
|
||||||
|
@ -284,15 +288,18 @@ asmlinkage int __kprobes __do_page_fault(struct pt_regs *regs,
|
||||||
pmd_t *pmd;
|
pmd_t *pmd;
|
||||||
pte_t *pte;
|
pte_t *pte;
|
||||||
pte_t entry;
|
pte_t entry;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
if (notify_page_fault(regs, lookup_exception_vector()))
|
if (notify_page_fault(regs, lookup_exception_vector()))
|
||||||
return 0;
|
goto out;
|
||||||
|
|
||||||
#ifdef CONFIG_SH_KGDB
|
#ifdef CONFIG_SH_KGDB
|
||||||
if (kgdb_nofault && kgdb_bus_err_hook)
|
if (kgdb_nofault && kgdb_bus_err_hook)
|
||||||
kgdb_bus_err_hook();
|
kgdb_bus_err_hook();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
ret = 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We don't take page faults for P1, P2, and parts of P4, these
|
* We don't take page faults for P1, P2, and parts of P4, these
|
||||||
* are always mapped, whether it be due to legacy behaviour in
|
* are always mapped, whether it be due to legacy behaviour in
|
||||||
|
@ -302,24 +309,23 @@ asmlinkage int __kprobes __do_page_fault(struct pt_regs *regs,
|
||||||
pgd = pgd_offset_k(address);
|
pgd = pgd_offset_k(address);
|
||||||
} else {
|
} else {
|
||||||
if (unlikely(address >= TASK_SIZE || !current->mm))
|
if (unlikely(address >= TASK_SIZE || !current->mm))
|
||||||
return 1;
|
goto out;
|
||||||
|
|
||||||
pgd = pgd_offset(current->mm, address);
|
pgd = pgd_offset(current->mm, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
pud = pud_offset(pgd, address);
|
pud = pud_offset(pgd, address);
|
||||||
if (pud_none_or_clear_bad(pud))
|
if (pud_none_or_clear_bad(pud))
|
||||||
return 1;
|
goto out;
|
||||||
pmd = pmd_offset(pud, address);
|
pmd = pmd_offset(pud, address);
|
||||||
if (pmd_none_or_clear_bad(pmd))
|
if (pmd_none_or_clear_bad(pmd))
|
||||||
return 1;
|
goto out;
|
||||||
|
|
||||||
pte = pte_offset_kernel(pmd, address);
|
pte = pte_offset_kernel(pmd, address);
|
||||||
entry = *pte;
|
entry = *pte;
|
||||||
if (unlikely(pte_none(entry) || pte_not_present(entry)))
|
if (unlikely(pte_none(entry) || pte_not_present(entry)))
|
||||||
return 1;
|
goto out;
|
||||||
if (unlikely(writeaccess && !pte_write(entry)))
|
if (unlikely(writeaccess && !pte_write(entry)))
|
||||||
return 1;
|
goto out;
|
||||||
|
|
||||||
if (writeaccess)
|
if (writeaccess)
|
||||||
entry = pte_mkdirty(entry);
|
entry = pte_mkdirty(entry);
|
||||||
|
@ -336,5 +342,8 @@ asmlinkage int __kprobes __do_page_fault(struct pt_regs *regs,
|
||||||
set_pte(pte, entry);
|
set_pte(pte, entry);
|
||||||
update_mmu_cache(NULL, address, entry);
|
update_mmu_cache(NULL, address, entry);
|
||||||
|
|
||||||
return 0;
|
ret = 0;
|
||||||
|
out:
|
||||||
|
trace_mark(kernel_arch_trap_exit, MARK_NOARGS);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче