lkml.org 
[lkml]   [2007]   [Feb]   [20]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[PATCH] UML utrace support, step 1
    Below is the first step in your Fix-Your-Broken-Arch-HOWTO for UML.

    Do you want incremental patches as I go along, or replacement ones?

    BTW, UML runs on the utrace in -mm (i.e. utrace on the host), which it
    didn't with several Fedora kernels.

    Jeff

    --
    Work email - jdike at linux dot intel dot com



    The first step in making the utrace arch changes for UML. It builds
    and runs now, but ptrace is broken.

    Signed-off-by: Jeff Dike <jdike@addtoit.com>
    --
    arch/um/kernel/exec.c | 1
    arch/um/kernel/process.c | 6
    arch/um/kernel/ptrace.c | 333 +++++-----------------------------------
    arch/um/kernel/signal.c | 5
    arch/um/kernel/skas/syscall.c | 4
    arch/um/sys-i386/signal.c | 4
    include/asm-um/ptrace-generic.h | 3
    include/asm-um/tracehook.h | 66 +++++++
    8 files changed, 115 insertions(+), 307 deletions(-)

    Index: linux-2.6.18-mm/arch/um/kernel/exec.c
    ===================================================================
    --- linux-2.6.18-mm.orig/arch/um/kernel/exec.c 2007-02-20 16:18:07.000000000 -0500
    +++ linux-2.6.18-mm/arch/um/kernel/exec.c 2007-02-20 16:18:50.000000000 -0500
    @@ -51,7 +51,6 @@ static long execve1(char *file, char __u
    error = do_execve(file, argv, env, &current->thread.regs);
    if (error == 0){
    task_lock(current);
    - current->ptrace &= ~PT_DTRACE;
    #ifdef SUBARCH_EXECVE1
    SUBARCH_EXECVE1(&current->thread.regs.regs);
    #endif
    Index: linux-2.6.18-mm/arch/um/kernel/process.c
    ===================================================================
    --- linux-2.6.18-mm.orig/arch/um/kernel/process.c 2007-02-20 16:18:07.000000000 -0500
    +++ linux-2.6.18-mm/arch/um/kernel/process.c 2007-02-20 16:18:50.000000000 -0500
    @@ -458,11 +458,11 @@ int singlestepping(void * t)
    {
    struct task_struct *task = t ? t : current;

    - if ( ! (task->ptrace & PT_DTRACE) )
    - return(0);
    + if (!test_thread_flag(TIF_SINGLESTEP))
    + return 0;

    if (task->thread.singlestep_syscall)
    - return(1);
    + return 1;

    return 2;
    }
    Index: linux-2.6.18-mm/arch/um/kernel/ptrace.c
    ===================================================================
    --- linux-2.6.18-mm.orig/arch/um/kernel/ptrace.c 2007-02-20 16:18:07.000000000 -0500
    +++ linux-2.6.18-mm/arch/um/kernel/ptrace.c 2007-02-20 16:18:50.000000000 -0500
    @@ -3,261 +3,29 @@
    * Licensed under the GPL
    */

    -#include "linux/sched.h"
    -#include "linux/mm.h"
    -#include "linux/errno.h"
    -#include "linux/smp_lock.h"
    -#include "linux/security.h"
    -#include "linux/ptrace.h"
    -#include "linux/audit.h"
    -#ifdef CONFIG_PROC_MM
    -#include "linux/proc_mm.h"
    -#endif
    -#include "asm/ptrace.h"
    -#include "asm/uaccess.h"
    -#include "kern_util.h"
    -#include "skas_ptrace.h"
    -#include "sysdep/ptrace.h"
    -#include "os.h"
    -
    -static inline void set_singlestepping(struct task_struct *child, int on)
    +#include <linux/audit.h>
    +#include <linux/elf.h>
    +#include <linux/module.h>
    +#include <linux/ptrace.h>
    +#include <linux/tracehook.h>
    +
    +const struct utrace_regset_view utrace_um_native = {
    + .name = "um",
    + .e_machine = ELF_ARCH,
    + .regsets = NULL,
    + .n = 0,
    +};
    +EXPORT_SYMBOL_GPL(utrace_um_native);
    +
    +int arch_ptrace(long *req, struct task_struct *child,
    + struct utrace_attached_engine *engine,
    + unsigned long addr, unsigned long data, long *val)
    {
    - if (on)
    - child->ptrace |= PT_DTRACE;
    - else
    - child->ptrace &= ~PT_DTRACE;
    - child->thread.singlestep_syscall = 0;
    -
    -#ifdef SUBARCH_SET_SINGLESTEPPING
    - SUBARCH_SET_SINGLESTEPPING(child, on);
    -#endif
    + return -ENOSYS;
    }

    -/*
    - * Called by kernel/ptrace.c when detaching..
    - */
    -void ptrace_disable(struct task_struct *child)
    -{
    - set_singlestepping(child,0);
    -}
    -
    -extern int peek_user(struct task_struct * child, long addr, long data);
    -extern int poke_user(struct task_struct * child, long addr, long data);
    -
    -long arch_ptrace(struct task_struct *child, long request, long addr, long data)
    -{
    - int i, ret;
    - unsigned long __user *p = (void __user *)(unsigned long)data;
    -
    - switch (request) {
    - /* when I and D space are separate, these will need to be fixed. */
    - case PTRACE_PEEKTEXT: /* read word at location addr. */
    - case PTRACE_PEEKDATA: {
    - unsigned long tmp;
    - int copied;
    -
    - ret = -EIO;
    - copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
    - if (copied != sizeof(tmp))
    - break;
    - ret = put_user(tmp, p);
    - break;
    - }
    -
    - /* read the word at location addr in the USER area. */
    - case PTRACE_PEEKUSR:
    - ret = peek_user(child, addr, data);
    - break;
    -
    - /* when I and D space are separate, this will have to be fixed. */
    - case PTRACE_POKETEXT: /* write the word at location addr. */
    - case PTRACE_POKEDATA:
    - ret = -EIO;
    - if (access_process_vm(child, addr, &data, sizeof(data),
    - 1) != sizeof(data))
    - break;
    - ret = 0;
    - break;
    -
    - case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
    - ret = poke_user(child, addr, data);
    - break;
    -
    - case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
    - case PTRACE_CONT: { /* restart after signal. */
    - ret = -EIO;
    - if (!valid_signal(data))
    - break;
    -
    - set_singlestepping(child, 0);
    - if (request == PTRACE_SYSCALL) {
    - set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
    - }
    - else {
    - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
    - }
    - child->exit_code = data;
    - wake_up_process(child);
    - ret = 0;
    - break;
    - }
    -
    -/*
    - * make the child exit. Best I can do is send it a sigkill.
    - * perhaps it should be put in the status that it wants to
    - * exit.
    - */
    - case PTRACE_KILL: {
    - ret = 0;
    - if (child->exit_state == EXIT_ZOMBIE) /* already dead */
    - break;
    -
    - set_singlestepping(child, 0);
    - child->exit_code = SIGKILL;
    - wake_up_process(child);
    - break;
    - }
    -
    - case PTRACE_SINGLESTEP: { /* set the trap flag. */
    - ret = -EIO;
    - if (!valid_signal(data))
    - break;
    - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
    - set_singlestepping(child, 1);
    - child->exit_code = data;
    - /* give it a chance to run. */
    - wake_up_process(child);
    - ret = 0;
    - break;
    - }
    -
    - case PTRACE_DETACH:
    - /* detach a process that was attached. */
    - ret = ptrace_detach(child, data);
    - break;
    -
    -#ifdef PTRACE_GETREGS
    - case PTRACE_GETREGS: { /* Get all gp regs from the child. */
    - if (!access_ok(VERIFY_WRITE, p, MAX_REG_OFFSET)) {
    - ret = -EIO;
    - break;
    - }
    - for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
    - __put_user(getreg(child, i), p);
    - p++;
    - }
    - ret = 0;
    - break;
    - }
    -#endif
    -#ifdef PTRACE_SETREGS
    - case PTRACE_SETREGS: { /* Set all gp regs in the child. */
    - unsigned long tmp = 0;
    - if (!access_ok(VERIFY_READ, p, MAX_REG_OFFSET)) {
    - ret = -EIO;
    - break;
    - }
    - for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
    - __get_user(tmp, p);
    - putreg(child, i, tmp);
    - p++;
    - }
    - ret = 0;
    - break;
    - }
    -#endif
    -#ifdef PTRACE_GETFPREGS
    - case PTRACE_GETFPREGS: /* Get the child FPU state. */
    - ret = get_fpregs(data, child);
    - break;
    -#endif
    -#ifdef PTRACE_SETFPREGS
    - case PTRACE_SETFPREGS: /* Set the child FPU state. */
    - ret = set_fpregs(data, child);
    - break;
    -#endif
    -#ifdef PTRACE_GETFPXREGS
    - case PTRACE_GETFPXREGS: /* Get the child FPU state. */
    - ret = get_fpxregs(data, child);
    - break;
    -#endif
    -#ifdef PTRACE_SETFPXREGS
    - case PTRACE_SETFPXREGS: /* Set the child FPU state. */
    - ret = set_fpxregs(data, child);
    - break;
    -#endif
    - case PTRACE_GET_THREAD_AREA:
    - ret = ptrace_get_thread_area(child, addr,
    - (struct user_desc __user *) data);
    - break;
    -
    - case PTRACE_SET_THREAD_AREA:
    - ret = ptrace_set_thread_area(child, addr,
    - (struct user_desc __user *) data);
    - break;
    -
    - case PTRACE_FAULTINFO: {
    - /* Take the info from thread->arch->faultinfo,
    - * but transfer max. sizeof(struct ptrace_faultinfo).
    - * On i386, ptrace_faultinfo is smaller!
    - */
    - ret = copy_to_user(p, &child->thread.arch.faultinfo,
    - sizeof(struct ptrace_faultinfo));
    - if(ret)
    - break;
    - break;
    - }
    -
    -#ifdef PTRACE_LDT
    - case PTRACE_LDT: {
    - struct ptrace_ldt ldt;
    -
    - if(copy_from_user(&ldt, p, sizeof(ldt))){
    - ret = -EIO;
    - break;
    - }
    -
    - /* This one is confusing, so just punt and return -EIO for
    - * now
    - */
    - ret = -EIO;
    - break;
    - }
    -#endif
    -#ifdef CONFIG_PROC_MM
    - case PTRACE_SWITCH_MM: {
    - struct mm_struct *old = child->mm;
    - struct mm_struct *new = proc_mm_get_mm(data);
    -
    - if(IS_ERR(new)){
    - ret = PTR_ERR(new);
    - break;
    - }
    -
    - atomic_inc(&new->mm_users);
    - child->mm = new;
    - child->active_mm = new;
    - mmput(old);
    - ret = 0;
    - break;
    - }
    -#endif
    -#ifdef PTRACE_ARCH_PRCTL
    - case PTRACE_ARCH_PRCTL:
    - /* XXX Calls ptrace on the host - needs some SMP thinking */
    - ret = arch_prctl_skas(child, data, (void *) addr);
    - break;
    -#endif
    - default:
    - ret = ptrace_request(child, request, addr, data);
    - break;
    - }
    -
    - return ret;
    -}
    -
    -void send_sigtrap(struct task_struct *tsk, union uml_pt_regs *regs,
    - int error_code)
    +static void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
    + int error_code)
    {
    struct siginfo info;

    @@ -266,56 +34,39 @@ void send_sigtrap(struct task_struct *ts
    info.si_code = TRAP_BRKPT;

    /* User-mode eip? */
    - info.si_addr = UPT_IS_USER(regs) ? (void __user *) UPT_IP(regs) : NULL;
    + info.si_addr = UPT_IS_USER(&regs->regs) ?
    + (void __user *) UPT_IP(&regs->regs) : NULL;

    /* Send us the fakey SIGTRAP */
    force_sig_info(SIGTRAP, &info, tsk);
    }

    -/* XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and
    - * PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check
    +/* notification of system call entry/exit
    + * - triggered by current->work.syscall_trace
    */
    -void syscall_trace(union uml_pt_regs *regs, int entryexit)
    +void do_syscall_trace(struct pt_regs *regs, int entryexit)
    {
    - int is_singlestep = (current->ptrace & PT_DTRACE) && entryexit;
    - int tracesysgood;
    + /* do the secure computing check first */
    + if (!entryexit)
    + secure_computing(PT_REGS_SYSCALL_NR(regs));
    +
    + if (unlikely(current->audit_context) && entryexit)
    + audit_syscall_exit(AUDITSC_RESULT(UPT_SYSCALL_RET(regs)),
    + UPT_SYSCALL_RET(regs));
    +
    + if (test_thread_flag(TIF_SYSCALL_TRACE))
    + tracehook_report_syscall(regs, entryexit);
    +
    + if (test_thread_flag(TIF_SINGLESTEP) && entryexit) {
    + send_sigtrap(current, regs, 0); /* XXX */
    + tracehook_report_syscall_step(regs);
    + }

    - if (unlikely(current->audit_context)) {
    - if (!entryexit)
    - audit_syscall_entry(HOST_AUDIT_ARCH,
    + if (unlikely(current->audit_context) && !entryexit)
    + audit_syscall_entry(HOST_AUDIT_ARCH,
    UPT_SYSCALL_NR(regs),
    UPT_SYSCALL_ARG1(regs),
    UPT_SYSCALL_ARG2(regs),
    UPT_SYSCALL_ARG3(regs),
    UPT_SYSCALL_ARG4(regs));
    - else audit_syscall_exit(AUDITSC_RESULT(UPT_SYSCALL_RET(regs)),
    - UPT_SYSCALL_RET(regs));
    - }
    -
    - /* Fake a debug trap */
    - if (is_singlestep)
    - send_sigtrap(current, regs, 0);
    -
    - if (!test_thread_flag(TIF_SYSCALL_TRACE))
    - return;
    -
    - if (!(current->ptrace & PT_PTRACED))
    - return;
    -
    - /* the 0x80 provides a way for the tracing parent to distinguish
    - between a syscall stop and SIGTRAP delivery */
    - tracesysgood = (current->ptrace & PT_TRACESYSGOOD);
    - ptrace_notify(SIGTRAP | (tracesysgood ? 0x80 : 0));
    -
    - if (entryexit) /* force do_signal() --> is_syscall() */
    - set_thread_flag(TIF_SIGPENDING);
    -
    - /* this isn't the same as continuing with a signal, but it will do
    - * for normal use. strace only continues with a signal if the
    - * stopping signal is not SIGTRAP. -brl
    - */
    - if (current->exit_code) {
    - send_sig(current->exit_code, current, 1);
    - current->exit_code = 0;
    - }
    }
    Index: linux-2.6.18-mm/include/asm-um/tracehook.h
    ===================================================================
    --- /dev/null 1970-01-01 00:00:00.000000000 +0000
    +++ linux-2.6.18-mm/include/asm-um/tracehook.h 2007-02-20 16:18:50.000000000 -0500
    @@ -0,0 +1,66 @@
    +/*
    + * Tracing hooks, i386 CPU support
    + *
    + * Copyright (C) 2006, 2007 Red Hat, Inc. All rights reserved.
    + *
    + * This copyrighted material is made available to anyone wishing to use,
    + * modify, copy, or redistribute it subject to the terms and conditions
    + * of the GNU General Public License v.2.
    + *
    + * Red Hat Author: Roland McGrath.
    + *
    + * Munged for UML - jdike@{addtoit,linux.intel}.com
    + */
    +
    +#ifndef _ASM_TRACEHOOK_H
    +#define _ASM_TRACEHOOK_H 1
    +
    +#include <linux/sched.h>
    +#include <asm/ptrace.h>
    +#include <asm/thread_info.h>
    +
    +/*
    + * See linux/tracehook.h for the descriptions of what these need to do.
    + */
    +
    +#define ARCH_HAS_SINGLE_STEP (1)
    +
    +static inline void tracehook_enable_single_step(struct task_struct *tsk)
    +{
    + set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
    +}
    +
    +static inline void tracehook_disable_single_step(struct task_struct *tsk)
    +{
    + clear_tsk_thread_flag(tsk, TIF_SINGLESTEP);
    +}
    +
    +static inline int tracehook_single_step_enabled(struct task_struct *tsk)
    +{
    + return test_tsk_thread_flag(tsk, TIF_SINGLESTEP);
    +}
    +
    +static inline void tracehook_enable_syscall_trace(struct task_struct *tsk)
    +{
    + set_tsk_thread_flag(tsk, TIF_SYSCALL_TRACE);
    +}
    +
    +static inline void tracehook_disable_syscall_trace(struct task_struct *tsk)
    +{
    + clear_tsk_thread_flag(tsk, TIF_SYSCALL_TRACE);
    +}
    +
    +static inline void tracehook_abort_syscall(struct pt_regs *regs)
    +{
    + PT_REGS_SYSCALL_NR(regs) = -1;
    +}
    +
    +extern const struct utrace_regset_view utrace_um_native;
    +static inline const struct utrace_regset_view *
    +utrace_native_view(struct task_struct *tsk)
    +{
    + return &utrace_um_native;
    +}
    +
    +
    +#endif
    Index: linux-2.6.18-mm/arch/um/kernel/signal.c
    ===================================================================
    --- linux-2.6.18-mm.orig/arch/um/kernel/signal.c 2007-02-20 16:18:37.000000000 -0500
    +++ linux-2.6.18-mm/arch/um/kernel/signal.c 2007-02-20 16:18:50.000000000 -0500
    @@ -14,6 +14,7 @@
    #include "linux/tty.h"
    #include "linux/binfmts.h"
    #include "linux/ptrace.h"
    +#include "linux/tracehook.h"
    #include "asm/signal.h"
    #include "asm/uaccess.h"
    #include "asm/unistd.h"
    @@ -93,6 +94,8 @@ static int handle_signal(struct pt_regs
    sigaddset(&current->blocked, signr);
    recalc_sigpending();
    spin_unlock_irq(&current->sighand->siglock);
    +
    + tracehook_report_handle_signal(signr, ka, oldset, regs);
    }

    return err;
    @@ -148,7 +151,7 @@ static int kern_do_signal(struct pt_regs
    * on the host. The tracing thread will check this flag and
    * PTRACE_SYSCALL if necessary.
    */
    - if(current->ptrace & PT_DTRACE)
    + if(test_thread_flag(TIF_SYSCALL_TRACE))
    current->thread.singlestep_syscall =
    is_syscall(PT_REGS_IP(&current->thread.regs));

    Index: linux-2.6.18-mm/arch/um/kernel/skas/syscall.c
    ===================================================================
    --- linux-2.6.18-mm.orig/arch/um/kernel/skas/syscall.c 2007-02-20 16:18:07.000000000 -0500
    +++ linux-2.6.18-mm/arch/um/kernel/skas/syscall.c 2007-02-20 16:18:50.000000000 -0500
    @@ -19,8 +19,6 @@ void handle_syscall(union uml_pt_regs *r
    long result;
    int syscall;

    - syscall_trace(r, 0);
    -
    current->thread.nsyscalls++;
    nsyscalls++;

    @@ -38,6 +36,4 @@ void handle_syscall(union uml_pt_regs *r
    else result = EXECUTE_SYSCALL(syscall, regs);

    REGS_SET_SYSCALL_RETURN(r->skas.regs, result);
    -
    - syscall_trace(r, 1);
    }
    Index: linux-2.6.18-mm/arch/um/sys-i386/signal.c
    ===================================================================
    --- linux-2.6.18-mm.orig/arch/um/sys-i386/signal.c 2007-02-20 16:18:07.000000000 -0500
    +++ linux-2.6.18-mm/arch/um/sys-i386/signal.c 2007-02-20 16:18:50.000000000 -0500
    @@ -267,8 +267,6 @@ int setup_signal_stack_sc(unsigned long
    PT_REGS_EDX(regs) = (unsigned long) 0;
    PT_REGS_ECX(regs) = (unsigned long) 0;

    - if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
    - ptrace_notify(SIGTRAP);
    return 0;

    err:
    @@ -324,8 +322,6 @@ int setup_signal_stack_si(unsigned long
    PT_REGS_EDX(regs) = (unsigned long) &frame->info;
    PT_REGS_ECX(regs) = (unsigned long) &frame->uc;

    - if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
    - ptrace_notify(SIGTRAP);
    return 0;

    err:
    Index: linux-2.6.18-mm/include/asm-um/ptrace-generic.h
    ===================================================================
    --- linux-2.6.18-mm.orig/include/asm-um/ptrace-generic.h 2007-02-20 16:18:07.000000000 -0500
    +++ linux-2.6.18-mm/include/asm-um/ptrace-generic.h 2007-02-20 16:18:50.000000000 -0500
    @@ -44,9 +44,6 @@ extern int set_fpxregs(unsigned long buf

    extern void show_regs(struct pt_regs *regs);

    -extern void send_sigtrap(struct task_struct *tsk, union uml_pt_regs *regs,
    - int error_code);
    -
    extern int arch_copy_tls(struct task_struct *new);
    extern void clear_flushed_tls(struct task_struct *task);

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/
    \
     
     \ /
      Last update: 2007-02-20 22:33    [W:4.123 / U:0.184 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site