um: Drop support for hosts without SYSEMU_SINGLESTEP support
These features have existed since Linux 2.6.14 and can be considered widely available at this point. Also drop the backward compatibility code for PTRACE_SETOPTIONS. Signed-off-by: Benjamin Berg <benjamin@sipsolutions.net> ---- v2: * Continue to define PTRACE_SYSEMU_SINGLESTEP as glibc only added it in version 2.27. Signed-off-by: Richard Weinberger <richard@nod.at>
This commit is contained in:
parent
a8e75902f4
commit
a55719847d
@ -22,7 +22,6 @@ struct mm_struct;
|
|||||||
struct thread_struct {
|
struct thread_struct {
|
||||||
struct pt_regs regs;
|
struct pt_regs regs;
|
||||||
struct pt_regs *segv_regs;
|
struct pt_regs *segv_regs;
|
||||||
int singlestep_syscall;
|
|
||||||
void *fault_addr;
|
void *fault_addr;
|
||||||
jmp_buf *fault_catcher;
|
jmp_buf *fault_catcher;
|
||||||
struct task_struct *prev_sched;
|
struct task_struct *prev_sched;
|
||||||
|
@ -34,7 +34,6 @@ extern int handle_page_fault(unsigned long address, unsigned long ip,
|
|||||||
|
|
||||||
extern unsigned int do_IRQ(int irq, struct uml_pt_regs *regs);
|
extern unsigned int do_IRQ(int irq, struct uml_pt_regs *regs);
|
||||||
extern void initial_thread_cb(void (*proc)(void *), void *arg);
|
extern void initial_thread_cb(void (*proc)(void *), void *arg);
|
||||||
extern int is_syscall(unsigned long addr);
|
|
||||||
|
|
||||||
extern void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs);
|
extern void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs);
|
||||||
|
|
||||||
@ -58,7 +57,7 @@ extern char *uml_strdup(const char *string);
|
|||||||
extern unsigned long to_irq_stack(unsigned long *mask_out);
|
extern unsigned long to_irq_stack(unsigned long *mask_out);
|
||||||
extern unsigned long from_irq_stack(int nested);
|
extern unsigned long from_irq_stack(int nested);
|
||||||
|
|
||||||
extern int singlestepping(void *t);
|
extern int singlestepping(void);
|
||||||
|
|
||||||
extern void segv_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs);
|
extern void segv_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs);
|
||||||
extern void bus_handler(int sig, struct siginfo *si, struct uml_pt_regs *regs);
|
extern void bus_handler(int sig, struct siginfo *si, struct uml_pt_regs *regs);
|
||||||
|
@ -12,45 +12,4 @@
|
|||||||
extern int ptrace_getregs(long pid, unsigned long *regs_out);
|
extern int ptrace_getregs(long pid, unsigned long *regs_out);
|
||||||
extern int ptrace_setregs(long pid, unsigned long *regs_in);
|
extern int ptrace_setregs(long pid, unsigned long *regs_in);
|
||||||
|
|
||||||
/* syscall emulation path in ptrace */
|
|
||||||
|
|
||||||
#ifndef PTRACE_SYSEMU
|
|
||||||
#define PTRACE_SYSEMU 31
|
|
||||||
#endif
|
|
||||||
#ifndef PTRACE_SYSEMU_SINGLESTEP
|
|
||||||
#define PTRACE_SYSEMU_SINGLESTEP 32
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* On architectures, that started to support PTRACE_O_TRACESYSGOOD
|
|
||||||
* in linux 2.4, there are two different definitions of
|
|
||||||
* PTRACE_SETOPTIONS: linux 2.4 uses 21 while linux 2.6 uses 0x4200.
|
|
||||||
* For binary compatibility, 2.6 also supports the old "21", named
|
|
||||||
* PTRACE_OLDSETOPTION. On these architectures, UML always must use
|
|
||||||
* "21", to ensure the kernel runs on 2.4 and 2.6 host without
|
|
||||||
* recompilation. So, we use PTRACE_OLDSETOPTIONS in UML.
|
|
||||||
* We also want to be able to build the kernel on 2.4, which doesn't
|
|
||||||
* have PTRACE_OLDSETOPTIONS. So, if it is missing, we declare
|
|
||||||
* PTRACE_OLDSETOPTIONS to be the same as PTRACE_SETOPTIONS.
|
|
||||||
*
|
|
||||||
* On architectures, that start to support PTRACE_O_TRACESYSGOOD on
|
|
||||||
* linux 2.6, PTRACE_OLDSETOPTIONS never is defined, and also isn't
|
|
||||||
* supported by the host kernel. In that case, our trick lets us use
|
|
||||||
* the new 0x4200 with the name PTRACE_OLDSETOPTIONS.
|
|
||||||
*/
|
|
||||||
#ifndef PTRACE_OLDSETOPTIONS
|
|
||||||
#define PTRACE_OLDSETOPTIONS PTRACE_SETOPTIONS
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void set_using_sysemu(int value);
|
|
||||||
int get_using_sysemu(void);
|
|
||||||
extern int sysemu_supported;
|
|
||||||
|
|
||||||
#define SELECT_PTRACE_OPERATION(sysemu_mode, singlestep_mode) \
|
|
||||||
(((int[3][3] ) { \
|
|
||||||
{ PTRACE_SYSCALL, PTRACE_SYSCALL, PTRACE_SINGLESTEP }, \
|
|
||||||
{ PTRACE_SYSEMU, PTRACE_SYSEMU, PTRACE_SINGLESTEP }, \
|
|
||||||
{ PTRACE_SYSEMU, PTRACE_SYSEMU_SINGLESTEP, \
|
|
||||||
PTRACE_SYSEMU_SINGLESTEP } }) \
|
|
||||||
[sysemu_mode][singlestep_mode])
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -332,17 +332,9 @@ int __init make_proc_sysemu(void)
|
|||||||
|
|
||||||
late_initcall(make_proc_sysemu);
|
late_initcall(make_proc_sysemu);
|
||||||
|
|
||||||
int singlestepping(void * t)
|
int singlestepping(void)
|
||||||
{
|
{
|
||||||
struct task_struct *task = t ? t : current;
|
return test_thread_flag(TIF_SINGLESTEP);
|
||||||
|
|
||||||
if (!test_thread_flag(TIF_SINGLESTEP))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (task->thread.singlestep_syscall)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
void user_enable_single_step(struct task_struct *child)
|
void user_enable_single_step(struct task_struct *child)
|
||||||
{
|
{
|
||||||
set_tsk_thread_flag(child, TIF_SINGLESTEP);
|
set_tsk_thread_flag(child, TIF_SINGLESTEP);
|
||||||
child->thread.singlestep_syscall = 0;
|
|
||||||
|
|
||||||
#ifdef SUBARCH_SET_SINGLESTEPPING
|
#ifdef SUBARCH_SET_SINGLESTEPPING
|
||||||
SUBARCH_SET_SINGLESTEPPING(child, 1);
|
SUBARCH_SET_SINGLESTEPPING(child, 1);
|
||||||
@ -22,7 +21,6 @@ void user_enable_single_step(struct task_struct *child)
|
|||||||
void user_disable_single_step(struct task_struct *child)
|
void user_disable_single_step(struct task_struct *child)
|
||||||
{
|
{
|
||||||
clear_tsk_thread_flag(child, TIF_SINGLESTEP);
|
clear_tsk_thread_flag(child, TIF_SINGLESTEP);
|
||||||
child->thread.singlestep_syscall = 0;
|
|
||||||
|
|
||||||
#ifdef SUBARCH_SET_SINGLESTEPPING
|
#ifdef SUBARCH_SET_SINGLESTEPPING
|
||||||
SUBARCH_SET_SINGLESTEPPING(child, 0);
|
SUBARCH_SET_SINGLESTEPPING(child, 0);
|
||||||
|
@ -120,18 +120,6 @@ void do_signal(struct pt_regs *regs)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* This closes a way to execute a system call on the host. If
|
|
||||||
* you set a breakpoint on a system call instruction and singlestep
|
|
||||||
* from it, the tracing thread used to PTRACE_SINGLESTEP the process
|
|
||||||
* rather than PTRACE_SYSCALL it, allowing the system call to execute
|
|
||||||
* on the host. The tracing thread will check this flag and
|
|
||||||
* PTRACE_SYSCALL if necessary.
|
|
||||||
*/
|
|
||||||
if (test_thread_flag(TIF_SINGLESTEP))
|
|
||||||
current->thread.singlestep_syscall =
|
|
||||||
is_syscall(PT_REGS_IP(¤t->thread.regs));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if there's no signal to deliver, we just put the saved sigmask
|
* if there's no signal to deliver, we just put the saved sigmask
|
||||||
* back
|
* back
|
||||||
|
@ -177,48 +177,11 @@ static void handle_segv(int pid, struct uml_pt_regs *regs, unsigned long *aux_fp
|
|||||||
segv(regs->faultinfo, 0, 1, NULL);
|
segv(regs->faultinfo, 0, 1, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static void handle_trap(int pid, struct uml_pt_regs *regs)
|
||||||
* To use the same value of using_sysemu as the caller, ask it that value
|
|
||||||
* (in local_using_sysemu
|
|
||||||
*/
|
|
||||||
static void handle_trap(int pid, struct uml_pt_regs *regs,
|
|
||||||
int local_using_sysemu)
|
|
||||||
{
|
{
|
||||||
int err, status;
|
|
||||||
|
|
||||||
if ((UPT_IP(regs) >= STUB_START) && (UPT_IP(regs) < STUB_END))
|
if ((UPT_IP(regs) >= STUB_START) && (UPT_IP(regs) < STUB_END))
|
||||||
fatal_sigsegv();
|
fatal_sigsegv();
|
||||||
|
|
||||||
if (!local_using_sysemu)
|
|
||||||
{
|
|
||||||
err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET,
|
|
||||||
__NR_getpid);
|
|
||||||
if (err < 0) {
|
|
||||||
printk(UM_KERN_ERR "%s - nullifying syscall failed, errno = %d\n",
|
|
||||||
__func__, errno);
|
|
||||||
fatal_sigsegv();
|
|
||||||
}
|
|
||||||
|
|
||||||
err = ptrace(PTRACE_SYSCALL, pid, 0, 0);
|
|
||||||
if (err < 0) {
|
|
||||||
printk(UM_KERN_ERR "%s - continuing to end of syscall failed, errno = %d\n",
|
|
||||||
__func__, errno);
|
|
||||||
fatal_sigsegv();
|
|
||||||
}
|
|
||||||
|
|
||||||
CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED | __WALL));
|
|
||||||
if ((err < 0) || !WIFSTOPPED(status) ||
|
|
||||||
(WSTOPSIG(status) != SIGTRAP + 0x80)) {
|
|
||||||
err = ptrace_dump_regs(pid);
|
|
||||||
if (err)
|
|
||||||
printk(UM_KERN_ERR "Failed to get registers from process, errno = %d\n",
|
|
||||||
-err);
|
|
||||||
printk(UM_KERN_ERR "%s - failed to wait at end of syscall, errno = %d, status = %d\n",
|
|
||||||
__func__, errno, status);
|
|
||||||
fatal_sigsegv();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handle_syscall(regs);
|
handle_syscall(regs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -355,10 +318,10 @@ int start_userspace(unsigned long stub_stack)
|
|||||||
goto out_kill;
|
goto out_kill;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL,
|
if (ptrace(PTRACE_SETOPTIONS, pid, NULL,
|
||||||
(void *) PTRACE_O_TRACESYSGOOD) < 0) {
|
(void *) PTRACE_O_TRACESYSGOOD) < 0) {
|
||||||
err = -errno;
|
err = -errno;
|
||||||
printk(UM_KERN_ERR "%s : PTRACE_OLDSETOPTIONS failed, errno = %d\n",
|
printk(UM_KERN_ERR "%s : PTRACE_SETOPTIONS failed, errno = %d\n",
|
||||||
__func__, errno);
|
__func__, errno);
|
||||||
goto out_kill;
|
goto out_kill;
|
||||||
}
|
}
|
||||||
@ -380,8 +343,6 @@ int start_userspace(unsigned long stub_stack)
|
|||||||
void userspace(struct uml_pt_regs *regs, unsigned long *aux_fp_regs)
|
void userspace(struct uml_pt_regs *regs, unsigned long *aux_fp_regs)
|
||||||
{
|
{
|
||||||
int err, status, op, pid = userspace_pid[0];
|
int err, status, op, pid = userspace_pid[0];
|
||||||
/* To prevent races if using_sysemu changes under us.*/
|
|
||||||
int local_using_sysemu;
|
|
||||||
siginfo_t si;
|
siginfo_t si;
|
||||||
|
|
||||||
/* Handle any immediate reschedules or signals */
|
/* Handle any immediate reschedules or signals */
|
||||||
@ -411,11 +372,10 @@ void userspace(struct uml_pt_regs *regs, unsigned long *aux_fp_regs)
|
|||||||
fatal_sigsegv();
|
fatal_sigsegv();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now we set local_using_sysemu to be used for one loop */
|
if (singlestepping())
|
||||||
local_using_sysemu = get_using_sysemu();
|
op = PTRACE_SYSEMU_SINGLESTEP;
|
||||||
|
else
|
||||||
op = SELECT_PTRACE_OPERATION(local_using_sysemu,
|
op = PTRACE_SYSEMU;
|
||||||
singlestepping(NULL));
|
|
||||||
|
|
||||||
if (ptrace(op, pid, 0, 0)) {
|
if (ptrace(op, pid, 0, 0)) {
|
||||||
printk(UM_KERN_ERR "%s - ptrace continue failed, op = %d, errno = %d\n",
|
printk(UM_KERN_ERR "%s - ptrace continue failed, op = %d, errno = %d\n",
|
||||||
@ -474,7 +434,7 @@ void userspace(struct uml_pt_regs *regs, unsigned long *aux_fp_regs)
|
|||||||
else handle_segv(pid, regs, aux_fp_regs);
|
else handle_segv(pid, regs, aux_fp_regs);
|
||||||
break;
|
break;
|
||||||
case SIGTRAP + 0x80:
|
case SIGTRAP + 0x80:
|
||||||
handle_trap(pid, regs, local_using_sysemu);
|
handle_trap(pid, regs);
|
||||||
break;
|
break;
|
||||||
case SIGTRAP:
|
case SIGTRAP:
|
||||||
relay_signal(SIGTRAP, (struct siginfo *)&si, regs);
|
relay_signal(SIGTRAP, (struct siginfo *)&si, regs);
|
||||||
@ -597,10 +557,10 @@ int copy_context_skas0(unsigned long new_stack, int pid)
|
|||||||
goto out_kill;
|
goto out_kill;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL,
|
if (ptrace(PTRACE_SETOPTIONS, pid, NULL,
|
||||||
(void *)PTRACE_O_TRACESYSGOOD) < 0) {
|
(void *)PTRACE_O_TRACESYSGOOD) < 0) {
|
||||||
err = -errno;
|
err = -errno;
|
||||||
printk(UM_KERN_ERR "%s : PTRACE_OLDSETOPTIONS failed, errno = %d\n",
|
printk(UM_KERN_ERR "%s : PTRACE_SETOPTIONS failed, errno = %d\n",
|
||||||
__func__, errno);
|
__func__, errno);
|
||||||
goto out_kill;
|
goto out_kill;
|
||||||
}
|
}
|
||||||
|
@ -143,71 +143,16 @@ static int stop_ptraced_child(int pid, int exitcode, int mustexit)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Changed only during early boot */
|
|
||||||
static int force_sysemu_disabled = 0;
|
|
||||||
|
|
||||||
static int __init nosysemu_cmd_param(char *str, int* add)
|
|
||||||
{
|
|
||||||
force_sysemu_disabled = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
__uml_setup("nosysemu", nosysemu_cmd_param,
|
|
||||||
"nosysemu\n"
|
|
||||||
" Turns off syscall emulation patch for ptrace (SYSEMU).\n"
|
|
||||||
" SYSEMU is a performance-patch introduced by Laurent Vivier. It changes\n"
|
|
||||||
" behaviour of ptrace() and helps reduce host context switch rates.\n"
|
|
||||||
" To make it work, you need a kernel patch for your host, too.\n"
|
|
||||||
" See http://perso.wanadoo.fr/laurent.vivier/UML/ for further \n"
|
|
||||||
" information.\n\n");
|
|
||||||
|
|
||||||
static void __init check_sysemu(void)
|
static void __init check_sysemu(void)
|
||||||
{
|
{
|
||||||
unsigned long regs[MAX_REG_NR];
|
|
||||||
int pid, n, status, count=0;
|
int pid, n, status, count=0;
|
||||||
|
|
||||||
os_info("Checking syscall emulation patch for ptrace...");
|
os_info("Checking syscall emulation for ptrace...");
|
||||||
sysemu_supported = 0;
|
|
||||||
pid = start_ptraced_child();
|
pid = start_ptraced_child();
|
||||||
|
|
||||||
if (ptrace(PTRACE_SYSEMU, pid, 0, 0) < 0)
|
if ((ptrace(PTRACE_SETOPTIONS, pid, 0,
|
||||||
goto fail;
|
|
||||||
|
|
||||||
CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
|
|
||||||
if (n < 0)
|
|
||||||
fatal_perror("check_sysemu : wait failed");
|
|
||||||
if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
|
|
||||||
fatal("check_sysemu : expected SIGTRAP, got status = %d\n",
|
|
||||||
status);
|
|
||||||
|
|
||||||
if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0)
|
|
||||||
fatal_perror("check_sysemu : PTRACE_GETREGS failed");
|
|
||||||
if (PT_SYSCALL_NR(regs) != __NR_getpid) {
|
|
||||||
non_fatal("check_sysemu got system call number %d, "
|
|
||||||
"expected %d...", PT_SYSCALL_NR(regs), __NR_getpid);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, os_getpid());
|
|
||||||
if (n < 0) {
|
|
||||||
non_fatal("check_sysemu : failed to modify system call "
|
|
||||||
"return");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stop_ptraced_child(pid, 0, 0) < 0)
|
|
||||||
goto fail_stopped;
|
|
||||||
|
|
||||||
sysemu_supported = 1;
|
|
||||||
os_info("OK\n");
|
|
||||||
set_using_sysemu(!force_sysemu_disabled);
|
|
||||||
|
|
||||||
os_info("Checking advanced syscall emulation patch for ptrace...");
|
|
||||||
pid = start_ptraced_child();
|
|
||||||
|
|
||||||
if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
|
|
||||||
(void *) PTRACE_O_TRACESYSGOOD) < 0))
|
(void *) PTRACE_O_TRACESYSGOOD) < 0))
|
||||||
fatal_perror("check_sysemu: PTRACE_OLDSETOPTIONS failed");
|
fatal_perror("check_sysemu: PTRACE_SETOPTIONS failed");
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
count++;
|
count++;
|
||||||
@ -243,17 +188,14 @@ static void __init check_sysemu(void)
|
|||||||
if (stop_ptraced_child(pid, 0, 0) < 0)
|
if (stop_ptraced_child(pid, 0, 0) < 0)
|
||||||
goto fail_stopped;
|
goto fail_stopped;
|
||||||
|
|
||||||
sysemu_supported = 2;
|
|
||||||
os_info("OK\n");
|
os_info("OK\n");
|
||||||
|
|
||||||
if (!force_sysemu_disabled)
|
|
||||||
set_using_sysemu(sysemu_supported);
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
stop_ptraced_child(pid, 1, 0);
|
stop_ptraced_child(pid, 1, 0);
|
||||||
fail_stopped:
|
fail_stopped:
|
||||||
non_fatal("missing\n");
|
fatal("missing\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __init check_ptrace(void)
|
static void __init check_ptrace(void)
|
||||||
@ -263,9 +205,9 @@ static void __init check_ptrace(void)
|
|||||||
os_info("Checking that ptrace can change system call numbers...");
|
os_info("Checking that ptrace can change system call numbers...");
|
||||||
pid = start_ptraced_child();
|
pid = start_ptraced_child();
|
||||||
|
|
||||||
if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
|
if ((ptrace(PTRACE_SETOPTIONS, pid, 0,
|
||||||
(void *) PTRACE_O_TRACESYSGOOD) < 0))
|
(void *) PTRACE_O_TRACESYSGOOD) < 0))
|
||||||
fatal_perror("check_ptrace: PTRACE_OLDSETOPTIONS failed");
|
fatal_perror("check_ptrace: PTRACE_SETOPTIONS failed");
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
|
if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
|
||||||
|
@ -25,30 +25,6 @@ void arch_switch_to(struct task_struct *to)
|
|||||||
printk(KERN_WARNING "arch_switch_tls failed, errno = EINVAL\n");
|
printk(KERN_WARNING "arch_switch_tls failed, errno = EINVAL\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
int is_syscall(unsigned long addr)
|
|
||||||
{
|
|
||||||
unsigned short instr;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
n = copy_from_user(&instr, (void __user *) addr, sizeof(instr));
|
|
||||||
if (n) {
|
|
||||||
/* access_process_vm() grants access to vsyscall and stub,
|
|
||||||
* while copy_from_user doesn't. Maybe access_process_vm is
|
|
||||||
* slow, but that doesn't matter, since it will be called only
|
|
||||||
* in case of singlestepping, if copy_from_user failed.
|
|
||||||
*/
|
|
||||||
n = access_process_vm(current, addr, &instr, sizeof(instr),
|
|
||||||
FOLL_FORCE);
|
|
||||||
if (n != sizeof(instr)) {
|
|
||||||
printk(KERN_ERR "is_syscall : failed to read "
|
|
||||||
"instruction from 0x%lx\n", addr);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* int 0x80 or sysenter */
|
|
||||||
return (instr == 0x80cd) || (instr == 0x340f);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* determines which flags the user has access to. */
|
/* determines which flags the user has access to. */
|
||||||
/* 1 = access 0 = no access */
|
/* 1 = access 0 = no access */
|
||||||
#define FLAG_MASK 0x00044dd5
|
#define FLAG_MASK 0x00044dd5
|
||||||
|
@ -188,32 +188,6 @@ int peek_user(struct task_struct *child, long addr, long data)
|
|||||||
return put_user(tmp, (unsigned long *) data);
|
return put_user(tmp, (unsigned long *) data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX Mostly copied from sys-i386 */
|
|
||||||
int is_syscall(unsigned long addr)
|
|
||||||
{
|
|
||||||
unsigned short instr;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
n = copy_from_user(&instr, (void __user *) addr, sizeof(instr));
|
|
||||||
if (n) {
|
|
||||||
/*
|
|
||||||
* access_process_vm() grants access to vsyscall and stub,
|
|
||||||
* while copy_from_user doesn't. Maybe access_process_vm is
|
|
||||||
* slow, but that doesn't matter, since it will be called only
|
|
||||||
* in case of singlestepping, if copy_from_user failed.
|
|
||||||
*/
|
|
||||||
n = access_process_vm(current, addr, &instr, sizeof(instr),
|
|
||||||
FOLL_FORCE);
|
|
||||||
if (n != sizeof(instr)) {
|
|
||||||
printk("is_syscall : failed to read instruction from "
|
|
||||||
"0x%lx\n", addr);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* sysenter */
|
|
||||||
return instr == 0x050f;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
|
static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
|
||||||
{
|
{
|
||||||
int err, n, cpu = ((struct thread_info *) child->stack)->cpu;
|
int err, n, cpu = ((struct thread_info *) child->stack)->cpu;
|
||||||
|
@ -8,10 +8,6 @@
|
|||||||
|
|
||||||
#define MAX_FP_NR HOST_FPX_SIZE
|
#define MAX_FP_NR HOST_FPX_SIZE
|
||||||
|
|
||||||
void set_using_sysemu(int value);
|
|
||||||
int get_using_sysemu(void);
|
|
||||||
extern int sysemu_supported;
|
|
||||||
|
|
||||||
#define UPT_SYSCALL_ARG1(r) UPT_BX(r)
|
#define UPT_SYSCALL_ARG1(r) UPT_BX(r)
|
||||||
#define UPT_SYSCALL_ARG2(r) UPT_CX(r)
|
#define UPT_SYSCALL_ARG2(r) UPT_CX(r)
|
||||||
#define UPT_SYSCALL_ARG3(r) UPT_DX(r)
|
#define UPT_SYSCALL_ARG3(r) UPT_DX(r)
|
||||||
|
@ -15,14 +15,12 @@
|
|||||||
#define FP_SIZE ((HOST_FPX_SIZE > HOST_FP_SIZE) ? HOST_FPX_SIZE : HOST_FP_SIZE)
|
#define FP_SIZE ((HOST_FPX_SIZE > HOST_FP_SIZE) ? HOST_FPX_SIZE : HOST_FP_SIZE)
|
||||||
#else
|
#else
|
||||||
#define FP_SIZE HOST_FP_SIZE
|
#define FP_SIZE HOST_FP_SIZE
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* x86_64 FC3 doesn't define this in /usr/include/linux/ptrace.h even though
|
* glibc before 2.27 does not include PTRACE_SYSEMU_SINGLESTEP in its enum,
|
||||||
* it's defined in the kernel's include/linux/ptrace.h. Additionally, use the
|
* ensure we have a definition by (re-)defining it here.
|
||||||
* 2.4 name and value for 2.4 host compatibility.
|
|
||||||
*/
|
*/
|
||||||
#ifndef PTRACE_OLDSETOPTIONS
|
#ifndef PTRACE_SYSEMU_SINGLESTEP
|
||||||
#define PTRACE_OLDSETOPTIONS 21
|
#define PTRACE_SYSEMU_SINGLESTEP 32
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user