mirror of
https://github.com/FEX-Emu/linux.git
synced 2025-01-20 08:40:47 +00:00
Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf fixes from Thomas Gleixner: "A couple of fixes for perf and kprobes: - Add he missing exclude_kernel attribute for the precise_ip level so !CAP_SYS_ADMIN users get the proper results. - Warn instead of failing completely when perf has no unwind support for a particular architectiure built in. - Ensure that jprobes are at function entry and not at some random place" * 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: kprobes: Ensure that jprobe probepoints are at function entry kprobes: Simplify register_jprobes() kprobes: Rename [arch_]function_offset_within_entry() to [arch_]kprobe_on_func_entry() perf unwind: Do not fail due to missing unwind support perf evsel: Set attr.exclude_kernel when probing max attr.precise_ip
This commit is contained in:
commit
c3931a87db
@ -217,7 +217,7 @@ static nokprobe_inline void set_current_kprobe(struct kprobe *p, struct pt_regs
|
|||||||
kcb->kprobe_saved_msr = regs->msr;
|
kcb->kprobe_saved_msr = regs->msr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool arch_function_offset_within_entry(unsigned long offset)
|
bool arch_kprobe_on_func_entry(unsigned long offset)
|
||||||
{
|
{
|
||||||
#ifdef PPC64_ELF_ABI_v2
|
#ifdef PPC64_ELF_ABI_v2
|
||||||
#ifdef CONFIG_KPROBES_ON_FTRACE
|
#ifdef CONFIG_KPROBES_ON_FTRACE
|
||||||
|
@ -267,8 +267,8 @@ extern int arch_init_kprobes(void);
|
|||||||
extern void show_registers(struct pt_regs *regs);
|
extern void show_registers(struct pt_regs *regs);
|
||||||
extern void kprobes_inc_nmissed_count(struct kprobe *p);
|
extern void kprobes_inc_nmissed_count(struct kprobe *p);
|
||||||
extern bool arch_within_kprobe_blacklist(unsigned long addr);
|
extern bool arch_within_kprobe_blacklist(unsigned long addr);
|
||||||
extern bool arch_function_offset_within_entry(unsigned long offset);
|
extern bool arch_kprobe_on_func_entry(unsigned long offset);
|
||||||
extern bool function_offset_within_entry(kprobe_opcode_t *addr, const char *sym, unsigned long offset);
|
extern bool kprobe_on_func_entry(kprobe_opcode_t *addr, const char *sym, unsigned long offset);
|
||||||
|
|
||||||
extern bool within_kprobe_blacklist(unsigned long addr);
|
extern bool within_kprobe_blacklist(unsigned long addr);
|
||||||
|
|
||||||
|
@ -1771,24 +1771,13 @@ unsigned long __weak arch_deref_entry_point(void *entry)
|
|||||||
|
|
||||||
int register_jprobes(struct jprobe **jps, int num)
|
int register_jprobes(struct jprobe **jps, int num)
|
||||||
{
|
{
|
||||||
struct jprobe *jp;
|
|
||||||
int ret = 0, i;
|
int ret = 0, i;
|
||||||
|
|
||||||
if (num <= 0)
|
if (num <= 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
for (i = 0; i < num; i++) {
|
|
||||||
unsigned long addr, offset;
|
|
||||||
jp = jps[i];
|
|
||||||
addr = arch_deref_entry_point(jp->entry);
|
|
||||||
|
|
||||||
/* Verify probepoint is a function entry point */
|
for (i = 0; i < num; i++) {
|
||||||
if (kallsyms_lookup_size_offset(addr, NULL, &offset) &&
|
ret = register_jprobe(jps[i]);
|
||||||
offset == 0) {
|
|
||||||
jp->kp.pre_handler = setjmp_pre_handler;
|
|
||||||
jp->kp.break_handler = longjmp_break_handler;
|
|
||||||
ret = register_kprobe(&jp->kp);
|
|
||||||
} else
|
|
||||||
ret = -EINVAL;
|
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
@ -1796,13 +1785,30 @@ int register_jprobes(struct jprobe **jps, int num)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(register_jprobes);
|
EXPORT_SYMBOL_GPL(register_jprobes);
|
||||||
|
|
||||||
int register_jprobe(struct jprobe *jp)
|
int register_jprobe(struct jprobe *jp)
|
||||||
{
|
{
|
||||||
return register_jprobes(&jp, 1);
|
unsigned long addr, offset;
|
||||||
|
struct kprobe *kp = &jp->kp;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verify probepoint as well as the jprobe handler are
|
||||||
|
* valid function entry points.
|
||||||
|
*/
|
||||||
|
addr = arch_deref_entry_point(jp->entry);
|
||||||
|
|
||||||
|
if (kallsyms_lookup_size_offset(addr, NULL, &offset) && offset == 0 &&
|
||||||
|
kprobe_on_func_entry(kp->addr, kp->symbol_name, kp->offset)) {
|
||||||
|
kp->pre_handler = setjmp_pre_handler;
|
||||||
|
kp->break_handler = longjmp_break_handler;
|
||||||
|
return register_kprobe(kp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(register_jprobe);
|
EXPORT_SYMBOL_GPL(register_jprobe);
|
||||||
|
|
||||||
@ -1888,12 +1894,12 @@ static int pre_handler_kretprobe(struct kprobe *p, struct pt_regs *regs)
|
|||||||
}
|
}
|
||||||
NOKPROBE_SYMBOL(pre_handler_kretprobe);
|
NOKPROBE_SYMBOL(pre_handler_kretprobe);
|
||||||
|
|
||||||
bool __weak arch_function_offset_within_entry(unsigned long offset)
|
bool __weak arch_kprobe_on_func_entry(unsigned long offset)
|
||||||
{
|
{
|
||||||
return !offset;
|
return !offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool function_offset_within_entry(kprobe_opcode_t *addr, const char *sym, unsigned long offset)
|
bool kprobe_on_func_entry(kprobe_opcode_t *addr, const char *sym, unsigned long offset)
|
||||||
{
|
{
|
||||||
kprobe_opcode_t *kp_addr = _kprobe_addr(addr, sym, offset);
|
kprobe_opcode_t *kp_addr = _kprobe_addr(addr, sym, offset);
|
||||||
|
|
||||||
@ -1901,7 +1907,7 @@ bool function_offset_within_entry(kprobe_opcode_t *addr, const char *sym, unsign
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!kallsyms_lookup_size_offset((unsigned long)kp_addr, NULL, &offset) ||
|
if (!kallsyms_lookup_size_offset((unsigned long)kp_addr, NULL, &offset) ||
|
||||||
!arch_function_offset_within_entry(offset))
|
!arch_kprobe_on_func_entry(offset))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -1914,7 +1920,7 @@ int register_kretprobe(struct kretprobe *rp)
|
|||||||
int i;
|
int i;
|
||||||
void *addr;
|
void *addr;
|
||||||
|
|
||||||
if (!function_offset_within_entry(rp->kp.addr, rp->kp.symbol_name, rp->kp.offset))
|
if (!kprobe_on_func_entry(rp->kp.addr, rp->kp.symbol_name, rp->kp.offset))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (kretprobe_blacklist_size) {
|
if (kretprobe_blacklist_size) {
|
||||||
|
@ -720,7 +720,7 @@ static int create_trace_kprobe(int argc, char **argv)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
if (offset && is_return &&
|
if (offset && is_return &&
|
||||||
!function_offset_within_entry(NULL, symbol, offset)) {
|
!kprobe_on_func_entry(NULL, symbol, offset)) {
|
||||||
pr_info("Given offset is not valid for return probe.\n");
|
pr_info("Given offset is not valid for return probe.\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -273,6 +273,7 @@ struct perf_evsel *perf_evsel__new_cycles(void)
|
|||||||
struct perf_event_attr attr = {
|
struct perf_event_attr attr = {
|
||||||
.type = PERF_TYPE_HARDWARE,
|
.type = PERF_TYPE_HARDWARE,
|
||||||
.config = PERF_COUNT_HW_CPU_CYCLES,
|
.config = PERF_COUNT_HW_CPU_CYCLES,
|
||||||
|
.exclude_kernel = 1,
|
||||||
};
|
};
|
||||||
struct perf_evsel *evsel;
|
struct perf_evsel *evsel;
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ int unwind__prepare_access(struct thread *thread, struct map *map,
|
|||||||
|
|
||||||
if (!ops) {
|
if (!ops) {
|
||||||
pr_err("unwind: target platform=%s is not supported\n", arch);
|
pr_err("unwind: target platform=%s is not supported\n", arch);
|
||||||
return -1;
|
return 0;
|
||||||
}
|
}
|
||||||
out_register:
|
out_register:
|
||||||
unwind__register_ops(thread, ops);
|
unwind__register_ops(thread, ops);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user