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