Commit eca9dfcd authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'perf-fixes-for-linus' of...

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

* 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  perf session: Make events_stats u64 to avoid overflow on 32-bit arches
  hw-breakpoints: Fix hardware breakpoints -> perf events dependency
  perf events: Dont report side-band events on each cpu for per-task-per-cpu events
  perf events, x86/stacktrace: Fix performance/softlockup by providing a special frame pointer-only stack walker
  perf events, x86/stacktrace: Make stack walking optional
  perf events: Remove unused perf_counter.h header file
  perf probe: Check new event name
  kprobe-tracer: Check new event/group name
  perf probe: Check whether debugfs path is correct
  perf probe: Fix libdwarf include path for Debian
parents 3981e152 b5b60fda
......@@ -135,9 +135,7 @@ config HAVE_DEFAULT_NO_SPIN_MUTEXES
config HAVE_HW_BREAKPOINT
bool
depends on HAVE_PERF_EVENTS
select ANON_INODES
select PERF_EVENTS
depends on PERF_EVENTS
config HAVE_USER_RETURN_NOTIFIER
bool
......
......@@ -50,6 +50,8 @@ config X86
select HAVE_KERNEL_BZIP2
select HAVE_KERNEL_LZMA
select HAVE_HW_BREAKPOINT
select PERF_EVENTS
select ANON_INODES
select HAVE_ARCH_KMEMCHECK
select HAVE_USER_RETURN_NOTIFIER
......
......@@ -5,6 +5,29 @@ extern int kstack_depth_to_print;
int x86_is_stack_id(int id, char *name);
struct thread_info;
struct stacktrace_ops;
typedef unsigned long (*walk_stack_t)(struct thread_info *tinfo,
unsigned long *stack,
unsigned long bp,
const struct stacktrace_ops *ops,
void *data,
unsigned long *end,
int *graph);
extern unsigned long
print_context_stack(struct thread_info *tinfo,
unsigned long *stack, unsigned long bp,
const struct stacktrace_ops *ops, void *data,
unsigned long *end, int *graph);
extern unsigned long
print_context_stack_bp(struct thread_info *tinfo,
unsigned long *stack, unsigned long bp,
const struct stacktrace_ops *ops, void *data,
unsigned long *end, int *graph);
/* Generic stack tracer with callbacks */
struct stacktrace_ops {
......@@ -14,6 +37,7 @@ struct stacktrace_ops {
void (*address)(void *data, unsigned long address, int reliable);
/* On negative return stop dumping */
int (*stack)(void *data, char *name);
walk_stack_t walk_stack;
};
void dump_trace(struct task_struct *tsk, struct pt_regs *regs,
......
......@@ -2336,6 +2336,7 @@ static const struct stacktrace_ops backtrace_ops = {
.warning_symbol = backtrace_warning_symbol,
.stack = backtrace_stack,
.address = backtrace_address,
.walk_stack = print_context_stack_bp,
};
#include "../dumpstack.h"
......
......@@ -109,6 +109,30 @@ print_context_stack(struct thread_info *tinfo,
}
return bp;
}
EXPORT_SYMBOL_GPL(print_context_stack);
unsigned long
print_context_stack_bp(struct thread_info *tinfo,
unsigned long *stack, unsigned long bp,
const struct stacktrace_ops *ops, void *data,
unsigned long *end, int *graph)
{
struct stack_frame *frame = (struct stack_frame *)bp;
unsigned long *ret_addr = &frame->return_address;
while (valid_stack_ptr(tinfo, ret_addr, sizeof(*ret_addr), end)) {
unsigned long addr = *ret_addr;
if (__kernel_text_address(addr)) {
ops->address(data, addr, 1);
frame = frame->next_frame;
ret_addr = &frame->return_address;
print_ftrace_graph_addr(addr, data, ops, tinfo, graph);
}
}
return (unsigned long)frame;
}
EXPORT_SYMBOL_GPL(print_context_stack_bp);
static void
......@@ -141,10 +165,11 @@ static void print_trace_address(void *data, unsigned long addr, int reliable)
}
static const struct stacktrace_ops print_trace_ops = {
.warning = print_trace_warning,
.warning_symbol = print_trace_warning_symbol,
.stack = print_trace_stack,
.address = print_trace_address,
.warning = print_trace_warning,
.warning_symbol = print_trace_warning_symbol,
.stack = print_trace_stack,
.address = print_trace_address,
.walk_stack = print_context_stack,
};
void
......
......@@ -14,12 +14,6 @@
#define get_bp(bp) asm("movq %%rbp, %0" : "=r" (bp) :)
#endif
extern unsigned long
print_context_stack(struct thread_info *tinfo,
unsigned long *stack, unsigned long bp,
const struct stacktrace_ops *ops, void *data,
unsigned long *end, int *graph);
extern void
show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
unsigned long *stack, unsigned long bp, char *log_lvl);
......
......@@ -58,7 +58,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
context = (struct thread_info *)
((unsigned long)stack & (~(THREAD_SIZE - 1)));
bp = print_context_stack(context, stack, bp, ops, data, NULL, &graph);
bp = ops->walk_stack(context, stack, bp, ops, data, NULL, &graph);
stack = (unsigned long *)context->previous_esp;
if (!stack)
......
......@@ -188,8 +188,8 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
if (ops->stack(data, id) < 0)
break;
bp = print_context_stack(tinfo, stack, bp, ops,
data, estack_end, &graph);
bp = ops->walk_stack(tinfo, stack, bp, ops,
data, estack_end, &graph);
ops->stack(data, "<EOE>");
/*
* We link to the next stack via the
......
......@@ -53,17 +53,19 @@ save_stack_address_nosched(void *data, unsigned long addr, int reliable)
}
static const struct stacktrace_ops save_stack_ops = {
.warning = save_stack_warning,
.warning_symbol = save_stack_warning_symbol,
.stack = save_stack_stack,
.address = save_stack_address,
.warning = save_stack_warning,
.warning_symbol = save_stack_warning_symbol,
.stack = save_stack_stack,
.address = save_stack_address,
.walk_stack = print_context_stack,
};
static const struct stacktrace_ops save_stack_ops_nosched = {
.warning = save_stack_warning,
.warning_symbol = save_stack_warning_symbol,
.stack = save_stack_stack,
.address = save_stack_address_nosched,
.warning = save_stack_warning,
.warning_symbol = save_stack_warning_symbol,
.stack = save_stack_stack,
.address = save_stack_address_nosched,
.walk_stack = print_context_stack,
};
/*
......
......@@ -41,10 +41,11 @@ static void backtrace_address(void *data, unsigned long addr, int reliable)
}
static struct stacktrace_ops backtrace_ops = {
.warning = backtrace_warning,
.warning_symbol = backtrace_warning_symbol,
.stack = backtrace_stack,
.address = backtrace_address,
.warning = backtrace_warning,
.warning_symbol = backtrace_warning_symbol,
.stack = backtrace_stack,
.address = backtrace_address,
.walk_stack = print_context_stack,
};
struct frame_head {
......
This diff is collapsed.
......@@ -1381,6 +1381,9 @@ static void perf_ctx_adjust_freq(struct perf_event_context *ctx)
if (event->state != PERF_EVENT_STATE_ACTIVE)
continue;
if (event->cpu != -1 && event->cpu != smp_processor_id())
continue;
hwc = &event->hw;
interrupts = hwc->interrupts;
......@@ -3265,6 +3268,9 @@ static void perf_event_task_output(struct perf_event *event,
static int perf_event_task_match(struct perf_event *event)
{
if (event->cpu != -1 && event->cpu != smp_processor_id())
return 0;
if (event->attr.comm || event->attr.mmap || event->attr.task)
return 1;
......@@ -3290,12 +3296,11 @@ static void perf_event_task_event(struct perf_task_event *task_event)
rcu_read_lock();
cpuctx = &get_cpu_var(perf_cpu_context);
perf_event_task_ctx(&cpuctx->ctx, task_event);
put_cpu_var(perf_cpu_context);
if (!ctx)
ctx = rcu_dereference(task_event->task->perf_event_ctxp);
if (ctx)
perf_event_task_ctx(ctx, task_event);
put_cpu_var(perf_cpu_context);
rcu_read_unlock();
}
......@@ -3372,6 +3377,9 @@ static void perf_event_comm_output(struct perf_event *event,
static int perf_event_comm_match(struct perf_event *event)
{
if (event->cpu != -1 && event->cpu != smp_processor_id())
return 0;
if (event->attr.comm)
return 1;
......@@ -3408,15 +3416,10 @@ static void perf_event_comm_event(struct perf_comm_event *comm_event)
rcu_read_lock();
cpuctx = &get_cpu_var(perf_cpu_context);
perf_event_comm_ctx(&cpuctx->ctx, comm_event);
put_cpu_var(perf_cpu_context);
/*
* doesn't really matter which of the child contexts the
* events ends up in.
*/
ctx = rcu_dereference(current->perf_event_ctxp);
if (ctx)
perf_event_comm_ctx(ctx, comm_event);
put_cpu_var(perf_cpu_context);
rcu_read_unlock();
}
......@@ -3491,6 +3494,9 @@ static void perf_event_mmap_output(struct perf_event *event,
static int perf_event_mmap_match(struct perf_event *event,
struct perf_mmap_event *mmap_event)
{
if (event->cpu != -1 && event->cpu != smp_processor_id())
return 0;
if (event->attr.mmap)
return 1;
......@@ -3564,15 +3570,10 @@ got_name:
rcu_read_lock();
cpuctx = &get_cpu_var(perf_cpu_context);
perf_event_mmap_ctx(&cpuctx->ctx, mmap_event);
put_cpu_var(perf_cpu_context);
/*
* doesn't really matter which of the child contexts the
* events ends up in.
*/
ctx = rcu_dereference(current->perf_event_ctxp);
if (ctx)
perf_event_mmap_ctx(ctx, mmap_event);
put_cpu_var(perf_cpu_context);
rcu_read_unlock();
kfree(buf);
......@@ -3863,6 +3864,9 @@ static int perf_swevent_match(struct perf_event *event,
struct perf_sample_data *data,
struct pt_regs *regs)
{
if (event->cpu != -1 && event->cpu != smp_processor_id())
return 0;
if (!perf_swevent_is_counting(event))
return 0;
......
......@@ -282,6 +282,18 @@ static int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs);
static int kretprobe_dispatcher(struct kretprobe_instance *ri,
struct pt_regs *regs);
/* Check the name is good for event/group */
static int check_event_name(const char *name)
{
if (!isalpha(*name) && *name != '_')
return 0;
while (*++name != '\0') {
if (!isalpha(*name) && !isdigit(*name) && *name != '_')
return 0;
}
return 1;
}
/*
* Allocate new trace_probe and initialize it (including kprobes).
*/
......@@ -293,10 +305,11 @@ static struct trace_probe *alloc_trace_probe(const char *group,
int nargs, int is_return)
{
struct trace_probe *tp;
int ret = -ENOMEM;
tp = kzalloc(SIZEOF_TRACE_PROBE(nargs), GFP_KERNEL);
if (!tp)
return ERR_PTR(-ENOMEM);
return ERR_PTR(ret);
if (symbol) {
tp->symbol = kstrdup(symbol, GFP_KERNEL);
......@@ -312,14 +325,20 @@ static struct trace_probe *alloc_trace_probe(const char *group,
else
tp->rp.kp.pre_handler = kprobe_dispatcher;
if (!event)
if (!event || !check_event_name(event)) {
ret = -EINVAL;
goto error;
}
tp->call.name = kstrdup(event, GFP_KERNEL);
if (!tp->call.name)
goto error;
if (!group)
if (!group || !check_event_name(group)) {
ret = -EINVAL;
goto error;
}
tp->call.system = kstrdup(group, GFP_KERNEL);
if (!tp->call.system)
goto error;
......@@ -330,7 +349,7 @@ error:
kfree(tp->call.name);
kfree(tp->symbol);
kfree(tp);
return ERR_PTR(-ENOMEM);
return ERR_PTR(ret);
}
static void free_probe_arg(struct probe_arg *arg)
......@@ -695,10 +714,10 @@ static int create_trace_probe(int argc, char **argv)
if (!event) {
/* Make a new event name */
if (symbol)
snprintf(buf, MAX_EVENT_NAME_LEN, "%c@%s%+ld",
snprintf(buf, MAX_EVENT_NAME_LEN, "%c_%s_%ld",
is_return ? 'r' : 'p', symbol, offset);
else
snprintf(buf, MAX_EVENT_NAME_LEN, "%c@0x%p",
snprintf(buf, MAX_EVENT_NAME_LEN, "%c_0x%p",
is_return ? 'r' : 'p', addr);
event = buf;
}
......
......@@ -93,6 +93,7 @@ static const struct stacktrace_ops backtrace_ops = {
.warning_symbol = backtrace_warning_symbol,
.stack = backtrace_stack,
.address = backtrace_address,
.walk_stack = print_context_stack,
};
static int
......
......@@ -487,10 +487,11 @@ else
msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]);
endif
ifneq ($(shell sh -c "(echo '\#include <libdwarf/dwarf.h>'; echo '\#include <libdwarf/libdwarf.h>'; echo 'int main(void) { Dwarf_Debug dbg; Dwarf_Error err; Dwarf_Ranges *rng; dwarf_init(0, DW_DLC_READ, 0, 0, &dbg, &err); dwarf_get_ranges(dbg, 0, &rng, 0, 0, &err); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -ldwarf -lelf -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
ifneq ($(shell sh -c "(echo '\#ifndef _MIPS_SZLONG'; echo '\#define _MIPS_SZLONG 0'; echo '\#endif'; echo '\#include <dwarf.h>'; echo '\#include <libdwarf.h>'; echo 'int main(void) { Dwarf_Debug dbg; Dwarf_Error err; Dwarf_Ranges *rng; dwarf_init(0, DW_DLC_READ, 0, 0, &dbg, &err); dwarf_get_ranges(dbg, 0, &rng, 0, 0, &err); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/libdwarf -ldwarf -lelf -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
msg := $(warning No libdwarf.h found or old libdwarf.h found, disables dwarf support. Please install libdwarf-dev/libdwarf-devel >= 20081231);
BASIC_CFLAGS += -DNO_LIBDWARF
else
BASIC_CFLAGS += -I/usr/include/libdwarf
EXTLIBS += -lelf -ldwarf
LIB_OBJS += util/probe-finder.o
endif
......
......@@ -38,6 +38,7 @@
#include "util/strlist.h"
#include "util/event.h"
#include "util/debug.h"
#include "util/debugfs.h"
#include "util/symbol.h"
#include "util/thread.h"
#include "util/session.h"
......@@ -205,6 +206,9 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
if ((!session.nr_probe && !session.dellist && !session.list_events))
usage_with_options(probe_usage, options);
if (debugfs_valid_mountpoint(debugfs_path) < 0)
die("Failed to find debugfs path.");
if (session.list_events) {
if (session.nr_probe != 0 || session.dellist) {
pr_warning(" Error: Don't use --list with"
......
......@@ -224,7 +224,7 @@ static int __cmd_report(void)
perf_session__collapse_resort(session);
perf_session__output_resort(session, session->events_stats.total);
fprintf(stdout, "# Samples: %ld\n#\n", session->events_stats.total);
fprintf(stdout, "# Samples: %Ld\n#\n", session->events_stats.total);
perf_session__fprintf_hists(session, NULL, false, stdout);
if (sort_order == default_sort_order &&
parent_pattern == default_parent_pattern)
......
......@@ -95,8 +95,8 @@ typedef union event_union {
} event_t;
struct events_stats {
unsigned long total;
unsigned long lost;
u64 total;
u64 lost;
};
void event__print_totals(void);
......
......@@ -62,6 +62,18 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
return ret;
}
/* Check the name is good for event/group */
static bool check_event_name(const char *name)
{
if (!isalpha(*name) && *name != '_')
return false;
while (*++name != '\0') {
if (!isalpha(*name) && !isdigit(*name) && *name != '_')
return false;
}
return true;
}
/* Parse probepoint definition. */
static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
{
......@@ -82,6 +94,9 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
ptr = strchr(arg, ':');
if (ptr) /* Group name is not supported yet. */
semantic_error("Group name is not supported yet.");
if (!check_event_name(arg))
semantic_error("%s is bad for event name -it must "
"follow C symbol-naming rule.", arg);
pp->event = strdup(arg);
arg = tmp;
}
......
#ifndef _PROBE_FINDER_H
#define _PROBE_FINDER_H
#define MAX_PATH_LEN 256
#define MAX_PROBE_BUFFER 1024
#define MAX_PROBES 128
#define MAX_PATH_LEN 256
#define MAX_PROBE_BUFFER 1024
#define MAX_PROBES 128
static inline int is_c_varname(const char *name)
{
......@@ -12,48 +12,53 @@ static inline int is_c_varname(const char *name)
}
struct probe_point {
char *event; /* Event name */
char *group; /* Event group */
char *event; /* Event name */
char *group; /* Event group */
/* Inputs */
char *file; /* File name */
int line; /* Line number */
char *file; /* File name */
int line; /* Line number */
char *function; /* Function name */
int offset; /* Offset bytes */
char *function; /* Function name */
int offset; /* Offset bytes */
int nr_args; /* Number of arguments */
char **args; /* Arguments */
int nr_args; /* Number of arguments */
char **args; /* Arguments */
int retprobe; /* Return probe */
int retprobe; /* Return probe */
/* Output */
int found; /* Number of found probe points */
char *probes[MAX_PROBES]; /* Output buffers (will be allocated)*/
int found; /* Number of found probe points */
char *probes[MAX_PROBES]; /* Output buffers (will be allocated)*/
};
#ifndef NO_LIBDWARF
extern int find_probepoint(int fd, struct probe_point *pp);
#include <libdwarf/dwarf.h>
#include <libdwarf/libdwarf.h>
/* Workaround for undefined _MIPS_SZLONG bug in libdwarf.h: */
#ifndef _MIPS_SZLONG
# define _MIPS_SZLONG 0
#endif
#include <dwarf.h>
#include <libdwarf.h>
struct probe_finder {
struct probe_point *pp; /* Target probe point */
struct probe_point *pp; /* Target probe point */
/* For function searching */
Dwarf_Addr addr; /* Address */
Dwarf_Unsigned fno; /* File number */
Dwarf_Unsigned lno; /* Line number */
Dwarf_Off inl_offs; /* Inline offset */
Dwarf_Die cu_die; /* Current CU */
Dwarf_Addr addr; /* Address */
Dwarf_Unsigned fno; /* File number */
Dwarf_Unsigned lno; /* Line number */
Dwarf_Off inl_offs; /* Inline offset */
Dwarf_Die cu_die; /* Current CU */
/* For variable searching */
Dwarf_Addr cu_base; /* Current CU base address */
Dwarf_Locdesc fbloc; /* Location of Current Frame Base */
const char *var; /* Current variable name */
char *buf; /* Current output buffer */
int len; /* Length of output buffer */
Dwarf_Addr cu_base; /* Current CU base address */
Dwarf_Locdesc fbloc; /* Location of Current Frame Base */
const char *var; /* Current variable name */
char *buf; /* Current output buffer */
int len; /* Length of output buffer */
};
#endif /* NO_LIBDWARF */
......
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