Skip to content

Commit

Permalink
hw-breakpoints: Rewrite the hw-breakpoints layer on top of perf events
Browse files Browse the repository at this point in the history
This patch rebase the implementation of the breakpoints API on top of
perf events instances.

Each breakpoints are now perf events that handle the
register scheduling, thread/cpu attachment, etc..

The new layering is now made as follows:

       ptrace       kgdb      ftrace   perf syscall
          \          |          /         /
           \         |         /         /
                                        /
            Core breakpoint API        /
                                      /
                     |               /
                     |              /

              Breakpoints perf events

                     |
                     |

               Breakpoints PMU ---- Debug Register constraints handling
                                    (Part of core breakpoint API)
                     |
                     |

             Hardware debug registers

Reasons of this rewrite:

- Use the centralized/optimized pmu registers scheduling,
  implying an easier arch integration
- More powerful register handling: perf attributes (pinned/flexible
  events, exclusive/non-exclusive, tunable period, etc...)

Impact:

- New perf ABI: the hardware breakpoints counters
- Ptrace breakpoints setting remains tricky and still needs some per
  thread breakpoints references.

Todo (in the order):

- Support breakpoints perf counter events for perf tools (ie: implement
  perf_bpcounter_event())
- Support from perf tools

Changes in v2:

- Follow the perf "event " rename
- The ptrace regression have been fixed (ptrace breakpoint perf events
  weren't released when a task ended)
- Drop the struct hw_breakpoint and store generic fields in
  perf_event_attr.
- Separate core and arch specific headers, drop
  asm-generic/hw_breakpoint.h and create linux/hw_breakpoint.h
- Use new generic len/type for breakpoint
- Handle off case: when breakpoints api is not supported by an arch

Changes in v3:

- Fix broken CONFIG_KVM, we need to propagate the breakpoint api
  changes to kvm when we exit the guest and restore the bp registers
  to the host.

Changes in v4:

- Drop the hw_breakpoint_restore() stub as it is only used by KVM
- EXPORT_SYMBOL_GPL hw_breakpoint_restore() as KVM can be built as a
  module
- Restore the breakpoints unconditionally on kvm guest exit:
  TIF_DEBUG_THREAD doesn't anymore cover every cases of running
  breakpoints and vcpu->arch.switch_db_regs might not always be
  set when the guest used debug registers.
  (Waiting for a reliable optimization)

Changes in v5:

- Split-up the asm-generic/hw-breakpoint.h moving to
  linux/hw_breakpoint.h into a separate patch
- Optimize the breakpoints restoring while switching from kvm guest
  to host. We only want to restore the state if we have active
  breakpoints to the host, otherwise we don't care about messed-up
  address registers.
- Add asm/hw_breakpoint.h to Kbuild
- Fix bad breakpoint type in trace_selftest.c

Changes in v6:

- Fix wrong header inclusion in trace.h (triggered a build
  error with CONFIG_FTRACE_SELFTEST

Signed-off-by: Frederic Weisbecker <[email protected]>
Cc: Prasad <[email protected]>
Cc: Alan Stern <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: Steven Rostedt <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jan Kiszka <[email protected]>
Cc: Jiri Slaby <[email protected]>
Cc: Li Zefan <[email protected]>
Cc: Avi Kivity <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Masami Hiramatsu <[email protected]>
Cc: Paul Mundt <[email protected]>
  • Loading branch information
fweisbec committed Nov 8, 2009
1 parent 2da3e16 commit 24f1e32
Show file tree
Hide file tree
Showing 22 changed files with 885 additions and 750 deletions.
3 changes: 3 additions & 0 deletions arch/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ config HAVE_DEFAULT_NO_SPIN_MUTEXES

config HAVE_HW_BREAKPOINT
bool
depends on HAVE_PERF_EVENTS
select ANON_INODES
select PERF_EVENTS


source "kernel/gcov/Kconfig"
1 change: 1 addition & 0 deletions arch/x86/include/asm/Kbuild
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ header-y += ptrace-abi.h
header-y += sigcontext32.h
header-y += ucontext.h
header-y += processor-flags.h
header-y += hw_breakpoint.h

unifdef-y += e820.h
unifdef-y += ist.h
Expand Down
11 changes: 5 additions & 6 deletions arch/x86/include/asm/debugreg.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,8 @@
*/
#ifdef __KERNEL__

/* For process management */
extern void flush_thread_hw_breakpoint(struct task_struct *tsk);
extern int copy_thread_hw_breakpoint(struct task_struct *tsk,
struct task_struct *child, unsigned long clone_flags);
DECLARE_PER_CPU(unsigned long, dr7);

/* For CPU management */
extern void load_debug_registers(void);
static inline void hw_breakpoint_disable(void)
{
/* Zero the control register for HW Breakpoint */
Expand All @@ -94,6 +89,10 @@ static inline void hw_breakpoint_disable(void)
set_debugreg(0UL, 3);
}

#ifdef CONFIG_KVM
extern void hw_breakpoint_restore(void);
#endif

#endif /* __KERNEL__ */

#endif /* _ASM_X86_DEBUGREG_H */
58 changes: 38 additions & 20 deletions arch/x86/include/asm/hw_breakpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
#ifdef __KERNEL__
#define __ARCH_HW_BREAKPOINT_H

/*
* The name should probably be something dealt in
* a higher level. While dealing with the user
* (display/resolving)
*/
struct arch_hw_breakpoint {
char *name; /* Contains name of the symbol to set bkpt */
unsigned long address;
Expand All @@ -12,44 +17,57 @@ struct arch_hw_breakpoint {
};

#include <linux/kdebug.h>
#include <linux/hw_breakpoint.h>
#include <linux/percpu.h>
#include <linux/list.h>

/* Available HW breakpoint length encodings */
#define HW_BREAKPOINT_LEN_1 0x40
#define HW_BREAKPOINT_LEN_2 0x44
#define HW_BREAKPOINT_LEN_4 0x4c
#define HW_BREAKPOINT_LEN_EXECUTE 0x40
#define X86_BREAKPOINT_LEN_1 0x40
#define X86_BREAKPOINT_LEN_2 0x44
#define X86_BREAKPOINT_LEN_4 0x4c
#define X86_BREAKPOINT_LEN_EXECUTE 0x40

#ifdef CONFIG_X86_64
#define HW_BREAKPOINT_LEN_8 0x48
#define X86_BREAKPOINT_LEN_8 0x48
#endif

/* Available HW breakpoint type encodings */

/* trigger on instruction execute */
#define HW_BREAKPOINT_EXECUTE 0x80
#define X86_BREAKPOINT_EXECUTE 0x80
/* trigger on memory write */
#define HW_BREAKPOINT_WRITE 0x81
#define X86_BREAKPOINT_WRITE 0x81
/* trigger on memory read or write */
#define HW_BREAKPOINT_RW 0x83
#define X86_BREAKPOINT_RW 0x83

/* Total number of available HW breakpoint registers */
#define HBP_NUM 4

extern struct hw_breakpoint *hbp_kernel[HBP_NUM];
DECLARE_PER_CPU(struct hw_breakpoint*, this_hbp_kernel[HBP_NUM]);
extern unsigned int hbp_user_refcount[HBP_NUM];
struct perf_event;
struct pmu;

extern void arch_install_thread_hw_breakpoint(struct task_struct *tsk);
extern void arch_uninstall_thread_hw_breakpoint(void);
extern int arch_check_va_in_userspace(unsigned long va, u8 hbp_len);
extern int arch_validate_hwbkpt_settings(struct hw_breakpoint *bp,
struct task_struct *tsk);
extern void arch_update_user_hw_breakpoint(int pos, struct task_struct *tsk);
extern void arch_flush_thread_hw_breakpoint(struct task_struct *tsk);
extern void arch_update_kernel_hw_breakpoint(void *);
extern int arch_validate_hwbkpt_settings(struct perf_event *bp,
struct task_struct *tsk);
extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
unsigned long val, void *data);
unsigned long val, void *data);


int arch_install_hw_breakpoint(struct perf_event *bp);
void arch_uninstall_hw_breakpoint(struct perf_event *bp);
void hw_breakpoint_pmu_read(struct perf_event *bp);
void hw_breakpoint_pmu_unthrottle(struct perf_event *bp);

extern void
arch_fill_perf_breakpoint(struct perf_event *bp);

unsigned long encode_dr7(int drnum, unsigned int len, unsigned int type);
int decode_dr7(unsigned long dr7, int bpnum, unsigned *len, unsigned *type);

extern int arch_bp_generic_fields(int x86_len, int x86_type,
int *gen_len, int *gen_type);

extern struct pmu perf_ops_bp;

#endif /* __KERNEL__ */
#endif /* _I386_HW_BREAKPOINT_H */

12 changes: 6 additions & 6 deletions arch/x86/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,8 @@ extern unsigned int xstate_size;
extern void free_thread_xstate(struct task_struct *);
extern struct kmem_cache *task_xstate_cachep;

struct perf_event;

struct thread_struct {
/* Cached TLS descriptors: */
struct desc_struct tls_array[GDT_ENTRY_TLS_ENTRIES];
Expand All @@ -444,12 +446,10 @@ struct thread_struct {
unsigned long fs;
#endif
unsigned long gs;
/* Hardware debugging registers: */
unsigned long debugreg[HBP_NUM];
unsigned long debugreg6;
unsigned long debugreg7;
/* Hardware breakpoint info */
struct hw_breakpoint *hbp[HBP_NUM];
/* Save middle states of ptrace breakpoints */
struct perf_event *ptrace_bps[HBP_NUM];
/* Debug status used for traps, single steps, etc... */
unsigned long debugreg6;
/* Fault info: */
unsigned long cr2;
unsigned long trap_no;
Expand Down
Loading

0 comments on commit 24f1e32

Please sign in to comment.