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