Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
4cc9bed0
Commit
4cc9bed0
authored
Jan 05, 2011
by
Martin Schwidefsky
Committed by
Martin Schwidefsky
Jan 05, 2011
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[S390] cleanup ftrace backend functions
Signed-off-by:
Martin Schwidefsky
<
schwidefsky@de.ibm.com
>
parent
5e9a2692
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
135 additions
and
171 deletions
+135
-171
arch/s390/include/asm/ftrace.h
arch/s390/include/asm/ftrace.h
+4
-7
arch/s390/kernel/ftrace.c
arch/s390/kernel/ftrace.c
+117
-121
arch/s390/kernel/mcount.S
arch/s390/kernel/mcount.S
+7
-23
arch/s390/kernel/mcount64.S
arch/s390/kernel/mcount64.S
+7
-20
No files found.
arch/s390/include/asm/ftrace.h
View file @
4cc9bed0
...
...
@@ -4,20 +4,17 @@
#ifndef __ASSEMBLY__
extern
void
_mcount
(
void
);
extern
unsigned
long
ftrace_dyn_func
;
struct
dyn_arch_ftrace
{
};
#define MCOUNT_ADDR ((long)_mcount)
#ifdef CONFIG_64BIT
#define MCOUNT_OFFSET_RET 18
#define MCOUNT_INSN_SIZE 24
#define MCOUNT_OFFSET 14
#else
#define MCOUNT_OFFSET_RET 26
#define MCOUNT_INSN_SIZE 30
#define MCOUNT_INSN_SIZE 12
#define MCOUNT_OFFSET 8
#else
#define MCOUNT_INSN_SIZE 20
#define MCOUNT_OFFSET 4
#endif
static
inline
unsigned
long
ftrace_call_adjust
(
unsigned
long
addr
)
...
...
arch/s390/kernel/ftrace.c
View file @
4cc9bed0
...
...
@@ -4,7 +4,7 @@
* Copyright IBM Corp. 2009
*
* Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
*
*
Martin Schwidefsky <schwidefsky@de.ibm.com>
*/
#include <linux/hardirq.h>
...
...
@@ -12,176 +12,144 @@
#include <linux/ftrace.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/kprobes.h>
#include <trace/syscall.h>
#include <asm/asm-offsets.h>
#ifdef CONFIG_64BIT
#define MCOUNT_OFFSET_RET 12
#else
#define MCOUNT_OFFSET_RET 22
#endif
#ifdef CONFIG_DYNAMIC_FTRACE
void
ftrace_disable_code
(
void
);
void
ftrace_disable_return
(
void
);
void
ftrace_call_code
(
void
);
void
ftrace_nop_code
(
void
);
#define FTRACE_INSN_SIZE 4
void
ftrace_enable_insn
(
void
);
#ifdef CONFIG_64BIT
/*
* The 64-bit mcount code looks like this:
* stg %r14,8(%r15) # offset 0
* > larl %r1,<&counter> # offset 6
* > brasl %r14,_mcount # offset 12
* lg %r14,8(%r15) # offset 18
* Total length is 24 bytes. The middle two instructions of the mcount
* block get overwritten by ftrace_make_nop / ftrace_make_call.
* The 64-bit enabled ftrace code block looks like this:
* stg %r14,8(%r15) # offset 0
* > lg %r1,__LC_FTRACE_FUNC # offset 6
* > lgr %r0,%r0 # offset 12
* > basr %r14,%r1 # offset 16
* lg %r14,8(%15) # offset 18
* The return points of the mcount/ftrace function have the same offset 18.
* The 64-bit disable ftrace code block looks like this:
* stg %r14,8(%r15) # offset 0
* > jg .+18 # offset 6
* > lgr %r0,%r0 # offset 12
* > basr %r14,%r1 # offset 16
* lg %r14,8(%15) # offset 18
* The jg instruction branches to offset 24 to skip as many instructions
* as possible.
*/
asm
(
" .align 4
\n
"
"ftrace_disable_code:
\n
"
" j 0f
\n
"
" .word 0x0024
\n
"
" lg %r1,"
__stringify
(
__LC_FTRACE_FUNC
)
"
\n
"
" basr %r14,%r1
\n
"
"ftrace_disable_return:
\n
"
" lg %r14,8(15)
\n
"
" jg 0f
\n
"
" lgr %r0,%r0
\n
"
"0:
\n
"
);
asm
(
" basr %r14,%r1
\n
"
"0:
\n
"
" .align 4
\n
"
"ftrace_
nop_code
:
\n
"
"
j .+"
__stringify
(
MCOUNT_INSN_SIZE
)
"
\n
"
);
"ftrace_
enable_insn
:
\n
"
"
lg %r1,"
__stringify
(
__LC_FTRACE_FUNC
)
"
\n
"
);
asm
(
" .align 4
\n
"
"ftrace_call_code:
\n
"
" stg %r14,8(%r15)
\n
"
);
#define FTRACE_INSN_SIZE 6
#else
/* CONFIG_64BIT */
/*
* The 31-bit mcount code looks like this:
* st %r14,4(%r15) # offset 0
* > bras %r1,0f # offset 4
* > .long _mcount # offset 8
* > .long <&counter> # offset 12
* > 0: l %r14,0(%r1) # offset 16
* > l %r1,4(%r1) # offset 20
* basr %r14,%r14 # offset 24
* l %r14,4(%r15) # offset 26
* Total length is 30 bytes. The twenty bytes starting from offset 4
* to offset 24 get overwritten by ftrace_make_nop / ftrace_make_call.
* The 31-bit enabled ftrace code block looks like this:
* st %r14,4(%r15) # offset 0
* > l %r14,__LC_FTRACE_FUNC # offset 4
* > j 0f # offset 8
* > .fill 12,1,0x07 # offset 12
* 0: basr %r14,%r14 # offset 24
* l %r14,4(%r14) # offset 26
* The return points of the mcount/ftrace function have the same offset 26.
* The 31-bit disabled ftrace code block looks like this:
* st %r14,4(%r15) # offset 0
* > j .+26 # offset 4
* > j 0f # offset 8
* > .fill 12,1,0x07 # offset 12
* 0: basr %r14,%r14 # offset 24
* l %r14,4(%r14) # offset 26
* The j instruction branches to offset 30 to skip as many instructions
* as possible.
*/
asm
(
" .align 4
\n
"
"ftrace_disable_code:
\n
"
" j 1f
\n
"
" j 0f
\n
"
" l %r1,"
__stringify
(
__LC_FTRACE_FUNC
)
"
\n
"
" basr %r14,%r1
\n
"
"ftrace_disable_return:
\n
"
" l %r14,4(%r15)
\n
"
" j 0f
\n
"
" bcr 0,%r7
\n
"
" bcr 0,%r7
\n
"
" bcr 0,%r7
\n
"
" bcr 0,%r7
\n
"
" bcr 0,%r7
\n
"
" bcr 0,%r7
\n
"
"0:
\n
"
);
asm
(
" .fill 12,1,0x07
\n
"
"0: basr %r14,%r14
\n
"
"1:
\n
"
" .align 4
\n
"
"ftrace_
nop_code
:
\n
"
"
j .+"
__stringify
(
MCOUNT_INSN_SIZE
)
"
\n
"
);
"ftrace_
enable_insn
:
\n
"
"
l %r14,"
__stringify
(
__LC_FTRACE_FUNC
)
"
\n
"
);
asm
(
" .align 4
\n
"
"ftrace_call_code:
\n
"
" st %r14,4(%r15)
\n
"
);
#define FTRACE_INSN_SIZE 4
#endif
/* CONFIG_64BIT */
static
int
ftrace_modify_code
(
unsigned
long
ip
,
void
*
old_code
,
int
old_size
,
void
*
new_code
,
int
new_size
)
{
unsigned
char
replaced
[
MCOUNT_INSN_SIZE
];
/*
* Note: Due to modules code can disappear and change.
* We need to protect against faulting as well as code
* changing. We do this by using the probe_kernel_*
* functions.
* This however is just a simple sanity check.
*/
if
(
probe_kernel_read
(
replaced
,
(
void
*
)
ip
,
old_size
))
return
-
EFAULT
;
if
(
memcmp
(
replaced
,
old_code
,
old_size
)
!=
0
)
return
-
EINVAL
;
if
(
probe_kernel_write
((
void
*
)
ip
,
new_code
,
new_size
))
return
-
EPERM
;
return
0
;
}
static
int
ftrace_make_initial_nop
(
struct
module
*
mod
,
struct
dyn_ftrace
*
rec
,
unsigned
long
addr
)
{
return
ftrace_modify_code
(
rec
->
ip
,
ftrace_call_code
,
FTRACE_INSN_SIZE
,
ftrace_disable_code
,
MCOUNT_INSN_SIZE
);
}
int
ftrace_make_nop
(
struct
module
*
mod
,
struct
dyn_ftrace
*
rec
,
unsigned
long
addr
)
{
if
(
addr
==
MCOUNT_ADDR
)
return
ftrace_make_initial_nop
(
mod
,
rec
,
addr
);
return
ftrace_modify_code
(
rec
->
ip
,
ftrace_call_code
,
FTRACE_INSN_SIZE
,
ftrace_nop_code
,
FTRACE_INSN_SIZE
);
if
(
probe_kernel_write
((
void
*
)
rec
->
ip
,
ftrace_disable_code
,
MCOUNT_INSN_SIZE
))
return
-
EPERM
;
return
0
;
}
int
ftrace_make_call
(
struct
dyn_ftrace
*
rec
,
unsigned
long
addr
)
{
return
ftrace_modify_code
(
rec
->
ip
,
ftrace_nop_code
,
FTRACE_INSN_SIZE
,
ftrace_call_code
,
FTRACE_INSN_SIZE
);
if
(
probe_kernel_write
((
void
*
)
rec
->
ip
,
ftrace_enable_insn
,
FTRACE_INSN_SIZE
))
return
-
EPERM
;
return
0
;
}
int
ftrace_update_ftrace_func
(
ftrace_func_t
func
)
{
ftrace_dyn_func
=
(
unsigned
long
)
func
;
return
0
;
}
int
__init
ftrace_dyn_arch_init
(
void
*
data
)
{
*
(
unsigned
long
*
)
data
=
0
;
*
(
unsigned
long
*
)
data
=
0
;
return
0
;
}
#endif
/* CONFIG_DYNAMIC_FTRACE */
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
#ifdef CONFIG_DYNAMIC_FTRACE
/*
* Patch the kernel code at ftrace_graph_caller location:
* The instruction there is branch relative on condition. The condition mask
* is either all ones (always branch aka disable ftrace_graph_caller) or all
* zeroes (nop aka enable ftrace_graph_caller).
* Instruction format for brc is a7m4xxxx where m is the condition mask.
*/
int
ftrace_enable_ftrace_graph_caller
(
void
)
{
unsigned
short
opcode
=
0xa704
;
return
probe_kernel_write
(
ftrace_graph_caller
,
&
opcode
,
sizeof
(
opcode
));
}
int
ftrace_disable_ftrace_graph_caller
(
void
)
{
unsigned
short
opcode
=
0xa7f4
;
return
probe_kernel_write
(
ftrace_graph_caller
,
&
opcode
,
sizeof
(
opcode
));
}
static
inline
unsigned
long
ftrace_mcount_call_adjust
(
unsigned
long
addr
)
{
return
addr
-
(
ftrace_disable_return
-
ftrace_disable_code
);
}
#else
/* CONFIG_DYNAMIC_FTRACE */
static
inline
unsigned
long
ftrace_mcount_call_adjust
(
unsigned
long
addr
)
{
return
addr
-
MCOUNT_OFFSET_RET
;
}
#endif
/* CONFIG_DYNAMIC_FTRACE */
/*
* Hook the return address and push it in the stack of return addresses
* in current thread info.
*/
unsigned
long
prepare_ftrace_return
(
unsigned
long
ip
,
unsigned
long
parent
)
unsigned
long
__kprobes
prepare_ftrace_return
(
unsigned
long
parent
,
unsigned
long
ip
)
{
struct
ftrace_graph_ent
trace
;
...
...
@@ -189,14 +157,42 @@ unsigned long prepare_ftrace_return(unsigned long ip, unsigned long parent)
goto
out
;
if
(
ftrace_push_return_trace
(
parent
,
ip
,
&
trace
.
depth
,
0
)
==
-
EBUSY
)
goto
out
;
trace
.
func
=
ftrace_mcount_call_adjust
(
ip
)
&
PSW_ADDR_INSN
;
trace
.
func
=
(
ip
&
PSW_ADDR_INSN
)
-
MCOUNT_OFFSET_RET
;
/* Only trace if the calling function expects to. */
if
(
!
ftrace_graph_entry
(
&
trace
))
{
current
->
curr_ret_stack
--
;
goto
out
;
}
parent
=
(
unsigned
long
)
return_to_handler
;
parent
=
(
unsigned
long
)
return_to_handler
;
out:
return
parent
;
}
#ifdef CONFIG_DYNAMIC_FTRACE
/*
* Patch the kernel code at ftrace_graph_caller location. The instruction
* there is branch relative and save to prepare_ftrace_return. To disable
* the call to prepare_ftrace_return we patch the bras offset to point
* directly after the instructions. To enable the call we calculate
* the original offset to prepare_ftrace_return and put it back.
*/
int
ftrace_enable_ftrace_graph_caller
(
void
)
{
unsigned
short
offset
;
offset
=
((
void
*
)
prepare_ftrace_return
-
(
void
*
)
ftrace_graph_caller
)
/
2
;
return
probe_kernel_write
(
ftrace_graph_caller
+
2
,
&
offset
,
sizeof
(
offset
));
}
int
ftrace_disable_ftrace_graph_caller
(
void
)
{
static
unsigned
short
offset
=
0x0002
;
return
probe_kernel_write
(
ftrace_graph_caller
+
2
,
&
offset
,
sizeof
(
offset
));
}
#endif
/* CONFIG_DYNAMIC_FTRACE */
#endif
/* CONFIG_FUNCTION_GRAPH_TRACER */
arch/s390/kernel/mcount.S
View file @
4cc9bed0
...
...
@@ -18,22 +18,12 @@ _mcount:
#ifdef CONFIG_DYNAMIC_FTRACE
br
%
r14
.
data
.
globl
ftrace_dyn_func
ftrace_dyn_func
:
.
long
ftrace_stub
.
previous
.
globl
ftrace_caller
ftrace_caller
:
#endif
stm
%
r2
,%
r5
,
16
(%
r15
)
bras
%
r1
,
2
f
#ifdef CONFIG_DYNAMIC_FTRACE
0
:
.
long
ftrace_dyn_func
#else
0
:
.
long
ftrace_trace_function
#endif
1
:
.
long
function_trace_stop
2
:
l
%
r2
,
1
b
-
0
b
(%
r1
)
icm
%
r2
,
0xf
,
0
(%
r2
)
...
...
@@ -49,21 +39,15 @@ ftrace_caller:
l
%
r14
,
0
(%
r14
)
basr
%
r14
,%
r14
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
#ifdef CONFIG_DYNAMIC_FTRACE
l
%
r2
,
100
(%
r15
)
l
%
r3
,
152
(%
r15
)
.
globl
ftrace_graph_caller
ftrace_graph_caller
:
#
This
unconditional
branch
gets
runtime
patched
.
Change
only
if
#
you
know
what
you
are
doing
.
See
ftrace_enable_graph_caller
()
.
j
1
f
#endif
bras
%
r1
,
0
f
.
long
prepare_ftrace_return
0
:
l
%
r2
,
152
(%
r15
)
l
%
r4
,
0
(%
r1
)
l
%
r3
,
100
(%
r15
)
basr
%
r14
,%
r4
st
%
r2
,
100
(%
r15
)
1
:
#
The
bras
instruction
gets
runtime
patched
to
call
prepare_ftrace_return
.
#
See
ftrace_enable_ftrace_graph_caller
.
The
patched
instruction
is
:
#
bras
%
r14
,
prepare_ftrace_return
bras
%
r14
,
0
f
0
:
st
%
r2
,
100
(%
r15
)
#endif
ahi
%
r15
,
96
l
%
r14
,
56
(%
r15
)
...
...
arch/s390/kernel/mcount64.S
View file @
4cc9bed0
...
...
@@ -18,12 +18,6 @@ _mcount:
#ifdef CONFIG_DYNAMIC_FTRACE
br
%
r14
.
data
.
globl
ftrace_dyn_func
ftrace_dyn_func
:
.
quad
ftrace_stub
.
previous
.
globl
ftrace_caller
ftrace_caller
:
#endif
...
...
@@ -37,26 +31,19 @@ ftrace_caller:
stg
%
r1
,
__SF_BACKCHAIN
(%
r15
)
lgr
%
r2
,%
r14
lg
%
r3
,
168
(%
r15
)
#ifdef CONFIG_DYNAMIC_FTRACE
larl
%
r14
,
ftrace_dyn_func
#else
larl
%
r14
,
ftrace_trace_function
#endif
lg
%
r14
,
0
(%
r14
)
basr
%
r14
,%
r14
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
#ifdef CONFIG_DYNAMIC_FTRACE
lg
%
r2
,
168
(%
r15
)
lg
%
r3
,
272
(%
r15
)
.
globl
ftrace_graph_caller
ftrace_graph_caller
:
#
This
unconditional
branch
gets
runtime
patched
.
Change
only
if
#
you
know
what
you
are
doing
.
See
ftrace_enable_graph_caller
()
.
j
0
f
#endif
lg
%
r2
,
272
(%
r15
)
lg
%
r3
,
168
(%
r15
)
brasl
%
r14
,
prepare_ftrace_return
stg
%
r2
,
168
(%
r15
)
0
:
#
The
bras
instruction
gets
runtime
patched
to
call
prepare_ftrace_return
.
#
See
ftrace_enable_ftrace_graph_caller
.
The
patched
instruction
is
:
#
bras
%
r14
,
prepare_ftrace_return
bras
%
r14
,
0
f
0
:
stg
%
r2
,
168
(%
r15
)
#endif
aghi
%
r15
,
160
lmg
%
r2
,%
r5
,
32
(%
r15
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment