summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJari Vetoniemi <mailroxas@gmail.com>2018-05-30 21:56:14 +0300
committerJari Vetoniemi <mailroxas@gmail.com>2018-05-30 21:56:14 +0300
commitfc4b58aba21f0f85210e838669f9867e48fe664e (patch)
tree166591c89316a8e0578e5dd7a810ad59b127d164 /src
parent0690ed07edb2a1a1336f73143420c85bd10bb492 (diff)
libc: Fix signal functions
bionic uses different sized types, also bugs: https://android.googlesource.com/platform/bionic/+/master/docs/32-bit-abi.md
Diffstat (limited to 'src')
-rw-r--r--src/libc.c66
1 files changed, 54 insertions, 12 deletions
diff --git a/src/libc.c b/src/libc.c
index 81ffd2a..a61acd0 100644
--- a/src/libc.c
+++ b/src/libc.c
@@ -3,6 +3,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
+#include <limits.h>
#include <math.h>
#include <dirent.h>
#include <assert.h>
@@ -23,14 +24,15 @@ struct bionic_dirent {
};
#ifdef ANDROID_X86_LINKER
+typedef unsigned long bionic_sigset_t;
struct bionic_sigaction {
union {
- __sighandler_t _sa_handler;
- void(* _sa_sigaction) (int, siginfo_t *, void *);
- } _u;
- sigset_t sa_mask;
+ void (*bsa_handler)(int);
+ void (*bsa_sigaction)(int, void*, void*);
+ };
+ bionic_sigset_t sa_mask;
int sa_flags;
- void(* sa_restorer) (void);
+ void (*sa_restorer)(void);
};
#else
# error "not implemented for this platform"
@@ -160,29 +162,69 @@ bionic_readdir_r(DIR *dirp, struct bionic_dirent *entry, struct bionic_dirent **
return 0;
}
+// Need to wrap bunch of signal crap
+// https://android.googlesource.com/platform/bionic/+/master/docs/32-bit-abi.md
+
+int
+bionic_sigaddset(const bionic_sigset_t *set, int sig)
+{
+ int bit = sig - 1; // Signal numbers start at 1, but bit positions start at 0.
+ unsigned long *local_set = (unsigned long*)set;
+ if (!set || bit < 0 || bit >= (int)(8 * sizeof(*set))) {
+ errno = EINVAL;
+ return -1;
+ }
+ local_set[bit / LONG_BIT] |= 1UL << (bit % LONG_BIT);
+ return 0;
+}
+
+int
+bionic_sigismember(const bionic_sigset_t *set, int sig)
+{
+ int bit = sig - 1; // Signal numbers start at 1, but bit positions start at 0.
+ const unsigned long *local_set = (const unsigned long*)set;
+ if (!set || bit < 0 || bit >= (int)(8 * sizeof(*set))) {
+ errno = EINVAL;
+ return -1;
+ }
+ return (int)((local_set[bit / LONG_BIT] >> (bit % LONG_BIT)) & 1);
+}
+
int
bionic_sigaction(int sig, const struct bionic_sigaction *restrict act, struct bionic_sigaction *restrict oact)
{
verbose("%d, %p, %p", sig, (void*)act, (void*)oact);
- if (!act)
- return 0;
-
struct sigaction goact = {0}, gact = {0};
if (act) {
- gact.sa_handler = act->_u._sa_handler;
- gact.sa_mask = act->sa_mask;
+ gact.sa_handler = act->bsa_handler;
gact.sa_flags = act->sa_flags;
gact.sa_restorer = act->sa_restorer;
+
+ // delete reserved signals
+ // 32 (__SIGRTMIN + 0) POSIX timers
+ // 33 (__SIGRTMIN + 1) libbacktrace
+ // 34 (__SIGRTMIN + 2) libcore
+ // 35 (__SIGRTMIN + 3) debuggerd -b
+ assert(35 < SIGRTMAX);
+ for (int signo = 35; signo < SIGRTMAX; ++signo) {
+ if (bionic_sigismember(&act->sa_mask, signo))
+ sigaddset(&gact.sa_mask, signo);
+ }
}
const int ret = sigaction(sig, (act ? &gact : NULL), (oact ? &goact : NULL));
if (oact) {
- oact->_u._sa_handler = goact.sa_handler;
- oact->sa_mask = goact.sa_mask;
+ *oact = (struct bionic_sigaction){0};
+ oact->bsa_handler = goact.sa_handler;
oact->sa_flags = goact.sa_flags;
oact->sa_restorer = goact.sa_restorer;
+
+ for (int signo = SIGRTMIN + 3; signo < SIGRTMAX; ++signo) {
+ if (sigismember(&goact.sa_mask, signo))
+ bionic_sigaddset(&oact->sa_mask, signo);
+ }
}
return ret;