aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/hw_breakpoint.c
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2009-11-26 22:55:53 -0500
committerIngo Molnar <mingo@elte.hu>2009-11-27 00:22:58 -0500
commit5fa10b28e57f94a90535cfeafe89dcee9f47d540 (patch)
tree951cf12a3b5b3a37546b4f6dd2994bebdac19dc0 /kernel/hw_breakpoint.c
parentb2e74a265ded1a185f762ebaab967e9e0d008dd8 (diff)
hw-breakpoints: Use struct perf_event_attr to define user breakpoints
In-kernel user breakpoints are created using functions in which we pass breakpoint parameters as individual variables: address, length and type. Although it fits well for x86, this just does not scale across archictectures that may support this api later as these may have more or different needs. Pass in a perf_event_attr structure instead because it is meant to evolve as much as possible into a generic hardware breakpoint parameter structure. Reported-by: K.Prasad <prasad@linux.vnet.ibm.com> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> LKML-Reference: <1259294154-5197-1-git-send-regression-fweisbec@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/hw_breakpoint.c')
-rw-r--r--kernel/hw_breakpoint.c87
1 files changed, 18 insertions, 69 deletions
diff --git a/kernel/hw_breakpoint.c b/kernel/hw_breakpoint.c
index 32e1018191be..2a47514f12fd 100644
--- a/kernel/hw_breakpoint.c
+++ b/kernel/hw_breakpoint.c
@@ -289,90 +289,32 @@ int register_perf_hw_breakpoint(struct perf_event *bp)
289 return __register_perf_hw_breakpoint(bp); 289 return __register_perf_hw_breakpoint(bp);
290} 290}
291 291
292/*
293 * Register a breakpoint bound to a task and a given cpu.
294 * If cpu is -1, the breakpoint is active for the task in every cpu
295 * If the task is -1, the breakpoint is active for every tasks in the given
296 * cpu.
297 */
298static struct perf_event *
299register_user_hw_breakpoint_cpu(unsigned long addr,
300 int len,
301 int type,
302 perf_callback_t triggered,
303 pid_t pid,
304 int cpu,
305 bool active)
306{
307 struct perf_event_attr *attr;
308 struct perf_event *bp;
309
310 attr = kzalloc(sizeof(*attr), GFP_KERNEL);
311 if (!attr)
312 return ERR_PTR(-ENOMEM);
313
314 attr->type = PERF_TYPE_BREAKPOINT;
315 attr->size = sizeof(*attr);
316 attr->bp_addr = addr;
317 attr->bp_len = len;
318 attr->bp_type = type;
319 /*
320 * Such breakpoints are used by debuggers to trigger signals when
321 * we hit the excepted memory op. We can't miss such events, they
322 * must be pinned.
323 */
324 attr->pinned = 1;
325
326 if (!active)
327 attr->disabled = 1;
328
329 bp = perf_event_create_kernel_counter(attr, cpu, pid, triggered);
330 kfree(attr);
331
332 return bp;
333}
334
335/** 292/**
336 * register_user_hw_breakpoint - register a hardware breakpoint for user space 293 * register_user_hw_breakpoint - register a hardware breakpoint for user space
337 * @addr: is the memory address that triggers the breakpoint 294 * @attr: breakpoint attributes
338 * @len: the length of the access to the memory (1 byte, 2 bytes etc...)
339 * @type: the type of the access to the memory (read/write/exec)
340 * @triggered: callback to trigger when we hit the breakpoint 295 * @triggered: callback to trigger when we hit the breakpoint
341 * @tsk: pointer to 'task_struct' of the process to which the address belongs 296 * @tsk: pointer to 'task_struct' of the process to which the address belongs
342 * @active: should we activate it while registering it
343 *
344 */ 297 */
345struct perf_event * 298struct perf_event *
346register_user_hw_breakpoint(unsigned long addr, 299register_user_hw_breakpoint(struct perf_event_attr *attr,
347 int len,
348 int type,
349 perf_callback_t triggered, 300 perf_callback_t triggered,
350 struct task_struct *tsk, 301 struct task_struct *tsk)
351 bool active)
352{ 302{
353 return register_user_hw_breakpoint_cpu(addr, len, type, triggered, 303 return perf_event_create_kernel_counter(attr, -1, tsk->pid, triggered);
354 tsk->pid, -1, active);
355} 304}
356EXPORT_SYMBOL_GPL(register_user_hw_breakpoint); 305EXPORT_SYMBOL_GPL(register_user_hw_breakpoint);
357 306
358/** 307/**
359 * modify_user_hw_breakpoint - modify a user-space hardware breakpoint 308 * modify_user_hw_breakpoint - modify a user-space hardware breakpoint
360 * @bp: the breakpoint structure to modify 309 * @bp: the breakpoint structure to modify
361 * @addr: is the memory address that triggers the breakpoint 310 * @attr: new breakpoint attributes
362 * @len: the length of the access to the memory (1 byte, 2 bytes etc...)
363 * @type: the type of the access to the memory (read/write/exec)
364 * @triggered: callback to trigger when we hit the breakpoint 311 * @triggered: callback to trigger when we hit the breakpoint
365 * @tsk: pointer to 'task_struct' of the process to which the address belongs 312 * @tsk: pointer to 'task_struct' of the process to which the address belongs
366 * @active: should we activate it while registering it
367 */ 313 */
368struct perf_event * 314struct perf_event *
369modify_user_hw_breakpoint(struct perf_event *bp, 315modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *attr,
370 unsigned long addr,
371 int len,
372 int type,
373 perf_callback_t triggered, 316 perf_callback_t triggered,
374 struct task_struct *tsk, 317 struct task_struct *tsk)
375 bool active)
376{ 318{
377 /* 319 /*
378 * FIXME: do it without unregistering 320 * FIXME: do it without unregistering
@@ -381,8 +323,7 @@ modify_user_hw_breakpoint(struct perf_event *bp,
381 */ 323 */
382 unregister_hw_breakpoint(bp); 324 unregister_hw_breakpoint(bp);
383 325
384 return register_user_hw_breakpoint(addr, len, type, triggered, 326 return perf_event_create_kernel_counter(attr, -1, tsk->pid, triggered);
385 tsk, active);
386} 327}
387EXPORT_SYMBOL_GPL(modify_user_hw_breakpoint); 328EXPORT_SYMBOL_GPL(modify_user_hw_breakpoint);
388 329
@@ -406,8 +347,16 @@ register_kernel_hw_breakpoint_cpu(unsigned long addr,
406 int cpu, 347 int cpu,
407 bool active) 348 bool active)
408{ 349{
409 return register_user_hw_breakpoint_cpu(addr, len, type, triggered, 350 DEFINE_BREAKPOINT_ATTR(attr);
410 -1, cpu, active); 351
352 attr.bp_addr = addr;
353 attr.bp_len = len;
354 attr.bp_type = type;
355
356 if (!active)
357 attr.disabled = 1;
358
359 return perf_event_create_kernel_counter(&attr, cpu, -1, triggered);
411} 360}
412 361
413/** 362/**