x86, ptrace: PEBS support
Subsystems (2)
PATCH 1/1 x86, ptrace: PEBS support
This is meant to update the previous version of this patch with commit number ae452ae05c96d0924d163831f5681babaf2dd0fd on x86.git.
It adds a few bugfixes that were detected during the perfmon2 adaptation.
---
Polish the ds.h interface and add support for PEBS.
Ds.c is meant to be the resource allocator for per-thread and per-cpu BTS and PEBS recording.
It is used by ptrace/utrace to provide execution tracing of debugged tasks. It will be used by profilers (e.g. perfmon2).
It may be used by kernel debuggers to provide a kernel execution trace.
Changes in detail:
- guard DS and ptrace by CONFIG macros
- separate DS and BTS more clearly
- simplify field accesses
- add functions to manage PEBS buffers
- add simple protection/allocation mechanism
- added support for Atom
Opens:
- buffer overflow handling
Currently, only circular buffers are supported. This is all we need for debugging. Profilers would want an overflow notification. This is planned to be added when perfmon2 is made to use the ds.h interface.
- utrace intermediate layer
---
arch/x86/Kconfig.cpu +18 -0
@@ -411,3 +411,21 @@ config X86_MINIMUM_CPU_FAMILY config X86_DEBUGCTLMSR def_bool y depends on !(M586MMX || M586TSC || M586 || M486 || M386) + +config X86_DS + bool "Debug Store support" + default y + help + Add support for Debug Store. + This allows the kernel to provide a memory buffer to the hardware + to store various profiling and tracing events. + +config X86_PTRACE_BTS + bool "ptrace interface to Branch Trace Store" + default y + depends on (X86_DS && X86_DEBUGCTLMSR) + help + Add a ptrace interface to allow collecting an execution trace + of the traced task. + This collects control flow changes in a (cyclic) buffer and allows + debuggers to fill in the gaps and show an execution trace of the debuggee.
arch/x86/kernel/cpu/intel.c +2 -1
@@ -222,10 +222,11 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c)set_cpu_cap (c,X86_FEATURE_BTS );if (!(l1 & (1 <<12 )))set_cpu_cap (c,X86_FEATURE_PEBS ); +ds_init_intel (c); }if (cpu_has_bts) -ds_init_intel (c); +ptrace_bts_init_intel (c); }static unsigned int __cpuinit intel_size_cache (struct cpuinfo_x86 *c,unsigned int size)
arch/x86/kernel/ds.c +718 -277
1,152 lines not on this page · raw message
arch/x86/kernel/process_32.c +31 -4
@@ -426,6 +426,14 @@ void exit_thread(void) tss->x86_tss.io_bitmap_base =INVALID_IO_BITMAP_OFFSET ;put_cpu (); } +#ifdef CONFIG_X86_DS +/* Free any DS contexts that have not been properly released. */ +if (unlikely (current->thread.ds_ctx)) { +/* we clear debugctl to make sure DS is not used. */ +update_debugctlmsr (0 ); +ds_free (current->thread.ds_ctx); + } +#endif /* CONFIG_X86_DS */ }void flush_thread (void )
@@ -451,6 +459,16 @@ void release_thread(struct task_struct *dead_task) {BUG_ON (dead_task->mm);release_vm86_irqs (dead_task); + +#ifdef CONFIG_X86_DS +/* Free any DS contexts that have not been properly released. */ +if (unlikely (dead_task->thread.ds_ctx)) { +/* we clear debugctl to make sure DS is not used. */ +if (dead_task == current) +update_debugctlmsr (0 ); +ds_free (dead_task->thread.ds_ctx); + } +#endif /* CONFIG_X86_DS */ }/*
@@ -592,18 +610,27 @@ __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p, {struct thread_struct *prev, *next;unsigned long debugctl; +unsigned long ds_prev =0 , ds_next =0 ; prev = &prev_p->thread; next = &next_p->thread; debugctl = prev->debugctlmsr; -if (next->ds_area_msr != prev->ds_area_msr) { + +#ifdef CONFIG_X86_DS +if (prev->ds_ctx) + ds_prev = (unsigned long )prev->ds_ctx->ds; +if (next->ds_ctx) + ds_next = (unsigned long )next->ds_ctx->ds; + +if (ds_next != ds_prev) {/* we clear debugctl to make sure DS * is not in use when we change it */ debugctl =0 ;update_debugctlmsr (0 ); -wrmsr (MSR_IA32_DS_AREA , next->ds_area_msr,0 ); +wrmsr (MSR_IA32_DS_AREA , ds_next,0 ); } +#endif /* CONFIG_X86_DS */ if (next->debugctlmsr != debugctl)update_debugctlmsr (next->debugctlmsr);
@@ -627,13 +654,13 @@ __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,hard_enable_TSC (); } -#ifdef X86_BTS +#ifdef CONFIG_X86_PTRACE_BTS if (test_tsk_thread_flag (prev_p,TIF_BTS_TRACE_TS ))ptrace_bts_take_timestamp (prev_p,BTS_TASK_DEPARTS );if (test_tsk_thread_flag (next_p,TIF_BTS_TRACE_TS ))ptrace_bts_take_timestamp (next_p,BTS_TASK_ARRIVES ); -#endif +#endif /* CONFIG_X86_PTRACE_BTS */ if (!test_tsk_thread_flag (next_p,TIF_IO_BITMAP )) {
arch/x86/kernel/process_64.c +21 -4
@@ -400,6 +400,14 @@ void exit_thread(void) t->io_bitmap_max =0 ;put_cpu (); } +#ifdef CONFIG_X86_DS +/* Free any DS contexts that have not been properly released. */ +if (unlikely (t->ds_ctx)) { +/* we clear debugctl to make sure DS is not used. */ +update_debugctlmsr (0 ); +ds_free (t->ds_ctx); + } +#endif /* CONFIG_X86_DS */ }void flush_thread (void )
@@ -625,18 +633,27 @@ static inline void __switch_to_xtra(struct task_struct *prev_p, {struct thread_struct *prev, *next;unsigned long debugctl; +unsigned long ds_prev =0 , ds_next =0 ; prev = &prev_p->thread, next = &next_p->thread; debugctl = prev->debugctlmsr; -if (next->ds_area_msr != prev->ds_area_msr) { + +#ifdef CONFIG_X86_DS +if (prev->ds_ctx) + ds_prev = (unsigned long )prev->ds_ctx->ds; +if (next->ds_ctx) + ds_next = (unsigned long )next->ds_ctx->ds; + +if (ds_next != ds_prev) {/* we clear debugctl to make sure DS * is not in use when we change it */ debugctl =0 ;update_debugctlmsr (0 ); -wrmsrl (MSR_IA32_DS_AREA , next->ds_area_msr); +wrmsrl (MSR_IA32_DS_AREA , ds_next); } +#endif /* CONFIG_X86_DS */ if (next->debugctlmsr != debugctl)update_debugctlmsr (next->debugctlmsr);
@@ -674,13 +691,13 @@ static inline void __switch_to_xtra(struct task_struct *prev_p,memset (tss->io_bitmap,0xff , prev->io_bitmap_max); } -#ifdef X86_BTS +#ifdef CONFIG_X86_PTRACE_BTS if (test_tsk_thread_flag (prev_p,TIF_BTS_TRACE_TS ))ptrace_bts_take_timestamp (prev_p,BTS_TASK_DEPARTS );if (test_tsk_thread_flag (next_p,TIF_BTS_TRACE_TS ))ptrace_bts_take_timestamp (next_p,BTS_TASK_ARRIVES ); -#endif +#endif /* CONFIG_X86_PTRACE_BTS */ }/*
arch/x86/kernel/ptrace.c +274 -177
612 lines not on this page · raw message
arch/x86/kernel/setup_64.c +2 -1
@@ -906,11 +906,12 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c)set_cpu_cap (c,X86_FEATURE_BTS );if (!(l1 & (1 <<12 )))set_cpu_cap (c,X86_FEATURE_PEBS ); +ds_init_intel (c); }if (cpu_has_bts) -ds_init_intel (c); +ptrace_bts_init_intel (c); n = c->extended_cpuid_level;if (n >=0x80000008 ) {
include/asm-x86/ds.h +212 -46
283 lines not on this page · raw message
include/asm-x86/processor.h +9 -3
@@ -23,6 +23,7 @@ struct mm_struct;#include <asm/msr.h> #include <asm/desc_defs.h> #include <asm/nops.h> +#include <asm/ds.h> #include <linux/personality.h> #include <linux/cpumask.h>
@@ -419,9 +420,14 @@ struct thread_struct {unsigned io_bitmap_max;/* MSR_IA32_DEBUGCTLMSR value to switch in if TIF_DEBUGCTLMSR is set. */ unsigned long debugctlmsr; -/* Debug Store - if not 0 points to a DS Save Area configuration; -* goes into MSR_IA32_DS_AREA */ -unsigned long ds_area_msr; +#ifdef CONFIG_X86_DS +/* Debug Store context; see include/asm-x86/ds.h; goes into MSR_IA32_DS_AREA */ +struct ds_context *ds_ctx; +#endif /* CONFIG_X86_DS */ +#ifdef CONFIG_X86_PTRACE_BTS +/* the signal to send on a bts buffer overflow */ +unsigned int bts_ovfl_signal; +#endif /* CONFIG_X86_PTRACE_BTS */ };static inline unsigned long native_get_debugreg (int regno)
include/asm-x86/ptrace-abi.h +8 -6
@@ -80,8 +80,9 @@#define PTRACE_SINGLEBLOCK 33/* resume execution until next branch */ -#ifndef __ASSEMBLY__ +#ifdef CONFIG_X86_PTRACE_BTS +#ifndef __ASSEMBLY__#include <asm/types.h> /* configuration/status structure used in PTRACE_BTS_CONFIG and
@@ -97,20 +98,20 @@ struct ptrace_bts_config {/* actual size of bts_struct in bytes */ __u32 bts_size; }; -#endif +#endif /* __ASSEMBLY__ */ #define PTRACE_BTS_O_TRACE 0x1/* branch trace */ #define PTRACE_BTS_O_SCHED 0x2/* scheduling events w/ jiffies */ #define PTRACE_BTS_O_SIGNAL 0x4/* send SIG<signal> on buffer overflow instead of wrapping around */ -#define PTRACE_BTS_O_CUT_SIZE 0x8/* cut requested size to max available -instead of failing */ +#define PTRACE_BTS_O_ALLOC 0x8/* (re)allocate buffer */ #define PTRACE_BTS_CONFIG 40/* Configure branch trace recording. ADDR points to a struct ptrace_bts_config. DATA gives the size of that buffer. -A new buffer is allocated, iff the size changes. +A new buffer is allocated, if requested in the flags. +An overflow signal may only be requested for new buffers. Returns the number of bytes read. */ #define PTRACE_BTS_STATUS 41
@@ -119,7 +120,7 @@ struct ptrace_bts_config {Returns the number of bytes written. */ #define PTRACE_BTS_SIZE 42 -/* Return the number of available BTS records. +/* Return the number of available BTS records for draining. DATA and ADDR are ignored. */ #define PTRACE_BTS_GET 43
@@ -139,5 +140,6 @@ struct ptrace_bts_config {BTS records are read from oldest to newest. Returns number of BTS records drained. */ +#endif /* CONFIG_X86_PTRACE_BTS */ #endif
include/asm-x86/ptrace.h +36 -2
@@ -125,14 +125,48 @@ struct pt_regs {#endif /* __KERNEL__ */ #endif /* !__i386__ */ + +#ifdef CONFIG_X86_PTRACE_BTS +/* a branch trace record entry +* +* In order to unify the interface between various processor versions, +* we use the below data structure for all processors. +*/ +enum bts_qualifier { +BTS_INVALID =0 , +BTS_BRANCH , +BTS_TASK_ARRIVES , +BTS_TASK_DEPARTS +}; + +struct bts_struct { +__u64 qualifier; +union { +/* BTS_BRANCH */ +struct { +__u64 from_ip; +__u64 to_ip; + } lbr; +/* BTS_TASK_ARRIVES or +BTS_TASK_DEPARTS */ +__u64 jiffies; + } variant; +}; +#endif /* CONFIG_X86_PTRACE_BTS */ +#ifdef __KERNEL__ -/* the DS BTS struct is used for ptrace as well */ -#include <asm/ds.h> +#include <linux/init.h> +struct cpuinfo_x86 ;struct task_struct ; +#ifdef CONFIG_X86_PTRACE_BTS +extern void __cpuinit ptrace_bts_init_intel (struct cpuinfo_x86 *);extern void ptrace_bts_take_timestamp (struct task_struct *,enum bts_qualifier ); +#else +#define ptrace_bts_init_intel (config) do {} while (0) +#endif /* CONFIG_X86_PTRACE_BTS */ extern unsigned long profile_pc (struct pt_regs *regs);
---------------------------------------------------------------------
Intel GmbH
Dornacher Strasse 1
85622 Feldkirchen/Muenchen Germany
Sitz der Gesellschaft: Feldkirchen bei Muenchen
Geschaeftsfuehrer: Douglas Lusk, Peter Gleissner, Hannes Schwaderer
Registergericht: Muenchen HRB 47456 Ust.-IdNr.
VAT Registration No.: DE129385895
Citibank Frankfurt (BLZ 502 109 00) 600119052
This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). Any review or distribution by others is strictly prohibited. If you are not the intended recipient, please contact the sender and delete all copies.