• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
WRAP(clone)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