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
nexedi
linux
Commits
d6ff268c
Commit
d6ff268c
authored
Oct 05, 2004
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
bk://kernel.bkbits.net/davem/sparc-2.6
into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents
8756f2ef
cb8b9b70
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
171 additions
and
73 deletions
+171
-73
arch/sparc64/defconfig
arch/sparc64/defconfig
+4
-3
arch/sparc64/kernel/kprobes.c
arch/sparc64/kernel/kprobes.c
+166
-69
arch/sparc64/kernel/signal32.c
arch/sparc64/kernel/signal32.c
+1
-1
No files found.
arch/sparc64/defconfig
View file @
d6ff268c
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.9-rc
2
#
Fri Sep 24 12:34:4
3 2004
# Linux kernel version: 2.6.9-rc
3
#
Sun Oct 3 14:28:5
3 2004
#
CONFIG_64BIT=y
CONFIG_MMU=y
...
...
@@ -561,6 +561,7 @@ CONFIG_IP_NF_MATCH_PHYSDEV=m
CONFIG_IP_NF_MATCH_ADDRTYPE=m
CONFIG_IP_NF_MATCH_REALM=m
CONFIG_IP_NF_MATCH_SCTP=m
CONFIG_IP_NF_MATCH_COMMENT=m
CONFIG_IP_NF_FILTER=m
CONFIG_IP_NF_TARGET_REJECT=m
CONFIG_IP_NF_TARGET_LOG=m
...
...
@@ -1784,7 +1785,7 @@ CONFIG_CRYPTO_MD5=y
CONFIG_CRYPTO_SHA1=y
CONFIG_CRYPTO_SHA256=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_W
HIRLPOOL
=m
CONFIG_CRYPTO_W
P512
=m
CONFIG_CRYPTO_DES=y
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_TWOFISH=m
...
...
arch/sparc64/kernel/kprobes.c
View file @
d6ff268c
...
...
@@ -10,84 +10,69 @@
#include <asm/kdebug.h>
#include <asm/signal.h>
/* We do not have hardware single-stepping, so in order
* to implement post handlers correctly we use two breakpoint
* instructions.
/* We do not have hardware single-stepping on sparc64.
* So we implement software single-stepping with breakpoint
* traps. The top-level scheme is similar to that used
* in the x86 kprobes implementation.
*
* 1) ta 0x70 --> 0x91d02070
* 2) ta 0x71 --> 0x91d02071
* In the kprobe->insn[] array we store the original
* instruction at index zero and a break instruction at
* index one.
*
* When these are hit, control is transferred to kprobe_trap()
* below. The arg 'level' tells us which of the two traps occurred.
* When we hit a kprobe we:
* - Run the pre-handler
* - Remember "regs->tnpc" and interrupt level stored in
* "regs->tstate" so we can restore them later
* - Disable PIL interrupts
* - Set regs->tpc to point to kprobe->insn[0]
* - Set regs->tnpc to point to kprobe->insn[1]
* - Mark that we are actively in a kprobe
*
* Initially, the instruction at p->addr gets set to "ta 0x70"
* by code in register_kprobe() by setting that memory address
* to BREAKPOINT_INSTRUCTION. When this breakpoint is hit
* the following happens:
*
* 1) We run the pre-handler
* 2) We replace p->addr with the original opcode
* 3) We set the instruction at "regs->npc" to "ta 0x71"
* 4) We mark that we are waiting for the second breakpoint
* to hit and return from the trap.
*
* At this point we wait for the second breakpoint to hit.
* When it does:
*
* 1) We run the post-handler
* 2) We re-install "ta 0x70" at p->addr
* 3) We restore the opcode at the "ta 0x71" breakpoint
* 4) We reset our "waiting for "ta 0x71" state
* 5) We return from the trap
*
* We could use the trick used by the i386 kprobe code but I
* think that scheme has problems with exception tables. On i386
* they single-step over the original instruction stored at
* kprobe->insn. So they set the processor to single step, and
* set the program counter to kprobe->insn.
*
* But that explodes if the original opcode is a user space
* access instruction and that faults. It will go wrong because
* since the location of the instruction being executed is
* different from that recorded in the exception tables, the
* kernel will not find it and this will cause an erroneous
* kernel OOPS.
* At this point we wait for the second breakpoint at
* kprobe->insn[1] to hit. When it does we:
* - Run the post-handler
* - Set regs->tpc to "remembered" regs->tnpc stored above,
* restore the PIL interrupt level in "regs->tstate" as well
* - Make any adjustments necessary to regs->tnpc in order
* to handle relative branches correctly. See below.
* - Mark that we are no longer actively in a kprobe.
*/
void
arch_prepare_kprobe
(
struct
kprobe
*
p
)
{
p
->
insn
[
0
]
=
*
p
->
addr
;
p
->
insn
[
1
]
=
0xdeadbeef
;
p
->
insn
[
1
]
=
BREAKPOINT_INSTRUCTION_2
;
}
static
void
prepare_singlestep
(
struct
kprobe
*
p
,
struct
pt_regs
*
regs
)
{
u32
*
insn2
=
(
u32
*
)
regs
->
tpc
;
p
->
insn
[
1
]
=
*
insn2
;
/* kprobe_status settings */
#define KPROBE_HIT_ACTIVE 0x00000001
#define KPROBE_HIT_SS 0x00000002
*
insn2
=
BREAKPOINT_INSTRUCTION_2
;
flushi
(
insn2
);
}
static
struct
kprobe
*
current_kprobe
;
static
unsigned
long
current_kprobe_orig_tnpc
;
static
unsigned
long
current_kprobe_orig_tstate_pil
;
static
unsigned
int
kprobe_status
;
static
void
undo
_singlestep
(
struct
kprobe
*
p
,
struct
pt_regs
*
regs
)
static
inline
void
prepare
_singlestep
(
struct
kprobe
*
p
,
struct
pt_regs
*
regs
)
{
u32
*
insn2
=
(
u32
*
)
regs
->
t
pc
;
BUG_ON
(
p
->
insn
[
1
]
==
0xdeadbeef
)
;
current_kprobe_orig_tnpc
=
regs
->
tn
pc
;
current_kprobe_orig_tstate_pil
=
(
regs
->
tstate
&
TSTATE_PIL
);
regs
->
tstate
|=
TSTATE_PIL
;
*
insn2
=
p
->
insn
[
1
];
flushi
(
insn2
);
p
->
insn
[
1
]
=
0xdeadbeef
;
regs
->
tpc
=
(
unsigned
long
)
&
p
->
insn
[
0
];
regs
->
tnpc
=
(
unsigned
long
)
&
p
->
insn
[
1
];
}
/* kprobe_status settings */
#define KPROBE_HIT_ACTIVE 0x00000001
#define KPROBE_HIT_SS 0x00000002
static
inline
void
disarm_kprobe
(
struct
kprobe
*
p
,
struct
pt_regs
*
regs
)
{
*
p
->
addr
=
p
->
opcode
;
flushi
(
p
->
addr
);
static
struct
kprobe
*
current_kprobe
;
static
unsigned
int
kprobe_status
;
regs
->
tpc
=
(
unsigned
long
)
p
->
addr
;
regs
->
tnpc
=
current_kprobe_orig_tnpc
;
regs
->
tstate
=
((
regs
->
tstate
&
~
TSTATE_PIL
)
|
current_kprobe_orig_tstate_pil
);
}
static
int
kprobe_handler
(
struct
pt_regs
*
regs
)
{
...
...
@@ -98,16 +83,19 @@ static int kprobe_handler(struct pt_regs *regs)
preempt_disable
();
if
(
kprobe_running
())
{
/* We *are* holding lock here, so this is safe.
* Disarm the probe we just hit, and ignore it.
*/
p
=
get_kprobe
(
addr
);
if
(
p
)
{
*
p
->
addr
=
p
->
opcode
;
flushi
(
p
->
addr
);
disarm_kprobe
(
p
,
regs
);
ret
=
1
;
}
else
{
p
=
current_kprobe
;
if
(
p
->
break_handler
&&
p
->
break_handler
(
p
,
regs
))
goto
ss_probe
;
}
/* If it's not ours, can't be delete race, (we hold lock). */
goto
no_kprobe
;
}
...
...
@@ -115,8 +103,17 @@ static int kprobe_handler(struct pt_regs *regs)
p
=
get_kprobe
(
addr
);
if
(
!
p
)
{
unlock_kprobes
();
if
(
*
(
u32
*
)
addr
!=
BREAKPOINT_INSTRUCTION
)
if
(
*
(
u32
*
)
addr
!=
BREAKPOINT_INSTRUCTION
)
{
/*
* The breakpoint instruction was removed right
* after we hit it. Another cpu has removed
* either a probepoint or a debugger breakpoint
* at this address. In either case, no further
* handling of this interrupt is appropriate.
*/
ret
=
1
;
}
/* Not one of ours: let kernel handle it */
goto
no_kprobe
;
}
...
...
@@ -135,17 +132,102 @@ static int kprobe_handler(struct pt_regs *regs)
return
ret
;
}
static
int
post_kprobe_handler
(
struct
pt_regs
*
regs
)
/* If INSN is a relative control transfer instruction,
* return the corrected branch destination value.
*
* The original INSN location was REAL_PC, it actually
* executed at PC and produced destination address NPC.
*/
static
unsigned
long
relbranch_fixup
(
u32
insn
,
unsigned
long
real_pc
,
unsigned
long
pc
,
unsigned
long
npc
)
{
u32
*
insn_p
=
(
u32
*
)
regs
->
tpc
;
/* Branch not taken, no mods necessary. */
if
(
npc
==
pc
+
0x4UL
)
return
real_pc
+
0x4UL
;
if
(
!
kprobe_running
()
||
(
*
insn_p
!=
BREAKPOINT_INSTRUCTION_2
))
/* The three cases are call, branch w/prediction,
* and traditional branch.
*/
if
((
insn
&
0xc0000000
)
==
0x40000000
||
(
insn
&
0xc1c00000
)
==
0x00400000
||
(
insn
&
0xc1c00000
)
==
0x00800000
)
{
/* The instruction did all the work for us
* already, just apply the offset to the correct
* instruction location.
*/
return
(
real_pc
+
(
npc
-
pc
));
}
return
real_pc
+
0x4UL
;
}
/* If INSN is an instruction which writes it's PC location
* into a destination register, fix that up.
*/
static
void
retpc_fixup
(
struct
pt_regs
*
regs
,
u32
insn
,
unsigned
long
real_pc
)
{
unsigned
long
*
slot
=
NULL
;
/* Simplest cast is call, which always uses %o7 */
if
((
insn
&
0xc0000000
)
==
0x40000000
)
{
slot
=
&
regs
->
u_regs
[
UREG_I7
];
}
/* Jmpl encodes the register inside of the opcode */
if
((
insn
&
0xc1f80000
)
==
0x81c00000
)
{
unsigned
long
rd
=
((
insn
>>
25
)
&
0x1f
);
if
(
rd
<=
15
)
{
slot
=
&
regs
->
u_regs
[
rd
];
}
else
{
/* Hard case, it goes onto the stack. */
flushw_all
();
rd
-=
16
;
slot
=
(
unsigned
long
*
)
(
regs
->
u_regs
[
UREG_FP
]
+
STACK_BIAS
);
slot
+=
rd
;
}
}
if
(
slot
!=
NULL
)
*
slot
=
real_pc
;
}
/*
* Called after single-stepping. p->addr is the address of the
* instruction whose first byte has been replaced by the breakpoint
* instruction. To avoid the SMP problems that can occur when we
* temporarily put back the original opcode to single-step, we
* single-stepped a copy of the instruction. The address of this
* copy is p->insn.
*
* This function prepares to return from the post-single-step
* breakpoint trap.
*/
static
void
resume_execution
(
struct
kprobe
*
p
,
struct
pt_regs
*
regs
)
{
u32
insn
=
p
->
insn
[
0
];
regs
->
tpc
=
current_kprobe_orig_tnpc
;
regs
->
tnpc
=
relbranch_fixup
(
insn
,
(
unsigned
long
)
p
->
addr
,
(
unsigned
long
)
&
p
->
insn
[
0
],
regs
->
tnpc
);
retpc_fixup
(
regs
,
insn
,
(
unsigned
long
)
p
->
addr
);
regs
->
tstate
=
((
regs
->
tstate
&
~
TSTATE_PIL
)
|
current_kprobe_orig_tstate_pil
);
}
static
inline
int
post_kprobe_handler
(
struct
pt_regs
*
regs
)
{
if
(
!
kprobe_running
())
return
0
;
if
(
current_kprobe
->
post_handler
)
current_kprobe
->
post_handler
(
current_kprobe
,
regs
,
0
);
undo_singlestep
(
current_kprobe
,
regs
);
resume_execution
(
current_kprobe
,
regs
);
unlock_kprobes
();
preempt_enable_no_resched
();
...
...
@@ -161,7 +243,7 @@ static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
return
1
;
if
(
kprobe_status
&
KPROBE_HIT_SS
)
{
undo_singlestep
(
current_kprobe
,
regs
);
resume_execution
(
current_kprobe
,
regs
);
unlock_kprobes
();
preempt_enable_no_resched
();
...
...
@@ -222,12 +304,14 @@ asmlinkage void kprobe_trap(unsigned long trap_level, struct pt_regs *regs)
/* Jprobes support. */
static
struct
pt_regs
jprobe_saved_regs
;
static
struct
pt_regs
*
jprobe_saved_regs_location
;
static
struct
sparc_stackf
jprobe_saved_stack
;
int
setjmp_pre_handler
(
struct
kprobe
*
p
,
struct
pt_regs
*
regs
)
{
struct
jprobe
*
jp
=
container_of
(
p
,
struct
jprobe
,
kp
);
jprobe_saved_regs_location
=
regs
;
memcpy
(
&
jprobe_saved_regs
,
regs
,
sizeof
(
*
regs
));
/* Save a whole stack frame, this gets arguments
...
...
@@ -240,6 +324,7 @@ int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
regs
->
tpc
=
(
unsigned
long
)
jp
->
entry
;
regs
->
tnpc
=
((
unsigned
long
)
jp
->
entry
)
+
0x4UL
;
regs
->
tstate
|=
TSTATE_PIL
;
return
1
;
}
...
...
@@ -255,11 +340,23 @@ void jprobe_return(void)
extern
void
jprobe_return_trap_instruction
(
void
);
extern
void
__show_regs
(
struct
pt_regs
*
regs
);
int
longjmp_break_handler
(
struct
kprobe
*
p
,
struct
pt_regs
*
regs
)
{
u32
*
addr
=
(
u32
*
)
regs
->
tpc
;
if
(
addr
==
(
u32
*
)
jprobe_return_trap_instruction
)
{
if
(
jprobe_saved_regs_location
!=
regs
)
{
printk
(
"JPROBE: Current regs (%p) does not match "
"saved regs (%p).
\n
"
,
regs
,
jprobe_saved_regs_location
);
printk
(
"JPROBE: Saved registers
\n
"
);
__show_regs
(
jprobe_saved_regs_location
);
printk
(
"JPROBE: Current registers
\n
"
);
__show_regs
(
regs
);
BUG
();
}
/* Restore old register state. Do pt_regs
* first so that UREG_FP is the original one for
* the stack frame restore.
...
...
arch/sparc64/kernel/signal32.c
View file @
d6ff268c
...
...
@@ -181,7 +181,7 @@ int copy_siginfo_to_user32(struct siginfo32 __user *to, siginfo_t *from)
case
__SI_TIMER
>>
16
:
err
|=
__put_user
(
from
->
si_tid
,
&
to
->
si_tid
);
err
|=
__put_user
(
from
->
si_overrun
,
&
to
->
si_overrun
);
err
|=
__put_user
(
(
u32
)(
u64
)
from
->
si_ptr
,
&
to
->
si_ptr
);
err
|=
__put_user
(
from
->
si_int
,
&
to
->
si_int
);
break
;
case
__SI_CHLD
>>
16
:
err
|=
__put_user
(
from
->
si_utime
,
&
to
->
si_utime
);
...
...
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