/* * Copyright 2012, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #define PORTABLE_TAG "signal_portable" #include #if SIGBUS_PORTABLE == SIGBUS #error Bad build environment #endif /* * The next five hidden functions are not exposed in the * libportable shared object. They are used here and other * functions, like waitpid(), which need to map signal numbers. */ __hidden char *map_portable_signum_to_name(int portable_signum) { char *name; switch(portable_signum) { case SIGHUP_PORTABLE: name = "SIGHUP_PORTABLE:1"; break; case SIGINT_PORTABLE: name = "SIGINT_PORTABLE:2"; break; case SIGQUIT_PORTABLE: name = "SIGQUIT_PORTABLE:3"; break; case SIGILL_PORTABLE: name = "SIGILL_PORTABLE:4"; break; case SIGTRAP_PORTABLE: name = "SIGTRAP_PORTABLE:5"; break; case SIGABRT_PORTABLE: name = "SIGABRT_PORTABLE:6"; break; case SIGBUS_PORTABLE: name = "SIGBUS_PORTABLE:7"; break; case SIGFPE_PORTABLE: name = "SIGFPE_PORTABLE:8"; break; case SIGKILL_PORTABLE: name = "SIGKILL_PORTABLE:9"; break; case SIGUSR1_PORTABLE: name = "SIGUSR1_PORTABLE:10"; break; case SIGSEGV_PORTABLE: name = "SIGSEGV_PORTABLE:11"; break; case SIGUSR2_PORTABLE: name = "SIGUSR2_PORTABLE:12"; break; case SIGPIPE_PORTABLE: name = "SIGPIPE_PORTABLE:13"; break; case SIGALRM_PORTABLE: name = "SIGALRM_PORTABLE:14"; break; case SIGTERM_PORTABLE: name = "SIGTERM_PORTABLE:15"; break; case SIGSTKFLT_PORTABLE: name = "SIGSTKFLT_PORTABLE:16"; break; case SIGCHLD_PORTABLE: name = "SIGCHLD_PORTABLE:17"; break; case SIGCONT_PORTABLE: name = "SIGCONT_PORTABLE:18"; break; case SIGSTOP_PORTABLE: name = "SIGSTOP_PORTABLE:19"; break; case SIGTSTP_PORTABLE: name = "SIGTSTP_PORTABLE:20"; break; case SIGTTIN_PORTABLE: name = "SIGTTIN_PORTABLE:21"; break; case SIGTTOU_PORTABLE: name = "SIGTTOU_PORTABLE:22"; break; case SIGURG_PORTABLE: name = "SIGURG_PORTABLE:23"; break; case SIGXCPU_PORTABLE: name = "SIGXCPU_PORTABLE:24"; break; case SIGXFSZ_PORTABLE: name = "SIGXFSZ_PORTABLE:25"; break; case SIGVTALRM_PORTABLE: name = "SIGVTALRM_PORTABLE:26"; break; case SIGPROF_PORTABLE: name = "SIGPROF_PORTABLE:27"; break; case SIGWINCH_PORTABLE: name = "SIGWINCH_PORTABLE:28"; break; case SIGIO_PORTABLE: name = "SIGIO_PORTABLE:29"; break; case SIGPWR_PORTABLE: name = "SIGPWR_PORTABLE:30"; break; case SIGSYS_PORTABLE: name = "SIGSYS_PORTABLE:31"; break; case SIGRTMIN_PORTABLE: name = "SIGRTMIN_PORTABLE:32"; break; default: name = "<>"; break; } return name; } __hidden char *map_mips_signum_to_name(int mips_signum) { char *name; switch(mips_signum) { case SIGHUP: name = "SIGHUP:1"; break; case SIGINT: name = "SIGINT:2"; break; case SIGQUIT: name = "SIGQUIT:3"; break; case SIGILL: name = "SIGILL:4"; break; case SIGTRAP: name = "SIGTRAP:5"; break; case SIGIOT: name = "SIGIOT:6"; break; case SIGEMT: name = "SIGEMT:7"; break; case SIGFPE: name = "SIGFPE:8"; break; case SIGKILL: name = "SIGKILL:9"; break; case SIGBUS: name = "SIGBUS:10"; break; case SIGSEGV: name = "SIGSEGV:11"; break; case SIGSYS: name = "SIGSYS:12"; break; case SIGPIPE: name = "SIGPIPE:13"; break; case SIGALRM: name = "SIGALRM:14"; break; case SIGTERM: name = "SIGTERM:15"; break; case SIGUSR1: name = "SIGUSR1:16"; break; case SIGUSR2: name = "SIGUSR2:17"; break; case SIGCHLD: name = "SIGCHLD:18"; break; case SIGPWR: name = "SIGPWR:19"; break; case SIGWINCH: name = "SIGWINCH:20"; break; case SIGURG: name = "SIGURG:21"; break; case SIGIO: name = "SIGIO:22"; break; case SIGSTOP: name = "SIGSTOP:23"; break; case SIGTSTP: name = "SIGTSTP:24"; break; case SIGCONT: name = "SIGCONT:25"; break; case SIGTTIN: name = "SIGTTIN:26"; break; case SIGTTOU: name = "SIGTTOU:27"; break; case SIGVTALRM: name = "SIGVTALRM:28"; break; case SIGPROF: name = "SIGPROF:29"; break; case SIGXCPU: name = "SIGXCPU:30"; break; case SIGXFSZ: name = "SIGXFSZ:31"; break; case SIGRTMIN: name = "SIGRTMIN:32"; break; default: name = "<>"; break; } return name; } __hidden int map_portable_signum_to_mips(int portable_signum) { int mips_signum = -1; switch(portable_signum) { case SIGHUP_PORTABLE: /* 1 */ return SIGHUP; case SIGINT_PORTABLE: /* 2 */ return SIGINT; case SIGQUIT_PORTABLE: /* 3 */ return SIGQUIT; case SIGILL_PORTABLE: /* 4 */ return SIGILL; case SIGTRAP_PORTABLE: /* 5 */ return SIGTRAP; case SIGABRT_PORTABLE: /* 6 */ return SIGABRT; case SIGBUS_PORTABLE: /* 7 --> 10 */ return SIGBUS; case SIGFPE_PORTABLE: /* 8 */ return SIGFPE; case SIGKILL_PORTABLE: /* 9 */ return SIGKILL; case SIGUSR1_PORTABLE: /* 10 --> 16 */ return SIGUSR1; case SIGSEGV_PORTABLE: /* 11 */ return SIGSEGV; case SIGUSR2_PORTABLE: /* 12 --> 17 */ return SIGUSR2; case SIGPIPE_PORTABLE: /* 13 */ return SIGPIPE; case SIGALRM_PORTABLE: /* 14 */ return SIGALRM; case SIGTERM_PORTABLE: /* 15 */ return SIGTERM; case SIGSTKFLT_PORTABLE: /* 16 --> VOID:0 */ /* No MIPS SIGSTKFLT Exits; try mapping it to zero */ return(0); case SIGCHLD_PORTABLE: /* 17 --> 18 */ return SIGCHLD; case SIGCONT_PORTABLE: return SIGCONT; /* 18 --> 25 */ case SIGSTOP_PORTABLE: /* 19 --> 23 */ return SIGSTOP; case SIGTSTP_PORTABLE: /* 20 --> 24 */ return SIGTSTP; case SIGTTIN_PORTABLE: /* 21 --> 26 */ return SIGTTIN; case SIGTTOU_PORTABLE: /* 22 --> 27 */ return SIGTTOU; case SIGURG_PORTABLE: /* 23 --> 21 */ return SIGURG; case SIGXCPU_PORTABLE: /* 24 --> 30 */ return SIGXCPU; case SIGXFSZ_PORTABLE: /* 25 --> 31 */ return SIGXFSZ; case SIGVTALRM_PORTABLE: /* 26 --> 28 */ return SIGVTALRM; case SIGPROF_PORTABLE: /* 27 --> 29 */ return SIGPROF; case SIGWINCH_PORTABLE: /* 28 --> 20 */ return SIGWINCH; case SIGIO_PORTABLE: /* 29 --> 22 */ return SIGIO; case SIGPWR_PORTABLE: /* 30 --> 19 */ return SIGPWR; case SIGSYS_PORTABLE: /* 31 --> 12 */ return SIGSYS; case SIGRTMIN_PORTABLE: /* 32 */ return SIGRTMIN; default: ALOGE("%s: switch default: NOTE portable_signum:%d not supported.", __func__, portable_signum); /* * User could be LTP testing with bogus signal numbers, * if so we mimic the test. * * If the signal is just outside the PORTABLE range * we use a signal just outside the MIPS range. */ if (portable_signum < 0) { mips_signum = portable_signum; } else if (portable_signum > NSIG_PORTABLE) { mips_signum = (portable_signum - NSIG_PORTABLE) + NSIG; } else { ALOGE("%s: 0 <= portable_signum:%d <= NSIG_PORTABLE:%d; not supported, Return(0);", __func__, portable_signum, NSIG_PORTABLE); mips_signum = 0; } break; } ALOGV("%s(portable_signum:%d): return(mips_signum:%d);", __func__, portable_signum, mips_signum); return mips_signum; } __hidden int map_mips_signum_to_portable(int mips_signum) { int portable_ssignum = -1; switch(mips_signum) { case SIGHUP: /* 1 */ return SIGHUP_PORTABLE; case SIGINT: /* 2 */ return SIGINT_PORTABLE; case SIGQUIT: /* 3 */ return SIGQUIT_PORTABLE; case SIGILL: /* 4 */ return SIGILL_PORTABLE; case SIGTRAP: /* 5 */ return SIGTRAP_PORTABLE; case SIGABRT: /* 6 */ return SIGABRT_PORTABLE; case SIGBUS: /* 7 <-- 10 */ return SIGBUS_PORTABLE; case SIGFPE: /* 8 */ return SIGFPE_PORTABLE; case SIGKILL: /* 9 */ return SIGKILL_PORTABLE; case SIGUSR1: /* 10 <-- 16 */ return SIGUSR1_PORTABLE; case SIGSEGV: /* 11 */ return SIGSEGV_PORTABLE; case SIGUSR2: /* 12 <-- 17 */ return SIGUSR2_PORTABLE; case SIGPIPE: /* 13 */ return SIGPIPE_PORTABLE; case SIGALRM: /* 14 */ return SIGALRM_PORTABLE; case SIGTERM_PORTABLE: /* 15 */ return SIGTERM; #if defined(SIGSTKFLT) case SIGSTKFLT: /* 16 <--- VOID; NOT SUPPORTED */ ASSERT(mips_signum != SIGSTKFLT_PORTABLE); return(-1); #endif case SIGCHLD: /* 17 <-- 18 */ return SIGCHLD_PORTABLE; case SIGCONT: /* 18 <-- 15 */ return SIGCONT_PORTABLE; case SIGSTOP: /* 19 <-- 23 */ return SIGSTOP_PORTABLE; case SIGTSTP: /* 20 <-- 24 */ return SIGTSTP_PORTABLE; case SIGTTIN: /* 21 <-- 26 */ return SIGTTIN_PORTABLE; case SIGTTOU: /* 22 <-- 27 */ return SIGTTOU_PORTABLE; case SIGURG: /* 23 <-- 21 */ return SIGURG_PORTABLE; case SIGXCPU: /* 24 <-- 30 */ return SIGXCPU_PORTABLE; case SIGXFSZ: /* 25 <-- 31 */ return SIGXFSZ_PORTABLE; case SIGVTALRM: /* 26 <-- 28 */ return SIGVTALRM_PORTABLE; case SIGPROF: /* 27 <-- 29 */ return SIGPROF_PORTABLE; case SIGWINCH: /* 28 <-- 20 */ return SIGWINCH_PORTABLE; case SIGIO: /* 29 <-- 22 */ return SIGIO_PORTABLE; case SIGPWR: /* 30 <-- 19 */ return SIGPWR_PORTABLE; case SIGSYS: /* 31 <-- 12 */ return SIGSYS_PORTABLE; case SIGRTMIN_PORTABLE: /* 32 */ return SIGRTMIN; default: ALOGE("%s: switch default: mips_signum:%d not supported! return(0);", __func__, mips_signum); #if 0 LOG_FATAL("%s: mips_signum:%d is not portable;", __func__, mips_signum); #endif return(0); } return portable_ssignum; } /* * Array of signal handlers as the portable users expects they * they have been registered in the kernel. Problem is we need * to have our own handler to map the MIPS signal number to a * portable signal number. */ sig3handler_portable_t mips_portable_sighandler[NSIG_PORTABLE] = { NULL }; static void mips_sigaction_handler(int mips_signum, siginfo_t *sip, void *ucp) { int portable_signum; char *portable_signame; char *mips_signame = map_mips_signum_to_name(mips_signum); sig3handler_portable_t portable_sighandler; siginfo_portable_t portable_si; siginfo_portable_t *portable_sip; ALOGV("%s(mips_signum:%d:'%s', sip:%p, ucp:%p) {", __func__, mips_signum, mips_signame, sip, ucp); portable_signum = map_mips_signum_to_portable(mips_signum); portable_signame = map_portable_signum_to_name(portable_signum); portable_sighandler = mips_portable_sighandler[portable_signum]; ASSERT(portable_sighandler != NULL); ASSERT(portable_sighandler != (sig3handler_portable_t) SIG_DFL); ASSERT(portable_sighandler != (sig3handler_portable_t) SIG_IGN); ASSERT(portable_sighandler != (sig3handler_portable_t) SIG_ERR); if (sip == NULL) { portable_sip = NULL; } else { int portable_si_errno; int portable_si_signo; char *mips_si_signame; char *portable_si_signame; /* * Map Structure members from MIPS to Portable. */ portable_si_signo = map_mips_signum_to_portable(sip->si_signo); portable_si_signame = map_portable_signum_to_name(portable_si_signo); portable_si_errno = ntop_errno(sip->si_errno); mips_si_signame = map_mips_signum_to_name(sip->si_signo); /* * Deal with siginfo structure being a bit different. */ ASSERT(sizeof(siginfo_portable_t) == sizeof(siginfo_t)); memcpy(&portable_si, sip, sizeof(portable_si)); /* Default to the same structure members */ portable_si.si_signo = portable_si_signo; portable_si.si_code = sip->si_code; /* code and errno are swapped between ARM and MIPS ... */ portable_si.si_errno = portable_si_errno; /* ... and errno needs to be translated. */ portable_sip = &portable_si; } /* if sip */ portable_sighandler(portable_signum, portable_sip, ucp); ALOGV("%s: return; }", __func__); } static void mips_sighandler(int mips_signum) { int portable_signum; char *portable_signame; char *mips_signame = map_mips_signum_to_name(mips_signum); sig3handler_portable_t portable_sighandler; ALOGV("%s(mips_signum:%d:'%s') {", __func__, mips_signum, mips_signame); mips_sigaction_handler(mips_signum, NULL, NULL); ALOGV("%s: return; }", __func__); } static sighandler_t map_portable_sighandler_to_mips(sighandler_portable_t portable_handler, int sigaction) { sighandler_t mips_handler; ALOGV("%s(portable_handler:%p, sigaction:%d) {", __func__, portable_handler, sigaction); switch((int) portable_handler) { case (int) SIG_DFL: case (int) SIG_IGN: case (int) SIG_ERR: mips_handler = portable_handler; break; default: if (sigaction) mips_handler = (sighandler_t) mips_sighandler; else mips_handler = (sighandler_t) mips_sigaction_handler; break; } ALOGV("%s: return(mips_handler:%p); }", __func__, mips_handler); return(mips_handler); } /* * This function maps the signal number and calls one of the low level mips signal() * functions implemented in portable-jb/bionic/libc/unistd/signal.c: * sysv_signal() * bsd_signal() * * The last 2 parameters to this static function, mips_signal_fn*, specify which of these functions to call. * We intercept the above to functions, as well as signal(), and call the associated *_portable() * functions below. * * In addition, we intercept the signal_handler with our own handlers that map the signal number from * the MIPS convention to the PORTABLE/ARM convention. */ static sighandler_portable_t _signal_portable(int portable_signum, sighandler_portable_t portable_handler, __sighandler_t (mips_signal_fn)(int, __sighandler_t), char *mips_signal_fn_name) { char *portable_signame = map_portable_signum_to_name(portable_signum); int mips_signum; sighandler_t mips_handler; sighandler_portable_t ret; sighandler_portable_t prev_portable_handler; ALOGV("%s(portable_signum:%d:%s, portable_handler:%p, mips_signal_fn:%p, mips_signal_fn_name:'%s') {", __func__, portable_signum, portable_signame, portable_handler, mips_signal_fn, mips_signal_fn_name); mips_signum = map_portable_signum_to_mips(portable_signum); if ((portable_signum != 0) && ((mips_signum <= 0) || (mips_signum > NSIG))) { /* * Invalid request; Let the kernel generate the proper return value and set errno. */ mips_handler = map_portable_sighandler_to_mips(portable_handler, 0); ret = mips_signal_fn(mips_signum, mips_handler); } else { /* * We have a usable signal number, redirect it to our signal handler * if a portable handler was provided so we can convert the signal number. * Save our current mapped signal handler for likely return. */ prev_portable_handler = (sighandler_portable_t) mips_portable_sighandler[portable_signum]; mips_handler = map_portable_sighandler_to_mips(portable_handler, 0); if (mips_handler != portable_handler) { mips_portable_sighandler[portable_signum] = (sig3handler_portable_t) portable_handler; } ret = mips_signal_fn(mips_signum, mips_handler); if ((ret == (sighandler_portable_t) mips_sighandler) || (ret == (sighandler_portable_t) mips_sigaction_handler)) { ret = (sighandler_t) prev_portable_handler; } } ALOGV("%s: return(ret:%p); }", __func__, ret); return(ret); } /* * signal() can't be called directly, due to an in-line function in signal.h which * redirects the call to bsd_signal(). _signal() is a static function; not to be called * directly. This function isn't actually needed. */ sighandler_portable_t signal_portable(int portable_signum, sighandler_portable_t handler) { sighandler_portable_t ret; ALOGV(" "); ALOGV("%s(portable_signum:%d, handler:%p);", __func__, portable_signum, handler); /* bsd does a SA_RESTART */ ret = _signal_portable(portable_signum, handler, bsd_signal, "bsd_signal"); ALOGV("%s: return(ret:%p); }", __func__, ret); return(ret); } sighandler_portable_t sysv_signal_portable(int portable_signum, sighandler_portable_t handler) { sighandler_portable_t ret; ALOGV(" "); ALOGV("%s(portable_signum:%d, handler:%p);", __func__, portable_signum, handler); /* sysv does a SA_RESETHAND */ ret = _signal_portable(portable_signum, handler, sysv_signal, "sysv_signal"); ALOGV("%s: return(ret:%p); }", __func__, ret); return(ret); } sighandler_portable_t bsd_signal_portable(int portable_signum, sighandler_portable_t handler) { sighandler_portable_t ret; ALOGV(" "); ALOGV("%s(portable_signum:%d, handler:%p) {", __func__, portable_signum, handler); /* bsd does a SA_RESTART */ ret = _signal_portable(portable_signum, handler, bsd_signal, "bsd_signal"); ALOGV("%s: return(ret:%p); }", __func__, ret); return(ret); } static int kill_helper(int id, int portable_signum, int (*fn)(int, int), const char *name) { char *portable_signame = map_portable_signum_to_name(portable_signum); int mips_signum; int ret; ALOGV("%s(id:%d, portable_signum:%d:'%s');", name, id, portable_signum, portable_signame); mips_signum = map_portable_signum_to_mips(portable_signum); if ((portable_signum != 0) && (mips_signum == 0)) return 0; return fn(id, mips_signum); } int killpg_portable(int pgrp, int portable_signum) { return kill_helper(pgrp, portable_signum, killpg, __func__); } int kill_portable(pid_t pid, int portable_signum) { return kill_helper(pid, portable_signum, kill, __func__); } int tkill_portable(int tid, int portable_signum) { extern int tkill(int, int); return kill_helper(tid, portable_signum, tkill, __func__); } /* tgkill is not exported from android-14 libc.so */ #if 0 int tgkill_portable(int tgid, int tid, int portable_signum) { extern int tgkill(int, int, int); char *portable_signame = map_portable_signum_to_name(portable_signum); int mips_signum; int rv; ALOGV("%s(tgid:%d, tid:%d, portable_signum:%d:'%s');", __func__, tgid, tid, portable_signum, portable_signame); mips_signum = map_portable_signum_to_mips(portable_signum); if ((portable_signum != 0) && (mips_signum == 0)) rv = 0; else rv = tgkill(tgid, tid, mips_signum); ALOGV("%s: return rv:%d;", __func__, rv); return rv; } #endif int raise_portable(int portable_signum) { char *portable_signame = map_portable_signum_to_name(portable_signum); int mips_signum = map_portable_signum_to_mips(portable_signum); int rv; ALOGV("%s(portable_signum:%d:'%s') {", __func__, portable_signum, portable_signame); if ((portable_signum != 0) && (mips_signum == 0)) rv = 0; else rv = raise(mips_signum); ALOGV("%s: return(rv:%d); }", __func__, rv); return(rv); } void map_portable_sigset_to_mips(sigset_portable_t *portable_sigset, sigset_t *mips_sigset) { int portable_signum; ASSERT(mips_sigset != NULL); ALOGV("%s(portable_sigset:%p, mips_sigset:%p) {", __func__, portable_sigset, mips_sigset); sigemptyset(mips_sigset); if (invalid_pointer((void *)portable_sigset)) { ALOGE("%s: portable_sigset:%p is not valid; returning empty set.", __func__, portable_sigset); goto done; } for(portable_signum = 1; portable_signum <= NSIG_PORTABLE; portable_signum++) { if (sigismember_portable(portable_sigset, portable_signum)) { char *portable_signame = map_portable_signum_to_name(portable_signum); int mips_signum = map_portable_signum_to_mips(portable_signum); char *mips_signame; if (mips_signum != 0) { int err; mips_signame = map_mips_signum_to_name(mips_signum); ALOGV("%s: sigaddset(mips_sigset:%p, mips_signum:%d:'%s'); [portable_signum:%d:'%s']", __func__, mips_sigset, mips_signum, mips_signame, portable_signum, portable_signame); err = sigaddset(mips_sigset, mips_signum); if (err == -1) { PERROR("sigaddset"); } } } } done: ALOGV("%s: return; }", __func__); return; } void map_mips_sigset_to_portable(const sigset_t *const_mips_sigset, sigset_portable_t *portable_sigset) { int mips_signum; sigset_t *mips_sigset = (sigset_t *) const_mips_sigset; ALOGV("%s(const_mips_sigset:%p, portable_sigset:%p) {", __func__, const_mips_sigset, portable_sigset); ASSERT(mips_sigset != NULL); if (invalid_pointer((void *)portable_sigset)) { ALOGE("%s: portable_sigset:%p is not Valid; can't return sigset", __func__, portable_sigset); goto done; } sigemptyset_portable(portable_sigset); for(mips_signum = 1; mips_signum <= NSIG; mips_signum++) { if (sigismember(mips_sigset, mips_signum)) { int portable_signum = map_mips_signum_to_portable(mips_signum); if (portable_signum != 0) sigaddset_portable(portable_sigset, portable_signum); } } done: ALOGV("%s: return; }", __func__); return; } static int map_portable_sigaction_flags_to_mips(int portable_flags) { int mips_flags = 0; if (portable_flags & SA_NOCLDSTOP_PORTABLE) mips_flags |= SA_NOCLDSTOP; if (portable_flags & SA_NOCLDWAIT_PORTABLE) mips_flags |= SA_NOCLDWAIT; if (portable_flags & SA_SIGINFO_PORTABLE) mips_flags |= SA_SIGINFO; if (portable_flags & SA_THIRTYTWO_PORTABLE) { ALOGV("%s: SA_THIRTYTWO_PORTABLE isn't SUPPORTED.", __func__); } if (portable_flags & SA_RESTORER_PORTABLE) mips_flags |= SA_RESTORER; if (portable_flags & SA_ONSTACK_PORTABLE) mips_flags |= SA_ONSTACK; if (portable_flags & SA_RESTART_PORTABLE) mips_flags |= SA_RESTART; if (portable_flags & SA_NODEFER_PORTABLE) mips_flags |= SA_NODEFER; if (portable_flags & SA_RESETHAND_PORTABLE) mips_flags |= SA_RESETHAND; ALOGV("%s(portable_flags:0x%x) return(mips_flags:0x%x);", __func__, portable_flags, mips_flags); return(mips_flags); } int map_mips_sigaction_flags_to_portable(int mips_flags) { int portable_flags = 0; if (mips_flags & SA_NOCLDSTOP) portable_flags |= SA_NOCLDSTOP_PORTABLE; if (mips_flags & SA_NOCLDWAIT) portable_flags |= SA_NOCLDWAIT_PORTABLE; if (mips_flags & SA_SIGINFO) portable_flags |= SA_SIGINFO_PORTABLE; #ifdef SA_THIRTYTWO if (mips_flags & SA_THIRTYTWO) portable_flags |= SA_THIRTYTWO_PORTABLE; #endif if (mips_flags & SA_RESTORER) portable_flags |= SA_RESTORER_PORTABLE; if (mips_flags & SA_ONSTACK) portable_flags |= SA_ONSTACK_PORTABLE; if (mips_flags & SA_RESTART) portable_flags |= SA_RESTART_PORTABLE; if (mips_flags & SA_NODEFER) portable_flags |= SA_NODEFER_PORTABLE; if (mips_flags & SA_RESETHAND) portable_flags |= SA_RESETHAND_PORTABLE; ALOGV("%s(mips_flags:0x%x) return(portable_flags:0x%x);", __func__, mips_flags, portable_flags); return(portable_flags); } /* * Called by portable/ARM code, which we map and do MIPS system calls. * * The incoming system call used a Portable/ARM sigaction structure: * ------------------------------------------------------------------ * struct sigaction_portable { * union { * __sighandler_portable_t _sa_handler; * __sigaction_handler_portable_t _sa_sigaction; * } _u; * sigset_portable_t sa_mask; * unsigned long sa_flags; * void (*sa_restorer)(void); * }; * * A similar, but different, structure is used in the MIPS/Native system call: * --------------------------------------------------------------------------- * struct sigaction { * unsigned int sa_flags; * union { * __sighandler_t sa_handler; * __sigaction_handler_portable_t _sa_sigaction; * } __u; * sigset_t sa_mask; * }; * * This sigaction structure needs to be mapped before the MIPS systems call as well as after for * returning the old/previous sigaction. Also, like signal_portable() above, we need to maintain * a table of signal handlers that our intercepting handler can call after it converts the signal * numbers. */ int sigaction_portable(int portable_signum, const struct sigaction_portable *act, struct sigaction_portable *oldact) { int mips_signum; char *mips_signame; struct sigaction mips_act; struct sigaction mips_oldact; sighandler_t mips_handler; sighandler_portable_t portable_handler; sig3handler_portable_t prev_portable_handler; char *portable_signame = map_portable_signum_to_name(portable_signum); int rv; ALOGV(" "); ALOGV("%s(portable_signum:%d:'%s', act:%p, oldact:%p) {", __func__, portable_signum, portable_signame, act, oldact); mips_signum = map_portable_signum_to_mips(portable_signum); mips_signame = map_mips_signum_to_name(mips_signum); if ((portable_signum != 0) && (mips_signum == 0)) { /* We got a portable signum that we can't map; Ignore the request */ rv = 0; goto done; } if (portable_signum >= 0 && portable_signum < NSIG_PORTABLE) prev_portable_handler = mips_portable_sighandler[portable_signum]; else prev_portable_handler = NULL; memset(&mips_act, 0, sizeof(mips_act)); if (invalid_pointer((void *)act)) { rv = sigaction(mips_signum, (struct sigaction *)act, &mips_oldact); } else { /* * Make the MIPS version of sigaction, which has no sa_restorer function pointer. Also the handler * will be called with a pointer to a to a sigcontext structure which is totally non-portable. */ map_portable_sigset_to_mips(((sigset_portable_t *)&act->sa_mask), ((sigset_t *) &mips_act.sa_mask)); mips_act.sa_flags = map_portable_sigaction_flags_to_mips(act->sa_flags); if (mips_act.sa_flags & SA_SIGINFO) { /* * Providing the three argument version of a signal handler. */ if (portable_signum >= 0 && portable_signum < NSIG_PORTABLE) { mips_portable_sighandler[portable_signum] = (sig3handler_portable_t) act->sa_sigaction_portable; mips_act.sa_sigaction = mips_sigaction_handler; } else { mips_act.sa_sigaction = act->sa_sigaction_portable; } } else { /* * Providing the classic single argument version of a signal handler. */ portable_handler = act->sa_handler_portable; if ((portable_signum < 0) || (portable_signum > NSIG_PORTABLE)) { /* * Let the kernel generate the proper return value and set errno. */ mips_act.sa_handler = (sighandler_t) portable_handler; } else { mips_handler = map_portable_sighandler_to_mips(portable_handler, 1); if (mips_handler != portable_handler) { mips_portable_sighandler[portable_signum] = (sig3handler_portable_t) portable_handler; } mips_act.sa_handler = mips_handler; } } rv = sigaction(mips_signum, &mips_act, &mips_oldact); } if (oldact) { if ((mips_oldact.sa_sigaction == (__sigaction_handler_portable_t) mips_sighandler) || (mips_oldact.sa_sigaction == (__sigaction_handler_portable_t) mips_sigaction_handler)) { oldact->sa_sigaction_portable = (__sigaction_handler_portable_t) prev_portable_handler; } else { oldact->sa_sigaction_portable = (__sigaction_handler_portable_t) mips_oldact.sa_sigaction; } map_mips_sigset_to_portable((sigset_t *) &(mips_oldact.sa_mask), (sigset_portable_t *) &(oldact->sa_mask)); oldact->sa_flags = map_mips_sigaction_flags_to_portable(mips_oldact.sa_flags); oldact->sa_restorer = NULL; } done: ALOGV("%s: return(rv:%d); }", __func__, rv); return(rv); } #if 0 /* * So far it appears that signalfd() isn't supported by bionic * the kernel trap numbers are available. */ int signalfd_portable(int fd, const sigset_t *portable_sigmask, int flags) { sigset_t mips_sigmask; map_portable_sigset_to_mips(portable_sigmask, &mips_sigmask); return signalfd(fd, &mips_sigmask, flags); } #endif int sigsuspend_portable(const sigset_portable_t *portable_sigmask) { int rv; sigset_t mips_sigmask; ALOGV("%s(portable_sigmask:%p) {", __func__, portable_sigmask); if (invalid_pointer((void *)portable_sigmask)) { errno = EFAULT; rv = -1; } else { map_portable_sigset_to_mips((sigset_portable_t *)portable_sigmask, &mips_sigmask); rv = sigsuspend(&mips_sigmask); } ALOGV("%s: return(rv:%d);", __func__, rv); return(rv); } int sigpending_portable(sigset_portable_t *portable_sigset) { int rv; sigset_t mips_sigset; ALOGV("%s(portable_sigset:%p) {", __func__, portable_sigset); if (invalid_pointer((void *)portable_sigset)) { errno = EFAULT; rv = -1; } else { rv = sigpending(&mips_sigset); map_mips_sigset_to_portable(&mips_sigset, portable_sigset); } ALOGV("%s: return(rv:%d);", __func__, rv); return(rv); } int sigwait_portable(const sigset_portable_t *portable_sigset, int *ptr_to_portable_sig) { int rv; sigset_t mips_sigset; int mips_sig; int portable_sig; ALOGV("%s(portable_sigset:%p, ptr_to_portable_sig:%p) {", __func__, portable_sigset, ptr_to_portable_sig); if (invalid_pointer((void *)portable_sigset)) { errno = EFAULT; rv = -1; } else { map_portable_sigset_to_mips((sigset_portable_t *)portable_sigset, &mips_sigset); rv = sigwait(&mips_sigset, &mips_sig); portable_sig = map_mips_signum_to_portable(mips_sig); *ptr_to_portable_sig = portable_sig; } ALOGV("%s: return(rv:%d);", __func__, rv); return(rv); } int siginterrupt_portable(int portable_signum, int flag) { int rv; int mips_signum; ALOGV("%s(portable_signum:%d, flag:0x%x) {", __func__, portable_signum, flag); mips_signum = map_portable_signum_to_mips(portable_signum); if ((portable_signum != 0) && (mips_signum == 0)) { ALOGE("%s: Unsupported portable_signum:%d; Ignoring.", __func__, portable_signum); rv = 0; } else { rv = siginterrupt(mips_signum, flag); } ALOGV("%s: return(rv:%d);", __func__, rv); return(rv); } __hidden int sigmask_helper(int portable_how, const sigset_portable_t *portable_sigset, sigset_portable_t *portable_oldset, sigmask_fn fn, char *fname) { int rv; int how; char *how_name; sigset_t mips_sigset, *mips_sigset_p; sigset_t mips_oldset, *mips_oldset_p; ALOGV(" "); ALOGV("%s(portable_how:%d, portable_sigset:%p, portable_oldset:%p) {", __func__, portable_how, portable_sigset, portable_oldset); switch(portable_how) { case SIG_BLOCK_PORTABLE: how = SIG_BLOCK; how_name = "SIG_BLOCK"; break; case SIG_UNBLOCK_PORTABLE: how = SIG_UNBLOCK; how_name = "SIG_UNBLOCK"; break; case SIG_SETMASK_PORTABLE: how = SIG_SETMASK; how_name = "SIG_SETMASK"; break; default: ALOGE("%s: portable_how:%d NOT SUPPORTED!", __func__, portable_how); how = -1; break; } if (invalid_pointer((void *)portable_sigset)) { mips_sigset_p = (sigset_t *) portable_sigset; } else { mips_sigset_p = &mips_sigset; memset(mips_sigset_p, 0, sizeof(mips_sigset)); sigemptyset(mips_sigset_p); map_portable_sigset_to_mips((sigset_portable_t *)portable_sigset, &mips_sigset); } if (invalid_pointer((void *)portable_oldset)) { mips_oldset_p = (sigset_t *) portable_oldset; } else { mips_oldset_p = &mips_oldset; memset(mips_oldset_p, 0, sizeof(mips_oldset)); sigemptyset(mips_oldset_p); } rv = fn(how, mips_sigset_p, mips_oldset_p); if (rv == 0 && !invalid_pointer(portable_oldset)) { /* Map returned mips_oldset to portable_oldset for return to caller */ map_mips_sigset_to_portable(mips_oldset_p, portable_oldset); } ALOGV("%s: return(rv:%d); }", __func__, rv); return(rv); } int sigprocmask_portable(int portable_how, const sigset_portable_t *portable_sigset, sigset_portable_t *portable_oldset) { return sigmask_helper(portable_how, portable_sigset, portable_oldset, sigprocmask, "sigprocmask"); } /* * ss_flags and ss_size are located in different locations in stack_t structure: * * Incomming ARM/Portable stack_t: Outgoing MIPS stack_t: * ------------------------------- ---------------------------- * typedef struct sigaltstack { typedef struct sigaltstack { * void __user *ss_sp; void *ss_sp; * int ss_flags; size_t ss_size; * size_t ss_size; int ss_flags; * } stack_t; * */ int sigaltstack_portable(const portable_stack_t *ss, portable_stack_t *oss) { int rv; stack_t new_stack, *mips_ss; stack_t old_stack, *mips_oss; ALOGV(" "); ALOGV("%s(ss:%p, oss:%p) {", __func__, ss, oss); if (ss == NULL) { mips_ss = NULL; } else { if (invalid_pointer((void *)ss)) { ALOGE("%s: invalid_pointer(ss:%p): Let kernel set proper errno and set return value.", __func__, ss); mips_ss = (stack_t *) ss; } else { memset(&new_stack, 0, sizeof(stack_t)); new_stack.ss_sp = ss->ss_sp; new_stack.ss_flags = ss->ss_flags; new_stack.ss_size = ss->ss_size; mips_ss = &new_stack; } } if (oss == NULL) { mips_oss = NULL; } else { if (invalid_pointer((void *)oss)) { ALOGE("%s: invalid_pointer(oss:%p): Let kernel set proper errno and set return value.", __func__, oss); mips_oss = (stack_t *)oss; } else { memset(&old_stack, 0, sizeof(stack_t)); mips_oss = &old_stack; } } rv = sigaltstack(mips_ss, mips_oss); if (!invalid_pointer(oss)) { oss->ss_sp = old_stack.ss_sp; oss->ss_flags = old_stack.ss_flags; oss->ss_size = old_stack.ss_size; } ALOGV("%s: return(rv:%d); }", __func__, rv); return(rv); }