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
1e56f6d2
Commit
1e56f6d2
authored
Jul 27, 2020
by
Al Viro
Browse files
Options
Browse Files
Download
Plain Diff
Merge branches 'regset.x86', 'regset.ia64', 'regset.sparc' and 'regset.arm64' into work.regset
parents
b4e9c954
4dfa103e
e3fdfa37
b7e46c52
d547175b
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
588 additions
and
410 deletions
+588
-410
arch/arm64/kernel/ptrace.c
arch/arm64/kernel/ptrace.c
+38
-29
arch/ia64/kernel/ptrace.c
arch/ia64/kernel/ptrace.c
+98
-177
arch/sparc/kernel/ptrace_32.c
arch/sparc/kernel/ptrace_32.c
+155
-71
arch/sparc/kernel/ptrace_64.c
arch/sparc/kernel/ptrace_64.c
+291
-110
arch/x86/include/asm/fpu/internal.h
arch/x86/include/asm/fpu/internal.h
+0
-1
arch/x86/kernel/fpu/regset.c
arch/x86/kernel/fpu/regset.c
+0
-16
arch/x86/kernel/fpu/signal.c
arch/x86/kernel/fpu/signal.c
+6
-6
No files found.
arch/arm64/kernel/ptrace.c
View file @
1e56f6d2
...
...
@@ -1237,6 +1237,22 @@ enum compat_regset {
REGSET_COMPAT_VFP
,
};
static
inline
compat_ulong_t
compat_get_user_reg
(
struct
task_struct
*
task
,
int
idx
)
{
struct
pt_regs
*
regs
=
task_pt_regs
(
task
);
switch
(
idx
)
{
case
15
:
return
regs
->
pc
;
case
16
:
return
pstate_to_compat_psr
(
regs
->
pstate
);
case
17
:
return
regs
->
orig_x0
;
default:
return
regs
->
regs
[
idx
];
}
}
static
int
compat_gpr_get
(
struct
task_struct
*
target
,
const
struct
user_regset
*
regset
,
unsigned
int
pos
,
unsigned
int
count
,
...
...
@@ -1255,23 +1271,7 @@ static int compat_gpr_get(struct task_struct *target,
return
-
EIO
;
for
(
i
=
0
;
i
<
num_regs
;
++
i
)
{
unsigned
int
idx
=
start
+
i
;
compat_ulong_t
reg
;
switch
(
idx
)
{
case
15
:
reg
=
task_pt_regs
(
target
)
->
pc
;
break
;
case
16
:
reg
=
task_pt_regs
(
target
)
->
pstate
;
reg
=
pstate_to_compat_psr
(
reg
);
break
;
case
17
:
reg
=
task_pt_regs
(
target
)
->
orig_x0
;
break
;
default:
reg
=
task_pt_regs
(
target
)
->
regs
[
idx
];
}
compat_ulong_t
reg
=
compat_get_user_reg
(
target
,
start
+
i
);
if
(
kbuf
)
{
memcpy
(
kbuf
,
&
reg
,
sizeof
(
reg
));
...
...
@@ -1541,9 +1541,7 @@ static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off,
else
if
(
off
==
COMPAT_PT_TEXT_END_ADDR
)
tmp
=
tsk
->
mm
->
end_code
;
else
if
(
off
<
sizeof
(
compat_elf_gregset_t
))
return
copy_regset_to_user
(
tsk
,
&
user_aarch32_view
,
REGSET_COMPAT_GPR
,
off
,
sizeof
(
compat_ulong_t
),
ret
);
tmp
=
compat_get_user_reg
(
tsk
,
off
>>
2
);
else
if
(
off
>=
COMPAT_USER_SZ
)
return
-
EIO
;
else
...
...
@@ -1555,8 +1553,8 @@ static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off,
static
int
compat_ptrace_write_user
(
struct
task_struct
*
tsk
,
compat_ulong_t
off
,
compat_ulong_t
val
)
{
int
ret
;
mm_segment_t
old_fs
=
get_fs
()
;
struct
pt_regs
newregs
=
*
task_pt_regs
(
tsk
)
;
unsigned
int
idx
=
off
/
4
;
if
(
off
&
3
||
off
>=
COMPAT_USER_SZ
)
return
-
EIO
;
...
...
@@ -1564,14 +1562,25 @@ static int compat_ptrace_write_user(struct task_struct *tsk, compat_ulong_t off,
if
(
off
>=
sizeof
(
compat_elf_gregset_t
))
return
0
;
set_fs
(
KERNEL_DS
);
ret
=
copy_regset_from_user
(
tsk
,
&
user_aarch32_view
,
REGSET_COMPAT_GPR
,
off
,
sizeof
(
compat_ulong_t
),
&
val
);
set_fs
(
old_fs
);
switch
(
idx
)
{
case
15
:
newregs
.
pc
=
val
;
break
;
case
16
:
newregs
.
pstate
=
compat_psr_to_pstate
(
val
);
break
;
case
17
:
newregs
.
orig_x0
=
val
;
break
;
default:
newregs
.
regs
[
idx
]
=
val
;
}
if
(
!
valid_user_regs
(
&
newregs
.
user_regs
,
tsk
))
return
-
EINVAL
;
return
ret
;
*
task_pt_regs
(
tsk
)
=
newregs
;
return
0
;
}
#ifdef CONFIG_HAVE_HW_BREAKPOINT
...
...
arch/ia64/kernel/ptrace.c
View file @
1e56f6d2
...
...
@@ -1273,52 +1273,43 @@ struct regset_getset {
int
ret
;
};
static
const
ptrdiff_t
pt_offsets
[
32
]
=
{
#define R(n) offsetof(struct pt_regs, r##n)
[
0
]
=
-
1
,
R
(
1
),
R
(
2
),
R
(
3
),
[
4
]
=
-
1
,
[
5
]
=
-
1
,
[
6
]
=
-
1
,
[
7
]
=
-
1
,
R
(
8
),
R
(
9
),
R
(
10
),
R
(
11
),
R
(
12
),
R
(
13
),
R
(
14
),
R
(
15
),
R
(
16
),
R
(
17
),
R
(
18
),
R
(
19
),
R
(
20
),
R
(
21
),
R
(
22
),
R
(
23
),
R
(
24
),
R
(
25
),
R
(
26
),
R
(
27
),
R
(
28
),
R
(
29
),
R
(
30
),
R
(
31
),
#undef R
};
static
int
access_elf_gpreg
(
struct
task_struct
*
target
,
struct
unw_frame_info
*
info
,
unsigned
long
addr
,
unsigned
long
*
data
,
int
write_access
)
{
struct
pt_regs
*
pt
;
unsigned
long
*
ptr
=
NULL
;
int
ret
;
char
nat
=
0
;
struct
pt_regs
*
pt
=
task_pt_regs
(
target
);
unsigned
reg
=
addr
/
sizeof
(
unsigned
long
);
ptrdiff_t
d
=
pt_offsets
[
reg
];
pt
=
task_pt_regs
(
target
);
switch
(
addr
)
{
case
ELF_GR_OFFSET
(
1
):
ptr
=
&
pt
->
r1
;
break
;
case
ELF_GR_OFFSET
(
2
):
case
ELF_GR_OFFSET
(
3
):
ptr
=
(
void
*
)
&
pt
->
r2
+
(
addr
-
ELF_GR_OFFSET
(
2
));
break
;
case
ELF_GR_OFFSET
(
4
)
...
ELF_GR_OFFSET
(
7
):
if
(
d
>=
0
)
{
unsigned
long
*
ptr
=
(
void
*
)
pt
+
d
;
if
(
write_access
)
*
ptr
=
*
data
;
else
*
data
=
*
ptr
;
return
0
;
}
else
{
char
nat
=
0
;
if
(
write_access
)
{
/* read NaT bit first: */
unsigned
long
dummy
;
ret
=
unw_get_gr
(
info
,
addr
/
8
,
&
dummy
,
&
nat
);
int
ret
=
unw_get_gr
(
info
,
reg
,
&
dummy
,
&
nat
);
if
(
ret
<
0
)
return
ret
;
}
return
unw_access_gr
(
info
,
addr
/
8
,
data
,
&
nat
,
write_access
);
case
ELF_GR_OFFSET
(
8
)
...
ELF_GR_OFFSET
(
11
):
ptr
=
(
void
*
)
&
pt
->
r8
+
addr
-
ELF_GR_OFFSET
(
8
);
break
;
case
ELF_GR_OFFSET
(
12
):
case
ELF_GR_OFFSET
(
13
):
ptr
=
(
void
*
)
&
pt
->
r12
+
addr
-
ELF_GR_OFFSET
(
12
);
break
;
case
ELF_GR_OFFSET
(
14
):
ptr
=
&
pt
->
r14
;
break
;
case
ELF_GR_OFFSET
(
15
):
ptr
=
&
pt
->
r15
;
return
unw_access_gr
(
info
,
reg
,
data
,
&
nat
,
write_access
);
}
if
(
write_access
)
*
ptr
=
*
data
;
else
*
data
=
*
ptr
;
return
0
;
}
static
int
...
...
@@ -1490,7 +1481,7 @@ static int
access_elf_reg
(
struct
task_struct
*
target
,
struct
unw_frame_info
*
info
,
unsigned
long
addr
,
unsigned
long
*
data
,
int
write_access
)
{
if
(
addr
>=
ELF_GR_OFFSET
(
1
)
&&
addr
<=
ELF_GR_OFFSET
(
15
))
if
(
addr
>=
ELF_GR_OFFSET
(
1
)
&&
addr
<=
ELF_GR_OFFSET
(
31
))
return
access_elf_gpreg
(
target
,
info
,
addr
,
data
,
write_access
);
else
if
(
addr
>=
ELF_BR_OFFSET
(
0
)
&&
addr
<=
ELF_BR_OFFSET
(
7
))
return
access_elf_breg
(
target
,
info
,
addr
,
data
,
write_access
);
...
...
@@ -1500,10 +1491,7 @@ access_elf_reg(struct task_struct *target, struct unw_frame_info *info,
void
do_gpregs_get
(
struct
unw_frame_info
*
info
,
void
*
arg
)
{
struct
pt_regs
*
pt
;
struct
regset_getset
*
dst
=
arg
;
elf_greg_t
tmp
[
16
];
unsigned
int
i
,
index
,
min_copy
;
if
(
unw_unwind_to_user
(
info
)
<
0
)
return
;
...
...
@@ -1526,160 +1514,70 @@ void do_gpregs_get(struct unw_frame_info *info, void *arg)
&
dst
->
u
.
get
.
kbuf
,
&
dst
->
u
.
get
.
ubuf
,
0
,
ELF_GR_OFFSET
(
1
));
if
(
dst
->
ret
||
dst
->
count
==
0
)
return
;
}
/* gr1 - gr15 */
if
(
dst
->
count
>
0
&&
dst
->
pos
<
ELF_GR_OFFSET
(
16
))
{
index
=
(
dst
->
pos
-
ELF_GR_OFFSET
(
1
))
/
sizeof
(
elf_greg_t
);
min_copy
=
ELF_GR_OFFSET
(
16
)
>
(
dst
->
pos
+
dst
->
count
)
?
(
dst
->
pos
+
dst
->
count
)
:
ELF_GR_OFFSET
(
16
);
for
(
i
=
dst
->
pos
;
i
<
min_copy
;
i
+=
sizeof
(
elf_greg_t
),
index
++
)
if
(
access_elf_reg
(
dst
->
target
,
info
,
i
,
&
tmp
[
index
],
0
)
<
0
)
{
dst
->
ret
=
-
EIO
;
return
;
}
dst
->
ret
=
user_regset_copyout
(
&
dst
->
pos
,
&
dst
->
count
,
&
dst
->
u
.
get
.
kbuf
,
&
dst
->
u
.
get
.
ubuf
,
tmp
,
ELF_GR_OFFSET
(
1
),
ELF_GR_OFFSET
(
16
));
if
(
dst
->
ret
||
dst
->
count
==
0
)
if
(
dst
->
ret
)
return
;
}
/* r16-r31 */
if
(
dst
->
count
>
0
&&
dst
->
pos
<
ELF_NAT_OFFSET
)
{
pt
=
task_pt_regs
(
dst
->
target
);
dst
->
ret
=
user_regset_copyout
(
&
dst
->
pos
,
&
dst
->
count
,
&
dst
->
u
.
get
.
kbuf
,
&
dst
->
u
.
get
.
ubuf
,
&
pt
->
r16
,
ELF_GR_OFFSET
(
16
),
ELF_NAT_OFFSET
);
if
(
dst
->
ret
||
dst
->
count
==
0
)
return
;
}
while
(
dst
->
count
&&
dst
->
pos
<
ELF_AR_END_OFFSET
)
{
unsigned
int
n
,
from
,
to
;
elf_greg_t
tmp
[
16
];
/* nat, pr, b0 - b7 */
if
(
dst
->
count
>
0
&&
dst
->
pos
<
ELF_CR_IIP_OFFSET
)
{
index
=
(
dst
->
pos
-
ELF_NAT_OFFSET
)
/
sizeof
(
elf_greg_t
);
min_copy
=
ELF_CR_IIP_OFFSET
>
(
dst
->
pos
+
dst
->
count
)
?
(
dst
->
pos
+
dst
->
count
)
:
ELF_CR_IIP_OFFSET
;
for
(
i
=
dst
->
pos
;
i
<
min_copy
;
i
+=
sizeof
(
elf_greg_t
),
index
++
)
if
(
access_elf_reg
(
dst
->
target
,
info
,
i
,
&
tmp
[
index
],
0
)
<
0
)
{
from
=
dst
->
pos
;
to
=
from
+
min
(
dst
->
count
,
(
unsigned
)
sizeof
(
tmp
));
if
(
to
>
ELF_AR_END_OFFSET
)
to
=
ELF_AR_END_OFFSET
;
for
(
n
=
0
;
from
<
to
;
from
+=
sizeof
(
elf_greg_t
),
n
++
)
{
if
(
access_elf_reg
(
dst
->
target
,
info
,
from
,
&
tmp
[
n
],
0
)
<
0
)
{
dst
->
ret
=
-
EIO
;
return
;
}
dst
->
ret
=
user_regset_copyout
(
&
dst
->
pos
,
&
dst
->
count
,
&
dst
->
u
.
get
.
kbuf
,
&
dst
->
u
.
get
.
ubuf
,
tmp
,
ELF_NAT_OFFSET
,
ELF_CR_IIP_OFFSET
);
if
(
dst
->
ret
||
dst
->
count
==
0
)
return
;
}
/* ip cfm psr ar.rsc ar.bsp ar.bspstore ar.rnat
* ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec ar.csd ar.ssd
*/
if
(
dst
->
count
>
0
&&
dst
->
pos
<
(
ELF_AR_END_OFFSET
))
{
index
=
(
dst
->
pos
-
ELF_CR_IIP_OFFSET
)
/
sizeof
(
elf_greg_t
);
min_copy
=
ELF_AR_END_OFFSET
>
(
dst
->
pos
+
dst
->
count
)
?
(
dst
->
pos
+
dst
->
count
)
:
ELF_AR_END_OFFSET
;
for
(
i
=
dst
->
pos
;
i
<
min_copy
;
i
+=
sizeof
(
elf_greg_t
),
index
++
)
if
(
access_elf_reg
(
dst
->
target
,
info
,
i
,
&
tmp
[
index
],
0
)
<
0
)
{
dst
->
ret
=
-
EIO
;
return
;
}
dst
->
ret
=
user_regset_copyout
(
&
dst
->
pos
,
&
dst
->
count
,
&
dst
->
u
.
get
.
kbuf
,
&
dst
->
u
.
get
.
ubuf
,
tmp
,
ELF_CR_IIP_OFFSET
,
ELF_AR_END_OFFSET
);
dst
->
pos
,
to
);
if
(
dst
->
ret
)
return
;
}
}
void
do_gpregs_set
(
struct
unw_frame_info
*
info
,
void
*
arg
)
{
struct
pt_regs
*
pt
;
struct
regset_getset
*
dst
=
arg
;
elf_greg_t
tmp
[
16
];
unsigned
int
i
,
index
;
if
(
unw_unwind_to_user
(
info
)
<
0
)
return
;
if
(
!
dst
->
count
)
return
;
/* Skip r0 */
if
(
dst
->
count
>
0
&&
dst
->
pos
<
ELF_GR_OFFSET
(
1
))
{
if
(
dst
->
pos
<
ELF_GR_OFFSET
(
1
))
{
dst
->
ret
=
user_regset_copyin_ignore
(
&
dst
->
pos
,
&
dst
->
count
,
&
dst
->
u
.
set
.
kbuf
,
&
dst
->
u
.
set
.
ubuf
,
0
,
ELF_GR_OFFSET
(
1
));
if
(
dst
->
ret
||
dst
->
count
==
0
)
return
;
}
/* gr1-gr15 */
if
(
dst
->
count
>
0
&&
dst
->
pos
<
ELF_GR_OFFSET
(
16
))
{
i
=
dst
->
pos
;
index
=
(
dst
->
pos
-
ELF_GR_OFFSET
(
1
))
/
sizeof
(
elf_greg_t
);
dst
->
ret
=
user_regset_copyin
(
&
dst
->
pos
,
&
dst
->
count
,
&
dst
->
u
.
set
.
kbuf
,
&
dst
->
u
.
set
.
ubuf
,
tmp
,
ELF_GR_OFFSET
(
1
),
ELF_GR_OFFSET
(
16
));
if
(
dst
->
ret
)
return
;
for
(
;
i
<
dst
->
pos
;
i
+=
sizeof
(
elf_greg_t
),
index
++
)
if
(
access_elf_reg
(
dst
->
target
,
info
,
i
,
&
tmp
[
index
],
1
)
<
0
)
{
dst
->
ret
=
-
EIO
;
return
;
}
if
(
dst
->
count
==
0
)
return
;
}
/* gr16-gr31 */
if
(
dst
->
count
>
0
&&
dst
->
pos
<
ELF_NAT_OFFSET
)
{
pt
=
task_pt_regs
(
dst
->
target
);
dst
->
ret
=
user_regset_copyin
(
&
dst
->
pos
,
&
dst
->
count
,
&
dst
->
u
.
set
.
kbuf
,
&
dst
->
u
.
set
.
ubuf
,
&
pt
->
r16
,
ELF_GR_OFFSET
(
16
),
ELF_NAT_OFFSET
);
if
(
dst
->
ret
||
dst
->
count
==
0
)
return
;
}
/* nat, pr, b0 - b7 */
if
(
dst
->
count
>
0
&&
dst
->
pos
<
ELF_CR_IIP_OFFSET
)
{
i
=
dst
->
pos
;
index
=
(
dst
->
pos
-
ELF_NAT_OFFSET
)
/
sizeof
(
elf_greg_t
);
dst
->
ret
=
user_regset_copyin
(
&
dst
->
pos
,
&
dst
->
count
,
&
dst
->
u
.
set
.
kbuf
,
&
dst
->
u
.
set
.
ubuf
,
tmp
,
ELF_NAT_OFFSET
,
ELF_CR_IIP_OFFSET
);
if
(
dst
->
ret
)
return
;
for
(;
i
<
dst
->
pos
;
i
+=
sizeof
(
elf_greg_t
),
index
++
)
if
(
access_elf_reg
(
dst
->
target
,
info
,
i
,
&
tmp
[
index
],
1
)
<
0
)
{
dst
->
ret
=
-
EIO
;
return
;
}
if
(
dst
->
count
==
0
)
return
;
}
while
(
dst
->
count
&&
dst
->
pos
<
ELF_AR_END_OFFSET
)
{
unsigned
int
n
,
from
,
to
;
elf_greg_t
tmp
[
16
];
/* ip cfm psr ar.rsc ar.bsp ar.bspstore ar.rnat
* ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec ar.csd ar.ssd
*/
if
(
dst
->
count
>
0
&&
dst
->
pos
<
(
ELF_AR_END_OFFSET
))
{
i
=
dst
->
pos
;
index
=
(
dst
->
pos
-
ELF_CR_IIP_OFFSET
)
/
sizeof
(
elf_greg_t
);
from
=
dst
->
pos
;
to
=
from
+
sizeof
(
tmp
);
if
(
to
>
ELF_AR_END_OFFSET
)
to
=
ELF_AR_END_OFFSET
;
/* get up to 16 values */
dst
->
ret
=
user_regset_copyin
(
&
dst
->
pos
,
&
dst
->
count
,
&
dst
->
u
.
set
.
kbuf
,
&
dst
->
u
.
set
.
ubuf
,
tmp
,
ELF_CR_IIP_OFFSET
,
ELF_AR_END_OFFSET
);
from
,
to
);
if
(
dst
->
ret
)
return
;
for
(
;
i
<
dst
->
pos
;
i
+=
sizeof
(
elf_greg_t
),
index
++
)
if
(
access_elf_reg
(
dst
->
target
,
info
,
i
,
&
tmp
[
index
],
1
)
<
0
)
{
/* now copy them into registers */
for
(
n
=
0
;
from
<
dst
->
pos
;
from
+=
sizeof
(
elf_greg_t
),
n
++
)
if
(
access_elf_reg
(
dst
->
target
,
info
,
from
,
&
tmp
[
n
],
1
)
<
0
)
{
dst
->
ret
=
-
EIO
;
return
;
}
...
...
@@ -1913,7 +1811,6 @@ access_uarea(struct task_struct *child, unsigned long addr,
unsigned
long
*
data
,
int
write_access
)
{
unsigned
int
pos
=
-
1
;
/* an invalid value */
int
ret
;
unsigned
long
*
ptr
,
regnum
;
if
((
addr
&
0x7
)
!=
0
)
{
...
...
@@ -1945,14 +1842,39 @@ access_uarea(struct task_struct *child, unsigned long addr,
}
if
(
pos
!=
-
1
)
{
unsigned
reg
=
pos
/
sizeof
(
elf_fpreg_t
);
int
which_half
=
(
pos
/
sizeof
(
unsigned
long
))
&
1
;
if
(
reg
<
32
)
{
/* fr2-fr31 */
struct
unw_frame_info
info
;
elf_fpreg_t
fpreg
;
memset
(
&
info
,
0
,
sizeof
(
info
));
unw_init_from_blocked_task
(
&
info
,
child
);
if
(
unw_unwind_to_user
(
&
info
)
<
0
)
return
0
;
if
(
unw_get_fr
(
&
info
,
reg
,
&
fpreg
))
return
-
1
;
if
(
write_access
)
{
fpreg
.
u
.
bits
[
which_half
]
=
*
data
;
if
(
unw_set_fr
(
&
info
,
reg
,
fpreg
))
return
-
1
;
}
else
{
*
data
=
fpreg
.
u
.
bits
[
which_half
];
}
}
else
{
/* fph */
elf_fpreg_t
*
p
=
&
child
->
thread
.
fph
[
reg
-
32
];
unsigned
long
*
bits
=
&
p
->
u
.
bits
[
which_half
];
ia64_sync_fph
(
child
);
if
(
write_access
)
ret
=
fpregs_set
(
child
,
NULL
,
pos
,
sizeof
(
unsigned
long
),
data
,
NULL
);
*
bits
=
*
data
;
else
if
(
child
->
thread
.
flags
&
IA64_THREAD_FPH_VALID
)
*
data
=
*
bits
;
else
ret
=
fpregs_get
(
child
,
NULL
,
pos
,
sizeof
(
unsigned
long
),
data
,
NULL
);
if
(
ret
!=
0
)
return
-
1
;
*
data
=
0
;
}
return
0
;
}
...
...
@@ -2038,15 +1960,14 @@ access_uarea(struct task_struct *child, unsigned long addr,
}
if
(
pos
!=
-
1
)
{
if
(
write_access
)
ret
=
gpregs_set
(
child
,
NULL
,
pos
,
sizeof
(
unsigned
long
),
data
,
NULL
);
else
ret
=
gpregs_get
(
child
,
NULL
,
pos
,
sizeof
(
unsigned
long
),
data
,
NULL
);
if
(
ret
!=
0
)
return
-
1
;
struct
unw_frame_info
info
;
memset
(
&
info
,
0
,
sizeof
(
info
));
unw_init_from_blocked_task
(
&
info
,
child
);
if
(
unw_unwind_to_user
(
&
info
)
<
0
)
return
0
;
return
access_elf_reg
(
child
,
&
info
,
pos
,
data
,
write_access
);
}
/* access debug registers */
...
...
arch/sparc/kernel/ptrace_32.c
View file @
1e56f6d2
...
...
@@ -99,15 +99,13 @@ static int genregs32_get(struct task_struct *target,
if
(
ret
||
!
count
)
return
ret
;
if
(
pos
<
32
*
sizeof
(
u32
))
{
if
(
regwindow32_get
(
target
,
regs
,
uregs
))
return
-
EFAULT
;
ret
=
user_regset_copyout
(
&
pos
,
&
count
,
&
kbuf
,
&
ubuf
,
uregs
,
16
*
sizeof
(
u32
),
32
*
sizeof
(
u32
));
if
(
ret
||
!
coun
t
)
if
(
re
t
)
return
ret
;
}
uregs
[
0
]
=
regs
->
psr
;
uregs
[
1
]
=
regs
->
pc
;
...
...
@@ -139,7 +137,6 @@ static int genregs32_set(struct task_struct *target,
if
(
ret
||
!
count
)
return
ret
;
if
(
pos
<
32
*
sizeof
(
u32
))
{
if
(
regwindow32_get
(
target
,
regs
,
uregs
))
return
-
EFAULT
;
ret
=
user_regset_copyin
(
&
pos
,
&
count
,
&
kbuf
,
&
ubuf
,
...
...
@@ -151,7 +148,7 @@ static int genregs32_set(struct task_struct *target,
return
-
EFAULT
;
if
(
!
count
)
return
0
;
}
ret
=
user_regset_copyin
(
&
pos
,
&
count
,
&
kbuf
,
&
ubuf
,
&
psr
,
32
*
sizeof
(
u32
),
33
*
sizeof
(
u32
));
...
...
@@ -243,13 +240,11 @@ static int fpregs32_set(struct task_struct *target,
user_regset_copyin_ignore
(
&
pos
,
&
count
,
&
kbuf
,
&
ubuf
,
32
*
sizeof
(
u32
),
33
*
sizeof
(
u32
));
if
(
!
ret
&&
count
>
0
)
{
if
(
!
ret
)
ret
=
user_regset_copyin
(
&
pos
,
&
count
,
&
kbuf
,
&
ubuf
,
&
target
->
thread
.
fsr
,
33
*
sizeof
(
u32
),
34
*
sizeof
(
u32
));
}
if
(
!
ret
)
ret
=
user_regset_copyin_ignore
(
&
pos
,
&
count
,
&
kbuf
,
&
ubuf
,
34
*
sizeof
(
u32
),
-
1
);
...
...
@@ -288,6 +283,125 @@ static const struct user_regset sparc32_regsets[] = {
},
};
static
int
getregs_get
(
struct
task_struct
*
target
,
const
struct
user_regset
*
regset
,
unsigned
int
pos
,
unsigned
int
count
,
void
*
kbuf
,
void
__user
*
ubuf
)
{
const
struct
pt_regs
*
regs
=
target
->
thread
.
kregs
;
u32
v
[
4
];
int
ret
;
if
(
target
==
current
)
flush_user_windows
();
v
[
0
]
=
regs
->
psr
;
v
[
1
]
=
regs
->
pc
;
v
[
2
]
=
regs
->
npc
;
v
[
3
]
=
regs
->
y
;
ret
=
user_regset_copyout
(
&
pos
,
&
count
,
&
kbuf
,
&
ubuf
,
v
,
0
*
sizeof
(
u32
),
4
*
sizeof
(
u32
));
if
(
ret
)
return
ret
;
return
user_regset_copyout
(
&
pos
,
&
count
,
&
kbuf
,
&
ubuf
,
regs
->
u_regs
+
1
,
4
*
sizeof
(
u32
),
19
*
sizeof
(
u32
));
}
static
int
setregs_set
(
struct
task_struct
*
target
,
const
struct
user_regset
*
regset
,
unsigned
int
pos
,
unsigned
int
count
,
const
void
*
kbuf
,
const
void
__user
*
ubuf
)
{
struct
pt_regs
*
regs
=
target
->
thread
.
kregs
;
u32
v
[
4
];
int
ret
;
if
(
target
==
current
)
flush_user_windows
();
ret
=
user_regset_copyin
(
&
pos
,
&
count
,
&
kbuf
,
&
ubuf
,
v
,
0
,
4
*
sizeof
(
u32
));
if
(
ret
)
return
ret
;
regs
->
psr
=
(
regs
->
psr
&
~
(
PSR_ICC
|
PSR_SYSCALL
))
|
(
v
[
0
]
&
(
PSR_ICC
|
PSR_SYSCALL
));
regs
->
pc
=
v
[
1
];
regs
->
npc
=
v
[
2
];
regs
->
y
=
v
[
3
];
return
user_regset_copyin
(
&
pos
,
&
count
,
&
kbuf
,
&
ubuf
,
regs
->
u_regs
+
1
,
4
*
sizeof
(
u32
)
,
19
*
sizeof
(
u32
));
}
static
int
getfpregs_get
(
struct
task_struct
*
target
,
const
struct
user_regset
*
regset
,
unsigned
int
pos
,
unsigned
int
count
,
void
*
kbuf
,
void
__user
*
ubuf
)
{
const
unsigned
long
*
fpregs
=
target
->
thread
.
float_regs
;
int
ret
=
0
;
#if 0
if (target == current)
save_and_clear_fpu();
#endif
ret
=
user_regset_copyout
(
&
pos
,
&
count
,
&
kbuf
,
&
ubuf
,
fpregs
,
0
,
32
*
sizeof
(
u32
));
if
(
ret
)
return
ret
;
ret
=
user_regset_copyout
(
&
pos
,
&
count
,
&
kbuf
,
&
ubuf
,
&
target
->
thread
.
fsr
,
32
*
sizeof
(
u32
),
33
*
sizeof
(
u32
));
if
(
ret
)
return
ret
;
return
user_regset_copyout_zero
(
&
pos
,
&
count
,
&
kbuf
,
&
ubuf
,
33
*
sizeof
(
u32
),
68
*
sizeof
(
u32
));
}
static
int
setfpregs_set
(
struct
task_struct
*
target
,
const
struct
user_regset
*
regset
,
unsigned
int
pos
,
unsigned
int
count
,
const
void
*
kbuf
,
const
void
__user
*
ubuf
)
{
unsigned
long
*
fpregs
=
target
->
thread
.
float_regs
;
int
ret
;
#if 0
if (target == current)
save_and_clear_fpu();
#endif
ret
=
user_regset_copyin
(
&
pos
,
&
count
,
&
kbuf
,
&
ubuf
,
fpregs
,
0
,
32
*
sizeof
(
u32
));
if
(
ret
)
return
ret
;
return
user_regset_copyin
(
&
pos
,
&
count
,
&
kbuf
,
&
ubuf
,
&
target
->
thread
.
fsr
,
32
*
sizeof
(
u32
),
33
*
sizeof
(
u32
));
}
static
const
struct
user_regset
ptrace32_regsets
[]
=
{
[
REGSET_GENERAL
]
=
{
.
n
=
19
,
.
size
=
sizeof
(
u32
),
.
get
=
getregs_get
,
.
set
=
setregs_set
,
},
[
REGSET_FP
]
=
{
.
n
=
68
,
.
size
=
sizeof
(
u32
),
.
get
=
getfpregs_get
,
.
set
=
setfpregs_set
,
},
};
static
const
struct
user_regset_view
ptrace32_view
=
{
.
regsets
=
ptrace32_regsets
,
.
n
=
ARRAY_SIZE
(
ptrace32_regsets
)
};
static
const
struct
user_regset_view
user_sparc32_view
=
{
.
name
=
"sparc"
,
.
e_machine
=
EM_SPARC
,
.
regsets
=
sparc32_regsets
,
.
n
=
ARRAY_SIZE
(
sparc32_regsets
)
...
...
@@ -315,74 +429,44 @@ long arch_ptrace(struct task_struct *child, long request,
{
unsigned
long
addr2
=
current
->
thread
.
kregs
->
u_regs
[
UREG_I4
];
void
__user
*
addr2p
;
const
struct
user_regset_view
*
view
;
struct
pt_regs
__user
*
pregs
;
struct
fps
__user
*
fps
;
int
ret
;
view
=
task_user_regset_view
(
current
);
addr2p
=
(
void
__user
*
)
addr2
;
pregs
=
(
struct
pt_regs
__user
*
)
addr
;
fps
=
(
struct
fps
__user
*
)
addr
;
switch
(
request
)
{
case
PTRACE_GETREGS
:
{
ret
=
copy_regset_to_user
(
child
,
view
,
REGSET_GENERAL
,
32
*
sizeof
(
u32
),
4
*
sizeof
(
u32
),
&
pregs
->
psr
);
if
(
!
ret
)
copy_regset_to_user
(
child
,
view
,
REGSET_GENERAL
,
1
*
sizeof
(
u32
),
15
*
sizeof
(
u32
),
&
pregs
->
u_regs
[
0
]);
ret
=
copy_regset_to_user
(
child
,
&
ptrace32_view
,
REGSET_GENERAL
,
0
,
19
*
sizeof
(
u32
),
pregs
);
break
;
}
case
PTRACE_SETREGS
:
{
ret
=
copy_regset_from_user
(
child
,
view
,
REGSET_GENERAL
,
32
*
sizeof
(
u32
),
4
*
sizeof
(
u32
),
&
pregs
->
psr
);
if
(
!
ret
)
copy_regset_from_user
(
child
,
view
,
REGSET_GENERAL
,
1
*
sizeof
(
u32
),
15
*
sizeof
(
u32
),
&
pregs
->
u_regs
[
0
]);
ret
=
copy_regset_from_user
(
child
,
&
ptrace32_view
,
REGSET_GENERAL
,
0
,
19
*
sizeof
(
u32
),
pregs
);
break
;
}
case
PTRACE_GETFPREGS
:
{
ret
=
copy_regset_to_user
(
child
,
view
,
REGSET_FP
,
0
*
sizeof
(
u32
),
32
*
sizeof
(
u32
),
&
fps
->
regs
[
0
]);
if
(
!
ret
)
ret
=
copy_regset_to_user
(
child
,
view
,
REGSET_FP
,
33
*
sizeof
(
u32
),
1
*
sizeof
(
u32
),
&
fps
->
fsr
);
if
(
!
ret
)
{
if
(
__put_user
(
0
,
&
fps
->
fpqd
)
||
__put_user
(
0
,
&
fps
->
flags
)
||
__put_user
(
0
,
&
fps
->
extra
)
||
clear_user
(
fps
->
fpq
,
sizeof
(
fps
->
fpq
)))
ret
=
-
EFAULT
;
}
ret
=
copy_regset_to_user
(
child
,
&
ptrace32_view
,
REGSET_FP
,
0
,
68
*
sizeof
(
u32
),
fps
);
break
;
}
case
PTRACE_SETFPREGS
:
{
ret
=
copy_regset_from_user
(
child
,
view
,
REGSET_FP
,
0
*
sizeof
(
u32
),
32
*
sizeof
(
u32
),
&
fps
->
regs
[
0
]);
if
(
!
ret
)
ret
=
copy_regset_from_user
(
child
,
view
,
REGSET_FP
,
ret
=
copy_regset_from_user
(
child
,
&
ptrace32_view
,
REGSET_FP
,
0
,
33
*
sizeof
(
u32
),
1
*
sizeof
(
u32
),
&
fps
->
fsr
);
fps
);
break
;
}
...
...
arch/sparc/kernel/ptrace_64.c
View file @
1e56f6d2
...
...
@@ -258,7 +258,7 @@ static int genregs64_get(struct task_struct *target,
ret
=
user_regset_copyout
(
&
pos
,
&
count
,
&
kbuf
,
&
ubuf
,
regs
->
u_regs
,
0
,
16
*
sizeof
(
u64
));
if
(
!
ret
&&
count
&&
pos
<
(
32
*
sizeof
(
u64
))
)
{
if
(
!
ret
&&
count
)
{
struct
reg_window
window
;
if
(
regwindow64_get
(
target
,
regs
,
&
window
))
...
...
@@ -506,6 +506,112 @@ static const struct user_regset sparc64_regsets[] = {
},
};
static
int
getregs64_get
(
struct
task_struct
*
target
,
const
struct
user_regset
*
regset
,
unsigned
int
pos
,
unsigned
int
count
,
void
*
kbuf
,
void
__user
*
ubuf
)
{
const
struct
pt_regs
*
regs
=
task_pt_regs
(
target
);
int
ret
;
if
(
target
==
current
)
flushw_user
();
ret
=
user_regset_copyout
(
&
pos
,
&
count
,
&
kbuf
,
&
ubuf
,
regs
->
u_regs
+
1
,
0
,
15
*
sizeof
(
u64
));
if
(
!
ret
)
ret
=
user_regset_copyout_zero
(
&
pos
,
&
count
,
&
kbuf
,
&
ubuf
,
15
*
sizeof
(
u64
),
16
*
sizeof
(
u64
));
if
(
!
ret
)
{
/* TSTATE, TPC, TNPC */
ret
=
user_regset_copyout
(
&
pos
,
&
count
,
&
kbuf
,
&
ubuf
,
&
regs
->
tstate
,
16
*
sizeof
(
u64
),
19
*
sizeof
(
u64
));
}
if
(
!
ret
)
{
unsigned
long
y
=
regs
->
y
;
ret
=
user_regset_copyout
(
&
pos
,
&
count
,
&
kbuf
,
&
ubuf
,
&
y
,
19
*
sizeof
(
u64
),
20
*
sizeof
(
u64
));
}
return
ret
;
}
static
int
setregs64_set
(
struct
task_struct
*
target
,
const
struct
user_regset
*
regset
,
unsigned
int
pos
,
unsigned
int
count
,
const
void
*
kbuf
,
const
void
__user
*
ubuf
)
{
struct
pt_regs
*
regs
=
task_pt_regs
(
target
);
unsigned
long
y
=
regs
->
y
;
unsigned
long
tstate
;
int
ret
;
if
(
target
==
current
)
flushw_user
();
ret
=
user_regset_copyin
(
&
pos
,
&
count
,
&
kbuf
,
&
ubuf
,
regs
->
u_regs
+
1
,
0
*
sizeof
(
u64
),
15
*
sizeof
(
u64
));
if
(
ret
)
return
ret
;
ret
=
user_regset_copyin_ignore
(
&
pos
,
&
count
,
&
kbuf
,
&
ubuf
,
15
*
sizeof
(
u64
),
16
*
sizeof
(
u64
));
if
(
ret
)
return
ret
;
/* TSTATE */
ret
=
user_regset_copyin
(
&
pos
,
&
count
,
&
kbuf
,
&
ubuf
,
&
tstate
,
16
*
sizeof
(
u64
),
17
*
sizeof
(
u64
));
if
(
ret
)
return
ret
;
/* Only the condition codes and the "in syscall"
* state can be modified in the %tstate register.
*/
tstate
&=
(
TSTATE_ICC
|
TSTATE_XCC
|
TSTATE_SYSCALL
);
regs
->
tstate
&=
~
(
TSTATE_ICC
|
TSTATE_XCC
|
TSTATE_SYSCALL
);
regs
->
tstate
|=
tstate
;
/* TPC, TNPC */
ret
=
user_regset_copyin
(
&
pos
,
&
count
,
&
kbuf
,
&
ubuf
,
&
regs
->
tpc
,
17
*
sizeof
(
u64
),
19
*
sizeof
(
u64
));
if
(
ret
)
return
ret
;
/* Y */
ret
=
user_regset_copyin
(
&
pos
,
&
count
,
&
kbuf
,
&
ubuf
,
&
y
,
19
*
sizeof
(
u64
),
20
*
sizeof
(
u64
));
if
(
!
ret
)
regs
->
y
=
y
;
return
ret
;
}
static
const
struct
user_regset
ptrace64_regsets
[]
=
{
/* Format is:
* G1 --> G7
* O0 --> O7
* 0
* TSTATE, TPC, TNPC, Y
*/
[
REGSET_GENERAL
]
=
{
.
n
=
20
,
.
size
=
sizeof
(
u64
),
.
get
=
getregs64_get
,
.
set
=
setregs64_set
,
},
};
static
const
struct
user_regset_view
ptrace64_view
=
{
.
regsets
=
ptrace64_regsets
,
.
n
=
ARRAY_SIZE
(
ptrace64_regsets
)
};
static
const
struct
user_regset_view
user_sparc64_view
=
{
.
name
=
"sparc64"
,
.
e_machine
=
EM_SPARCV9
,
.
regsets
=
sparc64_regsets
,
.
n
=
ARRAY_SIZE
(
sparc64_regsets
)
...
...
@@ -518,10 +624,10 @@ static int genregs32_get(struct task_struct *target,
void
*
kbuf
,
void
__user
*
ubuf
)
{
const
struct
pt_regs
*
regs
=
task_pt_regs
(
target
);
compat_ulong_t
__user
*
reg_window
;
compat_ulong_t
*
k
=
kbuf
;
compat_ulong_t
__user
*
u
=
ubuf
;
compat_ulong_t
reg
;
u32
uregs
[
16
];
u32
reg
;
if
(
target
==
current
)
flushw_user
();
...
...
@@ -533,52 +639,25 @@ static int genregs32_get(struct task_struct *target,
for
(;
count
>
0
&&
pos
<
16
;
count
--
)
*
k
++
=
regs
->
u_regs
[
pos
++
];
reg_window
=
(
compat_ulong_t
__user
*
)
regs
->
u_regs
[
UREG_I6
];
reg_window
-=
16
;
if
(
target
==
current
)
{
for
(;
count
>
0
&&
pos
<
32
;
count
--
)
{
if
(
get_user
(
*
k
++
,
&
reg_window
[
pos
++
]))
if
(
count
)
{
if
(
get_from_target
(
target
,
regs
->
u_regs
[
UREG_I6
],
uregs
,
sizeof
(
uregs
)))
return
-
EFAULT
;
for
(;
count
>
0
&&
pos
<
32
;
count
--
)
*
k
++
=
uregs
[
pos
++
-
16
];
}
}
else
{
for
(;
count
>
0
&&
pos
<
32
;
count
--
)
{
if
(
access_process_vm
(
target
,
(
unsigned
long
)
&
reg_window
[
pos
],
k
,
sizeof
(
*
k
),
FOLL_FORCE
)
!=
sizeof
(
*
k
))
return
-
EFAULT
;
k
++
;
pos
++
;
}
}
}
else
{
for
(;
count
>
0
&&
pos
<
16
;
count
--
)
{
for
(;
count
>
0
&&
pos
<
16
;
count
--
)
if
(
put_user
((
compat_ulong_t
)
regs
->
u_regs
[
pos
++
],
u
++
))
return
-
EFAULT
;
}
reg_window
=
(
compat_ulong_t
__user
*
)
regs
->
u_regs
[
UREG_I6
];
reg_window
-=
16
;
if
(
target
==
current
)
{
for
(;
count
>
0
&&
pos
<
32
;
count
--
)
{
if
(
get_user
(
reg
,
&
reg_window
[
pos
++
])
||
put_user
(
reg
,
u
++
))
if
(
count
)
{
if
(
get_from_target
(
target
,
regs
->
u_regs
[
UREG_I6
],
uregs
,
sizeof
(
uregs
)))
return
-
EFAULT
;
}
}
else
{
for
(;
count
>
0
&&
pos
<
32
;
count
--
)
{
if
(
access_process_vm
(
target
,
(
unsigned
long
)
&
reg_window
[
pos
++
],
&
reg
,
sizeof
(
reg
),
FOLL_FORCE
)
!=
sizeof
(
reg
))
for
(;
count
>
0
&&
pos
<
32
;
count
--
)
if
(
put_user
(
uregs
[
pos
++
-
16
],
u
++
))
return
-
EFAULT
;
if
(
put_user
(
reg
,
u
++
))
return
-
EFAULT
;
}
}
}
while
(
count
>
0
)
{
...
...
@@ -867,6 +946,150 @@ static const struct user_regset sparc32_regsets[] = {
},
};
static
int
getregs_get
(
struct
task_struct
*
target
,
const
struct
user_regset
*
regset
,
unsigned
int
pos
,
unsigned
int
count
,
void
*
kbuf
,
void
__user
*
ubuf
)
{
const
struct
pt_regs
*
regs
=
task_pt_regs
(
target
);
u32
uregs
[
19
];
int
i
;
if
(
target
==
current
)
flushw_user
();
uregs
[
0
]
=
tstate_to_psr
(
regs
->
tstate
);
uregs
[
1
]
=
regs
->
tpc
;
uregs
[
2
]
=
regs
->
tnpc
;
uregs
[
3
]
=
regs
->
y
;
for
(
i
=
1
;
i
<
16
;
i
++
)
uregs
[
3
+
i
]
=
regs
->
u_regs
[
i
];
return
user_regset_copyout
(
&
pos
,
&
count
,
&
kbuf
,
&
ubuf
,
uregs
,
0
,
19
*
sizeof
(
u32
));
}
static
int
setregs_set
(
struct
task_struct
*
target
,
const
struct
user_regset
*
regset
,
unsigned
int
pos
,
unsigned
int
count
,
const
void
*
kbuf
,
const
void
__user
*
ubuf
)
{
struct
pt_regs
*
regs
=
task_pt_regs
(
target
);
unsigned
long
tstate
;
u32
uregs
[
19
];
int
i
,
ret
;
if
(
target
==
current
)
flushw_user
();
ret
=
user_regset_copyin
(
&
pos
,
&
count
,
&
kbuf
,
&
ubuf
,
uregs
,
0
,
19
*
sizeof
(
u32
));
if
(
ret
)
return
ret
;
tstate
=
regs
->
tstate
;
tstate
&=
~
(
TSTATE_ICC
|
TSTATE_XCC
|
TSTATE_SYSCALL
);
tstate
|=
psr_to_tstate_icc
(
uregs
[
0
]);
if
(
uregs
[
0
]
&
PSR_SYSCALL
)
tstate
|=
TSTATE_SYSCALL
;
regs
->
tstate
=
tstate
;
regs
->
tpc
=
uregs
[
1
];
regs
->
tnpc
=
uregs
[
2
];
regs
->
y
=
uregs
[
3
];
for
(
i
=
1
;
i
<
15
;
i
++
)
regs
->
u_regs
[
i
]
=
uregs
[
3
+
i
];
return
0
;
}
static
int
getfpregs_get
(
struct
task_struct
*
target
,
const
struct
user_regset
*
regset
,
unsigned
int
pos
,
unsigned
int
count
,
void
*
kbuf
,
void
__user
*
ubuf
)
{
const
unsigned
long
*
fpregs
=
task_thread_info
(
target
)
->
fpregs
;
unsigned
long
fprs
;
compat_ulong_t
fsr
;
int
ret
=
0
;
if
(
target
==
current
)
save_and_clear_fpu
();
fprs
=
task_thread_info
(
target
)
->
fpsaved
[
0
];
if
(
fprs
&
FPRS_FEF
)
{
fsr
=
task_thread_info
(
target
)
->
xfsr
[
0
];
}
else
{
fsr
=
0
;
}
ret
=
user_regset_copyout
(
&
pos
,
&
count
,
&
kbuf
,
&
ubuf
,
fpregs
,
0
,
32
*
sizeof
(
u32
));
if
(
!
ret
)
ret
=
user_regset_copyout
(
&
pos
,
&
count
,
&
kbuf
,
&
ubuf
,
&
fsr
,
32
*
sizeof
(
u32
),
33
*
sizeof
(
u32
));
if
(
!
ret
)
ret
=
user_regset_copyout_zero
(
&
pos
,
&
count
,
&
kbuf
,
&
ubuf
,
33
*
sizeof
(
u32
),
68
*
sizeof
(
u32
));
return
ret
;
}
static
int
setfpregs_set
(
struct
task_struct
*
target
,
const
struct
user_regset
*
regset
,
unsigned
int
pos
,
unsigned
int
count
,
const
void
*
kbuf
,
const
void
__user
*
ubuf
)
{
unsigned
long
*
fpregs
=
task_thread_info
(
target
)
->
fpregs
;
unsigned
long
fprs
;
int
ret
;
if
(
target
==
current
)
save_and_clear_fpu
();
fprs
=
task_thread_info
(
target
)
->
fpsaved
[
0
];
ret
=
user_regset_copyin
(
&
pos
,
&
count
,
&
kbuf
,
&
ubuf
,
fpregs
,
0
,
32
*
sizeof
(
u32
));
if
(
!
ret
)
{
compat_ulong_t
fsr
;
unsigned
long
val
;
ret
=
user_regset_copyin
(
&
pos
,
&
count
,
&
kbuf
,
&
ubuf
,
&
fsr
,
32
*
sizeof
(
u32
),
33
*
sizeof
(
u32
));
if
(
!
ret
)
{
val
=
task_thread_info
(
target
)
->
xfsr
[
0
];
val
&=
0xffffffff00000000UL
;
val
|=
fsr
;
task_thread_info
(
target
)
->
xfsr
[
0
]
=
val
;
}
}
fprs
|=
(
FPRS_FEF
|
FPRS_DL
);
task_thread_info
(
target
)
->
fpsaved
[
0
]
=
fprs
;
return
ret
;
}
static
const
struct
user_regset
ptrace32_regsets
[]
=
{
[
REGSET_GENERAL
]
=
{
.
n
=
19
,
.
size
=
sizeof
(
u32
),
.
get
=
getregs_get
,
.
set
=
setregs_set
,
},
[
REGSET_FP
]
=
{
.
n
=
68
,
.
size
=
sizeof
(
u32
),
.
get
=
getfpregs_get
,
.
set
=
setfpregs_set
,
},
};
static
const
struct
user_regset_view
ptrace32_view
=
{
.
regsets
=
ptrace32_regsets
,
.
n
=
ARRAY_SIZE
(
ptrace32_regsets
)
};
static
const
struct
user_regset_view
user_sparc32_view
=
{
.
name
=
"sparc"
,
.
e_machine
=
EM_SPARC
,
.
regsets
=
sparc32_regsets
,
.
n
=
ARRAY_SIZE
(
sparc32_regsets
)
...
...
@@ -898,7 +1121,6 @@ struct compat_fps {
long
compat_arch_ptrace
(
struct
task_struct
*
child
,
compat_long_t
request
,
compat_ulong_t
caddr
,
compat_ulong_t
cdata
)
{
const
struct
user_regset_view
*
view
=
task_user_regset_view
(
current
);
compat_ulong_t
caddr2
=
task_pt_regs
(
current
)
->
u_regs
[
UREG_I4
];
struct
pt_regs32
__user
*
pregs
;
struct
compat_fps
__user
*
fps
;
...
...
@@ -916,58 +1138,31 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
break
;
case
PTRACE_GETREGS
:
ret
=
copy_regset_to_user
(
child
,
view
,
REGSET_GENERAL
,
32
*
sizeof
(
u32
),
4
*
sizeof
(
u32
),
&
pregs
->
psr
);
if
(
!
ret
)
ret
=
copy_regset_to_user
(
child
,
view
,
REGSET_GENERAL
,
1
*
sizeof
(
u32
),
15
*
sizeof
(
u32
),
&
pregs
->
u_regs
[
0
]);
ret
=
copy_regset_to_user
(
child
,
&
ptrace32_view
,
REGSET_GENERAL
,
0
,
19
*
sizeof
(
u32
),
pregs
);
break
;
case
PTRACE_SETREGS
:
ret
=
copy_regset_from_user
(
child
,
view
,
REGSET_GENERAL
,
32
*
sizeof
(
u32
),
4
*
sizeof
(
u32
),
&
pregs
->
psr
);
if
(
!
ret
)
ret
=
copy_regset_from_user
(
child
,
view
,
REGSET_GENERAL
,
1
*
sizeof
(
u32
),
15
*
sizeof
(
u32
),
&
pregs
->
u_regs
[
0
]);
ret
=
copy_regset_from_user
(
child
,
&
ptrace32_view
,
REGSET_GENERAL
,
0
,
19
*
sizeof
(
u32
),
pregs
);
break
;
case
PTRACE_GETFPREGS
:
ret
=
copy_regset_to_user
(
child
,
view
,
REGSET_FP
,
0
*
sizeof
(
u32
),
32
*
sizeof
(
u32
),
&
fps
->
regs
[
0
]);
if
(
!
ret
)
ret
=
copy_regset_to_user
(
child
,
view
,
REGSET_FP
,
33
*
sizeof
(
u32
),
1
*
sizeof
(
u32
),
&
fps
->
fsr
);
if
(
!
ret
)
{
if
(
__put_user
(
0
,
&
fps
->
flags
)
||
__put_user
(
0
,
&
fps
->
extra
)
||
__put_user
(
0
,
&
fps
->
fpqd
)
||
clear_user
(
&
fps
->
fpq
[
0
],
32
*
sizeof
(
unsigned
int
)))
ret
=
-
EFAULT
;
}
ret
=
copy_regset_to_user
(
child
,
&
ptrace32_view
,
REGSET_FP
,
0
,
68
*
sizeof
(
u32
),
fps
);
break
;
case
PTRACE_SETFPREGS
:
ret
=
copy_regset_from_user
(
child
,
view
,
REGSET_FP
,
0
*
sizeof
(
u32
),
32
*
sizeof
(
u32
),
&
fps
->
regs
[
0
]);
if
(
!
ret
)
ret
=
copy_regset_from_user
(
child
,
view
,
REGSET_FP
,
ret
=
copy_regset_from_user
(
child
,
&
ptrace32_view
,
REGSET_FP
,
0
,
33
*
sizeof
(
u32
),
1
*
sizeof
(
u32
),
&
fps
->
fsr
);
fps
);
break
;
case
PTRACE_READTEXT
:
...
...
@@ -1026,31 +1221,17 @@ long arch_ptrace(struct task_struct *child, long request,
break
;
case
PTRACE_GETREGS64
:
ret
=
copy_regset_to_user
(
child
,
view
,
REGSET_GENERAL
,
1
*
sizeof
(
u64
),
15
*
sizeof
(
u64
),
&
pregs
->
u_regs
[
0
]);
if
(
!
ret
)
{
/* XXX doesn't handle 'y' register correctly XXX */
ret
=
copy_regset_to_user
(
child
,
view
,
REGSET_GENERAL
,
32
*
sizeof
(
u64
),
4
*
sizeof
(
u64
),
&
pregs
->
tstate
);
}
ret
=
copy_regset_to_user
(
child
,
&
ptrace64_view
,
REGSET_GENERAL
,
0
,
19
*
sizeof
(
u64
),
pregs
);
break
;
case
PTRACE_SETREGS64
:
ret
=
copy_regset_from_user
(
child
,
view
,
REGSET_GENERAL
,
1
*
sizeof
(
u64
),
15
*
sizeof
(
u64
),
&
pregs
->
u_regs
[
0
]);
if
(
!
ret
)
{
/* XXX doesn't handle 'y' register correctly XXX */
ret
=
copy_regset_from_user
(
child
,
view
,
REGSET_GENERAL
,
32
*
sizeof
(
u64
),
4
*
sizeof
(
u64
),
&
pregs
->
tstate
);
}
ret
=
copy_regset_from_user
(
child
,
&
ptrace64_view
,
REGSET_GENERAL
,
0
,
19
*
sizeof
(
u64
),
pregs
);
break
;
case
PTRACE_GETFPREGS64
:
...
...
arch/x86/include/asm/fpu/internal.h
View file @
1e56f6d2
...
...
@@ -34,7 +34,6 @@ extern int fpu__copy(struct task_struct *dst, struct task_struct *src);
extern
void
fpu__clear_user_states
(
struct
fpu
*
fpu
);
extern
void
fpu__clear_all
(
struct
fpu
*
fpu
);
extern
int
fpu__exception_code
(
struct
fpu
*
fpu
,
int
trap_nr
);
extern
int
dump_fpu
(
struct
pt_regs
*
ptregs
,
struct
user_i387_struct
*
fpstate
);
/*
* Boot time FPU initialization functions:
...
...
arch/x86/kernel/fpu/regset.c
View file @
1e56f6d2
...
...
@@ -356,20 +356,4 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset,
return
ret
;
}
/*
* FPU state for core dumps.
* This is only used for a.out dumps now.
* It is declared generically using elf_fpregset_t (which is
* struct user_i387_struct) but is in fact only used for 32-bit
* dumps, so on 64-bit it is really struct user_i387_ia32_struct.
*/
int
dump_fpu
(
struct
pt_regs
*
regs
,
struct
user_i387_struct
*
ufpu
)
{
struct
task_struct
*
tsk
=
current
;
return
!
fpregs_get
(
tsk
,
NULL
,
0
,
sizeof
(
struct
user_i387_ia32_struct
),
ufpu
,
NULL
);
}
EXPORT_SYMBOL
(
dump_fpu
);
#endif
/* CONFIG_X86_32 || CONFIG_IA32_EMULATION */
arch/x86/kernel/fpu/signal.c
View file @
1e56f6d2
...
...
@@ -170,14 +170,14 @@ int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size)
ia32_fxstate
&=
(
IS_ENABLED
(
CONFIG_X86_32
)
||
IS_ENABLED
(
CONFIG_IA32_EMULATION
));
if
(
!
static_cpu_has
(
X86_FEATURE_FPU
))
{
struct
user_i387_ia32_struct
fp
;
fpregs_soft_get
(
current
,
NULL
,
0
,
sizeof
(
fp
),
&
fp
,
NULL
);
return
copy_to_user
(
buf
,
&
fp
,
sizeof
(
fp
))
?
-
EFAULT
:
0
;
}
if
(
!
access_ok
(
buf
,
size
))
return
-
EACCES
;
if
(
!
static_cpu_has
(
X86_FEATURE_FPU
))
return
fpregs_soft_get
(
current
,
NULL
,
0
,
sizeof
(
struct
user_i387_ia32_struct
),
NULL
,
(
struct
_fpstate_32
__user
*
)
buf
)
?
-
1
:
1
;
retry:
/*
* Load the FPU registers if they are not valid for the current task.
...
...
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