Commit b25c69b9 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull perf fixes from Ingo Molnar:
 "Misc fixes:
   - various tooling fixes
   - kretprobe fixes
   - kprobes annotation fixes
   - kprobes error checking fix
   - fix the default events for AMD Family 17h CPUs
   - PEBS fix
   - AUX record fix
   - address filtering fix"

* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/kprobes: Avoid kretprobe recursion bug
  kprobes: Mark ftrace mcount handler functions nokprobe
  x86/kprobes: Verify stack frame on kretprobe
  perf/x86/amd: Add event map for AMD Family 17h
  perf bpf: Return NULL when RB tree lookup fails in perf_env__find_btf()
  perf tools: Fix map reference counting
  perf evlist: Fix side band thread draining
  perf tools: Check maps for bpf programs
  perf bpf: Return NULL when RB tree lookup fails in perf_env__find_bpf_prog_info()
  tools include uapi: Sync sound/asound.h copy
  perf top: Always sample time to satisfy needs of use of ordered queuing
  perf evsel: Use hweight64() instead of hweight_long(attr.sample_regs_user)
  tools lib traceevent: Fix missing equality check for strcmp
  perf stat: Disable DIR_FORMAT feature for 'perf stat record'
  perf scripts python: export-to-sqlite.py: Fix use of parent_id in calls_view
  perf header: Fix lock/unlock imbalances when processing BPF/BTF info
  perf/x86: Fix incorrect PEBS_REGS
  perf/ring_buffer: Fix AUX record suppression
  perf/core: Fix the address filtering fix
  kprobes: Fix error check when reusing optimized probes
