Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 93fa7636 authored by Markus Metzger's avatar Markus Metzger Committed by Ingo Molnar
Browse files

x86, ptrace: PEBS support



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

Signed-off-by: default avatarMarkus Metzger <markus.t.metzger@intel.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent 492c2e47
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -415,3 +415,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.
+2 −1
Original line number Diff line number Diff line
@@ -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)
+676 −277

File changed.

Preview size limit exceeded, changes collapsed.

+21 −4
Original line number Diff line number Diff line
@@ -316,6 +316,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)
@@ -482,18 +490,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);
@@ -517,13 +534,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)) {
+21 −4
Original line number Diff line number Diff line
@@ -267,6 +267,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)
@@ -492,18 +500,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);
@@ -541,13 +558,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 */
}

/*
Loading