Home | History | Annotate | Download | only in arch-mips
      1 /*
      2  * Copyright 2012, The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define _GNU_SOURCE
     18 #include <portability.h>
     19 #include <sched.h>
     20 #include <stdarg.h>
     21 #include <stdlib.h>
     22 #include <signal.h>
     23 #include <signal_portable.h>
     24 #include <portability.h>
     25 #include <stdio.h>
     26 #include <errno.h>
     27 #include <filefd_portable.h>
     28 
     29 #define PORTABLE_TAG "clone_portable"
     30 #include <log_portable.h>
     31 
     32 
     33 /*
     34  * This function maps the clone function call defined in:
     35  *      $TOP/bionic/libc/bionic/bionic_clone.c
     36  *
     37  * which calls the __bionic_clone() system call which is defined in:
     38  *      $TOP/bionic/libc/unistd/arch-mips/bionic/clone.S
     39  *
     40  * We have to map the low byte of the 'flags' parameter which
     41  * contains the number of the termination signal sent to the
     42  * parent when the child dies.
     43  *
     44  * Note that if this signal is specified as anything other than
     45  * SIGCHLD, then the parent process must specify the __WALL or
     46  * __WCLONE options when waiting for the child with wait(2).
     47  *
     48  * If no signal is specified, then the parent process is not
     49  * signaled when the child terminates.
     50  */
     51 int WRAP(clone)(int (*fn)(void *), void *child_stack, int port_flags, void *arg, ...)
     52 {
     53     va_list     args;
     54     int         ret;
     55     int         mips_flags;
     56     void        *new_tls = NULL;
     57     int         *child_tidptr = NULL;
     58     int         *parent_tidptr = NULL;
     59     int         mips_term_signum;
     60     char        *mips_term_signame;
     61     int         portable_term_signum;
     62     char        *portable_term_signame;
     63     int         cloning_vm = ((port_flags & CLONE_VM) == CLONE_VM);
     64     int         cloning_files = ((port_flags & CLONE_FILES) == CLONE_FILES);
     65     int         cloning_sighand = ((port_flags & CLONE_SIGHAND) == CLONE_SIGHAND);
     66 
     67     ALOGV(" ");
     68     ALOGV("%s(fn:%p, child_stack:%p, port_flags:0x%x, arg:%p, ...) {", __func__,
     69               fn,    child_stack,    port_flags,      arg);
     70 
     71     /* Shared file descriptor table requires shared memory. */
     72     if (cloning_files != cloning_vm) {
     73         ALOGE("%s: cloning_files:%d != cloning_vm:%d) ...", __func__,
     74                    cloning_files,      cloning_vm);
     75 
     76         ALOGE("%s: ... port_flags:0x%x Not Supported by Lib-Portable!", __func__,
     77                        port_flags);
     78     }
     79 
     80     /* Shared signal handler table requires shared memory. */
     81     if (cloning_sighand != cloning_vm) {
     82         ALOGE("%s: cloning_sighand:%d != cloning_vm:%d) ...",  __func__,
     83                    cloning_sighand,      cloning_vm);
     84 
     85         ALOGE("%s: ... port_flags:0x%x Not Supported by Lib-Portable!", __func__,
     86                        port_flags);
     87     }
     88 
     89     /* Extract optional parameters - they are cumulative. */
     90     va_start(args, arg);
     91     if (port_flags & (CLONE_PARENT_SETTID|CLONE_SETTLS|CLONE_CHILD_SETTID)) {
     92         parent_tidptr = va_arg(args, int*);
     93     }
     94     if (port_flags & (CLONE_SETTLS|CLONE_CHILD_SETTID)) {
     95         new_tls = va_arg(args, void*);
     96     }
     97     if (port_flags & CLONE_CHILD_SETTID) {
     98         child_tidptr = va_arg(args, int*);
     99     }
    100     va_end(args);
    101 
    102     /*
    103      * Map the LSB of the flags as explained above.
    104      */
    105     portable_term_signum = port_flags & 0xFF;
    106     if (portable_term_signum == 0) {
    107         mips_flags = port_flags;
    108     } else {
    109         portable_term_signame = map_portable_signum_to_name(portable_term_signum);
    110         ALOGV("%s: portable_term_signum:0x%x:'%s'", __func__,
    111                    portable_term_signum, portable_term_signame);
    112         mips_term_signum = signum_pton(portable_term_signum);
    113         mips_term_signame = map_mips_signum_to_name(mips_term_signum);
    114         ALOGV("%s: mips_term_signum:0x%x:'%s'", __func__,
    115                    mips_term_signum, mips_term_signame);
    116         mips_flags = (port_flags & ~0xFF) | (mips_term_signum & 0xFF);
    117     }
    118     ALOGV("%s: clone(%p, %p, 0x%x, %p, %p, %p, %p);", __func__,
    119            fn, child_stack, mips_flags, arg, parent_tidptr, new_tls, child_tidptr);
    120 
    121     ret = REAL(clone)(fn, child_stack, mips_flags, arg, parent_tidptr,
    122                 new_tls, child_tidptr);
    123 
    124     if (ret > 0) {
    125         /*
    126          * Disable mapping in the parent if the child could interfere
    127          * and make things even worse than skipping the signal and
    128          * file read mapping.
    129          */
    130         if (cloning_files != cloning_vm) {
    131             filefd_disable_mapping();
    132         }
    133         if (cloning_sighand != cloning_vm) {
    134             signal_disable_mapping();
    135         }
    136     }
    137 
    138     ALOGV("%s: return(ret:%d); }", __func__, ret);
    139     return ret;
    140 }
    141