diff options
author | Frederic Weisbecker <fweisbec@gmail.com> | 2009-11-26 22:55:53 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-11-27 00:22:58 -0500 |
commit | 5fa10b28e57f94a90535cfeafe89dcee9f47d540 (patch) | |
tree | 951cf12a3b5b3a37546b4f6dd2994bebdac19dc0 /kernel/hw_breakpoint.c | |
parent | b2e74a265ded1a185f762ebaab967e9e0d008dd8 (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.c | 87 |
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 | */ | ||
298 | static struct perf_event * | ||
299 | register_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 | */ |
345 | struct perf_event * | 298 | struct perf_event * |
346 | register_user_hw_breakpoint(unsigned long addr, | 299 | register_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 | } |
356 | EXPORT_SYMBOL_GPL(register_user_hw_breakpoint); | 305 | EXPORT_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 | */ |
368 | struct perf_event * | 314 | struct perf_event * |
369 | modify_user_hw_breakpoint(struct perf_event *bp, | 315 | modify_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 | } |
387 | EXPORT_SYMBOL_GPL(modify_user_hw_breakpoint); | 328 | EXPORT_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 | /** |