parents 1fd91d71 7579dfc4
...@@ -117,22 +117,39 @@ static __initconst const u64 amd_hw_cache_event_ids ...@@ -117,22 +117,39 @@ static __initconst const u64 amd_hw_cache_event_ids
}; };
/* /*
* AMD Performance Monitor K7 and later. * AMD Performance Monitor K7 and later, up to and including Family 16h:
*/ */
static const u64 amd_perfmon_event_map[PERF_COUNT_HW_MAX] = static const u64 amd_perfmon_event_map[PERF_COUNT_HW_MAX] =
{ {
[PERF_COUNT_HW_CPU_CYCLES] = 0x0076, [PERF_COUNT_HW_CPU_CYCLES] = 0x0076,
[PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0, [PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0,
[PERF_COUNT_HW_CACHE_REFERENCES] = 0x077d, [PERF_COUNT_HW_CACHE_REFERENCES] = 0x077d,
[PERF_COUNT_HW_CACHE_MISSES] = 0x077e, [PERF_COUNT_HW_CACHE_MISSES] = 0x077e,
[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x00c2, [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x00c2,
[PERF_COUNT_HW_BRANCH_MISSES] = 0x00c3, [PERF_COUNT_HW_BRANCH_MISSES] = 0x00c3,
[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x00d0, /* "Decoder empty" event */ [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x00d0, /* "Decoder empty" event */
[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x00d1, /* "Dispatch stalls" event */ [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x00d1, /* "Dispatch stalls" event */
};
/*
* AMD Performance Monitor Family 17h and later:
*/
static const u64 amd_f17h_perfmon_event_map[PERF_COUNT_HW_MAX] =
{
[PERF_COUNT_HW_CPU_CYCLES] = 0x0076,
[PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0,
[PERF_COUNT_HW_CACHE_REFERENCES] = 0xff60,
[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x00c2,
[PERF_COUNT_HW_BRANCH_MISSES] = 0x00c3,
[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x0287,
[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x0187,
}; };
static u64 amd_pmu_event_map(int hw_event) static u64 amd_pmu_event_map(int hw_event)
{ {
if (boot_cpu_data.x86 >= 0x17)
return amd_f17h_perfmon_event_map[hw_event];
return amd_perfmon_event_map[hw_event]; return amd_perfmon_event_map[hw_event];
} }
......
...@@ -3131,7 +3131,7 @@ static unsigned long intel_pmu_large_pebs_flags(struct perf_event *event) ...@@ -3131,7 +3131,7 @@ static unsigned long intel_pmu_large_pebs_flags(struct perf_event *event)
flags &= ~PERF_SAMPLE_TIME; flags &= ~PERF_SAMPLE_TIME;
if (!event->attr.exclude_kernel) if (!event->attr.exclude_kernel)
flags &= ~PERF_SAMPLE_REGS_USER; flags &= ~PERF_SAMPLE_REGS_USER;
if (event->attr.sample_regs_user & ~PEBS_REGS) if (event->attr.sample_regs_user & ~PEBS_GP_REGS)
flags &= ~(PERF_SAMPLE_REGS_USER | PERF_SAMPLE_REGS_INTR); flags &= ~(PERF_SAMPLE_REGS_USER | PERF_SAMPLE_REGS_INTR);
return flags; return flags;
} }
......
...@@ -96,25 +96,25 @@ struct amd_nb { ...@@ -96,25 +96,25 @@ struct amd_nb {
PERF_SAMPLE_REGS_INTR | PERF_SAMPLE_REGS_USER | \ PERF_SAMPLE_REGS_INTR | PERF_SAMPLE_REGS_USER | \
PERF_SAMPLE_PERIOD) PERF_SAMPLE_PERIOD)
#define PEBS_REGS \ #define PEBS_GP_REGS \
(PERF_REG_X86_AX | \ ((1ULL << PERF_REG_X86_AX) | \
PERF_REG_X86_BX | \ (1ULL << PERF_REG_X86_BX) | \
PERF_REG_X86_CX | \ (1ULL << PERF_REG_X86_CX) | \
PERF_REG_X86_DX | \ (1ULL << PERF_REG_X86_DX) | \
PERF_REG_X86_DI | \ (1ULL << PERF_REG_X86_DI) | \
PERF_REG_X86_SI | \ (1ULL << PERF_REG_X86_SI) | \
PERF_REG_X86_SP | \ (1ULL << PERF_REG_X86_SP) | \
PERF_REG_X86_BP | \ (1ULL << PERF_REG_X86_BP) | \
PERF_REG_X86_IP | \ (1ULL << PERF_REG_X86_IP) | \
PERF_REG_X86_FLAGS | \ (1ULL << PERF_REG_X86_FLAGS) | \
PERF_REG_X86_R8 | \ (1ULL << PERF_REG_X86_R8) | \
PERF_REG_X86_R9 | \ (1ULL << PERF_REG_X86_R9) | \
PERF_REG_X86_R10 | \ (1ULL << PERF_REG_X86_R10) | \
PERF_REG_X86_R11 | \ (1ULL << PERF_REG_X86_R11) | \
PERF_REG_X86_R12 | \ (1ULL << PERF_REG_X86_R12) | \
PERF_REG_X86_R13 | \ (1ULL << PERF_REG_X86_R13) | \
PERF_REG_X86_R14 | \ (1ULL << PERF_REG_X86_R14) | \
PERF_REG_X86_R15) (1ULL << PERF_REG_X86_R15))
/* /*
* Per register state. * Per register state.
......
...@@ -569,6 +569,7 @@ void arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs) ...@@ -569,6 +569,7 @@ void arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs)
unsigned long *sara = stack_addr(regs); unsigned long *sara = stack_addr(regs);
ri->ret_addr = (kprobe_opcode_t *) *sara; ri->ret_addr = (kprobe_opcode_t *) *sara;
ri->fp = sara;
/* Replace the return addr with trampoline addr */ /* Replace the return addr with trampoline addr */
*sara = (unsigned long) &kretprobe_trampoline; *sara = (unsigned long) &kretprobe_trampoline;
...@@ -748,26 +749,48 @@ asm( ...@@ -748,26 +749,48 @@ asm(
NOKPROBE_SYMBOL(kretprobe_trampoline); NOKPROBE_SYMBOL(kretprobe_trampoline);
STACK_FRAME_NON_STANDARD(kretprobe_trampoline); STACK_FRAME_NON_STANDARD(kretprobe_trampoline);
static struct kprobe kretprobe_kprobe = {
.addr = (void *)kretprobe_trampoline,
};
/* /*
* Called from kretprobe_trampoline * Called from kretprobe_trampoline
*/ */
static __used void *trampoline_handler(struct pt_regs *regs) static __used void *trampoline_handler(struct pt_regs *regs)
{ {
struct kprobe_ctlblk *kcb;
struct kretprobe_instance *ri = NULL; struct kretprobe_instance *ri = NULL;
struct hlist_head *head, empty_rp; struct hlist_head *head, empty_rp;
struct hlist_node *tmp; struct hlist_node *tmp;
unsigned long flags, orig_ret_address = 0; unsigned long flags, orig_ret_address = 0;
unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline; unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline;
kprobe_opcode_t *correct_ret_addr = NULL; kprobe_opcode_t *correct_ret_addr = NULL;
void *frame_pointer;
bool skipped = false;
preempt_disable();
/*
* Set a dummy kprobe for avoiding kretprobe recursion.
* Since kretprobe never run in kprobe handler, kprobe must not
* be running at this point.
*/
kcb = get_kprobe_ctlblk();
__this_cpu_write(current_kprobe, &kretprobe_kprobe);
kcb->kprobe_status = KPROBE_HIT_ACTIVE;
INIT_HLIST_HEAD(&empty_rp); INIT_HLIST_HEAD(&empty_rp);
kretprobe_hash_lock(current, &head, &flags); kretprobe_hash_lock(current, &head, &flags);
/* fixup registers */ /* fixup registers */
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
regs->cs = __KERNEL_CS; regs->cs = __KERNEL_CS;
/* On x86-64, we use pt_regs->sp for return address holder. */
frame_pointer = &regs->sp;
#else #else
regs->cs = __KERNEL_CS | get_kernel_rpl(); regs->cs = __KERNEL_CS | get_kernel_rpl();
regs->gs = 0; regs->gs = 0;
/* On x86-32, we use pt_regs->flags for return address holder. */
frame_pointer = &regs->flags;
#endif #endif
regs->ip = trampoline_address; regs->ip = trampoline_address;
regs->orig_ax = ~0UL; regs->orig_ax = ~0UL;
...@@ -789,8 +812,25 @@ static __used void *trampoline_handler(struct pt_regs *regs) ...@@ -789,8 +812,25 @@ static __used void *trampoline_handler(struct pt_regs *regs)
if (ri->task != current) if (ri->task != current)
/* another task is sharing our hash bucket */ /* another task is sharing our hash bucket */
continue; continue;
/*
* Return probes must be pushed on this hash list correct
* order (same as return order) so that it can be poped
* correctly. However, if we find it is pushed it incorrect
* order, this means we find a function which should not be
* probed, because the wrong order entry is pushed on the
* path of processing other kretprobe itself.
*/
if (ri->fp != frame_pointer) {
if (!skipped)
pr_warn("kretprobe is stacked incorrectly. Trying to fixup.\n");
skipped = true;
continue;
}
orig_ret_address = (unsigned long)ri->ret_addr; orig_ret_address = (unsigned long)ri->ret_addr;
if (skipped)
pr_warn("%ps must be blacklisted because of incorrect kretprobe order\n",
ri->rp->kp.addr);
if (orig_ret_address != trampoline_address) if (orig_ret_address != trampoline_address)
/* /*
...@@ -808,14 +848,15 @@ static __used void *trampoline_handler(struct pt_regs *regs) ...@@ -808,14 +848,15 @@ static __used void *trampoline_handler(struct pt_regs *regs)
if (ri->task != current) if (ri->task != current)
/* another task is sharing our hash bucket */ /* another task is sharing our hash bucket */
continue; continue;
if (ri->fp != frame_pointer)
continue;
orig_ret_address = (unsigned long)ri->ret_addr; orig_ret_address = (unsigned long)ri->ret_addr;
if (ri->rp && ri->rp->handler) { if (ri->rp && ri->rp->handler) {
__this_cpu_write(current_kprobe, &ri->rp->kp); __this_cpu_write(current_kprobe, &ri->rp->kp);
get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE;
ri->ret_addr = correct_ret_addr; ri->ret_addr = correct_ret_addr;
ri->rp->handler(ri, regs); ri->rp->handler(ri, regs);
__this_cpu_write(current_kprobe, NULL); __this_cpu_write(current_kprobe, &kretprobe_kprobe);
} }
recycle_rp_inst(ri, &empty_rp); recycle_rp_inst(ri, &empty_rp);
...@@ -831,6 +872,9 @@ static __used void *trampoline_handler(struct pt_regs *regs) ...@@ -831,6 +872,9 @@ static __used void *trampoline_handler(struct pt_regs *regs)
kretprobe_hash_unlock(current, &flags); kretprobe_hash_unlock(current, &flags);
__this_cpu_write(current_kprobe, NULL);
preempt_enable();
hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) { hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
hlist_del(&ri->hlist); hlist_del(&ri->hlist);
kfree(ri); kfree(ri);
......
...@@ -173,6 +173,7 @@ struct kretprobe_instance { ...@@ -173,6 +173,7 @@ struct kretprobe_instance {
struct kretprobe *rp; struct kretprobe *rp;
kprobe_opcode_t *ret_addr; kprobe_opcode_t *ret_addr;
struct task_struct *task; struct task_struct *task;
void *fp;
char data[0]; char data[0];
}; };
......
...@@ -9077,26 +9077,29 @@ static void perf_event_addr_filters_apply(struct perf_event *event) ...@@ -9077,26 +9077,29 @@ static void perf_event_addr_filters_apply(struct perf_event *event)
if (task == TASK_TOMBSTONE) if (task == TASK_TOMBSTONE)
return; return;
if (!ifh->nr_file_filters) if (ifh->nr_file_filters) {
return; mm = get_task_mm(event->ctx->task);
if (!mm)
mm = get_task_mm(event->ctx->task); goto restart;
if (!mm)
goto restart;
down_read(&mm->mmap_sem); down_read(&mm->mmap_sem);
}
raw_spin_lock_irqsave(&ifh->lock, flags); raw_spin_lock_irqsave(&ifh->lock, flags);
list_for_each_entry(filter, &ifh->list, entry) { list_for_each_entry(filter, &ifh->list, entry) {
event->addr_filter_ranges[count].start = 0; if (filter->path.dentry) {
event->addr_filter_ranges[count].size = 0; /*
* Adjust base offset if the filter is associated to a
* binary that needs to be mapped:
*/
event->addr_filter_ranges[count].start = 0;
event->addr_filter_ranges[count].size = 0;
/*
* Adjust base offset if the filter is associated to a binary
* that needs to be mapped:
*/
if (filter->path.dentry)
perf_addr_filter_apply(filter, mm, &event->addr_filter_ranges[count]); perf_addr_filter_apply(filter, mm, &event->addr_filter_ranges[count]);
} else {
event->addr_filter_ranges[count].start = filter->offset;
event->addr_filter_ranges[count].size = filter->size;
}
count++; count++;
} }
...@@ -9104,9 +9107,11 @@ static void perf_event_addr_filters_apply(struct perf_event *event) ...@@ -9104,9 +9107,11 @@ static void perf_event_addr_filters_apply(struct perf_event *event)
event->addr_filters_gen++; event->addr_filters_gen++;
raw_spin_unlock_irqrestore(&ifh->lock, flags); raw_spin_unlock_irqrestore(&ifh->lock, flags);
up_read(&mm->mmap_sem); if (ifh->nr_file_filters) {
up_read(&mm->mmap_sem);
mmput(mm); mmput(mm);
}
restart: restart:
perf_event_stop(event, 1); perf_event_stop(event, 1);
......
...@@ -455,24 +455,21 @@ void perf_aux_output_end(struct perf_output_handle *handle, unsigned long size) ...@@ -455,24 +455,21 @@ void perf_aux_output_end(struct perf_output_handle *handle, unsigned long size)
rb->aux_head += size; rb->aux_head += size;
} }
if (size || handle->aux_flags) { /*
/* * Only send RECORD_AUX if we have something useful to communicate
* Only send RECORD_AUX if we have something useful to communicate *
* * Note: the OVERWRITE records by themselves are not considered
* Note: the OVERWRITE records by themselves are not considered * useful, as they don't communicate any *new* information,
* useful, as they don't communicate any *new* information, * aside from the short-lived offset, that becomes history at
* aside from the short-lived offset, that becomes history at * the next event sched-in and therefore isn't useful.
* the next event sched-in and therefore isn't useful. * The userspace that needs to copy out AUX data in overwrite
* The userspace that needs to copy out AUX data in overwrite * mode should know to use user_page::aux_head for the actual
* mode should know to use user_page::aux_head for the actual * offset. So, from now on we don't output AUX records that
* offset. So, from now on we don't output AUX records that * have *only* OVERWRITE flag set.
* have *only* OVERWRITE flag set. */
*/ if (size || (handle->aux_flags & ~(u64)PERF_AUX_FLAG_OVERWRITE))
perf_event_aux_event(handle->event, aux_head, size,
if (handle->aux_flags & ~(u64)PERF_AUX_FLAG_OVERWRITE) handle->aux_flags);
perf_event_aux_event(handle->event, aux_head, size,
handle->aux_flags);
}
rb->user_page->aux_head = rb->aux_head; rb->user_page->aux_head = rb->aux_head;
if (rb_need_aux_wakeup(rb)) if (rb_need_aux_wakeup(rb))
......
...@@ -709,7 +709,6 @@ static void unoptimize_kprobe(struct kprobe *p, bool force) ...@@ -709,7 +709,6 @@ static void unoptimize_kprobe(struct kprobe *p, bool force)
static int reuse_unused_kprobe(struct kprobe *ap) static int reuse_unused_kprobe(struct kprobe *ap)
{ {
struct optimized_kprobe *op; struct optimized_kprobe *op;
int ret;
/* /*
* Unused kprobe MUST be on the way of delayed unoptimizing (means * Unused kprobe MUST be on the way of delayed unoptimizing (means
...@@ -720,9 +719,8 @@ static int reuse_unused_kprobe(struct kprobe *ap) ...@@ -720,9 +719,8 @@ static int reuse_unused_kprobe(struct kprobe *ap)
/* Enable the probe again */ /* Enable the probe again */
ap->flags &= ~KPROBE_FLAG_DISABLED; ap->flags &= ~KPROBE_FLAG_DISABLED;
/* Optimize it again (remove from op->list) */ /* Optimize it again (remove from op->list) */
ret = kprobe_optready(ap); if (!kprobe_optready(ap))
if (ret) return -EINVAL;
return ret;
optimize_kprobe(ap); optimize_kprobe(ap);
return 0; return 0;
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/hash.h> #include <linux/hash.h>
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include <linux/kprobes.h>
#include <trace/events/sched.h> #include <trace/events/sched.h>
...@@ -6246,7 +6247,7 @@ void ftrace_reset_array_ops(struct trace_array *tr) ...@@ -6246,7 +6247,7 @@ void ftrace_reset_array_ops(struct trace_array *tr)
tr->ops->func = ftrace_stub; tr->ops->func = ftrace_stub;
} }
static inline void static nokprobe_inline void
__ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip, __ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip,
struct ftrace_ops *ignored, struct pt_regs *regs) struct ftrace_ops *ignored, struct pt_regs *regs)
{ {
...@@ -6306,11 +6307,13 @@ static void ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip, ...@@ -6306,11 +6307,13 @@ static void ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip,
{ {
__ftrace_ops_list_func(ip, parent_ip, NULL, regs); __ftrace_ops_list_func(ip, parent_ip, NULL, regs);
} }
NOKPROBE_SYMBOL(ftrace_ops_list_func);
#else #else
static void ftrace_ops_no_ops(unsigned long ip, unsigned long parent_ip) static void ftrace_ops_no_ops(unsigned long ip, unsigned long parent_ip)
{ {
__ftrace_ops_list_func(ip, parent_ip, NULL, NULL); __ftrace_ops_list_func(ip, parent_ip, NULL, NULL);
} }
NOKPROBE_SYMBOL(ftrace_ops_no_ops);
#endif #endif
/* /*
...@@ -6337,6 +6340,7 @@ static void ftrace_ops_assist_func(unsigned long ip, unsigned long parent_ip, ...@@ -6337,6 +6340,7 @@ static void ftrace_ops_assist_func(unsigned long ip, unsigned long parent_ip,
preempt_enable_notrace(); preempt_enable_notrace();
trace_clear_recursion(bit); trace_clear_recursion(bit);
} }
NOKPROBE_SYMBOL(ftrace_ops_assist_func);
/** /**
* ftrace_ops_get_func - get the function a trampoline should call * ftrace_ops_get_func - get the function a trampoline should call
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#ifndef __KERNEL__ #ifndef __KERNEL__
#include <stdlib.h> #include <stdlib.h>
#include <time.h>
#endif #endif
/* /*
......
...@@ -2233,7 +2233,7 @@ eval_type_str(unsigned long long val, const char *type, int pointer) ...@@ -2233,7 +2233,7 @@ eval_type_str(unsigned long long val, const char *type, int pointer)
return val & 0xffffffff; return val & 0xffffffff;
if (strcmp(type, "u64") == 0 || if (strcmp(type, "u64") == 0 ||
strcmp(type, "s64")) strcmp(type, "s64") == 0)
return val; return val;
if (strcmp(type, "s8") == 0) if (strcmp(type, "s8") == 0)
......
...@@ -1308,6 +1308,7 @@ static void init_features(struct perf_session *session) ...@@ -1308,6 +1308,7 @@ static void init_features(struct perf_session *session)
for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++) for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
perf_header__set_feat(&session->header, feat); perf_header__set_feat(&session->header, feat);
perf_header__clear_feat(&session->header, HEADER_DIR_FORMAT);
perf_header__clear_feat(&session->header, HEADER_BUILD_ID); perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
perf_header__clear_feat(&session->header, HEADER_TRACING_DATA); perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK); perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
......
...@@ -1377,6 +1377,7 @@ int cmd_top(int argc, const char **argv) ...@@ -1377,6 +1377,7 @@ int cmd_top(int argc, const char **argv)
* */ * */
.overwrite = 0, .overwrite = 0,
.sample_time = true, .sample_time = true,
.sample_time_set = true,
}, },
.max_stack = sysctl__max_stack(), .max_stack = sysctl__max_stack(),
.annotation_opts = annotation__default_options, .annotation_opts = annotation__default_options,
......
...@@ -331,7 +331,7 @@ if perf_db_export_calls: ...@@ -331,7 +331,7 @@ if perf_db_export_calls:
'return_id,' 'return_id,'
'CASE WHEN flags=0 THEN \'\' WHEN flags=1 THEN \'no call\' WHEN flags=2 THEN \'no return\' WHEN flags=3 THEN \'no call/return\' WHEN flags=6 THEN \'jump\' ELSE flags END AS flags,' 'CASE WHEN flags=0 THEN \'\' WHEN flags=1 THEN \'no call\' WHEN flags=2 THEN \'no return\' WHEN flags=3 THEN \'no call/return\' WHEN flags=6 THEN \'jump\' ELSE flags END AS flags,'
'parent_call_path_id,' 'parent_call_path_id,'
'parent_id' 'calls.parent_id'
' FROM calls INNER JOIN call_paths ON call_paths.id = call_path_id') ' FROM calls INNER JOIN call_paths ON call_paths.id = call_path_id')
do_query(query, 'CREATE VIEW samples_view AS ' do_query(query, 'CREATE VIEW samples_view AS '
......
...@@ -57,9 +57,11 @@ struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env, ...@@ -57,9 +57,11 @@ struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,
else if (prog_id > node->info_linear->info.id) else if (prog_id > node->info_linear->info.id)
n = n->rb_right; n = n->rb_right;
else else
break; goto out;
} }
node = NULL;
out:
up_read(&env->bpf_progs.lock); up_read(&env->bpf_progs.lock);
return node; return node;
} }
...@@ -109,10 +111,12 @@ struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id) ...@@ -109,10 +111,12 @@ struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id)
else if (btf_id > node->id) else if (btf_id > node->id)
n = n->rb_right; n = n->rb_right;
else else
break; goto out;
} }
node = NULL;
up_read(&env->bpf_progs.lock); up_read(&env->bpf_progs.lock);
out:
return node; return node;
} }
......
...@@ -1868,12 +1868,12 @@ static void *perf_evlist__poll_thread(void *arg) ...@@ -1868,12 +1868,12 @@ static void *perf_evlist__poll_thread(void *arg)
{ {
struct perf_evlist *evlist = arg; struct perf_evlist *evlist = arg;
bool draining = false; bool draining = false;
int i; int i, done = 0;
while (!done) {
bool got_data = false;
while (draining || !(evlist->thread.done)) { if (evlist->thread.done)
if (draining)
draining = false;
else if (evlist->thread.done)
draining = true; draining = true;
if (!draining) if (!draining)
...@@ -1894,9 +1894,13 @@ static void *perf_evlist__poll_thread(void *arg) ...@@ -1894,9 +1894,13 @@ static void *perf_evlist__poll_thread(void *arg)
pr_warning("cannot locate proper evsel for the side band event\n"); pr_warning("cannot locate proper evsel for the side band event\n");
perf_mmap__consume(map); perf_mmap__consume(map);
got_data = true;
} }
perf_mmap__read_done(map); perf_mmap__read_done(map);
} }
if (draining && !got_data)
break;
} }
return NULL; return NULL;
} }
......
...@@ -2368,7 +2368,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, ...@@ -2368,7 +2368,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
if (data->user_regs.abi) { if (data->user_regs.abi) {
u64 mask = evsel->attr.sample_regs_user; u64 mask = evsel->attr.sample_regs_user;
sz = hweight_long(mask) * sizeof(u64); sz = hweight64(mask) * sizeof(u64);
OVERFLOW_CHECK(array, sz, max_size); OVERFLOW_CHECK(array, sz, max_size);
data->user_regs.mask = mask; data->user_regs.mask = mask;
data->user_regs.regs = (u64 *)array; data->user_regs.regs = (u64 *)array;
...@@ -2424,7 +2424,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, ...@@ -2424,7 +2424,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
if (data->intr_regs.abi != PERF_SAMPLE_REGS_ABI_NONE) { if (data->intr_regs.abi != PERF_SAMPLE_REGS_ABI_NONE) {
u64 mask = evsel->attr.sample_regs_intr; u64 mask = evsel->attr.sample_regs_intr;
sz = hweight_long(mask) * sizeof(u64); sz = hweight64(mask) * sizeof(u64);
OVERFLOW_CHECK(array, sz, max_size); OVERFLOW_CHECK(array, sz, max_size);
data->intr_regs.mask = mask; data->intr_regs.mask = mask;
data->intr_regs.regs = (u64 *)array; data->intr_regs.regs = (u64 *)array;
...@@ -2552,7 +2552,7 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, ...@@ -2552,7 +2552,7 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
if (type & PERF_SAMPLE_REGS_USER) { if (type & PERF_SAMPLE_REGS_USER) {
if (sample->user_regs.abi) { if (sample->user_regs.abi) {
result += sizeof(u64); result += sizeof(u64);
sz = hweight_long(sample->user_regs.mask) * sizeof(u64); sz = hweight64(sample->user_regs.mask) * sizeof(u64);
result += sz; result += sz;
} else { } else {
result += sizeof(u64); result += sizeof(u64);
...@@ -2580,7 +2580,7 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, ...@@ -2580,7 +2580,7 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
if (type & PERF_SAMPLE_REGS_INTR) { if (type & PERF_SAMPLE_REGS_INTR) {
if (sample->intr_regs.abi) { if (sample->intr_regs.abi) {
result += sizeof(u64); result += sizeof(u64);
sz = hweight_long(sample->intr_regs.mask) * sizeof(u64); sz = hweight64(sample->intr_regs.mask) * sizeof(u64);
result += sz; result += sz;
} else { } else {
result += sizeof(u64); result += sizeof(u64);
...@@ -2710,7 +2710,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, ...@@ -2710,7 +2710,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
if (type & PERF_SAMPLE_REGS_USER) { if (type & PERF_SAMPLE_REGS_USER) {
if (sample->user_regs.abi) { if (sample->user_regs.abi) {
*array++ = sample->user_regs.abi; *array++ = sample->user_regs.abi;
sz = hweight_long(sample->user_regs.mask) * sizeof(u64); sz = hweight64(sample->user_regs.mask) * sizeof(u64);
memcpy(array, sample->user_regs.regs, sz); memcpy(array, sample->user_regs.regs, sz);
array = (void *)array + sz; array = (void *)array + sz;
} else { } else {
...@@ -2746,7 +2746,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, ...@@ -2746,7 +2746,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
if (type & PERF_SAMPLE_REGS_INTR) { if (type & PERF_SAMPLE_REGS_INTR) {
if (sample->intr_regs.abi) { if (sample->intr_regs.abi) {
*array++ = sample->intr_regs.abi; *array++ = sample->intr_regs.abi;
sz = hweight_long(sample->intr_regs.mask) * sizeof(u64); sz = hweight64(sample->intr_regs.mask) * sizeof(u64);
memcpy(array, sample->intr_regs.regs, sz); memcpy(array, sample->intr_regs.regs, sz);
array = (void *)array + sz; array = (void *)array + sz;
} else { } else {
......
...@@ -2606,6 +2606,7 @@ static int process_bpf_prog_info(struct feat_fd *ff, void *data __maybe_unused) ...@@ -2606,6 +2606,7 @@ static int process_bpf_prog_info(struct feat_fd *ff, void *data __maybe_unused)
perf_env__insert_bpf_prog_info(env, info_node); perf_env__insert_bpf_prog_info(env, info_node);
} }
up_write(&env->bpf_progs.lock);
return 0; return 0;
out: out:
free(info_linear); free(info_linear);
...@@ -2623,7 +2624,9 @@ static int process_bpf_prog_info(struct feat_fd *ff __maybe_unused, void *data _ ...@@ -2623,7 +2624,9 @@ static int process_bpf_prog_info(struct feat_fd *ff __maybe_unused, void *data _
static int process_bpf_btf(struct feat_fd *ff, void *data __maybe_unused) static int process_bpf_btf(struct feat_fd *ff, void *data __maybe_unused)
{ {
struct perf_env *env = &ff->ph->env; struct perf_env *env = &ff->ph->env;
struct btf_node *node = NULL;
u32 count, i; u32 count, i;
int err = -1;
if (ff->ph->needs_swap) { if (ff->ph->needs_swap) {
pr_warning("interpreting btf from systems with endianity is not yet supported\n"); pr_warning("interpreting btf from systems with endianity is not yet supported\n");
...@@ -2636,31 +2639,32 @@ static int process_bpf_btf(struct feat_fd *ff, void *data __maybe_unused) ...@@ -2636,31 +2639,32 @@ static int process_bpf_btf(struct feat_fd *ff, void *data __maybe_unused)
down_write(&env->bpf_progs.lock); down_write(&env->bpf_progs.lock);
for (i = 0; i < count; ++i) { for (i = 0; i < count; ++i) {
struct btf_node *node;
u32 id, data_size; u32 id, data_size;
if (do_read_u32(ff, &id)) if (do_read_u32(ff, &id))
return -1; goto out;
if (do_read_u32(ff, &data_size)) if (do_read_u32(ff, &data_size))
return -1; goto out;
node = malloc(sizeof(struct btf_node) + data_size); node = malloc(sizeof(struct btf_node) + data_size);
if (!node) if (!node)
return -1; goto out;
node->id = id; node->id = id;
node->data_size = data_size; node->data_size = data_size;
if (__do_read(ff, node->data, data_size)) { if (__do_read(ff, node->data, data_size))
free(node); goto out;
return -1;
}
perf_env__insert_btf(env, node); perf_env__insert_btf(env, node);
node = NULL;
} }
err = 0;
out:
up_write(&env->bpf_progs.lock); up_write(&env->bpf_progs.lock);
return 0; free(node);
return err;
} }
struct feature_ops { struct feature_ops {
......
...@@ -261,6 +261,22 @@ bool __map__is_extra_kernel_map(const struct map *map) ...@@ -261,6 +261,22 @@ bool __map__is_extra_kernel_map(const struct map *map)
return kmap && kmap->name[0]; return kmap && kmap->name[0];
} }
bool __map__is_bpf_prog(const struct map *map)
{
const char *name;
if (map->dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO)
return true;
/*
* If PERF_RECORD_BPF_EVENT is not included, the dso will not have
* type of DSO_BINARY_TYPE__BPF_PROG_INFO. In such cases, we can
* guess the type based on name.
*/
name = map->dso->short_name;
return name && (strstr(name, "bpf_prog_") == name);
}
bool map__has_symbols(const struct map *map) bool map__has_symbols(const struct map *map)
{ {
return dso__has_symbols(map->dso); return dso__has_symbols(map->dso);
...@@ -910,10 +926,8 @@ static void __maps__insert_name(struct maps *maps, struct map *map) ...@@ -910,10 +926,8 @@ static void __maps__insert_name(struct maps *maps, struct map *map)
rc = strcmp(m->dso->short_name, map->dso->short_name); rc = strcmp(m->dso->short_name, map->dso->short_name);
if (rc < 0) if (rc < 0)
p = &(*p)->rb_left; p = &(*p)->rb_left;
else if (rc > 0)
p = &(*p)->rb_right;
else else
return; p = &(*p)->rb_right;
} }
rb_link_node(&map->rb_node_name, parent, p); rb_link_node(&map->rb_node_name, parent, p);
rb_insert_color(&map->rb_node_name, &maps->names); rb_insert_color(&map->rb_node_name, &maps->names);
......
...@@ -159,10 +159,12 @@ int map__set_kallsyms_ref_reloc_sym(struct map *map, const char *symbol_name, ...@@ -159,10 +159,12 @@ int map__set_kallsyms_ref_reloc_sym(struct map *map, const char *symbol_name,
bool __map__is_kernel(const struct map *map); bool __map__is_kernel(const struct map *map);
bool __map__is_extra_kernel_map(const struct map *map); bool __map__is_extra_kernel_map(const struct map *map);
bool __map__is_bpf_prog(const struct map *map);
static inline bool __map__is_kmodule(const struct map *map) static inline bool __map__is_kmodule(const struct map *map)
{ {
return !__map__is_kernel(map) && !__map__is_extra_kernel_map(map); return !__map__is_kernel(map) && !__map__is_extra_kernel_map(map) &&
!__map__is_bpf_prog(map);
} }
bool map__has_symbols(const struct map *map); bool map__has_symbols(const struct map *map);
......
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