Commit b0f4b285 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'tracing-core-for-linus' of...

Merge branch 'tracing-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip

* 'tracing-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: (241 commits)
  sched, trace: update trace_sched_wakeup()
  tracing/ftrace: don't trace on early stage of a secondary cpu boot, v3
  Revert "x86: disable X86_PTRACE_BTS"
  ring-buffer: prevent false positive warning
  ring-buffer: fix dangling commit race
  ftrace: enable format arguments checking
  x86, bts: memory accounting
  x86, bts: add fork and exit handling
  ftrace: introduce tracing_reset_online_cpus() helper
  tracing: fix warnings in kernel/trace/trace_sched_switch.c
  tracing: fix warning in kernel/trace/trace.c
  tracing/ring-buffer: remove unused ring_buffer size
  trace: fix task state printout
  ftrace: add not to regex on filtering functions
  trace: better use of stack_trace_enabled for boot up code
  trace: add a way to enable or disable the stack tracer
  x86: entry_64 - introduce FTRACE_ frame macro v2
  tracing/ftrace: add the printk-msg-only option
  tracing/ftrace: use preempt_enable_no_resched_notrace in ring_buffer_time_stamp()
  x86, bts: correctly report invalid bts records
  ...

Fixed up trivial conflict in scripts/recordmcount.pl due to SH bits
being already partly merged by the SH merge.
parents be9c5ae4 5250d329
...@@ -82,7 +82,7 @@ of ftrace. Here is a list of some of the key files: ...@@ -82,7 +82,7 @@ of ftrace. Here is a list of some of the key files:
tracer is not adding more data, they will display tracer is not adding more data, they will display
the same information every time they are read. the same information every time they are read.
iter_ctrl: This file lets the user control the amount of data trace_options: This file lets the user control the amount of data
that is displayed in one of the above output that is displayed in one of the above output
files. files.
...@@ -94,10 +94,10 @@ of ftrace. Here is a list of some of the key files: ...@@ -94,10 +94,10 @@ of ftrace. Here is a list of some of the key files:
only be recorded if the latency is greater than only be recorded if the latency is greater than
the value in this file. (in microseconds) the value in this file. (in microseconds)
trace_entries: This sets or displays the number of bytes each CPU buffer_size_kb: This sets or displays the number of kilobytes each CPU
buffer can hold. The tracer buffers are the same size buffer can hold. The tracer buffers are the same size
for each CPU. The displayed number is the size of the for each CPU. The displayed number is the size of the
CPU buffer and not total size of all buffers. The CPU buffer and not total size of all buffers. The
trace buffers are allocated in pages (blocks of memory trace buffers are allocated in pages (blocks of memory
that the kernel uses for allocation, usually 4 KB in size). that the kernel uses for allocation, usually 4 KB in size).
If the last page allocated has room for more bytes If the last page allocated has room for more bytes
...@@ -127,6 +127,8 @@ of ftrace. Here is a list of some of the key files: ...@@ -127,6 +127,8 @@ of ftrace. Here is a list of some of the key files:
be traced. If a function exists in both set_ftrace_filter be traced. If a function exists in both set_ftrace_filter
and set_ftrace_notrace, the function will _not_ be traced. and set_ftrace_notrace, the function will _not_ be traced.
set_ftrace_pid: Have the function tracer only trace a single thread.
available_filter_functions: This lists the functions that ftrace available_filter_functions: This lists the functions that ftrace
has processed and can trace. These are the function has processed and can trace. These are the function
names that you can pass to "set_ftrace_filter" or names that you can pass to "set_ftrace_filter" or
...@@ -316,23 +318,23 @@ The above is mostly meaningful for kernel developers. ...@@ -316,23 +318,23 @@ The above is mostly meaningful for kernel developers.
The rest is the same as the 'trace' file. The rest is the same as the 'trace' file.
iter_ctrl trace_options
--------- -------------
The iter_ctrl file is used to control what gets printed in the trace The trace_options file is used to control what gets printed in the trace
output. To see what is available, simply cat the file: output. To see what is available, simply cat the file:
cat /debug/tracing/iter_ctrl cat /debug/tracing/trace_options
print-parent nosym-offset nosym-addr noverbose noraw nohex nobin \ print-parent nosym-offset nosym-addr noverbose noraw nohex nobin \
noblock nostacktrace nosched-tree noblock nostacktrace nosched-tree nouserstacktrace nosym-userobj
To disable one of the options, echo in the option prepended with "no". To disable one of the options, echo in the option prepended with "no".
echo noprint-parent > /debug/tracing/iter_ctrl echo noprint-parent > /debug/tracing/trace_options
To enable an option, leave off the "no". To enable an option, leave off the "no".
echo sym-offset > /debug/tracing/iter_ctrl echo sym-offset > /debug/tracing/trace_options
Here are the available options: Here are the available options:
...@@ -378,6 +380,20 @@ Here are the available options: ...@@ -378,6 +380,20 @@ Here are the available options:
When a trace is recorded, so is the stack of functions. When a trace is recorded, so is the stack of functions.
This allows for back traces of trace sites. This allows for back traces of trace sites.
userstacktrace - This option changes the trace.
It records a stacktrace of the current userspace thread.
sym-userobj - when user stacktrace are enabled, look up which object the
address belongs to, and print a relative address
This is especially useful when ASLR is on, otherwise you don't
get a chance to resolve the address to object/file/line after the app is no
longer running
The lookup is performed when you read trace,trace_pipe,latency_trace. Example:
a.out-1623 [000] 40874.465068: /root/a.out[+0x480] <-/root/a.out[+0
x494] <- /root/a.out[+0x4a8] <- /lib/libc-2.7.so[+0x1e1a6]
sched-tree - TBD (any users??) sched-tree - TBD (any users??)
...@@ -1059,6 +1075,83 @@ For simple one time traces, the above is sufficent. For anything else, ...@@ -1059,6 +1075,83 @@ For simple one time traces, the above is sufficent. For anything else,
a search through /proc/mounts may be needed to find where the debugfs a search through /proc/mounts may be needed to find where the debugfs
file-system is mounted. file-system is mounted.
Single thread tracing
---------------------
By writing into /debug/tracing/set_ftrace_pid you can trace a
single thread. For example:
# cat /debug/tracing/set_ftrace_pid
no pid
# echo 3111 > /debug/tracing/set_ftrace_pid
# cat /debug/tracing/set_ftrace_pid
3111
# echo function > /debug/tracing/current_tracer
# cat /debug/tracing/trace | head
# tracer: function
#
# TASK-PID CPU# TIMESTAMP FUNCTION
# | | | | |
yum-updatesd-3111 [003] 1637.254676: finish_task_switch <-thread_return
yum-updatesd-3111 [003] 1637.254681: hrtimer_cancel <-schedule_hrtimeout_range
yum-updatesd-3111 [003] 1637.254682: hrtimer_try_to_cancel <-hrtimer_cancel
yum-updatesd-3111 [003] 1637.254683: lock_hrtimer_base <-hrtimer_try_to_cancel
yum-updatesd-3111 [003] 1637.254685: fget_light <-do_sys_poll
yum-updatesd-3111 [003] 1637.254686: pipe_poll <-do_sys_poll
# echo -1 > /debug/tracing/set_ftrace_pid
# cat /debug/tracing/trace |head
# tracer: function
#
# TASK-PID CPU# TIMESTAMP FUNCTION
# | | | | |
##### CPU 3 buffer started ####
yum-updatesd-3111 [003] 1701.957688: free_poll_entry <-poll_freewait
yum-updatesd-3111 [003] 1701.957689: remove_wait_queue <-free_poll_entry
yum-updatesd-3111 [003] 1701.957691: fput <-free_poll_entry
yum-updatesd-3111 [003] 1701.957692: audit_syscall_exit <-sysret_audit
yum-updatesd-3111 [003] 1701.957693: path_put <-audit_syscall_exit
If you want to trace a function when executing, you could use
something like this simple program:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main (int argc, char **argv)
{
if (argc < 1)
exit(-1);
if (fork() > 0) {
int fd, ffd;
char line[64];
int s;
ffd = open("/debug/tracing/current_tracer", O_WRONLY);
if (ffd < 0)
exit(-1);
write(ffd, "nop", 3);
fd = open("/debug/tracing/set_ftrace_pid", O_WRONLY);
s = sprintf(line, "%d\n", getpid());
write(fd, line, s);
write(ffd, "function", 8);
close(fd);
close(ffd);
execvp(argv[1], argv+1);
}
return 0;
}
dynamic ftrace dynamic ftrace
-------------- --------------
...@@ -1158,7 +1251,11 @@ These are the only wild cards which are supported. ...@@ -1158,7 +1251,11 @@ These are the only wild cards which are supported.
<match>*<match> will not work. <match>*<match> will not work.
# echo hrtimer_* > /debug/tracing/set_ftrace_filter Note: It is better to use quotes to enclose the wild cards, otherwise
the shell may expand the parameters into names of files in the local
directory.
# echo 'hrtimer_*' > /debug/tracing/set_ftrace_filter
Produces: Produces:
...@@ -1213,7 +1310,7 @@ Again, now we want to append. ...@@ -1213,7 +1310,7 @@ Again, now we want to append.
# echo sys_nanosleep > /debug/tracing/set_ftrace_filter # echo sys_nanosleep > /debug/tracing/set_ftrace_filter
# cat /debug/tracing/set_ftrace_filter # cat /debug/tracing/set_ftrace_filter
sys_nanosleep sys_nanosleep
# echo hrtimer_* >> /debug/tracing/set_ftrace_filter # echo 'hrtimer_*' >> /debug/tracing/set_ftrace_filter
# cat /debug/tracing/set_ftrace_filter # cat /debug/tracing/set_ftrace_filter
hrtimer_run_queues hrtimer_run_queues
hrtimer_run_pending hrtimer_run_pending
...@@ -1299,41 +1396,29 @@ trace entries ...@@ -1299,41 +1396,29 @@ trace entries
------------- -------------
Having too much or not enough data can be troublesome in diagnosing Having too much or not enough data can be troublesome in diagnosing
an issue in the kernel. The file trace_entries is used to modify an issue in the kernel. The file buffer_size_kb is used to modify
the size of the internal trace buffers. The number listed the size of the internal trace buffers. The number listed
is the number of entries that can be recorded per CPU. To know is the number of entries that can be recorded per CPU. To know
the full size, multiply the number of possible CPUS with the the full size, multiply the number of possible CPUS with the
number of entries. number of entries.
# cat /debug/tracing/trace_entries # cat /debug/tracing/buffer_size_kb
65620 1408 (units kilobytes)
Note, to modify this, you must have tracing completely disabled. To do that, Note, to modify this, you must have tracing completely disabled. To do that,
echo "nop" into the current_tracer. If the current_tracer is not set echo "nop" into the current_tracer. If the current_tracer is not set
to "nop", an EINVAL error will be returned. to "nop", an EINVAL error will be returned.
# echo nop > /debug/tracing/current_tracer # echo nop > /debug/tracing/current_tracer
# echo 100000 > /debug/tracing/trace_entries # echo 10000 > /debug/tracing/buffer_size_kb
# cat /debug/tracing/trace_entries # cat /debug/tracing/buffer_size_kb
100045 10000 (units kilobytes)
Notice that we echoed in 100,000 but the size is 100,045. The entries
are held in individual pages. It allocates the number of pages it takes
to fulfill the request. If more entries may fit on the last page
then they will be added.
# echo 1 > /debug/tracing/trace_entries
# cat /debug/tracing/trace_entries
85
This shows us that 85 entries can fit in a single page.
The number of pages which will be allocated is limited to a percentage The number of pages which will be allocated is limited to a percentage
of available memory. Allocating too much will produce an error. of available memory. Allocating too much will produce an error.
# echo 1000000000000 > /debug/tracing/trace_entries # echo 1000000000000 > /debug/tracing/buffer_size_kb
-bash: echo: write error: Cannot allocate memory -bash: echo: write error: Cannot allocate memory
# cat /debug/tracing/trace_entries # cat /debug/tracing/buffer_size_kb
85 85
...@@ -89,6 +89,7 @@ parameter is applicable: ...@@ -89,6 +89,7 @@ parameter is applicable:
SPARC Sparc architecture is enabled. SPARC Sparc architecture is enabled.
SWSUSP Software suspend (hibernation) is enabled. SWSUSP Software suspend (hibernation) is enabled.
SUSPEND System suspend states are enabled. SUSPEND System suspend states are enabled.
FTRACE Function tracing enabled.
TS Appropriate touchscreen support is enabled. TS Appropriate touchscreen support is enabled.
USB USB support is enabled. USB USB support is enabled.
USBHID USB Human Interface Device support is enabled. USBHID USB Human Interface Device support is enabled.
...@@ -753,6 +754,14 @@ and is between 256 and 4096 characters. It is defined in the file ...@@ -753,6 +754,14 @@ and is between 256 and 4096 characters. It is defined in the file
parameter will force ia64_sal_cache_flush to call parameter will force ia64_sal_cache_flush to call
ia64_pal_cache_flush instead of SAL_CACHE_FLUSH. ia64_pal_cache_flush instead of SAL_CACHE_FLUSH.
ftrace=[tracer]
[ftrace] will set and start the specified tracer
as early as possible in order to facilitate early
boot debugging.
ftrace_dump_on_oops
[ftrace] will dump the trace buffers on oops.
gamecon.map[2|3]= gamecon.map[2|3]=
[HW,JOY] Multisystem joystick and NES/SNES/PSX pad [HW,JOY] Multisystem joystick and NES/SNES/PSX pad
support via parallel port (up to 5 devices per port) support via parallel port (up to 5 devices per port)
...@@ -2196,6 +2205,9 @@ and is between 256 and 4096 characters. It is defined in the file ...@@ -2196,6 +2205,9 @@ and is between 256 and 4096 characters. It is defined in the file
st= [HW,SCSI] SCSI tape parameters (buffers, etc.) st= [HW,SCSI] SCSI tape parameters (buffers, etc.)
See Documentation/scsi/st.txt. See Documentation/scsi/st.txt.
stacktrace [FTRACE]
Enabled the stack tracer on boot up.
sti= [PARISC,HW] sti= [PARISC,HW]
Format: <num> Format: <num>
Set the STI (builtin display/keyboard on the HP-PARISC Set the STI (builtin display/keyboard on the HP-PARISC
......
...@@ -51,11 +51,16 @@ to call) for the specific marker through marker_probe_register() and can be ...@@ -51,11 +51,16 @@ to call) for the specific marker through marker_probe_register() and can be
activated by calling marker_arm(). Marker deactivation can be done by calling activated by calling marker_arm(). Marker deactivation can be done by calling
marker_disarm() as many times as marker_arm() has been called. Removing a probe marker_disarm() as many times as marker_arm() has been called. Removing a probe
is done through marker_probe_unregister(); it will disarm the probe. is done through marker_probe_unregister(); it will disarm the probe.
marker_synchronize_unregister() must be called before the end of the module exit
function to make sure there is no caller left using the probe. This, and the marker_synchronize_unregister() must be called between probe unregistration and
fact that preemption is disabled around the probe call, make sure that probe the first occurrence of
removal and module unload are safe. See the "Probe example" section below for a - the end of module exit function,
sample probe module. to make sure there is no caller left using the probe;
- the free of any resource used by the probes,
to make sure the probes wont be accessing invalid data.
This, and the fact that preemption is disabled around the probe call, make sure
that probe removal and module unload are safe. See the "Probe example" section
below for a sample probe module.
The marker mechanism supports inserting multiple instances of the same marker. The marker mechanism supports inserting multiple instances of the same marker.
Markers can be put in inline functions, inlined static functions, and Markers can be put in inline functions, inlined static functions, and
...@@ -70,6 +75,20 @@ a printk warning which identifies the inconsistency: ...@@ -70,6 +75,20 @@ a printk warning which identifies the inconsistency:
"Format mismatch for probe probe_name (format), marker (format)" "Format mismatch for probe probe_name (format), marker (format)"
Another way to use markers is to simply define the marker without generating any
function call to actually call into the marker. This is useful in combination
with tracepoint probes in a scheme like this :
void probe_tracepoint_name(unsigned int arg1, struct task_struct *tsk);
DEFINE_MARKER_TP(marker_eventname, tracepoint_name, probe_tracepoint_name,
"arg1 %u pid %d");
notrace void probe_tracepoint_name(unsigned int arg1, struct task_struct *tsk)
{
struct marker *marker = &GET_MARKER(kernel_irq_entry);
/* write data to trace buffers ... */
}
* Probe / marker example * Probe / marker example
......
...@@ -3,28 +3,30 @@ ...@@ -3,28 +3,30 @@
Mathieu Desnoyers Mathieu Desnoyers
This document introduces Linux Kernel Tracepoints and their use. It provides This document introduces Linux Kernel Tracepoints and their use. It
examples of how to insert tracepoints in the kernel and connect probe functions provides examples of how to insert tracepoints in the kernel and
to them and provides some examples of probe functions. connect probe functions to them and provides some examples of probe
functions.
* Purpose of tracepoints * Purpose of tracepoints
A tracepoint placed in code provides a hook to call a function (probe) that you A tracepoint placed in code provides a hook to call a function (probe)
can provide at runtime. A tracepoint can be "on" (a probe is connected to it) or that you can provide at runtime. A tracepoint can be "on" (a probe is
"off" (no probe is attached). When a tracepoint is "off" it has no effect, connected to it) or "off" (no probe is attached). When a tracepoint is
except for adding a tiny time penalty (checking a condition for a branch) and "off" it has no effect, except for adding a tiny time penalty
space penalty (adding a few bytes for the function call at the end of the (checking a condition for a branch) and space penalty (adding a few
instrumented function and adds a data structure in a separate section). When a bytes for the function call at the end of the instrumented function
tracepoint is "on", the function you provide is called each time the tracepoint and adds a data structure in a separate section). When a tracepoint
is executed, in the execution context of the caller. When the function provided is "on", the function you provide is called each time the tracepoint
ends its execution, it returns to the caller (continuing from the tracepoint is executed, in the execution context of the caller. When the function
site). provided ends its execution, it returns to the caller (continuing from
the tracepoint site).
You can put tracepoints at important locations in the code. They are You can put tracepoints at important locations in the code. They are
lightweight hooks that can pass an arbitrary number of parameters, lightweight hooks that can pass an arbitrary number of parameters,
which prototypes are described in a tracepoint declaration placed in a header which prototypes are described in a tracepoint declaration placed in a
file. header file.
They can be used for tracing and performance accounting. They can be used for tracing and performance accounting.
...@@ -42,14 +44,16 @@ In include/trace/subsys.h : ...@@ -42,14 +44,16 @@ In include/trace/subsys.h :
#include <linux/tracepoint.h> #include <linux/tracepoint.h>
DEFINE_TRACE(subsys_eventname, DECLARE_TRACE(subsys_eventname,
TPPTOTO(int firstarg, struct task_struct *p), TPPROTO(int firstarg, struct task_struct *p),
TPARGS(firstarg, p)); TPARGS(firstarg, p));
In subsys/file.c (where the tracing statement must be added) : In subsys/file.c (where the tracing statement must be added) :
#include <trace/subsys.h> #include <trace/subsys.h>
DEFINE_TRACE(subsys_eventname);
void somefct(void) void somefct(void)
{ {
... ...
...@@ -61,31 +65,41 @@ Where : ...@@ -61,31 +65,41 @@ Where :
- subsys_eventname is an identifier unique to your event - subsys_eventname is an identifier unique to your event
- subsys is the name of your subsystem. - subsys is the name of your subsystem.
- eventname is the name of the event to trace. - eventname is the name of the event to trace.
- TPPTOTO(int firstarg, struct task_struct *p) is the prototype of the function
called by this tracepoint.
- TPARGS(firstarg, p) are the parameters names, same as found in the prototype.
Connecting a function (probe) to a tracepoint is done by providing a probe - TPPROTO(int firstarg, struct task_struct *p) is the prototype of the
(function to call) for the specific tracepoint through function called by this tracepoint.
register_trace_subsys_eventname(). Removing a probe is done through
unregister_trace_subsys_eventname(); it will remove the probe sure there is no
caller left using the probe when it returns. Probe removal is preempt-safe
because preemption is disabled around the probe call. See the "Probe example"
section below for a sample probe module.
The tracepoint mechanism supports inserting multiple instances of the same
tracepoint, but a single definition must be made of a given tracepoint name over
all the kernel to make sure no type conflict will occur. Name mangling of the
tracepoints is done using the prototypes to make sure typing is correct.
Verification of probe type correctness is done at the registration site by the
compiler. Tracepoints can be put in inline functions, inlined static functions,
and unrolled loops as well as regular functions.
The naming scheme "subsys_event" is suggested here as a convention intended
to limit collisions. Tracepoint names are global to the kernel: they are
considered as being the same whether they are in the core kernel image or in
modules.
- TPARGS(firstarg, p) are the parameters names, same as found in the
prototype.
Connecting a function (probe) to a tracepoint is done by providing a
probe (function to call) for the specific tracepoint through
register_trace_subsys_eventname(). Removing a probe is done through
unregister_trace_subsys_eventname(); it will remove the probe.
tracepoint_synchronize_unregister() must be called before the end of
the module exit function to make sure there is no caller left using
the probe. This, and the fact that preemption is disabled around the
probe call, make sure that probe removal and module unload are safe.
See the "Probe example" section below for a sample probe module.
The tracepoint mechanism supports inserting multiple instances of the
same tracepoint, but a single definition must be made of a given
tracepoint name over all the kernel to make sure no type conflict will
occur. Name mangling of the tracepoints is done using the prototypes
to make sure typing is correct. Verification of probe type correctness
is done at the registration site by the compiler. Tracepoints can be
put in inline functions, inlined static functions, and unrolled loops
as well as regular functions.
The naming scheme "subsys_event" is suggested here as a convention
intended to limit collisions. Tracepoint names are global to the
kernel: they are considered as being the same whether they are in the
core kernel image or in modules.
If the tracepoint has to be used in kernel modules, an
EXPORT_TRACEPOINT_SYMBOL_GPL() or EXPORT_TRACEPOINT_SYMBOL() can be
used to export the defined tracepoints.
* Probe / tracepoint example * Probe / tracepoint example
......
...@@ -7,7 +7,19 @@ ...@@ -7,7 +7,19 @@
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
extern void _mcount(void); extern void _mcount(void);
#endif
#ifdef CONFIG_DYNAMIC_FTRACE
static inline unsigned long ftrace_call_adjust(unsigned long addr)
{
/* reloction of mcount call site is the same as the address */
return addr;
}
struct dyn_arch_ftrace {
struct module *mod;
};
#endif /* CONFIG_DYNAMIC_FTRACE */
#endif /* __ASSEMBLY__ */
#endif #endif
......
...@@ -34,11 +34,19 @@ struct mod_arch_specific { ...@@ -34,11 +34,19 @@ struct mod_arch_specific {
#ifdef __powerpc64__ #ifdef __powerpc64__
unsigned int stubs_section; /* Index of stubs section in module */ unsigned int stubs_section; /* Index of stubs section in module */
unsigned int toc_section; /* What section is the TOC? */ unsigned int toc_section; /* What section is the TOC? */
#else #ifdef CONFIG_DYNAMIC_FTRACE
unsigned long toc;
unsigned long tramp;
#endif
#else /* powerpc64 */
/* Indices of PLT sections within module. */ /* Indices of PLT sections within module. */
unsigned int core_plt_section; unsigned int core_plt_section;
unsigned int init_plt_section; unsigned int init_plt_section;
#ifdef CONFIG_DYNAMIC_FTRACE
unsigned long tramp;
#endif #endif
#endif /* powerpc64 */
/* List of BUG addresses, source line numbers and filenames */ /* List of BUG addresses, source line numbers and filenames */
struct list_head bug_list; struct list_head bug_list;
...@@ -68,6 +76,12 @@ struct mod_arch_specific { ...@@ -68,6 +76,12 @@ struct mod_arch_specific {
# endif /* MODULE */ # endif /* MODULE */
#endif #endif
#ifdef CONFIG_DYNAMIC_FTRACE
# ifdef MODULE
asm(".section .ftrace.tramp,\"ax\",@nobits; .align 3; .previous");
# endif /* MODULE */
#endif
struct exception_table_entry; struct exception_table_entry;
void sort_ex_table(struct exception_table_entry *start, void sort_ex_table(struct exception_table_entry *start,
......
...@@ -17,6 +17,7 @@ ifdef CONFIG_FUNCTION_TRACER ...@@ -17,6 +17,7 @@ ifdef CONFIG_FUNCTION_TRACER
CFLAGS_REMOVE_cputable.o = -pg -mno-sched-epilog CFLAGS_REMOVE_cputable.o = -pg -mno-sched-epilog
CFLAGS_REMOVE_prom_init.o = -pg -mno-sched-epilog CFLAGS_REMOVE_prom_init.o = -pg -mno-sched-epilog
CFLAGS_REMOVE_btext.o = -pg -mno-sched-epilog CFLAGS_REMOVE_btext.o = -pg -mno-sched-epilog
CFLAGS_REMOVE_prom.o = -pg -mno-sched-epilog
ifdef CONFIG_DYNAMIC_FTRACE ifdef CONFIG_DYNAMIC_FTRACE
# dynamic ftrace setup. # dynamic ftrace setup.
......
...@@ -1162,39 +1162,17 @@ machine_check_in_rtas: ...@@ -1162,39 +1162,17 @@ machine_check_in_rtas:
#ifdef CONFIG_DYNAMIC_FTRACE #ifdef CONFIG_DYNAMIC_FTRACE
_GLOBAL(mcount) _GLOBAL(mcount)
_GLOBAL(_mcount) _GLOBAL(_mcount)
stwu r1,-48(r1) /*
stw r3, 12(r1) * It is required that _mcount on PPC32 must preserve the
stw r4, 16(r1) * link register. But we have r0 to play with. We use r0
stw r5, 20(r1) * to push the return address back to the caller of mcount
stw r6, 24(r1) * into the ctr register, restore the link register and
mflr r3 * then jump back using the ctr register.
stw r7, 28(r1) */
mfcr r5 mflr r0
stw r8, 32(r1)
stw r9, 36(r1)
stw r10,40(r1)
stw r3, 44(r1)
stw r5, 8(r1)
subi r3, r3, MCOUNT_INSN_SIZE
.globl mcount_call
mcount_call:
bl ftrace_stub
nop
lwz r6, 8(r1)
lwz r0, 44(r1)
lwz r3, 12(r1)
mtctr r0 mtctr r0
lwz r4, 16(r1) lwz r0, 4(r1)
mtcr r6
lwz r5, 20(r1)
lwz r6, 24(r1)
lwz r0, 52(r1)
lwz r7, 28(r1)
lwz r8, 32(r1)
mtlr r0 mtlr r0
lwz r9, 36(r1)
lwz r10,40(r1)
addi r1, r1, 48
bctr bctr
_GLOBAL(ftrace_caller) _GLOBAL(ftrace_caller)
......
...@@ -894,18 +894,6 @@ _GLOBAL(enter_prom) ...@@ -894,18 +894,6 @@ _GLOBAL(enter_prom)
#ifdef CONFIG_DYNAMIC_FTRACE #ifdef CONFIG_DYNAMIC_FTRACE
_GLOBAL(mcount) _GLOBAL(mcount)
_GLOBAL(_mcount) _GLOBAL(_mcount)
/* Taken from output of objdump from lib64/glibc */
mflr r3
stdu r1, -112(r1)
std r3, 128(r1)
subi r3, r3, MCOUNT_INSN_SIZE
.globl mcount_call
mcount_call:
bl ftrace_stub
nop
ld r0, 128(r1)
mtlr r0
addi r1, r1, 112
blr blr
_GLOBAL(ftrace_caller) _GLOBAL(ftrace_caller)
......
This diff is collapsed.
...@@ -69,10 +69,15 @@ void cpu_idle(void) ...@@ -69,10 +69,15 @@ void cpu_idle(void)
smp_mb(); smp_mb();
local_irq_disable(); local_irq_disable();
/* Don't trace irqs off for idle */
stop_critical_timings();
/* check again after disabling irqs */ /* check again after disabling irqs */
if (!need_resched() && !cpu_should_die()) if (!need_resched() && !cpu_should_die())
ppc_md.power_save(); ppc_md.power_save();
start_critical_timings();
local_irq_enable(); local_irq_enable();
set_thread_flag(TIF_POLLING_NRFLAG); set_thread_flag(TIF_POLLING_NRFLAG);
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/ftrace.h>
#include <linux/cache.h> #include <linux/cache.h>
#include <linux/bug.h> #include <linux/bug.h>
#include <linux/sort.h> #include <linux/sort.h>
...@@ -53,6 +54,9 @@ static unsigned int count_relocs(const Elf32_Rela *rela, unsigned int num) ...@@ -53,6 +54,9 @@ static unsigned int count_relocs(const Elf32_Rela *rela, unsigned int num)
r_addend = rela[i].r_addend; r_addend = rela[i].r_addend;
} }
#ifdef CONFIG_DYNAMIC_FTRACE
_count_relocs++; /* add one for ftrace_caller */
#endif
return _count_relocs; return _count_relocs;
} }
...@@ -306,5 +310,11 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, ...@@ -306,5 +310,11 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
return -ENOEXEC; return -ENOEXEC;
} }
} }
#ifdef CONFIG_DYNAMIC_FTRACE
module->arch.tramp =
do_plt_call(module->module_core,
(unsigned long)ftrace_caller,
sechdrs, module);
#endif
return 0; return 0;
} }
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/moduleloader.h> #include <linux/moduleloader.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/ftrace.h>
#include <linux/bug.h> #include <linux/bug.h>
#include <asm/module.h> #include <asm/module.h>
#include <asm/firmware.h> #include <asm/firmware.h>
...@@ -163,6 +164,11 @@ static unsigned long get_stubs_size(const Elf64_Ehdr *hdr, ...@@ -163,6 +164,11 @@ static unsigned long get_stubs_size(const Elf64_Ehdr *hdr,
} }
} }
#ifdef CONFIG_DYNAMIC_FTRACE
/* make the trampoline to the ftrace_caller */
relocs++;
#endif
DEBUGP("Looks like a total of %lu stubs, max\n", relocs); DEBUGP("Looks like a total of %lu stubs, max\n", relocs);
return relocs * sizeof(struct ppc64_stub_entry); return relocs * sizeof(struct ppc64_stub_entry);
} }
...@@ -441,5 +447,12 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, ...@@ -441,5 +447,12 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
} }
} }
#ifdef CONFIG_DYNAMIC_FTRACE
me->arch.toc = my_r2(sechdrs, me);
me->arch.tramp = stub_for_addr(sechdrs,
(unsigned long)ftrace_caller,
me);
#endif
return 0; return 0;
} }
...@@ -6,6 +6,9 @@ ifeq ($(CONFIG_PPC64),y) ...@@ -6,6 +6,9 @@ ifeq ($(CONFIG_PPC64),y)
EXTRA_CFLAGS += -mno-minimal-toc EXTRA_CFLAGS += -mno-minimal-toc
endif endif
CFLAGS_REMOVE_code-patching.o = -pg
CFLAGS_REMOVE_feature-fixups.o = -pg
obj-y := string.o alloc.o \ obj-y := string.o alloc.o \
checksum_$(CONFIG_WORD_SIZE).o checksum_$(CONFIG_WORD_SIZE).o
obj-$(CONFIG_PPC32) += div64.o copy_32.o crtsavres.o obj-$(CONFIG_PPC32) += div64.o copy_32.o crtsavres.o
......
...@@ -31,11 +31,14 @@ config X86 ...@@ -31,11 +31,14 @@ config X86
select HAVE_FTRACE_MCOUNT_RECORD select HAVE_FTRACE_MCOUNT_RECORD
select HAVE_DYNAMIC_FTRACE select HAVE_DYNAMIC_FTRACE
select HAVE_FUNCTION_TRACER select HAVE_FUNCTION_TRACER
select HAVE_FUNCTION_GRAPH_TRACER
select HAVE_FUNCTION_TRACE_MCOUNT_TEST
select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64) select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64)
select HAVE_ARCH_KGDB if !X86_VOYAGER select HAVE_ARCH_KGDB if !X86_VOYAGER
select HAVE_ARCH_TRACEHOOK select HAVE_ARCH_TRACEHOOK
select HAVE_GENERIC_DMA_COHERENT if X86_32 select HAVE_GENERIC_DMA_COHERENT if X86_32
select HAVE_EFFICIENT_UNALIGNED_ACCESS select HAVE_EFFICIENT_UNALIGNED_ACCESS
select USER_STACKTRACE_SUPPORT
config ARCH_DEFCONFIG config ARCH_DEFCONFIG
string string
......
...@@ -515,12 +515,12 @@ config CPU_SUP_UMC_32 ...@@ -515,12 +515,12 @@ config CPU_SUP_UMC_32
config X86_DS config X86_DS
def_bool X86_PTRACE_BTS def_bool X86_PTRACE_BTS
depends on X86_DEBUGCTLMSR depends on X86_DEBUGCTLMSR
select HAVE_HW_BRANCH_TRACER
config X86_PTRACE_BTS config X86_PTRACE_BTS
bool "Branch Trace Store" bool "Branch Trace Store"
default y default y
depends on X86_DEBUGCTLMSR depends on X86_DEBUGCTLMSR
depends on BROKEN
help help
This adds a ptrace interface to the hardware's branch trace store. This adds a ptrace interface to the hardware's branch trace store.
......
...@@ -174,14 +174,10 @@ config IOMMU_LEAK ...@@ -174,14 +174,10 @@ config IOMMU_LEAK
Add a simple leak tracer to the IOMMU code. This is useful when you Add a simple leak tracer to the IOMMU code. This is useful when you
are debugging a buggy device driver that leaks IOMMU mappings. are debugging a buggy device driver that leaks IOMMU mappings.
config MMIOTRACE_HOOKS
bool
config MMIOTRACE config MMIOTRACE
bool "Memory mapped IO tracing" bool "Memory mapped IO tracing"
depends on DEBUG_KERNEL && PCI depends on DEBUG_KERNEL && PCI
select TRACING select TRACING
select MMIOTRACE_HOOKS
help help
Mmiotrace traces Memory Mapped I/O access and is meant for Mmiotrace traces Memory Mapped I/O access and is meant for
debugging and reverse engineering. It is called from the ioremap debugging and reverse engineering. It is called from the ioremap
......
This diff is collapsed.
#ifndef _ASM_X86_FTRACE_H #ifndef _ASM_X86_FTRACE_H
#define _ASM_X86_FTRACE_H #define _ASM_X86_FTRACE_H
#ifdef __ASSEMBLY__
.macro MCOUNT_SAVE_FRAME
/* taken from glibc */
subq $0x38, %rsp
movq %rax, (%rsp)
movq %rcx, 8(%rsp)
movq %rdx, 16(%rsp)
movq %rsi, 24(%rsp)
movq %rdi, 32(%rsp)
movq %r8, 40(%rsp)
movq %r9, 48(%rsp)
.endm
.macro MCOUNT_RESTORE_FRAME
movq 48(%rsp), %r9
movq 40(%rsp), %r8
movq 32(%rsp), %rdi
movq 24(%rsp), %rsi
movq 16(%rsp), %rdx
movq 8(%rsp), %rcx
movq (%rsp), %rax
addq $0x38, %rsp
.endm
#endif
#ifdef CONFIG_FUNCTION_TRACER #ifdef CONFIG_FUNCTION_TRACER
#define MCOUNT_ADDR ((long)(mcount)) #define MCOUNT_ADDR ((long)(mcount))
#define MCOUNT_INSN_SIZE 5 /* sizeof mcount call */ #define MCOUNT_INSN_SIZE 5 /* sizeof mcount call */
...@@ -17,8 +44,40 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr) ...@@ -17,8 +44,40 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr)
*/ */
return addr - 1; return addr - 1;
} }
#endif
#ifdef CONFIG_DYNAMIC_FTRACE
struct dyn_arch_ftrace {
/* No extra data needed for x86 */
};
#endif /* CONFIG_DYNAMIC_FTRACE */
#endif /* __ASSEMBLY__ */
#endif /* CONFIG_FUNCTION_TRACER */ #endif /* CONFIG_FUNCTION_TRACER */
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
#ifndef __ASSEMBLY__
/*
* Stack of return addresses for functions
* of a thread.
* Used in struct thread_info
*/
struct ftrace_ret_stack {
unsigned long ret;
unsigned long func;
unsigned long long calltime;
};
/*
* Primary handler of a function return.
* It relays on ftrace_return_to_handler.
* Defined in entry_32/64.S
*/
extern void return_to_handler(void);
#endif /* __ASSEMBLY__ */
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
#endif /* _ASM_X86_FTRACE_H */ #endif /* _ASM_X86_FTRACE_H */
...@@ -85,7 +85,8 @@ static inline void native_write_msr(unsigned int msr, ...@@ -85,7 +85,8 @@ static inline void native_write_msr(unsigned int msr,
asm volatile("wrmsr" : : "c" (msr), "a"(low), "d" (high) : "memory"); asm volatile("wrmsr" : : "c" (msr), "a"(low), "d" (high) : "memory");
} }
static inline int native_write_msr_safe(unsigned int msr, /* Can be uninlined because referenced by paravirt */
notrace static inline int native_write_msr_safe(unsigned int msr,
unsigned low, unsigned high) unsigned low, unsigned high)
{ {
int err; int err;
......
...@@ -756,6 +756,19 @@ extern void switch_to_new_gdt(void); ...@@ -756,6 +756,19 @@ extern void switch_to_new_gdt(void);
extern void cpu_init(void); extern void cpu_init(void);
extern void init_gdt(int cpu); extern void init_gdt(int cpu);
static inline unsigned long get_debugctlmsr(void)
{
unsigned long debugctlmsr = 0;
#ifndef CONFIG_X86_DEBUGCTLMSR
if (boot_cpu_data.x86 < 6)
return 0;
#endif
rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctlmsr);
return debugctlmsr;
}
static inline void update_debugctlmsr(unsigned long debugctlmsr) static inline void update_debugctlmsr(unsigned long debugctlmsr)
{ {
#ifndef CONFIG_X86_DEBUGCTLMSR #ifndef CONFIG_X86_DEBUGCTLMSR
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
#include <asm/processor-flags.h> #include <asm/processor-flags.h>
#ifdef __KERNEL__ #ifdef __KERNEL__
#include <asm/ds.h> /* the DS BTS struct is used for ptrace too */
#include <asm/segment.h> #include <asm/segment.h>
#endif #endif
...@@ -128,34 +127,6 @@ struct pt_regs { ...@@ -128,34 +127,6 @@ struct pt_regs {
#endif /* !__i386__ */ #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__ #ifdef __KERNEL__
#include <linux/init.h> #include <linux/init.h>
...@@ -163,13 +134,6 @@ struct bts_struct { ...@@ -163,13 +134,6 @@ struct bts_struct {
struct cpuinfo_x86; struct cpuinfo_x86;
struct task_struct; 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); extern unsigned long profile_pc(struct pt_regs *regs);
extern unsigned long extern unsigned long
...@@ -271,6 +235,13 @@ extern int do_get_thread_area(struct task_struct *p, int idx, ...@@ -271,6 +235,13 @@ extern int do_get_thread_area(struct task_struct *p, int idx,
extern int do_set_thread_area(struct task_struct *p, int idx, extern int do_set_thread_area(struct task_struct *p, int idx,
struct user_desc __user *info, int can_allocate); struct user_desc __user *info, int can_allocate);
extern void x86_ptrace_untrace(struct task_struct *);
extern void x86_ptrace_fork(struct task_struct *child,
unsigned long clone_flags);
#define arch_ptrace_untrace(tsk) x86_ptrace_untrace(tsk)
#define arch_ptrace_fork(child, flags) x86_ptrace_fork(child, flags)
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* !__ASSEMBLY__ */ #endif /* !__ASSEMBLY__ */
......
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
struct task_struct; struct task_struct;
struct exec_domain; struct exec_domain;
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/ftrace.h>
#include <asm/atomic.h>
struct thread_info { struct thread_info {
struct task_struct *task; /* main task structure */ struct task_struct *task; /* main task structure */
...@@ -91,7 +93,6 @@ struct thread_info { ...@@ -91,7 +93,6 @@ struct thread_info {
#define TIF_FORCED_TF 24 /* true if TF in eflags artificially */ #define TIF_FORCED_TF 24 /* true if TF in eflags artificially */
#define TIF_DEBUGCTLMSR 25 /* uses thread_struct.debugctlmsr */ #define TIF_DEBUGCTLMSR 25 /* uses thread_struct.debugctlmsr */
#define TIF_DS_AREA_MSR 26 /* uses thread_struct.ds_area_msr */ #define TIF_DS_AREA_MSR 26 /* uses thread_struct.ds_area_msr */
#define TIF_BTS_TRACE_TS 27 /* record scheduling event timestamps */
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
...@@ -113,7 +114,6 @@ struct thread_info { ...@@ -113,7 +114,6 @@ struct thread_info {
#define _TIF_FORCED_TF (1 << TIF_FORCED_TF) #define _TIF_FORCED_TF (1 << TIF_FORCED_TF)
#define _TIF_DEBUGCTLMSR (1 << TIF_DEBUGCTLMSR) #define _TIF_DEBUGCTLMSR (1 << TIF_DEBUGCTLMSR)
#define _TIF_DS_AREA_MSR (1 << TIF_DS_AREA_MSR) #define _TIF_DS_AREA_MSR (1 << TIF_DS_AREA_MSR)
#define _TIF_BTS_TRACE_TS (1 << TIF_BTS_TRACE_TS)
/* work to do in syscall_trace_enter() */ /* work to do in syscall_trace_enter() */
#define _TIF_WORK_SYSCALL_ENTRY \ #define _TIF_WORK_SYSCALL_ENTRY \
...@@ -139,8 +139,7 @@ struct thread_info { ...@@ -139,8 +139,7 @@ struct thread_info {
/* flags to check in __switch_to() */ /* flags to check in __switch_to() */
#define _TIF_WORK_CTXSW \ #define _TIF_WORK_CTXSW \
(_TIF_IO_BITMAP|_TIF_DEBUGCTLMSR|_TIF_DS_AREA_MSR|_TIF_BTS_TRACE_TS| \ (_TIF_IO_BITMAP|_TIF_DEBUGCTLMSR|_TIF_DS_AREA_MSR|_TIF_NOTSC)
_TIF_NOTSC)
#define _TIF_WORK_CTXSW_PREV _TIF_WORK_CTXSW #define _TIF_WORK_CTXSW_PREV _TIF_WORK_CTXSW
#define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW|_TIF_DEBUG) #define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW|_TIF_DEBUG)
......
...@@ -66,6 +66,7 @@ obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o ...@@ -66,6 +66,7 @@ obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o
obj-$(CONFIG_X86_IO_APIC) += io_apic.o obj-$(CONFIG_X86_IO_APIC) += io_apic.o
obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups_32.o obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups_32.o
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
obj-$(CONFIG_KEXEC) += machine_kexec_$(BITS).o obj-$(CONFIG_KEXEC) += machine_kexec_$(BITS).o
obj-$(CONFIG_KEXEC) += relocate_kernel_$(BITS).o crash.o obj-$(CONFIG_KEXEC) += relocate_kernel_$(BITS).o crash.o
obj-$(CONFIG_CRASH_DUMP) += crash_dump_$(BITS).o obj-$(CONFIG_CRASH_DUMP) += crash_dump_$(BITS).o
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/dmi.h> #include <linux/dmi.h>
#include <linux/dmar.h> #include <linux/dmar.h>
#include <linux/ftrace.h>
#include <asm/atomic.h> #include <asm/atomic.h>
#include <asm/smp.h> #include <asm/smp.h>
...@@ -790,7 +791,7 @@ static void local_apic_timer_interrupt(void) ...@@ -790,7 +791,7 @@ static void local_apic_timer_interrupt(void)
* [ if a single-CPU system runs an SMP kernel then we call the local * [ if a single-CPU system runs an SMP kernel then we call the local
* interrupt as well. Thus we cannot inline the local irq ... ] * interrupt as well. Thus we cannot inline the local irq ... ]
*/ */
void smp_apic_timer_interrupt(struct pt_regs *regs) void __irq_entry smp_apic_timer_interrupt(struct pt_regs *regs)
{ {
struct pt_regs *old_regs = set_irq_regs(regs); struct pt_regs *old_regs = set_irq_regs(regs);
......
...@@ -2,6 +2,11 @@ ...@@ -2,6 +2,11 @@
# Makefile for x86-compatible CPU details and quirks # Makefile for x86-compatible CPU details and quirks
# #
# Don't trace early stages of a secondary CPU boot
ifdef CONFIG_FUNCTION_TRACER
CFLAGS_REMOVE_common.o = -pg
endif
obj-y := intel_cacheinfo.o addon_cpuid_features.o obj-y := intel_cacheinfo.o addon_cpuid_features.o
obj-y += proc.o capflags.o powerflags.o common.o obj-y += proc.o capflags.o powerflags.o common.o
obj-y += vmware.o hypervisor.o obj-y += vmware.o hypervisor.o
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/dmi.h> #include <linux/dmi.h>
#include <linux/ftrace.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <acpi/processor.h> #include <acpi/processor.h>
...@@ -391,6 +392,7 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, ...@@ -391,6 +392,7 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
unsigned int next_perf_state = 0; /* Index into perf table */ unsigned int next_perf_state = 0; /* Index into perf table */
unsigned int i; unsigned int i;
int result = 0; int result = 0;
struct power_trace it;
dprintk("acpi_cpufreq_target %d (%d)\n", target_freq, policy->cpu); dprintk("acpi_cpufreq_target %d (%d)\n", target_freq, policy->cpu);
...@@ -427,6 +429,8 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, ...@@ -427,6 +429,8 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
} }
} }
trace_power_mark(&it, POWER_PSTATE, next_perf_state);
switch (data->cpu_feature) { switch (data->cpu_feature) {
case SYSTEM_INTEL_MSR_CAPABLE: case SYSTEM_INTEL_MSR_CAPABLE:
cmd.type = SYSTEM_INTEL_MSR_CAPABLE; cmd.type = SYSTEM_INTEL_MSR_CAPABLE;
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/msr.h> #include <asm/msr.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/ptrace.h>
#include <asm/ds.h> #include <asm/ds.h>
#include <asm/bugs.h> #include <asm/bugs.h>
...@@ -326,9 +325,6 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c) ...@@ -326,9 +325,6 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c)
set_cpu_cap(c, X86_FEATURE_P3); set_cpu_cap(c, X86_FEATURE_P3);
#endif #endif
if (cpu_has_bts)
ptrace_bts_init_intel(c);
if (!cpu_has(c, X86_FEATURE_XTOPOLOGY)) { if (!cpu_has(c, X86_FEATURE_XTOPOLOGY)) {
/* /*
* let's use the legacy cpuid vector 0x1 and 0x4 for topology * let's use the legacy cpuid vector 0x1 and 0x4 for topology
......
This diff is collapsed.
...@@ -30,6 +30,37 @@ void printk_address(unsigned long address, int reliable) ...@@ -30,6 +30,37 @@ void printk_address(unsigned long address, int reliable)
reliable ? "" : "? ", (void *) address); reliable ? "" : "? ", (void *) address);
} }
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
static void
print_ftrace_graph_addr(unsigned long addr, void *data,
const struct stacktrace_ops *ops,
struct thread_info *tinfo, int *graph)
{
struct task_struct *task = tinfo->task;
unsigned long ret_addr;
int index = task->curr_ret_stack;
if (addr != (unsigned long)return_to_handler)
return;
if (!task->ret_stack || index < *graph)
return;
index -= *graph;
ret_addr = task->ret_stack[index].ret;
ops->address(data, ret_addr, 1);
(*graph)++;
}
#else
static inline void
print_ftrace_graph_addr(unsigned long addr, void *data,
const struct stacktrace_ops *ops,
struct thread_info *tinfo, int *graph)
{ }
#endif
/* /*
* x86-64 can have up to three kernel stacks: * x86-64 can have up to three kernel stacks:
* process stack * process stack
...@@ -54,7 +85,7 @@ unsigned long ...@@ -54,7 +85,7 @@ unsigned long
print_context_stack(struct thread_info *tinfo, print_context_stack(struct thread_info *tinfo,
unsigned long *stack, unsigned long bp, unsigned long *stack, unsigned long bp,
const struct stacktrace_ops *ops, void *data, const struct stacktrace_ops *ops, void *data,
unsigned long *end) unsigned long *end, int *graph)
{ {
struct stack_frame *frame = (struct stack_frame *)bp; struct stack_frame *frame = (struct stack_frame *)bp;
...@@ -70,6 +101,7 @@ print_context_stack(struct thread_info *tinfo, ...@@ -70,6 +101,7 @@ print_context_stack(struct thread_info *tinfo,
} else { } else {
ops->address(data, addr, bp == 0); ops->address(data, addr, bp == 0);
} }
print_ftrace_graph_addr(addr, data, ops, tinfo, graph);
} }
stack++; stack++;
} }
......
...@@ -18,7 +18,7 @@ extern unsigned long ...@@ -18,7 +18,7 @@ extern unsigned long
print_context_stack(struct thread_info *tinfo, print_context_stack(struct thread_info *tinfo,
unsigned long *stack, unsigned long bp, unsigned long *stack, unsigned long bp,
const struct stacktrace_ops *ops, void *data, const struct stacktrace_ops *ops, void *data,
unsigned long *end); unsigned long *end, int *graph);
extern void extern void
show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
......
...@@ -23,6 +23,8 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, ...@@ -23,6 +23,8 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
unsigned long *stack, unsigned long bp, unsigned long *stack, unsigned long bp,
const struct stacktrace_ops *ops, void *data) const struct stacktrace_ops *ops, void *data)
{ {
int graph = 0;
if (!task) if (!task)
task = current; task = current;
...@@ -50,7 +52,8 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, ...@@ -50,7 +52,8 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
context = (struct thread_info *) context = (struct thread_info *)
((unsigned long)stack & (~(THREAD_SIZE - 1))); ((unsigned long)stack & (~(THREAD_SIZE - 1)));
bp = print_context_stack(context, stack, bp, ops, data, NULL); bp = print_context_stack(context, stack, bp, ops,
data, NULL, &graph);
stack = (unsigned long *)context->previous_esp; stack = (unsigned long *)context->previous_esp;
if (!stack) if (!stack)
......
...@@ -109,6 +109,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, ...@@ -109,6 +109,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr; unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr;
unsigned used = 0; unsigned used = 0;
struct thread_info *tinfo; struct thread_info *tinfo;
int graph = 0;
if (!task) if (!task)
task = current; task = current;
...@@ -149,7 +150,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, ...@@ -149,7 +150,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
break; break;
bp = print_context_stack(tinfo, stack, bp, ops, bp = print_context_stack(tinfo, stack, bp, ops,
data, estack_end); data, estack_end, &graph);
ops->stack(data, "<EOE>"); ops->stack(data, "<EOE>");
/* /*
* We link to the next stack via the * We link to the next stack via the
...@@ -168,7 +169,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, ...@@ -168,7 +169,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
if (ops->stack(data, "IRQ") < 0) if (ops->stack(data, "IRQ") < 0)
break; break;
bp = print_context_stack(tinfo, stack, bp, bp = print_context_stack(tinfo, stack, bp,
ops, data, irqstack_end); ops, data, irqstack_end, &graph);
/* /*
* We link to the next stack (which would be * We link to the next stack (which would be
* the process stack normally) the last * the process stack normally) the last
...@@ -186,7 +187,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, ...@@ -186,7 +187,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
/* /*
* This handles the process stack: * This handles the process stack:
*/ */
bp = print_context_stack(tinfo, stack, bp, ops, data, NULL); bp = print_context_stack(tinfo, stack, bp, ops, data, NULL, &graph);
put_cpu(); put_cpu();
} }
EXPORT_SYMBOL(dump_trace); EXPORT_SYMBOL(dump_trace);
......
...@@ -954,6 +954,9 @@ ENTRY(mcount) ...@@ -954,6 +954,9 @@ ENTRY(mcount)
END(mcount) END(mcount)
ENTRY(ftrace_caller) ENTRY(ftrace_caller)
cmpl $0, function_trace_stop
jne ftrace_stub
pushl %eax pushl %eax
pushl %ecx pushl %ecx
pushl %edx pushl %edx
...@@ -968,6 +971,11 @@ ftrace_call: ...@@ -968,6 +971,11 @@ ftrace_call:
popl %edx popl %edx
popl %ecx popl %ecx
popl %eax popl %eax
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
.globl ftrace_graph_call
ftrace_graph_call:
jmp ftrace_stub
#endif
.globl ftrace_stub .globl ftrace_stub
ftrace_stub: ftrace_stub:
...@@ -977,8 +985,18 @@ END(ftrace_caller) ...@@ -977,8 +985,18 @@ END(ftrace_caller)
#else /* ! CONFIG_DYNAMIC_FTRACE */ #else /* ! CONFIG_DYNAMIC_FTRACE */
ENTRY(mcount) ENTRY(mcount)
cmpl $0, function_trace_stop
jne ftrace_stub
cmpl $ftrace_stub, ftrace_trace_function cmpl $ftrace_stub, ftrace_trace_function
jnz trace jnz trace
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
cmpl $ftrace_stub, ftrace_graph_return
jnz ftrace_graph_caller
cmpl $ftrace_graph_entry_stub, ftrace_graph_entry
jnz ftrace_graph_caller
#endif
.globl ftrace_stub .globl ftrace_stub
ftrace_stub: ftrace_stub:
ret ret
...@@ -997,12 +1015,43 @@ trace: ...@@ -997,12 +1015,43 @@ trace:
popl %edx popl %edx
popl %ecx popl %ecx
popl %eax popl %eax
jmp ftrace_stub jmp ftrace_stub
END(mcount) END(mcount)
#endif /* CONFIG_DYNAMIC_FTRACE */ #endif /* CONFIG_DYNAMIC_FTRACE */
#endif /* CONFIG_FUNCTION_TRACER */ #endif /* CONFIG_FUNCTION_TRACER */
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
ENTRY(ftrace_graph_caller)
cmpl $0, function_trace_stop
jne ftrace_stub
pushl %eax
pushl %ecx
pushl %edx
movl 0xc(%esp), %edx
lea 0x4(%ebp), %eax
subl $MCOUNT_INSN_SIZE, %edx
call prepare_ftrace_return
popl %edx
popl %ecx
popl %eax
ret
END(ftrace_graph_caller)
.globl return_to_handler
return_to_handler:
pushl $0
pushl %eax
pushl %ecx
pushl %edx
call ftrace_return_to_handler
movl %eax, 0xc(%esp)
popl %edx
popl %ecx
popl %eax
ret
#endif
.section .rodata,"a" .section .rodata,"a"
#include "syscall_table_32.S" #include "syscall_table_32.S"
......
...@@ -67,16 +67,10 @@ ENTRY(mcount) ...@@ -67,16 +67,10 @@ ENTRY(mcount)
END(mcount) END(mcount)
ENTRY(ftrace_caller) ENTRY(ftrace_caller)
cmpl $0, function_trace_stop
jne ftrace_stub
/* taken from glibc */ MCOUNT_SAVE_FRAME
subq $0x38, %rsp
movq %rax, (%rsp)
movq %rcx, 8(%rsp)
movq %rdx, 16(%rsp)
movq %rsi, 24(%rsp)
movq %rdi, 32(%rsp)
movq %r8, 40(%rsp)
movq %r9, 48(%rsp)
movq 0x38(%rsp), %rdi movq 0x38(%rsp), %rdi
movq 8(%rbp), %rsi movq 8(%rbp), %rsi
...@@ -86,14 +80,13 @@ ENTRY(ftrace_caller) ...@@ -86,14 +80,13 @@ ENTRY(ftrace_caller)
ftrace_call: ftrace_call:
call ftrace_stub call ftrace_stub
movq 48(%rsp), %r9 MCOUNT_RESTORE_FRAME
movq 40(%rsp), %r8
movq 32(%rsp), %rdi #ifdef CONFIG_FUNCTION_GRAPH_TRACER
movq 24(%rsp), %rsi .globl ftrace_graph_call
movq 16(%rsp), %rdx ftrace_graph_call:
movq 8(%rsp), %rcx jmp ftrace_stub
movq (%rsp), %rax #endif
addq $0x38, %rsp
.globl ftrace_stub .globl ftrace_stub
ftrace_stub: ftrace_stub:
...@@ -102,15 +95,63 @@ END(ftrace_caller) ...@@ -102,15 +95,63 @@ END(ftrace_caller)
#else /* ! CONFIG_DYNAMIC_FTRACE */ #else /* ! CONFIG_DYNAMIC_FTRACE */
ENTRY(mcount) ENTRY(mcount)
cmpl $0, function_trace_stop
jne ftrace_stub
cmpq $ftrace_stub, ftrace_trace_function cmpq $ftrace_stub, ftrace_trace_function
jnz trace jnz trace
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
cmpq $ftrace_stub, ftrace_graph_return
jnz ftrace_graph_caller
cmpq $ftrace_graph_entry_stub, ftrace_graph_entry
jnz ftrace_graph_caller
#endif
.globl ftrace_stub .globl ftrace_stub
ftrace_stub: ftrace_stub:
retq retq
trace: trace:
/* taken from glibc */ MCOUNT_SAVE_FRAME
subq $0x38, %rsp
movq 0x38(%rsp), %rdi
movq 8(%rbp), %rsi
subq $MCOUNT_INSN_SIZE, %rdi
call *ftrace_trace_function
MCOUNT_RESTORE_FRAME
jmp ftrace_stub
END(mcount)
#endif /* CONFIG_DYNAMIC_FTRACE */
#endif /* CONFIG_FUNCTION_TRACER */
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
ENTRY(ftrace_graph_caller)
cmpl $0, function_trace_stop
jne ftrace_stub
MCOUNT_SAVE_FRAME
leaq 8(%rbp), %rdi
movq 0x38(%rsp), %rsi
subq $MCOUNT_INSN_SIZE, %rsi
call prepare_ftrace_return
MCOUNT_RESTORE_FRAME
retq
END(ftrace_graph_caller)
.globl return_to_handler
return_to_handler:
subq $80, %rsp
movq %rax, (%rsp) movq %rax, (%rsp)
movq %rcx, 8(%rsp) movq %rcx, 8(%rsp)
movq %rdx, 16(%rsp) movq %rdx, 16(%rsp)
...@@ -118,13 +159,14 @@ trace: ...@@ -118,13 +159,14 @@ trace:
movq %rdi, 32(%rsp) movq %rdi, 32(%rsp)
movq %r8, 40(%rsp) movq %r8, 40(%rsp)
movq %r9, 48(%rsp) movq %r9, 48(%rsp)
movq %r10, 56(%rsp)
movq %r11, 64(%rsp)
movq 0x38(%rsp), %rdi call ftrace_return_to_handler
movq 8(%rbp), %rsi
subq $MCOUNT_INSN_SIZE, %rdi
call *ftrace_trace_function
movq %rax, 72(%rsp)
movq 64(%rsp), %r11
movq 56(%rsp), %r10
movq 48(%rsp), %r9 movq 48(%rsp), %r9
movq 40(%rsp), %r8 movq 40(%rsp), %r8
movq 32(%rsp), %rdi movq 32(%rsp), %rdi
...@@ -132,12 +174,10 @@ trace: ...@@ -132,12 +174,10 @@ trace:
movq 16(%rsp), %rdx movq 16(%rsp), %rdx
movq 8(%rsp), %rcx movq 8(%rsp), %rcx
movq (%rsp), %rax movq (%rsp), %rax
addq $0x38, %rsp addq $72, %rsp
retq
#endif
jmp ftrace_stub
END(mcount)
#endif /* CONFIG_DYNAMIC_FTRACE */
#endif /* CONFIG_FUNCTION_TRACER */
#ifndef CONFIG_PREEMPT #ifndef CONFIG_PREEMPT
#define retint_kernel retint_restore_args #define retint_kernel retint_restore_args
......
This diff is collapsed.
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/ftrace.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/io_apic.h> #include <asm/io_apic.h>
#include <asm/idle.h> #include <asm/idle.h>
...@@ -45,7 +46,7 @@ static inline void stack_overflow_check(struct pt_regs *regs) ...@@ -45,7 +46,7 @@ static inline void stack_overflow_check(struct pt_regs *regs)
* SMP cross-CPU interrupts have their own specific * SMP cross-CPU interrupts have their own specific
* handlers). * handlers).
*/ */
asmlinkage unsigned int do_IRQ(struct pt_regs *regs) asmlinkage unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
{ {
struct pt_regs *old_regs = set_irq_regs(regs); struct pt_regs *old_regs = set_irq_regs(regs);
struct irq_desc *desc; struct irq_desc *desc;
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/clockchips.h> #include <linux/clockchips.h>
#include <linux/ftrace.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/apic.h> #include <asm/apic.h>
...@@ -102,6 +103,9 @@ static inline int hlt_use_halt(void) ...@@ -102,6 +103,9 @@ static inline int hlt_use_halt(void)
void default_idle(void) void default_idle(void)
{ {
if (hlt_use_halt()) { if (hlt_use_halt()) {
struct power_trace it;
trace_power_start(&it, POWER_CSTATE, 1);
current_thread_info()->status &= ~TS_POLLING; current_thread_info()->status &= ~TS_POLLING;
/* /*
* TS_POLLING-cleared state must be visible before we * TS_POLLING-cleared state must be visible before we
...@@ -114,6 +118,7 @@ void default_idle(void) ...@@ -114,6 +118,7 @@ void default_idle(void)
else else
local_irq_enable(); local_irq_enable();
current_thread_info()->status |= TS_POLLING; current_thread_info()->status |= TS_POLLING;
trace_power_end(&it);
} else { } else {
local_irq_enable(); local_irq_enable();
/* loop is done by the caller */ /* loop is done by the caller */
...@@ -171,24 +176,31 @@ EXPORT_SYMBOL_GPL(cpu_idle_wait); ...@@ -171,24 +176,31 @@ EXPORT_SYMBOL_GPL(cpu_idle_wait);
*/ */
void mwait_idle_with_hints(unsigned long ax, unsigned long cx) void mwait_idle_with_hints(unsigned long ax, unsigned long cx)
{ {
struct power_trace it;
trace_power_start(&it, POWER_CSTATE, (ax>>4)+1);
if (!need_resched()) { if (!need_resched()) {
__monitor((void *)&current_thread_info()->flags, 0, 0); __monitor((void *)&current_thread_info()->flags, 0, 0);
smp_mb(); smp_mb();
if (!need_resched()) if (!need_resched())
__mwait(ax, cx); __mwait(ax, cx);
} }
trace_power_end(&it);
} }
/* Default MONITOR/MWAIT with no hints, used for default C1 state */ /* Default MONITOR/MWAIT with no hints, used for default C1 state */
static void mwait_idle(void) static void mwait_idle(void)
{ {
struct power_trace it;
if (!need_resched()) { if (!need_resched()) {
trace_power_start(&it, POWER_CSTATE, 1);
__monitor((void *)&current_thread_info()->flags, 0, 0); __monitor((void *)&current_thread_info()->flags, 0, 0);
smp_mb(); smp_mb();
if (!need_resched()) if (!need_resched())
__sti_mwait(0, 0); __sti_mwait(0, 0);
else else
local_irq_enable(); local_irq_enable();
trace_power_end(&it);
} else } else
local_irq_enable(); local_irq_enable();
} }
...@@ -200,9 +212,13 @@ static void mwait_idle(void) ...@@ -200,9 +212,13 @@ static void mwait_idle(void)
*/ */
static void poll_idle(void) static void poll_idle(void)
{ {
struct power_trace it;
trace_power_start(&it, POWER_CSTATE, 0);
local_irq_enable(); local_irq_enable();
while (!need_resched()) while (!need_resched())
cpu_relax(); cpu_relax();
trace_power_end(&it);
} }
/* /*
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include <linux/percpu.h> #include <linux/percpu.h>
#include <linux/prctl.h> #include <linux/prctl.h>
#include <linux/dmi.h> #include <linux/dmi.h>
#include <linux/ftrace.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
...@@ -59,6 +60,7 @@ ...@@ -59,6 +60,7 @@
#include <asm/idle.h> #include <asm/idle.h>
#include <asm/syscalls.h> #include <asm/syscalls.h>
#include <asm/smp.h> #include <asm/smp.h>
#include <asm/ds.h>
asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
...@@ -250,14 +252,8 @@ void exit_thread(void) ...@@ -250,14 +252,8 @@ void exit_thread(void)
tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET; tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET;
put_cpu(); put_cpu();
} }
#ifdef CONFIG_X86_DS
/* Free any DS contexts that have not been properly released. */ ds_exit_thread(current);
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) void flush_thread(void)
...@@ -339,6 +335,12 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, ...@@ -339,6 +335,12 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
kfree(p->thread.io_bitmap_ptr); kfree(p->thread.io_bitmap_ptr);
p->thread.io_bitmap_max = 0; p->thread.io_bitmap_max = 0;
} }
ds_copy_thread(p, current);
clear_tsk_thread_flag(p, TIF_DEBUGCTLMSR);
p->thread.debugctlmsr = 0;
return err; return err;
} }
...@@ -419,48 +421,19 @@ int set_tsc_mode(unsigned int val) ...@@ -419,48 +421,19 @@ int set_tsc_mode(unsigned int val)
return 0; return 0;
} }
#ifdef CONFIG_X86_DS
static int update_debugctl(struct thread_struct *prev,
struct thread_struct *next, unsigned long debugctl)
{
unsigned long ds_prev = 0;
unsigned long ds_next = 0;
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, ds_next, 0);
}
return debugctl;
}
#else
static int update_debugctl(struct thread_struct *prev,
struct thread_struct *next, unsigned long debugctl)
{
return debugctl;
}
#endif /* CONFIG_X86_DS */
static noinline void static noinline void
__switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p, __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,
struct tss_struct *tss) struct tss_struct *tss)
{ {
struct thread_struct *prev, *next; struct thread_struct *prev, *next;
unsigned long debugctl;
prev = &prev_p->thread; prev = &prev_p->thread;
next = &next_p->thread; next = &next_p->thread;
debugctl = update_debugctl(prev, next, prev->debugctlmsr); if (test_tsk_thread_flag(next_p, TIF_DS_AREA_MSR) ||
test_tsk_thread_flag(prev_p, TIF_DS_AREA_MSR))
if (next->debugctlmsr != debugctl) ds_switch_to(prev_p, next_p);
else if (next->debugctlmsr != prev->debugctlmsr)
update_debugctlmsr(next->debugctlmsr); update_debugctlmsr(next->debugctlmsr);
if (test_tsk_thread_flag(next_p, TIF_DEBUG)) { if (test_tsk_thread_flag(next_p, TIF_DEBUG)) {
...@@ -482,15 +455,6 @@ __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p, ...@@ -482,15 +455,6 @@ __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,
hard_enable_TSC(); hard_enable_TSC();
} }
#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 /* CONFIG_X86_PTRACE_BTS */
if (!test_tsk_thread_flag(next_p, TIF_IO_BITMAP)) { if (!test_tsk_thread_flag(next_p, TIF_IO_BITMAP)) {
/* /*
* Disable the bitmap via an invalid offset. We still cache * Disable the bitmap via an invalid offset. We still cache
...@@ -548,7 +512,8 @@ __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p, ...@@ -548,7 +512,8 @@ __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,
* the task-switch, and shows up in ret_from_fork in entry.S, * the task-switch, and shows up in ret_from_fork in entry.S,
* for example. * for example.
*/ */
struct task_struct * __switch_to(struct task_struct *prev_p, struct task_struct *next_p) __notrace_funcgraph struct task_struct *
__switch_to(struct task_struct *prev_p, struct task_struct *next_p)
{ {
struct thread_struct *prev = &prev_p->thread, struct thread_struct *prev = &prev_p->thread,
*next = &next_p->thread; *next = &next_p->thread;
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <linux/prctl.h> #include <linux/prctl.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/ftrace.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/system.h> #include <asm/system.h>
...@@ -52,6 +53,7 @@ ...@@ -52,6 +53,7 @@
#include <asm/ia32.h> #include <asm/ia32.h>
#include <asm/idle.h> #include <asm/idle.h>
#include <asm/syscalls.h> #include <asm/syscalls.h>
#include <asm/ds.h>
asmlinkage extern void ret_from_fork(void); asmlinkage extern void ret_from_fork(void);
...@@ -235,14 +237,8 @@ void exit_thread(void) ...@@ -235,14 +237,8 @@ void exit_thread(void)
t->io_bitmap_max = 0; t->io_bitmap_max = 0;
put_cpu(); put_cpu();
} }
#ifdef CONFIG_X86_DS
/* Free any DS contexts that have not been properly released. */ ds_exit_thread(current);
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) void flush_thread(void)
...@@ -372,6 +368,12 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, ...@@ -372,6 +368,12 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
if (err) if (err)
goto out; goto out;
} }
ds_copy_thread(p, me);
clear_tsk_thread_flag(p, TIF_DEBUGCTLMSR);
p->thread.debugctlmsr = 0;
err = 0; err = 0;
out: out:
if (err && p->thread.io_bitmap_ptr) { if (err && p->thread.io_bitmap_ptr) {
...@@ -470,35 +472,14 @@ static inline void __switch_to_xtra(struct task_struct *prev_p, ...@@ -470,35 +472,14 @@ static inline void __switch_to_xtra(struct task_struct *prev_p,
struct tss_struct *tss) struct tss_struct *tss)
{ {
struct thread_struct *prev, *next; struct thread_struct *prev, *next;
unsigned long debugctl;
prev = &prev_p->thread, prev = &prev_p->thread,
next = &next_p->thread; next = &next_p->thread;
debugctl = prev->debugctlmsr; if (test_tsk_thread_flag(next_p, TIF_DS_AREA_MSR) ||
test_tsk_thread_flag(prev_p, TIF_DS_AREA_MSR))
#ifdef CONFIG_X86_DS ds_switch_to(prev_p, next_p);
{ else if (next->debugctlmsr != prev->debugctlmsr)
unsigned long ds_prev = 0, ds_next = 0;
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, ds_next);
}
}
#endif /* CONFIG_X86_DS */
if (next->debugctlmsr != debugctl)
update_debugctlmsr(next->debugctlmsr); update_debugctlmsr(next->debugctlmsr);
if (test_tsk_thread_flag(next_p, TIF_DEBUG)) { if (test_tsk_thread_flag(next_p, TIF_DEBUG)) {
...@@ -533,14 +514,6 @@ static inline void __switch_to_xtra(struct task_struct *prev_p, ...@@ -533,14 +514,6 @@ static inline void __switch_to_xtra(struct task_struct *prev_p,
*/ */
memset(tss->io_bitmap, 0xff, prev->io_bitmap_max); memset(tss->io_bitmap, 0xff, prev->io_bitmap_max);
} }
#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 /* CONFIG_X86_PTRACE_BTS */
} }
/* /*
...@@ -551,8 +524,9 @@ static inline void __switch_to_xtra(struct task_struct *prev_p, ...@@ -551,8 +524,9 @@ static inline void __switch_to_xtra(struct task_struct *prev_p,
* - could test fs/gs bitsliced * - could test fs/gs bitsliced
* *
* Kprobes not supported here. Set the probe on schedule instead. * Kprobes not supported here. Set the probe on schedule instead.
* Function graph tracer not supported too.
*/ */
struct task_struct * __notrace_funcgraph struct task_struct *
__switch_to(struct task_struct *prev_p, struct task_struct *next_p) __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
{ {
struct thread_struct *prev = &prev_p->thread; struct thread_struct *prev = &prev_p->thread;
......
This diff is collapsed.
...@@ -288,7 +288,7 @@ static int __cpuinitdata unsafe_smp; ...@@ -288,7 +288,7 @@ static int __cpuinitdata unsafe_smp;
/* /*
* Activate a secondary processor. * Activate a secondary processor.
*/ */
static void __cpuinit start_secondary(void *unused) notrace static void __cpuinit start_secondary(void *unused)
{ {
/* /*
* Don't put *anything* before cpu_init(), SMP booting is too * Don't put *anything* before cpu_init(), SMP booting is too
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/stacktrace.h> #include <linux/stacktrace.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/uaccess.h>
#include <asm/stacktrace.h> #include <asm/stacktrace.h>
static void save_stack_warning(void *data, char *msg) static void save_stack_warning(void *data, char *msg)
...@@ -83,3 +84,66 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) ...@@ -83,3 +84,66 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
trace->entries[trace->nr_entries++] = ULONG_MAX; trace->entries[trace->nr_entries++] = ULONG_MAX;
} }
EXPORT_SYMBOL_GPL(save_stack_trace_tsk); EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
/* Userspace stacktrace - based on kernel/trace/trace_sysprof.c */
struct stack_frame {
const void __user *next_fp;
unsigned long ret_addr;
};
static int copy_stack_frame(const void __user *fp, struct stack_frame *frame)
{
int ret;
if (!access_ok(VERIFY_READ, fp, sizeof(*frame)))
return 0;
ret = 1;
pagefault_disable();
if (__copy_from_user_inatomic(frame, fp, sizeof(*frame)))
ret = 0;
pagefault_enable();
return ret;
}
static inline void __save_stack_trace_user(struct stack_trace *trace)
{
const struct pt_regs *regs = task_pt_regs(current);
const void __user *fp = (const void __user *)regs->bp;
if (trace->nr_entries < trace->max_entries)
trace->entries[trace->nr_entries++] = regs->ip;
while (trace->nr_entries < trace->max_entries) {
struct stack_frame frame;
frame.next_fp = NULL;
frame.ret_addr = 0;
if (!copy_stack_frame(fp, &frame))
break;
if ((unsigned long)fp < regs->sp)
break;
if (frame.ret_addr) {
trace->entries[trace->nr_entries++] =
frame.ret_addr;
}
if (fp == frame.next_fp)
break;
fp = frame.next_fp;
}
}
void save_stack_trace_user(struct stack_trace *trace)
{
/*
* Trace user stack if we are not a kernel thread
*/
if (current->mm) {
__save_stack_trace_user(trace);
}
if (trace->nr_entries < trace->max_entries)
trace->entries[trace->nr_entries++] = ULONG_MAX;
}
...@@ -44,6 +44,7 @@ SECTIONS ...@@ -44,6 +44,7 @@ SECTIONS
SCHED_TEXT SCHED_TEXT
LOCK_TEXT LOCK_TEXT
KPROBES_TEXT KPROBES_TEXT
IRQENTRY_TEXT
*(.fixup) *(.fixup)
*(.gnu.warning) *(.gnu.warning)
_etext = .; /* End of text section */ _etext = .; /* End of text section */
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment