Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 169810
b: refs/heads/master
c: dd1853c
h: refs/heads/master
v: v3
  • Loading branch information
Frederic Weisbecker authored and Ingo Molnar committed Nov 27, 2009
1 parent cbfb610 commit c1bfd84
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 79 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 5fa10b28e57f94a90535cfeafe89dcee9f47d540
refs/heads/master: dd1853c3f493f6d22d9e5390b192a07b73d2ac0a
35 changes: 15 additions & 20 deletions trunk/include/linux/hw_breakpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ struct perf_event_attr name = { \
.pinned = 1, \
};

static inline void hw_breakpoint_init(struct perf_event_attr *attr)
{
attr->type = PERF_TYPE_BREAKPOINT;
attr->size = sizeof(*attr);
attr->pinned = 1;
}

static inline unsigned long hw_breakpoint_addr(struct perf_event *bp)
{
return bp->attr.bp_addr;
Expand Down Expand Up @@ -59,19 +66,13 @@ modify_user_hw_breakpoint(struct perf_event *bp,
* Kernel breakpoints are not associated with any particular thread.
*/
extern struct perf_event *
register_wide_hw_breakpoint_cpu(unsigned long addr,
int len,
int type,
register_wide_hw_breakpoint_cpu(struct perf_event_attr *attr,
perf_callback_t triggered,
int cpu,
bool active);
int cpu);

extern struct perf_event **
register_wide_hw_breakpoint(unsigned long addr,
int len,
int type,
perf_callback_t triggered,
bool active);
register_wide_hw_breakpoint(struct perf_event_attr *attr,
perf_callback_t triggered);

extern int register_perf_hw_breakpoint(struct perf_event *bp);
extern int __register_perf_hw_breakpoint(struct perf_event *bp);
Expand Down Expand Up @@ -100,18 +101,12 @@ modify_user_hw_breakpoint(struct perf_event *bp,
perf_callback_t triggered,
struct task_struct *tsk) { return NULL; }
static inline struct perf_event *
register_wide_hw_breakpoint_cpu(unsigned long addr,
int len,
int type,
register_wide_hw_breakpoint_cpu(struct perf_event_attr *attr,
perf_callback_t triggered,
int cpu,
bool active) { return NULL; }
int cpu) { return NULL; }
static inline struct perf_event **
register_wide_hw_breakpoint(unsigned long addr,
int len,
int type,
perf_callback_t triggered,
bool active) { return NULL; }
register_wide_hw_breakpoint(struct perf_event_attr *attr,
perf_callback_t triggered) { return NULL; }
static inline int
register_perf_hw_breakpoint(struct perf_event *bp) { return -ENOSYS; }
static inline int
Expand Down
35 changes: 4 additions & 31 deletions trunk/kernel/hw_breakpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -339,42 +339,16 @@ void unregister_hw_breakpoint(struct perf_event *bp)
}
EXPORT_SYMBOL_GPL(unregister_hw_breakpoint);

static struct perf_event *
register_kernel_hw_breakpoint_cpu(unsigned long addr,
int len,
int type,
perf_callback_t triggered,
int cpu,
bool active)
{
DEFINE_BREAKPOINT_ATTR(attr);

attr.bp_addr = addr;
attr.bp_len = len;
attr.bp_type = type;

if (!active)
attr.disabled = 1;

return perf_event_create_kernel_counter(&attr, cpu, -1, triggered);
}

/**
* register_wide_hw_breakpoint - register a wide breakpoint in the kernel
* @addr: is the memory address that triggers the breakpoint
* @len: the length of the access to the memory (1 byte, 2 bytes etc...)
* @type: the type of the access to the memory (read/write/exec)
* @attr: breakpoint attributes
* @triggered: callback to trigger when we hit the breakpoint
* @active: should we activate it while registering it
*
* @return a set of per_cpu pointers to perf events
*/
struct perf_event **
register_wide_hw_breakpoint(unsigned long addr,
int len,
int type,
perf_callback_t triggered,
bool active)
register_wide_hw_breakpoint(struct perf_event_attr *attr,
perf_callback_t triggered)
{
struct perf_event **cpu_events, **pevent, *bp;
long err;
Expand All @@ -386,8 +360,7 @@ register_wide_hw_breakpoint(unsigned long addr,

for_each_possible_cpu(cpu) {
pevent = per_cpu_ptr(cpu_events, cpu);
bp = register_kernel_hw_breakpoint_cpu(addr, len, type,
triggered, cpu, active);
bp = perf_event_create_kernel_counter(attr, cpu, -1, triggered);

*pevent = bp;

Expand Down
42 changes: 20 additions & 22 deletions trunk/kernel/trace/trace_ksym.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,7 @@

struct trace_ksym {
struct perf_event **ksym_hbp;
unsigned long ksym_addr;
int type;
int len;
struct perf_event_attr attr;
#ifdef CONFIG_PROFILE_KSYM_TRACER
unsigned long counter;
#endif
Expand All @@ -71,7 +69,7 @@ void ksym_collect_stats(unsigned long hbp_hit_addr)

rcu_read_lock();
hlist_for_each_entry_rcu(entry, node, &ksym_filter_head, ksym_hlist) {
if ((entry->ksym_addr == hbp_hit_addr) &&
if ((entry->attr.bp_addr == hbp_hit_addr) &&
(entry->counter <= MAX_UL_INT)) {
entry->counter++;
break;
Expand Down Expand Up @@ -192,14 +190,15 @@ int process_new_ksym_entry(char *ksymname, int op, unsigned long addr)
if (!entry)
return -ENOMEM;

entry->type = op;
entry->ksym_addr = addr;
entry->len = HW_BREAKPOINT_LEN_4;
hw_breakpoint_init(&entry->attr);

entry->attr.bp_type = op;
entry->attr.bp_addr = addr;
entry->attr.bp_len = HW_BREAKPOINT_LEN_4;

ret = -EAGAIN;
entry->ksym_hbp = register_wide_hw_breakpoint(entry->ksym_addr,
entry->len, entry->type,
ksym_hbp_handler, true);
entry->ksym_hbp = register_wide_hw_breakpoint(&entry->attr,
ksym_hbp_handler);

if (IS_ERR(entry->ksym_hbp)) {
ret = PTR_ERR(entry->ksym_hbp);
Expand Down Expand Up @@ -236,12 +235,12 @@ static ssize_t ksym_trace_filter_read(struct file *filp, char __user *ubuf,
mutex_lock(&ksym_tracer_mutex);

hlist_for_each_entry(entry, node, &ksym_filter_head, ksym_hlist) {
ret = trace_seq_printf(s, "%pS:", (void *)entry->ksym_addr);
if (entry->type == HW_BREAKPOINT_R)
ret = trace_seq_printf(s, "%pS:", (void *)entry->attr.bp_addr);
if (entry->attr.bp_type == HW_BREAKPOINT_R)
ret = trace_seq_puts(s, "r--\n");
else if (entry->type == HW_BREAKPOINT_W)
else if (entry->attr.bp_type == HW_BREAKPOINT_W)
ret = trace_seq_puts(s, "-w-\n");
else if (entry->type == (HW_BREAKPOINT_W | HW_BREAKPOINT_R))
else if (entry->attr.bp_type == (HW_BREAKPOINT_W | HW_BREAKPOINT_R))
ret = trace_seq_puts(s, "rw-\n");
WARN_ON_ONCE(!ret);
}
Expand Down Expand Up @@ -317,9 +316,9 @@ static ssize_t ksym_trace_filter_write(struct file *file,

ret = -EINVAL;
hlist_for_each_entry(entry, node, &ksym_filter_head, ksym_hlist) {
if (entry->ksym_addr == ksym_addr) {
if (entry->attr.bp_addr == ksym_addr) {
/* Check for malformed request: (6) */
if (entry->type != op)
if (entry->attr.bp_type != op)
changed = 1;
else
goto out;
Expand All @@ -328,13 +327,12 @@ static ssize_t ksym_trace_filter_write(struct file *file,
}
if (changed) {
unregister_wide_hw_breakpoint(entry->ksym_hbp);
entry->type = op;
entry->attr.bp_type = op;
ret = 0;
if (op > 0) {
entry->ksym_hbp =
register_wide_hw_breakpoint(entry->ksym_addr,
entry->len, entry->type,
ksym_hbp_handler, true);
register_wide_hw_breakpoint(&entry->attr,
ksym_hbp_handler);
if (IS_ERR(entry->ksym_hbp))
ret = PTR_ERR(entry->ksym_hbp);
else
Expand Down Expand Up @@ -489,7 +487,7 @@ static int ksym_tracer_stat_show(struct seq_file *m, void *v)

entry = hlist_entry(stat, struct trace_ksym, ksym_hlist);

access_type = entry->type;
access_type = entry->attr.bp_type;

switch (access_type) {
case HW_BREAKPOINT_R:
Expand All @@ -505,7 +503,7 @@ static int ksym_tracer_stat_show(struct seq_file *m, void *v)
seq_puts(m, " NA ");
}

if (lookup_symbol_name(entry->ksym_addr, fn_name) >= 0)
if (lookup_symbol_name(entry->attr.bp_addr, fn_name) >= 0)
seq_printf(m, " %-36s", fn_name);
else
seq_printf(m, " %-36s", "<NA>");
Expand Down
10 changes: 5 additions & 5 deletions trunk/samples/hw_breakpoint/data_breakpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@ static void sample_hbp_handler(struct perf_event *temp, void *data)
static int __init hw_break_module_init(void)
{
int ret;
unsigned long addr;
DEFINE_BREAKPOINT_ATTR(attr);

addr = kallsyms_lookup_name(ksym_name);
attr.bp_addr = kallsyms_lookup_name(ksym_name);
attr.bp_len = HW_BREAKPOINT_LEN_4;
attr.bp_type = HW_BREAKPOINT_W | HW_BREAKPOINT_R;

sample_hbp = register_wide_hw_breakpoint(addr, HW_BREAKPOINT_LEN_4,
HW_BREAKPOINT_W | HW_BREAKPOINT_R,
sample_hbp_handler, true);
sample_hbp = register_wide_hw_breakpoint(&attr, sample_hbp_handler);
if (IS_ERR(sample_hbp)) {
ret = PTR_ERR(sample_hbp);
goto fail;
Expand Down

0 comments on commit c1bfd84

Please sign in to comment.