From 31cf2bb1bc3a501a14ea9647f2bc7ad25fb2fce4 Mon Sep 17 00:00:00 2001 From: jgravelle-google Date: Mon, 13 Mar 2017 09:11:40 -0700 Subject: [PATCH] Update musl to 1.1.15 (#4813) * Revert all emscripten musl changes * Update musl to 1.1.5 * Reapply emscripten patches * Fix up libs to partially compile * Revert emscripten musl include folder * Update musl include folder to 1.1.5 * Reapply emscripten libc include changes * Get compiling again! * Restore alltypes.h to have emscripten-specific changes alltypes.h is autogenerated, and we've since overridden the types Longer-term, we should figure out a way to either autogenerate the types to match what emscripten expects, or change emscripten's expectation to support musl's assumptions. Probably worth including with merging the asm&wasm ABIs. * Update expected langinfo test output for fixes in upstream musl * Canonicalize nans in hyperbolic test Nans are now printed out with their sign if negative. Asm and wasm treat these differently, so canonicalize how they print. * Tweak how musl forwards syscalls to emscripten Before: pass all syscall args as varargs, args are int32 After: cast all syscall args to int32, pass as varargs This fixes and prevents aliasing issues, and is more consistent with other architectures * Change __syscall to syscall in isatty to set errno POSIX specifies that isatty sets errno in the case that it fails. __syscall doesn't set errno, and syscall does. * Update struct_info again * Always allocate pthread_self, even in the stub * sys_open should call __syscall_ret * Fix up pthread js for optimized code (remove __asm: true) * Canonicalize more nans in testsuite * Re-set expected langinfo output * Update align_moar expected addresses * Disable assert in wasm_backend llseek syscall * Update now-passing wasm_backend tests * Update other.test_locale to non-stub setlocale * Fix compiling with -s USE_PTHREADS=1 * Initialize __pthread_self() when using pthread_stub * Canonicalize nans for test_zerodiv * Update count of globals in test_dlfcn_self * Rework how we initialize pthread_self for non-threaded applications * Prefer 'EMSCRIPTEN_START_FUNCS' in test_memorygrowth, because 'var TOTAL_MEMORY' can move around * Now that CURRENT_LOCALE isn't reading off NULL, test_langinfo should expect ASCII * Re-disable test_demangle_stacks - was spuriously passing earlier * Explicitly pass 0 as the high bits for SYS__llseek * Enable v8 for test_readdir now that it supports printErr * Only use __syscall_emscripten if __EMSCRIPTEN__ is defined * Move O_LARGEFILE as default back to libc * libc #if to #ifdef * Rename pthread import funcs to not rely on alias * Consistently reference pthread_setcancelstate by alias in libc * Stub out fcntl64 for NO_FILESYSTEM case * Update emscripten-specific pthread struct fields * Consistently reference pthread_testcancel by alias in libc * Stub out SYS_rt_sigqueueinfo syscall * Stub out SYS_sendmmsg syscall * Stub out SYS_recvmmsg syscall * Revert "Consistently reference pthread_testcancel by alias in libc" This reverts commit 43563a5b141a47d4a7aa7e48c059ed0e98597fbb. * Revert "Consistently reference pthread_setcancelstate by alias in libc" This reverts commit 2ca2eded8a0d50bb3847cda0a99c900532f6937b. * Correctly fix unresolved symbol: __pthread_setcancelstate * Update library_pthread.c pthread_testcancel to match musl's expectations * test_strftime.c -> test_strftime.cpp * library_pthread_stub pthread_exit should call exit, not nothing * TEMP: init pthread_self->locale with pthreads enabled * Initialize pthread global data from libc in JS * Move _b_lock and _b_waiters back to not emscripten-only * Remove untrue __asm annotation from threaded pthread_self, make stub pthread_self non-asm * Remove old unneeded pthread init exported functions * Move pthread_self in stub case to libc C code * Move emscripten_pthread initialization to its own file, out from locale_map.c * Statically allocate the pthread struct and not just a pointer in the stub case * Remove commented-out test args * Remove misleading __asm annotation for _register_pthread_ptr * Do module-side pthread initialization in-module * Don't cast away volatile when calling emscripten_futex_wake in __wake * Expose libc struct to emscripten, use that for non-main pthread initialization * Re-add pthread_impl.h import to library_pthread.c * Update align_moar alignment post-rebase * Update emscripten header include in libc.c * Remove obsolete locale preallocating code in newlocale We previously statically allocated a single locale in the event that we needed to dynamically allocate one during startup. musl changed their implementation to statically allocate C_LOCALE and UTF8_LOCALE, so we already get that behavior. In addition this was causing invalid locales to get allocated instead of returning NULL, because the preceding logic changed. That was caught by other.test_locale_wrong * Update test_llvm_lto * Bump version to 1.37.5 --- emscripten-version.txt | 2 +- src/library.js | 8 +- src/library_pthread.js | 6 +- src/library_pthread_stub.js | 11 +- src/library_syscall.js | 32 + src/struct_info.compiled.json | 2 +- src/struct_info.json | 18 +- system/include/emscripten/threading.h | 6 +- system/include/libc/aio.h | 2 +- system/include/libc/alltypes.h.in | 3 + system/include/libc/arpa/nameser.h | 58 +- system/include/libc/assert.h | 6 +- system/include/libc/complex.h | 20 +- system/include/libc/ctype.h | 20 +- system/include/libc/dirent.h | 3 +- system/include/libc/elf.h | 272 ++- system/include/libc/errno.h | 3 - system/include/libc/fcntl.h | 19 +- system/include/libc/features.h | 6 +- system/include/libc/float.h | 18 + system/include/libc/fmtmsg.h | 47 + system/include/libc/ftw.h | 3 +- system/include/libc/getopt.h | 3 +- system/include/libc/glob.h | 1 + system/include/libc/grp.h | 3 +- system/include/libc/libintl.h | 20 +- system/include/libc/malloc.h | 25 + system/include/libc/mntent.h | 3 +- system/include/libc/net/if.h | 3 +- system/include/libc/netdb.h | 20 +- system/include/libc/netinet/ether.h | 8 + system/include/libc/netinet/if_ether.h | 7 +- system/include/libc/netinet/in.h | 57 +- system/include/libc/netinet/ip.h | 12 + system/include/libc/netinet/tcp.h | 32 +- system/include/libc/netpacket/packet.h | 17 + system/include/libc/poll.h | 3 +- system/include/libc/pthread.h | 8 +- system/include/libc/pwd.h | 3 +- system/include/libc/sched.h | 3 + system/include/libc/search.h | 12 + system/include/libc/semaphore.h | 2 +- system/include/libc/setjmp.h | 1 - system/include/libc/signal.h | 89 +- system/include/libc/stdalign.h | 5 + system/include/libc/stdc-predef.h | 10 + system/include/libc/stddef.h | 3 + system/include/libc/stdint.h | 4 +- system/include/libc/stdlib.h | 8 +- system/include/libc/stdnoreturn.h | 2 + system/include/libc/strings.h | 4 + system/include/libc/sys/acct.h | 6 +- system/include/libc/sys/auxv.h | 16 + system/include/libc/sys/epoll.h | 1 + system/include/libc/sys/mman.h | 63 + system/include/libc/sys/mount.h | 3 +- system/include/libc/sys/prctl.h | 38 + system/include/libc/sys/procfs.h | 3 +- system/include/libc/sys/ptrace.h | 4 +- system/include/libc/sys/quota.h | 6 +- system/include/libc/sys/resource.h | 12 +- system/include/libc/sys/select.h | 3 +- system/include/libc/sys/socket.h | 66 +- system/include/libc/sys/stat.h | 3 +- system/include/libc/sys/time.h | 3 +- system/include/libc/sys/timerfd.h | 2 + system/include/libc/sys/times.h | 3 +- system/include/libc/sys/types.h | 17 +- system/include/libc/sys/un.h | 3 +- system/include/libc/sys/utsname.h | 3 +- system/include/libc/threads.h | 87 + system/include/libc/time.h | 12 +- system/include/libc/uchar.h | 27 + system/include/libc/unistd.h | 67 +- system/include/libc/utime.h | 3 +- system/include/libc/utmp.h | 4 +- system/include/libc/utmpx.h | 4 +- system/include/libc/wchar.h | 11 +- system/include/libc/wctype.h | 4 +- system/include/libc/wordexp.h | 3 +- system/lib/libc/musl/COPYRIGHT | 71 +- system/lib/libc/musl/INSTALL | 51 +- system/lib/libc/musl/Makefile | 220 +- system/lib/libc/musl/README | 2 +- system/lib/libc/musl/VERSION | 2 +- system/lib/libc/musl/WHATSNEW | 487 ++++- .../emscripten/{atomic.h => atomic_arch.h} | 30 + .../libc/musl/arch/emscripten/bits/alltypes.h | 31 +- .../libc/musl/arch/emscripten/bits/fcntl.h | 1 + .../libc/musl/arch/emscripten/bits/syscall.h | 2 + .../libc/musl/arch/emscripten/syscall_arch.h | 5 + system/lib/libc/musl/configure | 341 ++- system/lib/libc/musl/ldso/dlstart.c | 148 ++ system/lib/libc/musl/ldso/dynlink.c | 1934 +++++++++++++++++ system/lib/libc/musl/src/aio/aio.c | 379 ++++ system/lib/libc/musl/src/aio/aio_suspend.c | 86 +- system/lib/libc/musl/src/aio/lio_listio.c | 3 +- system/lib/libc/musl/src/complex/ctanh.c | 4 +- system/lib/libc/musl/src/complex/ctanhf.c | 2 +- system/lib/libc/musl/src/conf/legacy.c | 22 + system/lib/libc/musl/src/conf/sysconf.c | 157 +- system/lib/libc/musl/src/crypt/crypt_sha256.c | 2 +- system/lib/libc/musl/src/crypt/crypt_sha512.c | 2 +- .../musl/src/ctype/__ctype_get_mb_cur_max.c | 5 +- system/lib/libc/musl/src/ctype/isalnum.c | 8 + system/lib/libc/musl/src/ctype/isalpha.c | 8 + system/lib/libc/musl/src/ctype/isascii.c | 1 + system/lib/libc/musl/src/ctype/isblank.c | 8 + system/lib/libc/musl/src/ctype/iscntrl.c | 8 + system/lib/libc/musl/src/ctype/isdigit.c | 8 + system/lib/libc/musl/src/ctype/isgraph.c | 11 + system/lib/libc/musl/src/ctype/islower.c | 8 + system/lib/libc/musl/src/ctype/isprint.c | 11 + system/lib/libc/musl/src/ctype/ispunct.c | 8 + system/lib/libc/musl/src/ctype/isspace.c | 9 + system/lib/libc/musl/src/ctype/isupper.c | 8 + system/lib/libc/musl/src/ctype/iswalnum.c | 9 +- system/lib/libc/musl/src/ctype/iswalpha.c | 8 + system/lib/libc/musl/src/ctype/iswblank.c | 9 +- system/lib/libc/musl/src/ctype/iswcntrl.c | 9 +- system/lib/libc/musl/src/ctype/iswctype.c | 15 +- system/lib/libc/musl/src/ctype/iswdigit.c | 9 +- system/lib/libc/musl/src/ctype/iswgraph.c | 8 + system/lib/libc/musl/src/ctype/iswlower.c | 10 +- system/lib/libc/musl/src/ctype/iswprint.c | 8 + system/lib/libc/musl/src/ctype/iswpunct.c | 8 + system/lib/libc/musl/src/ctype/iswspace.c | 9 +- system/lib/libc/musl/src/ctype/iswupper.c | 8 + system/lib/libc/musl/src/ctype/iswxdigit.c | 9 +- system/lib/libc/musl/src/ctype/isxdigit.c | 8 + system/lib/libc/musl/src/ctype/tolower.c | 8 + system/lib/libc/musl/src/ctype/toupper.c | 8 + system/lib/libc/musl/src/ctype/towctrans.c | 17 +- system/lib/libc/musl/src/ctype/wctrans.c | 14 + system/lib/libc/musl/src/dirent/__dirent.h | 2 +- system/lib/libc/musl/src/dirent/versionsort.c | 4 + system/lib/libc/musl/src/env/__init_tls.c | 133 +- .../lib/libc/musl/src/env/__libc_start_main.c | 57 +- system/lib/libc/musl/src/env/__reset_tls.c | 22 +- .../lib/libc/musl/src/env/__stack_chk_fail.c | 16 +- system/lib/libc/musl/src/env/putenv.c | 1 + .../libc/musl/src/errno/__errno_location.c | 4 +- system/lib/libc/musl/src/errno/strerror.c | 13 +- system/lib/libc/musl/src/exit/abort.c | 6 +- system/lib/libc/musl/src/exit/at_quick_exit.c | 2 +- system/lib/libc/musl/src/exit/atexit.c | 23 +- system/lib/libc/musl/src/exit/exit.c | 30 +- system/lib/libc/musl/src/exit/quick_exit.c | 4 - system/lib/libc/musl/src/fcntl/fcntl.c | 1 - system/lib/libc/musl/src/fcntl/open.c | 20 +- .../lib/libc/musl/src/fcntl/posix_fadvise.c | 9 +- system/lib/libc/musl/src/fenv/__flt_rounds.c | 19 + system/lib/libc/musl/src/internal/atomic.h | 293 +++ system/lib/libc/musl/src/internal/dynlink.h | 98 + system/lib/libc/musl/src/internal/fdpic_crt.h | 28 + system/lib/libc/musl/src/internal/floatscan.c | 10 +- system/lib/libc/musl/src/internal/futex.h | 2 + .../lib/libc/musl/src/internal/ksigaction.h | 2 + system/lib/libc/musl/src/internal/libc.c | 19 +- system/lib/libc/musl/src/internal/libc.h | 42 +- system/lib/libc/musl/src/internal/libm.h | 26 + .../lib/libc/musl/src/internal/locale_impl.h | 39 +- .../lib/libc/musl/src/internal/pthread_impl.h | 99 +- .../lib/libc/musl/src/internal/stdio_impl.h | 14 +- system/lib/libc/musl/src/internal/syscall.h | 108 +- system/lib/libc/musl/src/internal/vdso.c | 91 + system/lib/libc/musl/src/internal/version.c | 5 +- system/lib/libc/musl/src/internal/version.h | 1 + system/lib/libc/musl/src/internal/vis.h | 27 + system/lib/libc/musl/src/ldso/__dlsym.c | 13 + .../lib/libc/musl/src/ldso/dl_iterate_phdr.c | 7 +- system/lib/libc/musl/src/ldso/dladdr.c | 9 +- system/lib/libc/musl/src/ldso/dlclose.c | 9 + system/lib/libc/musl/src/ldso/dlerror.c | 64 + system/lib/libc/musl/src/ldso/dlinfo.c | 14 +- system/lib/libc/musl/src/ldso/dlopen.c | 13 + system/lib/libc/musl/src/ldso/tlsdesc.c | 12 + system/lib/libc/musl/src/legacy/futimes.c | 1 + system/lib/libc/musl/src/legacy/getloadavg.c | 18 +- system/lib/libc/musl/src/legacy/utmpx.c | 9 + system/lib/libc/musl/src/linux/epoll.c | 17 +- system/lib/libc/musl/src/linux/eventfd.c | 7 +- system/lib/libc/musl/src/linux/inotify.c | 9 +- system/lib/libc/musl/src/linux/signalfd.c | 2 + system/lib/libc/musl/src/linux/syncfs.c | 4 +- system/lib/libc/musl/src/linux/sysinfo.c | 5 +- system/lib/libc/musl/src/linux/utimes.c | 5 +- system/lib/libc/musl/src/locale/__lctrans.c | 20 + system/lib/libc/musl/src/locale/__mo_lookup.c | 42 + .../musl/src/locale/bind_textdomain_codeset.c | 11 + system/lib/libc/musl/src/locale/c_locale.c | 15 + system/lib/libc/musl/src/locale/codepages.h | 303 +-- system/lib/libc/musl/src/locale/dcngettext.c | 249 +++ system/lib/libc/musl/src/locale/duplocale.c | 11 +- system/lib/libc/musl/src/locale/freelocale.c | 4 +- system/lib/libc/musl/src/locale/iconv.c | 15 +- system/lib/libc/musl/src/locale/intl.c | 68 - system/lib/libc/musl/src/locale/langinfo.c | 16 +- system/lib/libc/musl/src/locale/legacychars.h | 80 +- system/lib/libc/musl/src/locale/locale_map.c | 116 + system/lib/libc/musl/src/locale/localeconv.c | 29 +- system/lib/libc/musl/src/locale/newlocale.c | 53 +- system/lib/libc/musl/src/locale/pleval.c | 157 ++ system/lib/libc/musl/src/locale/setlocale.c | 71 +- system/lib/libc/musl/src/locale/strcoll.c | 3 +- system/lib/libc/musl/src/locale/strfmon.c | 3 +- system/lib/libc/musl/src/locale/strxfrm.c | 3 +- system/lib/libc/musl/src/locale/textdomain.c | 44 + system/lib/libc/musl/src/locale/uselocale.c | 13 +- system/lib/libc/musl/src/locale/wcscoll.c | 3 +- system/lib/libc/musl/src/locale/wcsxfrm.c | 3 +- system/lib/libc/musl/src/math/__fpclassifyl.c | 10 +- system/lib/libc/musl/src/math/__polevll.c | 3 + system/lib/libc/musl/src/math/__rem_pio2.c | 14 +- system/lib/libc/musl/src/math/__rem_pio2f.c | 13 +- system/lib/libc/musl/src/math/__rem_pio2l.c | 6 +- system/lib/libc/musl/src/math/__signbitl.c | 5 + system/lib/libc/musl/src/math/acoshl.c | 6 + system/lib/libc/musl/src/math/asinhl.c | 6 + system/lib/libc/musl/src/math/atanhl.c | 2 +- system/lib/libc/musl/src/math/ceil.c | 11 +- system/lib/libc/musl/src/math/ceill.c | 12 +- system/lib/libc/musl/src/math/coshl.c | 6 + system/lib/libc/musl/src/math/erfl.c | 10 + system/lib/libc/musl/src/math/exp10.c | 5 +- system/lib/libc/musl/src/math/exp10f.c | 5 +- system/lib/libc/musl/src/math/exp10l.c | 13 +- system/lib/libc/musl/src/math/exp2f.c | 2 + system/lib/libc/musl/src/math/exp2l.c | 367 +++- system/lib/libc/musl/src/math/expf.c | 2 + system/lib/libc/musl/src/math/expl.c | 6 + system/lib/libc/musl/src/math/expm1l.c | 6 + system/lib/libc/musl/src/math/floor.c | 11 +- system/lib/libc/musl/src/math/floorl.c | 12 +- system/lib/libc/musl/src/math/fmodl.c | 2 +- system/lib/libc/musl/src/math/hypot.c | 4 +- system/lib/libc/musl/src/math/lgammal.c | 10 +- system/lib/libc/musl/src/math/log10l.c | 6 + system/lib/libc/musl/src/math/log1pl.c | 6 + system/lib/libc/musl/src/math/log2l.c | 6 + system/lib/libc/musl/src/math/logl.c | 6 + system/lib/libc/musl/src/math/modfl.c | 10 +- system/lib/libc/musl/src/math/pow.c | 2 +- system/lib/libc/musl/src/math/powf.c | 2 +- system/lib/libc/musl/src/math/powl.c | 9 +- system/lib/libc/musl/src/math/rint.c | 12 +- system/lib/libc/musl/src/math/rintf.c | 14 +- system/lib/libc/musl/src/math/rintl.c | 12 +- system/lib/libc/musl/src/math/round.c | 11 +- system/lib/libc/musl/src/math/roundf.c | 13 +- system/lib/libc/musl/src/math/roundl.c | 12 +- system/lib/libc/musl/src/math/sinhl.c | 6 + system/lib/libc/musl/src/math/tanhl.c | 6 + system/lib/libc/musl/src/math/tgammal.c | 6 + system/lib/libc/musl/src/math/truncl.c | 10 +- system/lib/libc/musl/src/misc/a64l.c | 9 +- .../libc/musl/src/misc/emscripten_pthread.c | 15 + system/lib/libc/musl/src/misc/ffsl.c | 7 + system/lib/libc/musl/src/misc/ffsll.c | 7 + system/lib/libc/musl/src/misc/fmtmsg.c | 90 + system/lib/libc/musl/src/misc/forkpty.c | 71 +- system/lib/libc/musl/src/misc/getauxval.c | 13 + system/lib/libc/musl/src/misc/getopt.c | 65 +- system/lib/libc/musl/src/misc/getopt_long.c | 100 +- system/lib/libc/musl/src/misc/getsubopt.c | 2 +- system/lib/libc/musl/src/misc/issetugid.c | 7 + system/lib/libc/musl/src/misc/login_tty.c | 14 + system/lib/libc/musl/src/misc/mntent.c | 2 +- system/lib/libc/musl/src/misc/openpty.c | 35 +- system/lib/libc/musl/src/misc/realpath.c | 2 +- system/lib/libc/musl/src/misc/setrlimit.c | 6 +- system/lib/libc/musl/src/misc/syslog.c | 49 +- system/lib/libc/musl/src/mman/mmap.c | 21 +- system/lib/libc/musl/src/mman/mprotect.c | 4 +- system/lib/libc/musl/src/mman/mremap.c | 24 +- system/lib/libc/musl/src/mman/msync.c | 2 +- system/lib/libc/musl/src/mman/munmap.c | 13 +- system/lib/libc/musl/src/multibyte/btowc.c | 5 +- system/lib/libc/musl/src/multibyte/c16rtomb.c | 35 + system/lib/libc/musl/src/multibyte/c32rtomb.c | 7 + system/lib/libc/musl/src/multibyte/internal.c | 10 - system/lib/libc/musl/src/multibyte/internal.h | 21 +- system/lib/libc/musl/src/multibyte/mblen.c | 6 - system/lib/libc/musl/src/multibyte/mbrlen.c | 6 - system/lib/libc/musl/src/multibyte/mbrtoc16.c | 30 + system/lib/libc/musl/src/multibyte/mbrtoc32.c | 13 + system/lib/libc/musl/src/multibyte/mbrtowc.c | 8 +- system/lib/libc/musl/src/multibyte/mbsinit.c | 6 - .../lib/libc/musl/src/multibyte/mbsnrtowcs.c | 6 - .../lib/libc/musl/src/multibyte/mbsrtowcs.c | 25 +- system/lib/libc/musl/src/multibyte/mbtowc.c | 8 +- system/lib/libc/musl/src/multibyte/wcrtomb.c | 15 +- .../lib/libc/musl/src/multibyte/wcsnrtombs.c | 8 +- .../lib/libc/musl/src/multibyte/wcsrtombs.c | 6 - system/lib/libc/musl/src/multibyte/wctob.c | 5 +- system/lib/libc/musl/src/multibyte/wctomb.c | 6 - system/lib/libc/musl/src/network/dn_comp.c | 103 +- system/lib/libc/musl/src/network/dns_parse.c | 32 + .../lib/libc/musl/src/network/gai_strerror.c | 4 +- .../lib/libc/musl/src/network/getaddrinfo.c | 307 +-- .../libc/musl/src/network/gethostbyaddr_r.c | 1 + .../libc/musl/src/network/gethostbyname2_r.c | 68 +- system/lib/libc/musl/src/network/getifaddrs.c | 327 +-- .../lib/libc/musl/src/network/getnameinfo.c | 173 +- .../lib/libc/musl/src/network/getservbyname.c | 2 +- .../libc/musl/src/network/getservbyname_r.c | 36 +- system/lib/libc/musl/src/network/hstrerror.c | 4 +- .../lib/libc/musl/src/network/if_nameindex.c | 135 +- .../libc/musl/src/network/if_nametoindex.c | 2 +- system/lib/libc/musl/src/network/inet_addr.c | 9 +- system/lib/libc/musl/src/network/inet_aton.c | 41 + .../lib/libc/musl/src/network/inet_legacy.c | 9 - system/lib/libc/musl/src/network/lookup.h | 39 + .../libc/musl/src/network/lookup_ipliteral.c | 57 + .../lib/libc/musl/src/network/lookup_name.c | 398 ++++ .../lib/libc/musl/src/network/lookup_serv.c | 113 + system/lib/libc/musl/src/network/netlink.c | 52 + system/lib/libc/musl/src/network/netlink.h | 94 + system/lib/libc/musl/src/network/ns_parse.c | 171 ++ system/lib/libc/musl/src/network/proto.c | 57 +- system/lib/libc/musl/src/network/recvmmsg.c | 15 + system/lib/libc/musl/src/network/res_init.c | 2 + .../lib/libc/musl/src/network/res_mkquery.c | 44 + system/lib/libc/musl/src/network/res_msend.c | 184 ++ system/lib/libc/musl/src/network/res_query.c | 28 +- .../libc/musl/src/network/res_querydomain.c | 14 + system/lib/libc/musl/src/network/res_send.c | 12 + system/lib/libc/musl/src/network/resolvconf.c | 93 + system/lib/libc/musl/src/network/sendmmsg.c | 30 + system/lib/libc/musl/src/network/socket.c | 4 +- system/lib/libc/musl/src/network/socketpair.c | 20 +- system/lib/libc/musl/src/passwd/fgetgrent.c | 4 +- system/lib/libc/musl/src/passwd/fgetpwent.c | 4 +- system/lib/libc/musl/src/passwd/getgr_a.c | 169 ++ system/lib/libc/musl/src/passwd/getgr_r.c | 42 +- system/lib/libc/musl/src/passwd/getgrent.c | 32 +- system/lib/libc/musl/src/passwd/getgrent_a.c | 12 +- .../lib/libc/musl/src/passwd/getgrouplist.c | 80 + system/lib/libc/musl/src/passwd/getpw_a.c | 142 ++ system/lib/libc/musl/src/passwd/getpw_r.c | 36 +- system/lib/libc/musl/src/passwd/getpwent.c | 32 +- system/lib/libc/musl/src/passwd/getpwent_a.c | 8 +- system/lib/libc/musl/src/passwd/nscd.h | 44 + system/lib/libc/musl/src/passwd/nscd_query.c | 107 + system/lib/libc/musl/src/passwd/pwf.h | 6 +- system/lib/libc/musl/src/prng/random.c | 2 +- system/lib/libc/musl/src/process/execvp.c | 8 +- system/lib/libc/musl/src/process/fork.c | 13 +- .../lib/libc/musl/src/process/posix_spawn.c | 32 +- system/lib/libc/musl/src/process/vfork.c | 5 + system/lib/libc/musl/src/regex/fnmatch.c | 39 +- system/lib/libc/musl/src/regex/regcomp.c | 1741 ++++++--------- system/lib/libc/musl/src/regex/regerror.c | 2 + system/lib/libc/musl/src/sched/sched_getcpu.c | 44 + system/lib/libc/musl/src/search/hsearch.c | 122 +- system/lib/libc/musl/src/search/tsearch_avl.c | 77 +- system/lib/libc/musl/src/select/poll.c | 8 + system/lib/libc/musl/src/select/pselect.c | 3 +- system/lib/libc/musl/src/select/select.c | 18 + system/lib/libc/musl/src/signal/raise.c | 5 +- system/lib/libc/musl/src/signal/sigaction.c | 27 +- system/lib/libc/musl/src/signal/siglongjmp.c | 1 - system/lib/libc/musl/src/signal/signal.c | 1 + system/lib/libc/musl/src/signal/sigsetjmp.c | 14 - .../lib/libc/musl/src/signal/sigsetjmp_tail.c | 11 + system/lib/libc/musl/src/stat/__fxstat.c | 9 - system/lib/libc/musl/src/stat/__fxstatat.c | 9 - system/lib/libc/musl/src/stat/__lxstat.c | 9 - system/lib/libc/musl/src/stat/__xstat.c | 28 + system/lib/libc/musl/src/stat/chmod.c | 5 + system/lib/libc/musl/src/stat/fchmod.c | 4 + system/lib/libc/musl/src/stat/fstat.c | 4 + system/lib/libc/musl/src/stat/futimesat.c | 21 +- system/lib/libc/musl/src/stat/lstat.c | 5 + system/lib/libc/musl/src/stat/mkdir.c | 5 + system/lib/libc/musl/src/stat/mknod.c | 5 + system/lib/libc/musl/src/stat/stat.c | 5 + system/lib/libc/musl/src/stat/utimensat.c | 32 +- system/lib/libc/musl/src/stdio/__fdopen.c | 13 +- .../lib/libc/musl/src/stdio/__fopen_rb_ca.c | 3 +- .../lib/libc/musl/src/stdio/__stdio_close.c | 9 +- system/lib/libc/musl/src/stdio/__stdio_exit.c | 3 +- system/lib/libc/musl/src/stdio/__stdio_read.c | 16 +- .../lib/libc/musl/src/stdio/__stdio_write.c | 18 +- .../lib/libc/musl/src/stdio/__stdout_write.c | 5 +- system/lib/libc/musl/src/stdio/__toread.c | 10 +- system/lib/libc/musl/src/stdio/__uflow.c | 6 +- system/lib/libc/musl/src/stdio/fclose.c | 17 +- system/lib/libc/musl/src/stdio/fflush.c | 5 +- system/lib/libc/musl/src/stdio/fgetwc.c | 15 +- system/lib/libc/musl/src/stdio/fmemopen.c | 8 +- system/lib/libc/musl/src/stdio/fopen.c | 4 +- system/lib/libc/musl/src/stdio/fputs.c | 3 +- system/lib/libc/musl/src/stdio/fputwc.c | 7 +- system/lib/libc/musl/src/stdio/fputws.c | 7 +- system/lib/libc/musl/src/stdio/fread.c | 1 + system/lib/libc/musl/src/stdio/ftrylockfile.c | 23 +- system/lib/libc/musl/src/stdio/funlockfile.c | 10 +- system/lib/libc/musl/src/stdio/fwide.c | 11 +- system/lib/libc/musl/src/stdio/fwrite.c | 5 +- system/lib/libc/musl/src/stdio/getdelim.c | 20 +- system/lib/libc/musl/src/stdio/ofl.c | 16 + system/lib/libc/musl/src/stdio/ofl_add.c | 11 + .../lib/libc/musl/src/stdio/open_memstream.c | 19 +- .../lib/libc/musl/src/stdio/open_wmemstream.c | 19 +- system/lib/libc/musl/src/stdio/remove.c | 14 +- system/lib/libc/musl/src/stdio/rename.c | 5 + system/lib/libc/musl/src/stdio/tempnam.c | 61 +- system/lib/libc/musl/src/stdio/tmpfile.c | 17 +- system/lib/libc/musl/src/stdio/tmpnam.c | 46 +- system/lib/libc/musl/src/stdio/ungetc.c | 3 +- system/lib/libc/musl/src/stdio/ungetwc.c | 21 +- system/lib/libc/musl/src/stdio/vasprintf.c | 15 +- system/lib/libc/musl/src/stdio/vfprintf.c | 6 +- system/lib/libc/musl/src/stdio/vfwprintf.c | 13 +- system/lib/libc/musl/src/stdio/vfwscanf.c | 2 +- system/lib/libc/musl/src/string/memmem.c | 1 + system/lib/libc/musl/src/string/strcasecmp.c | 8 + system/lib/libc/musl/src/string/strncasecmp.c | 8 + system/lib/libc/musl/src/string/strsignal.c | 5 +- system/lib/libc/musl/src/string/strverscmp.c | 57 +- system/lib/libc/musl/src/temp/mkostemps.c | 1 + .../lib/libc/musl/src/termios/cfgetospeed.c | 1 + .../lib/libc/musl/src/termios/cfsetospeed.c | 1 + .../lib/libc/musl/src/thread/__syscall_cp.c | 21 + system/lib/libc/musl/src/thread/__timedwait.c | 35 +- .../lib/libc/musl/src/thread/__tls_get_addr.c | 16 + system/lib/libc/musl/src/thread/__unmapself.c | 29 + system/lib/libc/musl/src/thread/__wait.c | 9 +- system/lib/libc/musl/src/thread/call_once.c | 8 + .../lib/libc/musl/src/thread/cnd_broadcast.c | 10 + system/lib/libc/musl/src/thread/cnd_destroy.c | 6 + system/lib/libc/musl/src/thread/cnd_init.c | 7 + system/lib/libc/musl/src/thread/cnd_signal.c | 10 + .../lib/libc/musl/src/thread/cnd_timedwait.c | 15 + system/lib/libc/musl/src/thread/cnd_wait.c | 9 + system/lib/libc/musl/src/thread/mtx_destroy.c | 5 + system/lib/libc/musl/src/thread/mtx_init.c | 10 + system/lib/libc/musl/src/thread/mtx_lock.c | 12 + .../lib/libc/musl/src/thread/mtx_timedlock.c | 14 + system/lib/libc/musl/src/thread/mtx_trylock.c | 17 + system/lib/libc/musl/src/thread/mtx_unlock.c | 11 + .../lib/libc/musl/src/thread/pthread_atfork.c | 2 +- .../libc/musl/src/thread/pthread_attr_get.c | 2 +- .../musl/src/thread/pthread_barrier_destroy.c | 5 +- .../musl/src/thread/pthread_barrier_wait.c | 20 +- .../lib/libc/musl/src/thread/pthread_cancel.c | 97 + .../musl/src/thread/pthread_cleanup_push.c | 20 + .../musl/src/thread/pthread_cond_broadcast.c | 50 +- .../musl/src/thread/pthread_cond_destroy.c | 15 +- .../libc/musl/src/thread/pthread_cond_init.c | 2 +- .../musl/src/thread/pthread_cond_signal.c | 5 +- .../musl/src/thread/pthread_cond_timedwait.c | 241 +- .../lib/libc/musl/src/thread/pthread_create.c | 97 +- .../lib/libc/musl/src/thread/pthread_detach.c | 10 +- .../lib/libc/musl/src/thread/pthread_equal.c | 7 +- .../musl/src/thread/pthread_getspecific.c | 6 +- .../lib/libc/musl/src/thread/pthread_join.c | 35 +- .../libc/musl/src/thread/pthread_key_create.c | 19 +- .../lib/libc/musl/src/thread/pthread_kill.c | 2 +- .../src/thread/pthread_mutex_consistent.c | 6 +- .../libc/musl/src/thread/pthread_mutex_init.c | 2 +- .../libc/musl/src/thread/pthread_mutex_lock.c | 11 +- .../musl/src/thread/pthread_mutex_timedlock.c | 24 +- .../musl/src/thread/pthread_mutex_trylock.c | 68 +- .../musl/src/thread/pthread_mutex_unlock.c | 40 +- .../src/thread/pthread_mutexattr_setpshared.c | 4 +- .../lib/libc/musl/src/thread/pthread_once.c | 45 +- .../musl/src/thread/pthread_rwlock_init.c | 3 +- .../src/thread/pthread_rwlock_timedrdlock.c | 9 +- .../src/thread/pthread_rwlock_timedwrlock.c | 9 +- .../musl/src/thread/pthread_rwlock_unlock.c | 4 +- .../lib/libc/musl/src/thread/pthread_self.c | 44 +- .../musl/src/thread/pthread_setcancelstate.c | 17 +- .../musl/src/thread/pthread_setcanceltype.c | 2 +- .../libc/musl/src/thread/pthread_spin_lock.c | 3 +- .../musl/src/thread/pthread_spin_trylock.c | 3 +- .../libc/musl/src/thread/pthread_testcancel.c | 11 +- system/lib/libc/musl/src/thread/sem_init.c | 1 + system/lib/libc/musl/src/thread/sem_open.c | 3 +- system/lib/libc/musl/src/thread/sem_post.c | 4 +- .../lib/libc/musl/src/thread/sem_timedwait.c | 16 +- system/lib/libc/musl/src/thread/synccall.c | 184 +- system/lib/libc/musl/src/thread/thrd_create.c | 14 + system/lib/libc/musl/src/thread/thrd_exit.c | 9 + system/lib/libc/musl/src/thread/thrd_join.c | 12 + system/lib/libc/musl/src/thread/thrd_sleep.c | 13 + system/lib/libc/musl/src/thread/thrd_yield.c | 7 + system/lib/libc/musl/src/thread/tss_create.c | 11 + system/lib/libc/musl/src/thread/tss_delete.c | 8 + system/lib/libc/musl/src/thread/tss_set.c | 13 + system/lib/libc/musl/src/thread/vmlock.c | 25 +- system/lib/libc/musl/src/time/__map_file.c | 8 +- system/lib/libc/musl/src/time/__secs_to_tm.c | 6 +- system/lib/libc/musl/src/time/__tz.c | 39 +- system/lib/libc/musl/src/time/clock_gettime.c | 55 +- system/lib/libc/musl/src/time/localtime_r.c | 2 +- system/lib/libc/musl/src/time/mktime.c | 6 +- system/lib/libc/musl/src/time/strftime.c | 27 +- system/lib/libc/musl/src/time/strptime.c | 14 +- system/lib/libc/musl/src/time/timespec_get.c | 12 + system/lib/libc/musl/src/time/utime.c | 15 +- system/lib/libc/musl/src/time/wcsftime.c | 3 +- system/lib/libc/musl/src/unistd/access.c | 5 + system/lib/libc/musl/src/unistd/chown.c | 5 + system/lib/libc/musl/src/unistd/close.c | 10 +- system/lib/libc/musl/src/unistd/ctermid.c | 16 +- system/lib/libc/musl/src/unistd/dup2.c | 10 + system/lib/libc/musl/src/unistd/dup3.c | 4 + system/lib/libc/musl/src/unistd/fchown.c | 5 + system/lib/libc/musl/src/unistd/fdatasync.c | 2 +- system/lib/libc/musl/src/unistd/fsync.c | 2 +- system/lib/libc/musl/src/unistd/getpgrp.c | 2 +- system/lib/libc/musl/src/unistd/isatty.c | 7 +- system/lib/libc/musl/src/unistd/lchown.c | 5 + system/lib/libc/musl/src/unistd/link.c | 5 + system/lib/libc/musl/src/unistd/lseek.c | 8 +- system/lib/libc/musl/src/unistd/pause.c | 5 + system/lib/libc/musl/src/unistd/pipe.c | 4 + system/lib/libc/musl/src/unistd/readlink.c | 5 + system/lib/libc/musl/src/unistd/rmdir.c | 5 + system/lib/libc/musl/src/unistd/setxid.c | 49 +- system/lib/libc/musl/src/unistd/symlink.c | 5 + system/lib/libc/musl/src/unistd/unlink.c | 5 + system/lib/pthread/library_pthread.c | 15 +- tests/core/test_simd_float32x4.c | 18 +- tests/core/test_simd_float64x2.c | 14 +- .../{test_strftime.c => test_strftime.cpp} | 7 + .../core/{test_wprintf.c => test_wprintf.cpp} | 0 tests/core/test_zerodiv.c | 18 +- tests/hyperbolic/src.c | 15 +- tests/langinfo/output.txt | 6 +- tests/pthread/test_pthread_locale.c | 54 + tests/test_browser.py | 9 + tests/test_core.py | 25 +- tests/test_other.py | 22 +- tools/shared.py | 2 +- 537 files changed, 14060 insertions(+), 4250 deletions(-) create mode 100644 system/include/libc/fmtmsg.h create mode 100644 system/include/libc/stdc-predef.h create mode 100644 system/include/libc/sys/auxv.h create mode 100644 system/include/libc/threads.h create mode 100644 system/include/libc/uchar.h rename system/lib/libc/musl/arch/emscripten/{atomic.h => atomic_arch.h} (81%) create mode 100644 system/lib/libc/musl/ldso/dlstart.c create mode 100644 system/lib/libc/musl/ldso/dynlink.c create mode 100644 system/lib/libc/musl/src/aio/aio.c create mode 100644 system/lib/libc/musl/src/conf/legacy.c create mode 100644 system/lib/libc/musl/src/fenv/__flt_rounds.c create mode 100644 system/lib/libc/musl/src/internal/atomic.h create mode 100644 system/lib/libc/musl/src/internal/dynlink.h create mode 100644 system/lib/libc/musl/src/internal/fdpic_crt.h create mode 100644 system/lib/libc/musl/src/internal/vdso.c create mode 100644 system/lib/libc/musl/src/internal/version.h create mode 100644 system/lib/libc/musl/src/internal/vis.h create mode 100644 system/lib/libc/musl/src/ldso/__dlsym.c create mode 100644 system/lib/libc/musl/src/ldso/dlclose.c create mode 100644 system/lib/libc/musl/src/ldso/dlerror.c create mode 100644 system/lib/libc/musl/src/ldso/dlopen.c create mode 100644 system/lib/libc/musl/src/ldso/tlsdesc.c create mode 100644 system/lib/libc/musl/src/locale/__lctrans.c create mode 100644 system/lib/libc/musl/src/locale/__mo_lookup.c create mode 100644 system/lib/libc/musl/src/locale/bind_textdomain_codeset.c create mode 100644 system/lib/libc/musl/src/locale/c_locale.c create mode 100644 system/lib/libc/musl/src/locale/dcngettext.c delete mode 100644 system/lib/libc/musl/src/locale/intl.c create mode 100644 system/lib/libc/musl/src/locale/locale_map.c create mode 100644 system/lib/libc/musl/src/locale/pleval.c create mode 100644 system/lib/libc/musl/src/locale/textdomain.c create mode 100644 system/lib/libc/musl/src/misc/emscripten_pthread.c create mode 100644 system/lib/libc/musl/src/misc/ffsl.c create mode 100644 system/lib/libc/musl/src/misc/ffsll.c create mode 100644 system/lib/libc/musl/src/misc/fmtmsg.c create mode 100644 system/lib/libc/musl/src/misc/getauxval.c create mode 100644 system/lib/libc/musl/src/misc/issetugid.c create mode 100644 system/lib/libc/musl/src/misc/login_tty.c create mode 100644 system/lib/libc/musl/src/multibyte/c16rtomb.c create mode 100644 system/lib/libc/musl/src/multibyte/c32rtomb.c create mode 100644 system/lib/libc/musl/src/multibyte/mbrtoc16.c create mode 100644 system/lib/libc/musl/src/multibyte/mbrtoc32.c create mode 100644 system/lib/libc/musl/src/network/dns_parse.c create mode 100644 system/lib/libc/musl/src/network/inet_aton.c create mode 100644 system/lib/libc/musl/src/network/lookup.h create mode 100644 system/lib/libc/musl/src/network/lookup_ipliteral.c create mode 100644 system/lib/libc/musl/src/network/lookup_name.c create mode 100644 system/lib/libc/musl/src/network/lookup_serv.c create mode 100644 system/lib/libc/musl/src/network/netlink.c create mode 100644 system/lib/libc/musl/src/network/netlink.h create mode 100644 system/lib/libc/musl/src/network/ns_parse.c create mode 100644 system/lib/libc/musl/src/network/recvmmsg.c create mode 100644 system/lib/libc/musl/src/network/res_mkquery.c create mode 100644 system/lib/libc/musl/src/network/res_msend.c create mode 100644 system/lib/libc/musl/src/network/res_querydomain.c create mode 100644 system/lib/libc/musl/src/network/res_send.c create mode 100644 system/lib/libc/musl/src/network/resolvconf.c create mode 100644 system/lib/libc/musl/src/network/sendmmsg.c create mode 100644 system/lib/libc/musl/src/passwd/getgr_a.c create mode 100644 system/lib/libc/musl/src/passwd/getgrouplist.c create mode 100644 system/lib/libc/musl/src/passwd/getpw_a.c create mode 100644 system/lib/libc/musl/src/passwd/nscd.h create mode 100644 system/lib/libc/musl/src/passwd/nscd_query.c create mode 100644 system/lib/libc/musl/src/sched/sched_getcpu.c create mode 100644 system/lib/libc/musl/src/signal/sigsetjmp_tail.c delete mode 100644 system/lib/libc/musl/src/stat/__fxstat.c delete mode 100644 system/lib/libc/musl/src/stat/__fxstatat.c delete mode 100644 system/lib/libc/musl/src/stat/__lxstat.c create mode 100644 system/lib/libc/musl/src/stdio/ofl.c create mode 100644 system/lib/libc/musl/src/stdio/ofl_add.c create mode 100644 system/lib/libc/musl/src/thread/__syscall_cp.c create mode 100644 system/lib/libc/musl/src/thread/__tls_get_addr.c create mode 100644 system/lib/libc/musl/src/thread/call_once.c create mode 100644 system/lib/libc/musl/src/thread/cnd_broadcast.c create mode 100644 system/lib/libc/musl/src/thread/cnd_destroy.c create mode 100644 system/lib/libc/musl/src/thread/cnd_init.c create mode 100644 system/lib/libc/musl/src/thread/cnd_signal.c create mode 100644 system/lib/libc/musl/src/thread/cnd_timedwait.c create mode 100644 system/lib/libc/musl/src/thread/cnd_wait.c create mode 100644 system/lib/libc/musl/src/thread/mtx_destroy.c create mode 100644 system/lib/libc/musl/src/thread/mtx_init.c create mode 100644 system/lib/libc/musl/src/thread/mtx_lock.c create mode 100644 system/lib/libc/musl/src/thread/mtx_timedlock.c create mode 100644 system/lib/libc/musl/src/thread/mtx_trylock.c create mode 100644 system/lib/libc/musl/src/thread/mtx_unlock.c create mode 100644 system/lib/libc/musl/src/thread/pthread_cancel.c create mode 100644 system/lib/libc/musl/src/thread/pthread_cleanup_push.c create mode 100644 system/lib/libc/musl/src/thread/thrd_create.c create mode 100644 system/lib/libc/musl/src/thread/thrd_exit.c create mode 100644 system/lib/libc/musl/src/thread/thrd_join.c create mode 100644 system/lib/libc/musl/src/thread/thrd_sleep.c create mode 100644 system/lib/libc/musl/src/thread/thrd_yield.c create mode 100644 system/lib/libc/musl/src/thread/tss_create.c create mode 100644 system/lib/libc/musl/src/thread/tss_delete.c create mode 100644 system/lib/libc/musl/src/thread/tss_set.c create mode 100644 system/lib/libc/musl/src/time/timespec_get.c rename tests/core/{test_strftime.c => test_strftime.cpp} (97%) rename tests/core/{test_wprintf.c => test_wprintf.cpp} (100%) create mode 100644 tests/pthread/test_pthread_locale.c diff --git a/emscripten-version.txt b/emscripten-version.txt index c7e079dda6941..3da2da767a817 100644 --- a/emscripten-version.txt +++ b/emscripten-version.txt @@ -1 +1 @@ -"1.37.4" +"1.37.5" diff --git a/src/library.js b/src/library.js index 79d98a4580e06..75f5051b7ffc8 100644 --- a/src/library.js +++ b/src/library.js @@ -2107,6 +2107,12 @@ LibraryManager.library = { return -1; }, + __map_file__deps: ['$ERRNO_CODES', '__setErrNo'], + __map_file: function(pathname, size) { + ___setErrNo(ERRNO_CODES.EPERM); + return -1; + }, + _MONTH_DAYS_REGULAR: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], _MONTH_DAYS_LEAP: [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], @@ -4282,7 +4288,7 @@ LibraryManager.library = { _pthread_cleanup_push: function(){}, _pthread_cleanup_pop: function(){}, __pthread_self: function() { abort() }, - pthread_setcancelstate: function() { return 0 }, + __pthread_setcancelstate: function() { return 0 }, // libunwind diff --git a/src/library_pthread.js b/src/library_pthread.js index 93a67dece9016..2cbf9ccb9a439 100644 --- a/src/library_pthread.js +++ b/src/library_pthread.js @@ -416,6 +416,10 @@ var LibraryPThread = { Atomics.store(HEAPU32, (pthread.threadInfoStruct + {{{ C_STRUCTS.pthread.attr }}} + 20) >> 2, threadParams.schedPolicy); Atomics.store(HEAPU32, (pthread.threadInfoStruct + {{{ C_STRUCTS.pthread.attr }}} + 24) >> 2, threadParams.schedPrio); + var global_libc = _emscripten_get_global_libc(); + var global_locale = global_libc + {{{ C_STRUCTS.libc.global_locale }}}; + Atomics.store(HEAPU32, (pthread.threadInfoStruct + {{{ C_STRUCTS.pthread.locale }}}) >> 2, global_locale); + #if PTHREADS_PROFILING PThread.createProfilerBlock(pthread.threadInfoStruct); #endif @@ -735,7 +739,6 @@ var LibraryPThread = { _pthread_is_main_runtime_thread: 0, _pthread_is_main_browser_thread: 0, - _register_pthread_ptr__asm: true, _register_pthread_ptr__deps: ['_pthread_ptr', '_pthread_is_main_runtime_thread', '_pthread_is_main_browser_thread'], _register_pthread_ptr: function(pthreadPtr, isMainBrowserThread, isMainRuntimeThread) { pthreadPtr = pthreadPtr|0; @@ -747,7 +750,6 @@ var LibraryPThread = { }, // Public pthread_self() function which returns a unique ID for the thread. - pthread_self__asm: true, pthread_self__deps: ['_pthread_ptr'], pthread_self: function() { return __pthread_ptr|0; diff --git a/src/library_pthread_stub.js b/src/library_pthread_stub.js index c7e578924795c..164d32d7eb83f 100644 --- a/src/library_pthread_stub.js +++ b/src/library_pthread_stub.js @@ -79,12 +79,6 @@ var LibraryPThreadStub = { return 0; }, - pthread_self__asm: true, - pthread_self__sig: 'i', - pthread_self: function() { - return 0; - }, - pthread_attr_init: function(attr) { /* int pthread_attr_init(pthread_attr_t *attr); */ //FIXME: should allocate a pthread_attr_t @@ -194,7 +188,10 @@ var LibraryPThreadStub = { return {{{ cDefine('EAGAIN') }}}; }, pthread_cancel: function() {}, - pthread_exit: function() {}, + pthread_exit__deps: ['exit'], + pthread_exit: function(status) { + _exit(status); + }, pthread_equal: function() {}, pthread_join: function() {}, diff --git a/src/library_syscall.js b/src/library_syscall.js index 8b2d825a125c8..423073d395627 100644 --- a/src/library_syscall.js +++ b/src/library_syscall.js @@ -332,6 +332,12 @@ var SyscallsLibrary = { var argp = SYSCALLS.get(); return FS.ioctl(stream, op, argp); } + case {{{ cDefine('TIOCGWINSZ') }}}: { + // TODO: in theory we should write to the winsize struct that gets + // passed in, but for now musl doesn't read anything on it + if (!stream.tty) return -ERRNO_CODES.ENOTTY; + return 0; + } default: abort('bad ioctl syscall ' + op); } #endif // NO_FILESYSTEM @@ -833,6 +839,12 @@ var SyscallsLibrary = { } return nonzero; }, + __syscall178: function(which, varargs) { // rt_sigqueueinfo +#if SYSCALL_DEBUG + Module.printErr('warning: ignoring SYS_rt_sigqueueinfo'); +#endif + return 0; + }, __syscall180: function(which, varargs) { // pread64 var stream = SYSCALLS.getStreamFromFD(), buf = SYSCALLS.get(), count = SYSCALLS.get(), zero = SYSCALLS.getZero(), offset = SYSCALLS.get64(); return FS.read(stream, {{{ heapAndOffset('HEAP8', 'buf') }}}, count, offset); @@ -996,6 +1008,12 @@ var SyscallsLibrary = { }, __syscall221__deps: ['__setErrNo'], __syscall221: function(which, varargs) { // fcntl64 +#if NO_FILESYSTEM +#if SYSCALL_DEBUG + Module.printErr('no-op in fcntl64 syscall due to NO_FILESYSTEM'); +#endif + return 0; +#else var stream = SYSCALLS.getStreamFromFD(), cmd = SYSCALLS.get(); switch (cmd) { case {{{ cDefine('F_DUPFD') }}}: { @@ -1044,6 +1062,7 @@ var SyscallsLibrary = { return -ERRNO_CODES.EINVAL; } } +#endif // NO_FILESYSTEM }, __syscall265: function(which, varargs) { // clock_nanosleep #if SYSCALL_DEBUG @@ -1231,6 +1250,12 @@ var SyscallsLibrary = { var stream = SYSCALLS.getStreamFromFD(), iov = SYSCALLS.get(), iovcnt = SYSCALLS.get(), offset = SYSCALLS.get(); return SYSCALLS.doWritev(stream, iov, iovcnt, offset); }, + __syscall337: function(which, varargs) { // recvmmsg +#if SYSCALL_DEBUG + Module.printErr('warning: ignoring SYS_recvmmsg'); +#endif + return 0; + }, __syscall340: function(which, varargs) { // prlimit64 var pid = SYSCALLS.get(), resource = SYSCALLS.get(), new_limit = SYSCALLS.get(), old_limit = SYSCALLS.get(); if (old_limit) { // just report no limits @@ -1241,6 +1266,12 @@ var SyscallsLibrary = { } return 0; }, + __syscall345: function(which, varargs) { // sendmmsg +#if SYSCALL_DEBUG + Module.printErr('warning: ignoring SYS_sendmmsg'); +#endif + return 0; + }, }; if (SYSCALL_DEBUG) { @@ -1577,6 +1608,7 @@ if (SYSCALL_DEBUG) { SYS_inotify_init1: 332, SYS_preadv: 333, SYS_pwritev: 334, + SYS_recvmmsg: 337, SYS_prlimit64: 340, SYS_name_to_handle_at: 341, SYS_open_by_handle_at: 342, diff --git a/src/struct_info.compiled.json b/src/struct_info.compiled.json index 465a51eee8f9a..bf639dbf3e4e7 100644 --- a/src/struct_info.compiled.json +++ b/src/struct_info.compiled.json @@ -1 +1 @@ -{"structs":{"utsname":{"sysname":0,"nodename":65,"domainname":325,"machine":260,"version":195,"release":130,"__size__":390},"sockaddr":{"sa_data":2,"sa_family":0,"__size__":16},"addrinfo":{"ai_flags":0,"ai_next":28,"ai_canonname":24,"ai_socktype":8,"ai_addr":20,"ai_protocol":12,"ai_family":4,"ai_addrlen":16,"__size__":32},"timespec":{"tv_sec":0,"tv_nsec":4,"__size__":8},"utimbuf":{"modtime":4,"actime":0,"__size__":8},"EmscriptenVisibilityChangeEvent":{"hidden":0,"visibilityState":4,"__size__":8},"SDL_MouseButtonEvent":{"timestamp":4,"button":16,"state":17,"windowID":8,"which":12,"y":24,"x":20,"padding2":19,"type":0,"padding1":18,"__size__":28},"sockaddr_in":{"sin_port":2,"sin_addr":{"s_addr":4,"__size__":4},"sin_family":0,"sin_zero":8,"__size__":16},"pthread":{"tsd":116,"attr":120,"canceldisable":72,"threadStatus":0,"tsd_used":56,"pid":52,"stack":92,"cancelasync":76,"tid":48,"threadExitCode":4,"detached":80,"profilerBlock":20,"self":24,"stack_size":96,"__size__":220},"WebVRFieldOfView":{"leftDegrees":24,"upDegrees":0,"downDegrees":16,"rightDegrees":8,"__size__":32},"SDL_KeyboardEvent":{"repeat":9,"keysym":12,"state":8,"windowID":4,"__size__":28,"type":0,"padding3":11,"padding2":10},"SDL_MouseMotionEvent":{"yrel":32,"timestamp":4,"state":16,"windowID":8,"which":12,"xrel":28,"y":24,"x":20,"type":0,"__size__":36},"SDL_Rect":{"y":4,"x":0,"h":12,"w":8,"__size__":16},"itimerspec":{"it_interval":{"tv_sec":0,"tv_nsec":4,"__size__":8},"it_value":{"tv_sec":8,"tv_nsec":12,"__size__":8},"__size__":16},"iovec":{"iov_len":4,"iov_base":0,"__size__":8},"timezone":{"tz_dsttime":4,"tz_minuteswest":0,"__size__":8},"flock":{"l_whence":2,"l_type":0,"l_start":4,"__size__":16,"l_len":8,"l_pid":12},"EmscriptenOrientationChangeEvent":{"orientationIndex":0,"orientationAngle":4,"__size__":8},"EmscriptenMouseEvent":{"clientX":16,"clientY":20,"targetX":52,"buttons":42,"timestamp":0,"button":40,"targetY":56,"altKey":32,"canvasY":64,"metaKey":36,"movementX":44,"movementY":48,"shiftKey":28,"ctrlKey":24,"screenY":12,"screenX":8,"canvasX":60,"__size__":72},"SDL_ResizeEvent":{"h":8,"type":0,"w":4,"__size__":12},"tms":{"tms_stime":4,"tms_utime":0,"tms_cstime":12,"tms_cutime":8,"__size__":16},"SDL_Color":{"unused":3,"r":0,"b":2,"g":1,"__size__":4},"EmscriptenKeyboardEvent":{"code":32,"charValue":120,"locale":88,"shiftKey":72,"altKey":76,"which":160,"metaKey":80,"location":64,"key":0,"ctrlKey":68,"charCode":152,"keyCode":156,"repeat":84,"__size__":164},"rusage":{"ru_msgrcv":56,"ru_utime":{"tv_sec":0,"tv_usec":4,"__size__":8},"ru_isrss":28,"ru_stime":{"tv_sec":8,"tv_usec":12,"__size__":8},"ru_nsignals":60,"ru_nivcsw":68,"ru_msgsnd":52,"ru_nswap":40,"ru_minflt":32,"ru_nvcsw":64,"ru_ixrss":20,"ru_inblock":44,"ru_idrss":24,"ru_maxrss":16,"ru_oublock":48,"ru_majflt":36,"__size__":136},"div_t":{"quot":0,"rem":4,"__size__":8},"timeval":{"tv_sec":0,"tv_usec":4,"__size__":8},"rlimit":{"rlim_cur":0,"rlim_max":8,"__size__":16},"in6_addr":{"__in6_union":{"__s6_addr16":0,"__s6_addr":0,"__s6_addr32":0,"__size__":16},"__size__":16},"tm":{"tm_sec":0,"tm_hour":8,"tm_mday":12,"tm_isdst":32,"tm_year":20,"tm_zone":40,"tm_mon":16,"tm_yday":28,"tm_gmtoff":36,"tm_wday":24,"tm_min":4,"__size__":44},"EmscriptenWebGLContextAttributes":{"majorVersion":32,"stencil":8,"preserveDrawingBuffer":20,"failIfMajorPerformanceCaveat":28,"explicitSwapControl":44,"antialias":12,"depth":4,"minorVersion":36,"premultipliedAlpha":16,"enableExtensionsByDefault":40,"alpha":0,"preferLowPowerToHighPerformance":24,"__size__":48},"EmscriptenBatteryEvent":{"dischargingTime":8,"level":16,"charging":24,"chargingTime":0,"__size__":32},"protoent":{"p_aliases":4,"p_proto":8,"p_name":0,"__size__":12},"SDL_Surface":{"userdata":24,"locked":28,"clip_rect":36,"format":4,"h":12,"refcount":56,"map":52,"flags":0,"w":8,"pitch":16,"lock_data":32,"pixels":20,"__size__":60},"EmscriptenTouchEvent":{"touches":20,"shiftKey":8,"altKey":12,"metaKey":16,"ctrlKey":4,"__size__":1684,"numTouches":0},"EmscriptenFocusEvent":{"id":128,"nodeName":0,"__size__":256},"sockaddr_in6":{"sin6_family":0,"sin6_flowinfo":4,"sin6_scope_id":24,"sin6_addr":{"__in6_union":{"__s6_addr16":8,"__s6_addr":8,"__s6_addr32":8,"__size__":16},"__size__":16},"__size__":28,"sin6_port":2},"SDL_JoyAxisEvent":{"__size__":12,"type":0,"value":8,"which":4,"padding2":7,"padding1":6,"axis":5},"netent":{"n_name":0,"n_net":12,"n_addrtype":8,"n_aliases":4,"__size__":16},"SDL_PixelFormat":{"palette":4,"Gloss":29,"Bmask":20,"Bloss":30,"Rloss":28,"format":0,"Gshift":33,"Aloss":31,"BitsPerPixel":8,"refcount":36,"next":40,"padding":10,"Rmask":12,"Bshift":34,"Gmask":16,"BytesPerPixel":9,"Amask":24,"Rshift":32,"Ashift":35,"__size__":44},"SDL_JoyButtonEvent":{"type":0,"button":5,"state":6,"which":4,"padding1":7,"__size__":8},"EmscriptenPointerlockChangeEvent":{"id":132,"nodeName":4,"isActive":0,"__size__":260},"in_addr":{"s_addr":0,"__size__":4},"EmscriptenDeviceOrientationEvent":{"timestamp":0,"beta":16,"alpha":8,"__size__":40,"gamma":24,"absolute":32},"SDL_WindowEvent":{"data2":16,"type":0,"data1":12,"windowID":4,"__size__":20,"padding1":9,"event":8,"padding3":11,"padding2":10},"SDL_Keysym":{"scancode":0,"mod":8,"unicode":12,"sym":4,"__size__":16},"cmsghdr":{"cmsg_type":8,"cmsg_level":4,"cmsg_len":0,"__size__":12},"EmscriptenUiEvent":{"windowInnerWidth":12,"detail":0,"scrollLeft":32,"documentBodyClientHeight":8,"windowInnerHeight":16,"scrollTop":28,"windowOuterHeight":24,"windowOuterWidth":20,"documentBodyClientWidth":4,"__size__":36},"thread_profiler_block":{"threadStatus":0,"timeSpentInStatus":16,"currentStatusStartTime":8,"name":72,"__size__":104},"stat":{"st_rdev":28,"st_mtim":{"tv_sec":56,"tv_nsec":60,"__size__":8},"st_blocks":44,"st_atim":{"tv_sec":48,"tv_nsec":52,"__size__":8},"st_nlink":16,"__st_ino_truncated":8,"st_ctim":{"tv_sec":64,"tv_nsec":68,"__size__":8},"st_mode":12,"st_blksize":40,"__st_dev_padding":4,"st_dev":0,"st_size":36,"st_gid":24,"__st_rdev_padding":32,"st_uid":20,"st_ino":72,"__size__":76},"pollfd":{"fd":0,"events":4,"revents":6,"__size__":8},"WebVRPositionState":{"linearVelocity":{"y":56,"x":48,"z":64,"w":72,"__size__":32},"orientation":{"y":128,"x":120,"z":136,"w":144,"__size__":32},"timeStamp":0,"angularVelocity":{"y":160,"x":152,"z":168,"w":176,"__size__":32},"hasPosition":8,"angularAcceleration":{"y":192,"x":184,"z":200,"w":208,"__size__":32},"linearAcceleration":{"y":88,"x":80,"z":96,"w":104,"__size__":32},"hasOrientation":112,"position":{"y":24,"x":16,"z":32,"w":40,"__size__":32},"__size__":216},"dirent":{"d_name":11,"d_off":4,"d_ino":0,"d_reclen":8,"d_type":10,"__size__":268},"EmscriptenTouchPoint":{"clientX":12,"clientY":16,"identifier":0,"targetX":36,"targetY":40,"isChanged":28,"canvasY":48,"canvasX":44,"pageX":20,"pageY":24,"screenY":8,"screenX":4,"onTarget":32,"__size__":52},"EmscriptenDeviceMotionEvent":{"timestamp":0,"accelerationIncludingGravityZ":48,"accelerationIncludingGravityX":32,"accelerationIncludingGravityY":40,"accelerationY":16,"accelerationX":8,"rotationRateBeta":64,"accelerationZ":24,"rotationRateGamma":72,"rotationRateAlpha":56,"__size__":80},"SDL_AudioSpec":{"padding":10,"userdata":20,"format":4,"channels":6,"callback":16,"samples":8,"freq":0,"size":12,"silence":7,"__size__":24},"hostent":{"h_addrtype":8,"h_addr_list":16,"h_name":0,"__size__":20,"h_aliases":4,"h_length":12},"SDL_MouseWheelEvent":{"timestamp":4,"windowID":8,"which":12,"y":20,"x":16,"type":0,"__size__":24},"linger":{"l_onoff":0,"l_linger":4,"__size__":8},"SDL_version":{"major":0,"patch":2,"minor":1,"__size__":3},"statvfs":{"f_bsize":0,"f_bavail":16,"f_fsid":32,"f_favail":28,"f_files":20,"f_frsize":4,"f_blocks":8,"f_ffree":24,"f_bfree":12,"f_flag":40,"f_namemax":44,"__size__":72},"EmscriptenFullscreenChangeEvent":{"elementWidth":264,"screenWidth":272,"nodeName":8,"elementHeight":268,"fullscreenEnabled":4,"screenHeight":276,"isFullscreen":0,"id":136,"__size__":280},"EmscriptenWheelEvent":{"deltaX":72,"deltaY":80,"deltaZ":88,"deltaMode":96,"mouse":0,"__size__":104},"WebVRIntRect":{"y":4,"x":0,"height":12,"width":8,"__size__":16},"SDL_TouchFingerEvent":{"timestamp":4,"dy":36,"touchId":8,"pressure":40,"dx":32,"type":0,"y":28,"x":24,"fingerId":16,"__size__":48},"SDL_AudioCVT":{"len_ratio":32,"len_cvt":24,"rate_incr":8,"filters":40,"len":20,"needed":0,"filter_index":80,"src_format":4,"len_mult":28,"__size__":88,"buf":16,"dst_format":6},"WebVRPoint":{"y":8,"x":0,"z":16,"w":24,"__size__":32},"timeb":{"dstflag":8,"timezone":6,"time":0,"millitm":4,"__size__":12},"statfs":{"f_bsize":4,"f_bavail":16,"f_fsid":28,"f_files":20,"f_frsize":40,"f_namelen":36,"f_blocks":8,"f_ffree":24,"f_bfree":12,"f_flags":44,"__size__":64},"msghdr":{"msg_iov":8,"msg_iovlen":12,"msg_namelen":4,"msg_controllen":20,"msg_flags":24,"msg_name":0,"msg_control":16,"__size__":28},"WebVREyeParameters":{"currentFieldOfView":{"leftDegrees":152,"upDegrees":128,"downDegrees":144,"rightDegrees":136,"__size__":32},"recommendedFieldOfView":{"leftDegrees":88,"upDegrees":64,"downDegrees":80,"rightDegrees":72,"__size__":32},"eyeTranslation":{"y":104,"x":96,"z":112,"w":120,"__size__":32},"renderRect":{"y":164,"x":160,"height":172,"width":168,"__size__":16},"minimumFieldOfView":{"leftDegrees":24,"upDegrees":0,"downDegrees":16,"rightDegrees":8,"__size__":32},"maximumFieldOfView":{"leftDegrees":56,"upDegrees":32,"downDegrees":48,"rightDegrees":40,"__size__":32},"__size__":176},"SDL_Palette":{"ncolors":0,"colors":4,"version":8,"refcount":12,"__size__":16},"EmscriptenFullscreenStrategy":{"canvasResizedCallbackUserData":16,"canvasResolutionScaleMode":4,"scaleMode":0,"canvasResizedCallback":12,"filteringMode":8,"__size__":20},"EmscriptenGamepadEvent":{"index":1300,"analogButton":528,"timestamp":0,"numButtons":12,"mapping":1368,"digitalButton":1040,"connected":1296,"numAxes":8,"__size__":1432,"id":1304,"axis":16},"SDL_TextInputEvent":{"text":8,"windowID":4,"type":0,"__size__":40}},"defines":{"ETXTBSY":26,"EOF":-1,"EMSCRIPTEN_EVENT_MOUSEOVER":35,"ETOOMANYREFS":109,"ENAMETOOLONG":36,"ENOPKG":65,"UUID_TYPE_DCE_TIME":1,"_SC_XOPEN_LEGACY":129,"_SC_XOPEN_VERSION":89,"F_UNLCK":2,"_SC_BC_DIM_MAX":37,"EL3HLT":46,"S_IFDIR":16384,"EMSCRIPTEN_EVENT_KEYPRESS":1,"EINPROGRESS":115,"_SC_BARRIERS":133,"EMSCRIPTEN_EVENT_TOUCHMOVE":24,"SDL_AUDIO_ALLOW_FREQUENCY_CHANGE":1,"AUDIO_U8":8,"EAI_AGAIN":-3,"_PC_MAX_CANON":1,"ENOTSUP":95,"EFBIG":27,"O_CREAT":64,"EMSCRIPTEN_EVENT_POINTERLOCKERROR":38,"_SC_2_PBS_LOCATE":170,"EM_PROXIED_SETENV":113,"_CS_POSIX_V6_LP64_OFF64_LIBS":1126,"ENOLINK":67,"ABDAY_7":131078,"ABDAY_6":131077,"ABDAY_5":131076,"ABDAY_4":131075,"ABDAY_3":131074,"ABDAY_2":131073,"ABDAY_1":131072,"EL3RST":47,"YESEXPR":327680,"_SC_V6_ILP32_OFFBIG":177,"SDL_MINOR_VERSION":3,"EM_PROXIED_CLEARENV":112,"_SC_MEMLOCK":17,"ENOTUNIQ":76,"EMSCRIPTEN_RESULT_FAILED":-6,"ABMON_1":131086,"ELNRNG":48,"UUID_VARIANT_MICROSOFT":2,"EMSCRIPTEN_EVENT_TOUCHSTART":22,"ENOANO":55,"EMSCRIPTEN_EVENT_FOCUSIN":14,"EMSCRIPTEN_EVENT_MOUSEUP":6,"ENOPROTOOPT":92,"POLLIN":1,"S_IALLUGO":4095,"_SC_THREAD_KEYS_MAX":74,"EM_THREAD_STATUS_WAITPROXY":5,"O_RDWR":2,"EREMCHG":78,"EMSCRIPTEN_EVENT_GAMEPADDISCONNECTED":27,"_SC_2_PBS":168,"_SC_TRACE_INHERIT":183,"_SC_REGEXP":155,"_CS_POSIX_V6_LP64_OFF64_CFLAGS":1124,"_SC_DELAYTIMER_MAX":26,"S_IWUGO":146,"S_IFREG":32768,"F_GETLK64":12,"O_DIRECTORY":65536,"EM_PROXIED_UTIMES":13,"POLLHUP":16,"S_IFMT":61440,"F_SETLK64":13,"_SC_XOPEN_CRYPT":92,"_SC_CLOCK_SELECTION":137,"_PC_CHOWN_RESTRICTED":6,"E2BIG":7,"ABMON_3":131088,"AM_STR":131110,"SDL_AUDIO_MASK_ENDIAN":4096,"ALT_DIGITS":131119,"EHOSTDOWN":112,"EBFONT":59,"ENOTEMPTY":39,"AUDIO_S16":32784,"TIOCGPGRP":21519,"EBUSY":16,"_SC_MQ_PRIO_MAX":28,"_SC_PAGE_SIZE":30,"EADDRINUSE":98,"ENOTSOCK":88,"PM_STR":131111,"O_WRONLY":1,"_SC_STREAM_MAX":5,"ABMON_9":131094,"ELIBACC":79,"S_IFIFO":4096,"EDQUOT":122,"EAI_SYSTEM":-11,"ENOENT":2,"_SC_TIMERS":11,"O_SYNC":1052672,"SEEK_END":2,"EM_THREAD_STATUS_FINISHED":6,"_PC_REC_MIN_XFER_SIZE":16,"_PC_PATH_MAX":4,"_SC_SPORADIC_SERVER":160,"ECOMM":70,"_SC_NPROCESSORS_ONLN":84,"_CS_POSIX_V6_LPBIG_OFFBIG_LIBS":1130,"_PC_MAX_INPUT":2,"_SC_VERSION":29,"_SC_XBS5_LPBIG_OFFBIG":128,"_SC_CLK_TCK":2,"ABMON_2":131087,"EXFULL":54,"ABMON_7":131092,"ABMON_6":131091,"ABMON_5":131090,"ABMON_4":131089,"ENOTDIR":20,"ABMON_8":131093,"_SC_AIO_MAX":24,"ERA":131116,"EM_PROXIED_UNSETENV":114,"_SC_THREAD_PRIO_INHERIT":80,"_PC_2_SYMLINKS":20,"_SC_XBS5_LP64_OFF64":127,"EMSCRIPTEN_EVENT_BATTERYLEVELCHANGE":30,"ENETRESET":102,"EAFNOSUPPORT":97,"MON_2":131099,"MON_3":131100,"MON_1":131098,"EMSCRIPTEN_EVENT_DEVICEORIENTATION":16,"MON_7":131104,"MON_4":131101,"MON_5":131102,"_SC_SPAWN":159,"MON_8":131105,"MON_9":131106,"_CS_POSIX_V6_ILP32_OFF32_LDFLAGS":1117,"S_IFSOCK":49152,"S_IRUGO":292,"SOCK_DGRAM":2,"POLLERR":8,"EINVAL":22,"_CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS":1128,"POLLRDNORM":64,"AUDIO_F32SYS":33056,"_SC_TRACE_SYS_MAX":244,"AI_V4MAPPED":8,"AI_NUMERICHOST":4,"_CS_POSIX_V6_WIDTH_RESTRICTED_ENVS":1,"EHOSTUNREACH":113,"ENOCSI":50,"EPROTONOSUPPORT":93,"_SC_AIO_PRIO_DELTA_MAX":25,"_SC_MONOTONIC_CLOCK":149,"ETIME":62,"ENOTTY":25,"_SC_XOPEN_ENH_I18N":93,"EAI_SERVICE":-8,"EAGAIN":11,"F_SETLKW64":14,"EMSGSIZE":90,"ELIBEXEC":83,"_SC_MEMORY_PROTECTION":19,"EMSCRIPTEN_FULLSCREEN_SCALE_CENTER":3,"SDL_AUDIO_ALLOW_FORMAT_CHANGE":2,"ECANCELED":125,"_SC_SPIN_LOCKS":154,"_SC_XOPEN_SHM":94,"_PC_LINK_MAX":0,"TIOCSPGRP":21520,"EOPNOTSUPP":95,"EMSCRIPTEN_EVENT_MOUSEENTER":33,"EAI_FAIL":-4,"NOEXPR":327681,"_SC_FSYNC":15,"_SC_GETGR_R_SIZE_MAX":69,"EDESTADDRREQ":89,"EADDRNOTAVAIL":99,"AUDIO_S32SYS":32800,"_SC_TRACE_NAME_MAX":243,"_SC_BC_BASE_MAX":36,"EMSCRIPTEN_EVENT_CANVASRESIZED":37,"EPERM":1,"EAI_FAMILY":-6,"O_NOFOLLOW":131072,"SOCK_STREAM":1,"O_APPEND":1024,"_SC_XOPEN_STREAMS":246,"_SC_GETPW_R_SIZE_MAX":70,"MON_6":131103,"EPROTOTYPE":91,"_SC_CPUTIME":138,"EISCONN":106,"_SC_XBS5_ILP32_OFFBIG":126,"S_IFBLK":24576,"T_FMT_AMPM":131115,"SDL_PIXELFORMAT_RGBA8888":-2042224636,"F_SETLKW":14,"SDL_TOUCH_MOUSEID":-1,"EMSCRIPTEN_EVENT_SCROLL":11,"ELOOP":40,"_SC_OPEN_MAX":4,"_SC_2_FORT_RUN":50,"EMSCRIPTEN_EVENT_VISIBILITYCHANGE":21,"EREMOTE":66,"_SC_RE_DUP_MAX":44,"_SC_THREAD_PRIO_PROTECT":81,"_SC_2_PBS_CHECKPOINT":175,"_SC_2_PBS_TRACK":172,"MON_10":131107,"MON_11":131108,"MON_12":131109,"TCGETS":21505,"_SC_THREAD_PROCESS_SHARED":82,"AF_INET":2,"_SC_SHARED_MEMORY_OBJECTS":22,"F_GETFD":1,"EMSCRIPTEN_EVENT_DEVICEMOTION":17,"SDL_MIX_MAXVOLUME":128,"_PC_ALLOC_SIZE_MIN":18,"TCSETS":21506,"ELIBMAX":82,"_SC_READER_WRITER_LOCKS":153,"EMULTIHOP":72,"IPPROTO_TCP":6,"_SC_PHYS_PAGES":85,"_SC_MEMLOCK_RANGE":18,"_SC_PRIORITY_SCHEDULING":10,"T_FMT":131114,"AI_ALL":16,"_PC_VDISABLE":8,"THOUSEP":65537,"_SC_TRACE_EVENT_FILTER":182,"ERA_T_FMT":131121,"_SC_THREAD_ATTR_STACKADDR":77,"_SC_THREAD_THREADS_MAX":76,"_SC_LOGIN_NAME_MAX":71,"_SC_2_C_BIND":47,"_PC_NO_TRUNC":7,"ECONNABORTED":103,"EMSCRIPTEN_RESULT_SUCCESS":0,"_SC_SHELL":157,"EFAULT":14,"_SC_V6_LP64_OFF64":178,"_CS_GNU_LIBC_VERSION":2,"ENODATA":61,"_SC_SEM_VALUE_MAX":33,"_SC_MQ_OPEN_MAX":27,"AI_ADDRCONFIG":32,"_SC_HOST_NAME_MAX":180,"_SC_THREAD_STACK_MIN":75,"_SC_TIMEOUTS":164,"POLLOUT":4,"_SC_IPV6":235,"_SC_CHILD_MAX":1,"EDOM":33,"_SC_2_PBS_MESSAGE":171,"EILSEQ":84,"UUID_VARIANT_DCE":1,"_SC_2_C_DEV":48,"_SC_TIMER_MAX":35,"FP_ZERO":2,"EPFNOSUPPORT":96,"ENONET":64,"ECHRNG":44,"_SC_THREADS":67,"_SC_REALTIME_SIGNALS":9,"CLOCKS_PER_SEC":1000000,"ERA_D_T_FMT":131120,"ESRCH":3,"D_FMT":131113,"POLLPRI":2,"_PC_ASYNC_IO":10,"DAY_2":131080,"DAY_3":131081,"DAY_1":131079,"DAY_6":131084,"DAY_7":131085,"DAY_4":131082,"DAY_5":131083,"_SC_SYNCHRONIZED_IO":14,"EL2HLT":51,"EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF":1,"IPPROTO_UDP":17,"_SC_MAPPED_FILES":16,"EL2NSYNC":45,"_SC_NGROUPS_MAX":3,"ENOMSG":42,"EISDIR":21,"_SC_SEMAPHORES":21,"AI_NUMERICSERV":1024,"EDEADLOCK":35,"EMSCRIPTEN_EVENT_WEBGLCONTEXTLOST":31,"EMSCRIPTEN_EVENT_BATTERYCHARGINGCHANGE":29,"AUDIO_F32LSB":33056,"_SC_COLL_WEIGHTS_MAX":40,"SO_ERROR":4,"ECONNRESET":104,"AT_SYMLINK_NOFOLLOW":256,"_SC_TRACE_LOG":184,"AUDIO_U16LSB":16,"ESTRPIPE":86,"ESHUTDOWN":108,"_PC_SOCK_MAXBUF":12,"_CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS":1129,"EDEADLK":35,"_CS_POSIX_V6_ILP32_OFF32_CFLAGS":1116,"EBADRQC":56,"_SC_THREAD_DESTRUCTOR_ITERATIONS":73,"_SC_TYPED_MEMORY_OBJECTS":165,"_SC_TRACE_EVENT_NAME_MAX":242,"_SC_BC_STRING_MAX":39,"_SC_2_SW_DEV":51,"FP_NAN":0,"F_SETOWN":8,"EMSCRIPTEN_EVENT_RESIZE":10,"_SC_ARG_MAX":0,"_SC_THREAD_PRIORITY_SCHEDULING":79,"F_GETLK":12,"EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF":2,"FIONREAD":21531,"_SC_THREAD_CPUTIME":139,"EMSCRIPTEN_EVENT_POINTERLOCKCHANGE":20,"EM_THREAD_STATUS_NOTSTARTED":0,"_CS_POSIX_V6_ILP32_OFF32_LIBS":1118,"EUNATCH":49,"AUDIO_S8":32776,"AUDIO_S32LSB":32800,"SDL_AUDIO_MASK_BITSIZE":255,"ERA_D_FMT":131118,"AUDIO_F32MSB":37152,"_CS_POSIX_V6_LP64_OFF64_LDFLAGS":1125,"FP_INFINITE":1,"ECHILD":10,"EAI_MEMORY":-10,"EM_PROXIED_FPATHCONF":46,"O_TRUNC":512,"ETIMEDOUT":110,"S_IRWXO":7,"EALREADY":114,"ENXIO":6,"NI_NUMERICHOST":1,"EMFILE":24,"F_GETOWN":9,"EMLINK":31,"F_SETFD":2,"ENFILE":23,"EM_PROXIED_SYSCONF":72,"EM_PROXIED_GETENV":111,"SDL_MAJOR_VERSION":1,"ENOMEM":12,"ENOSR":63,"SDL_AUDIO_ALLOW_ANY_CHANGE":7,"EOWNERDEAD":130,"_PC_PRIO_IO":11,"ELIBSCN":81,"_SC_V6_LPBIG_OFFBIG":179,"EM_PROXIED_CHROOT":37,"EMSCRIPTEN_EVENT_CLICK":4,"_SC_EXPR_NEST_MAX":42,"_CS_POSIX_V6_ILP32_OFFBIG_CFLAGS":1120,"EBADSLT":57,"AUDIO_S16MSB":36880,"S_ISVTX":512,"EMSCRIPTEN_RESULT_DEFERRED":1,"EMSCRIPTEN_RESULT_UNKNOWN_TARGET":-4,"S_IRWXUGO":511,"EM_PROXIED_TZSET":119,"_CS_GNU_LIBPTHREAD_VERSION":3,"_PC_REC_MAX_XFER_SIZE":15,"UUID_VARIANT_OTHER":3,"EMSCRIPTEN_EVENT_WEBGLCONTEXTRESTORED":32,"EM_PROXIED_PTHREAD_CREATE":137,"EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT":0,"RADIXCHAR":65536,"AF_UNSPEC":0,"ENOSTR":60,"W_OK":2,"AUDIO_S32":32800,"EACCES":13,"R_OK":4,"EM_HTML5_MEDIUM_STRING_LEN_BYTES":64,"_SC_V6_ILP32_OFF32":176,"EMSCRIPTEN_EVENT_FULLSCREENCHANGE":19,"EIO":5,"EMSCRIPTEN_RESULT_NOT_SUPPORTED":-1,"EM_PROXIED_CONFSTR":68,"_SC_SIGQUEUE_MAX":34,"EWOULDBLOCK":11,"AUDIO_U16SYS":16,"EMSCRIPTEN_EVENT_FOCUSOUT":15,"EAI_OVERFLOW":-12,"SDL_AUDIO_MASK_DATATYPE":256,"MAP_PRIVATE":2,"_SC_TZNAME_MAX":6,"_CS_PATH":0,"SEEK_SET":0,"EBADE":52,"EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED":-2,"INT_MAX":2147483647,"EMSCRIPTEN_EVENT_KEYDOWN":2,"EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH":1,"_SC_MESSAGE_PASSING":20,"_SC_THREAD_SAFE_FUNCTIONS":68,"_SC_SYMLOOP_MAX":173,"_PC_NAME_MAX":3,"O_EXCL":128,"_SC_TRACE_USER_EVENT_MAX":245,"_PC_REC_XFER_ALIGN":17,"EMSCRIPTEN_FULLSCREEN_SCALE_DEFAULT":0,"_SC_RAW_SOCKETS":236,"_SC_2_UPE":97,"EMSCRIPTEN_RESULT_NO_DATA":-7,"EMSCRIPTEN_EVENT_BLUR":12,"_SC_TTY_NAME_MAX":72,"_SC_RTSIG_MAX":31,"ESOCKTNOSUPPORT":94,"_SC_PRIORITIZED_IO":13,"_SC_XOPEN_UNIX":91,"CODESET":14,"EPIPE":32,"_PC_REC_INCR_XFER_SIZE":14,"F_SETLK":13,"_PC_FILESIZEBITS":13,"_SC_XBS5_ILP32_OFF32":125,"RAND_MAX":2147483647,"EM_PROXIED_SYSCALL":138,"ENOLCK":37,"EM_PROXIED_PUTENV":115,"AUDIO_U16":16,"EMSCRIPTEN_EVENT_MOUSELEAVE":34,"EMSCRIPTEN_EVENT_MOUSEOUT":36,"_PC_SYNC_IO":9,"EEXIST":17,"FP_NORMAL":4,"O_RDONLY":0,"_SC_SEM_NSEMS_MAX":32,"_SC_IOV_MAX":60,"EPROTO":71,"_SC_TRACE":181,"ESRMNT":69,"EM_HTML5_LONG_STRING_LEN_BYTES":128,"_CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS":1121,"INADDR_LOOPBACK":2130706433,"EXDEV":18,"EM_THREAD_STATUS_RUNNING":1,"EMSCRIPTEN_EVENT_BEFOREUNLOAD":28,"EM_THREAD_STATUS_WAITFUTEX":3,"EMSCRIPTEN_RESULT_INVALID_TARGET":-3,"_SC_THREAD_SPORADIC_SERVER":161,"F_SETFL":4,"AI_PASSIVE":1,"ELIBBAD":80,"_SC_LINE_MAX":43,"D_T_FMT":131112,"ERANGE":34,"ESTALE":116,"F_DUPFD":0,"AUDIO_F32":33056,"CLOCK_MONOTONIC":1,"EMSCRIPTEN_EVENT_GAMEPADCONNECTED":26,"F_GETOWN_EX":16,"_SC_ASYNCHRONOUS_IO":12,"ENOTRECOVERABLE":131,"ENOBUFS":105,"EIDRM":43,"EMSCRIPTEN_EVENT_ORIENTATIONCHANGE":18,"CRNCYSTR":262159,"EINTR":4,"EADV":68,"ENOSYS":38,"_CS_POSIX_V6_ILP32_OFFBIG_LIBS":1122,"EM_PROXIED_UTIME":12,"F_GETFL":3,"S_IXUGO":73,"_SC_2_FORT_DEV":49,"SDL_COMPILEDVERSION":1300,"EBADMSG":74,"EUSERS":87,"CLOCK_REALTIME":0,"ENODEV":19,"AF_INET6":10,"_SC_ATEXIT_MAX":87,"_SC_SAVED_IDS":8,"SOL_SOCKET":1,"S_IFLNK":40960,"AUDIO_S16LSB":32784,"POLLNVAL":32,"EMSCRIPTEN_EVENT_TOUCHCANCEL":25,"EMSCRIPTEN_RESULT_INVALID_PARAM":-5,"EMSCRIPTEN_EVENT_MOUSEDOWN":5,"EM_THREAD_STATUS_SLEEPING":2,"_SC_JOB_CONTROL":7,"NI_NAMEREQD":8,"EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT":2,"EMSCRIPTEN_EVENT_MOUSEMOVE":8,"UUID_TYPE_DCE_RANDOM":4,"ENOTCONN":107,"_SC_ADVISORY_INFO":132,"ENETUNREACH":101,"_SC_XOPEN_REALTIME_THREADS":131,"_SC_2_LOCALEDEF":52,"_PC_SYMLINK_MAX":19,"X_OK":1,"EMSCRIPTEN_EVENT_KEYUP":3,"AI_CANONNAME":2,"UUID_VARIANT_NCS":0,"ESPIPE":29,"AUDIO_S32MSB":36896,"EMSCRIPTEN_EVENT_WHEEL":9,"SDL_AUDIO_ALLOW_CHANNELS_CHANGE":4,"_SC_XOPEN_REALTIME":130,"EAI_NONAME":-2,"_PC_PIPE_BUF":5,"EROFS":30,"EM_PROXIED_ATEXIT":110,"ECONNREFUSED":111,"_SC_2_PBS_ACCOUNTING":169,"EMSCRIPTEN_EVENT_FOCUS":13,"AUDIO_S16SYS":32784,"ENETDOWN":100,"ENOEXEC":8,"ENOSPC":28,"EBADF":9,"EAI_SOCKTYPE":-7,"EDOTDOT":73,"_SC_THREAD_ATTR_STACKSIZE":78,"EBADFD":77,"O_ACCMODE":2097155,"EBADR":53,"_SC_2_VERSION":46,"S_IFCHR":8192,"SDL_PATCHLEVEL":0,"ABMON_12":131097,"PTHREAD_KEYS_MAX":128,"ENOMEDIUM":123,"EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE":0,"AUDIO_U16MSB":4112,"EMSCRIPTEN_FULLSCREEN_FILTERING_BILINEAR":2,"_SC_2_CHAR_TERM":95,"EMSCRIPTEN_EVENT_TOUCHEND":23,"_SC_AIO_LISTIO_MAX":23,"_SC_BC_SCALE_MAX":38,"ENOTBLK":15,"EAI_BADFLAGS":-1,"EOVERFLOW":75,"EMSCRIPTEN_EVENT_DBLCLICK":7,"SDL_AUDIO_MASK_SIGNED":32768,"EMSCRIPTEN_FULLSCREEN_FILTERING_NEAREST":1,"ABMON_11":131096,"ABMON_10":131095,"AT_FDCWD":-100,"EM_HTML5_SHORT_STRING_LEN_BYTES":32}} \ No newline at end of file +{"structs":{"utsname":{"sysname":0,"nodename":65,"domainname":325,"machine":260,"version":195,"release":130,"__size__":390},"sockaddr":{"sa_data":2,"sa_family":0,"__size__":16},"addrinfo":{"ai_flags":0,"ai_next":28,"ai_canonname":24,"ai_socktype":8,"ai_addr":20,"ai_protocol":12,"ai_family":4,"ai_addrlen":16,"__size__":32},"timespec":{"tv_sec":0,"tv_nsec":4,"__size__":8},"utimbuf":{"modtime":4,"actime":0,"__size__":8},"EmscriptenVisibilityChangeEvent":{"hidden":0,"visibilityState":4,"__size__":8},"SDL_MouseButtonEvent":{"timestamp":4,"button":16,"state":17,"windowID":8,"which":12,"y":24,"x":20,"padding2":19,"type":0,"padding1":18,"__size__":28},"sockaddr_in":{"sin_port":2,"sin_addr":{"s_addr":4,"__size__":4},"sin_family":0,"sin_zero":8,"__size__":16},"pthread":{"tsd":116,"attr":120,"canceldisable":72,"locale":188,"threadStatus":0,"tsd_used":60,"pid":56,"stack":92,"cancelasync":76,"tid":52,"threadExitCode":4,"detached":80,"profilerBlock":20,"self":24,"stack_size":96,"__size__":244},"WebVRFieldOfView":{"leftDegrees":24,"upDegrees":0,"downDegrees":16,"rightDegrees":8,"__size__":32},"SDL_KeyboardEvent":{"repeat":9,"keysym":12,"state":8,"windowID":4,"__size__":28,"type":0,"padding3":11,"padding2":10},"SDL_MouseMotionEvent":{"yrel":32,"timestamp":4,"state":16,"windowID":8,"which":12,"xrel":28,"y":24,"x":20,"type":0,"__size__":36},"SDL_Rect":{"y":4,"x":0,"h":12,"w":8,"__size__":16},"itimerspec":{"it_interval":{"tv_sec":0,"tv_nsec":4,"__size__":8},"it_value":{"tv_sec":8,"tv_nsec":12,"__size__":8},"__size__":16},"iovec":{"iov_len":4,"iov_base":0,"__size__":8},"timezone":{"tz_dsttime":4,"tz_minuteswest":0,"__size__":8},"flock":{"l_whence":2,"l_type":0,"l_start":4,"__size__":16,"l_len":8,"l_pid":12},"EmscriptenOrientationChangeEvent":{"orientationIndex":0,"orientationAngle":4,"__size__":8},"EmscriptenMouseEvent":{"clientX":16,"clientY":20,"targetX":52,"buttons":42,"timestamp":0,"button":40,"targetY":56,"altKey":32,"canvasY":64,"metaKey":36,"movementX":44,"movementY":48,"shiftKey":28,"ctrlKey":24,"screenY":12,"screenX":8,"canvasX":60,"__size__":72},"SDL_ResizeEvent":{"h":8,"type":0,"w":4,"__size__":12},"tms":{"tms_stime":4,"tms_utime":0,"tms_cstime":12,"tms_cutime":8,"__size__":16},"SDL_Color":{"unused":3,"r":0,"b":2,"g":1,"__size__":4},"EmscriptenKeyboardEvent":{"code":32,"charValue":120,"locale":88,"shiftKey":72,"altKey":76,"which":160,"metaKey":80,"location":64,"key":0,"ctrlKey":68,"charCode":152,"keyCode":156,"repeat":84,"__size__":164},"rusage":{"ru_msgrcv":56,"ru_utime":{"tv_sec":0,"tv_usec":4,"__size__":8},"ru_isrss":28,"ru_stime":{"tv_sec":8,"tv_usec":12,"__size__":8},"ru_nsignals":60,"ru_nivcsw":68,"ru_msgsnd":52,"ru_nswap":40,"ru_minflt":32,"ru_nvcsw":64,"ru_ixrss":20,"ru_inblock":44,"ru_idrss":24,"ru_maxrss":16,"ru_oublock":48,"ru_majflt":36,"__size__":136},"div_t":{"quot":0,"rem":4,"__size__":8},"timeval":{"tv_sec":0,"tv_usec":4,"__size__":8},"rlimit":{"rlim_cur":0,"rlim_max":8,"__size__":16},"in6_addr":{"__in6_union":{"__s6_addr16":0,"__s6_addr":0,"__s6_addr32":0,"__size__":16},"__size__":16},"tm":{"tm_sec":0,"tm_hour":8,"tm_mday":12,"tm_isdst":32,"tm_year":20,"tm_zone":40,"tm_mon":16,"tm_yday":28,"tm_gmtoff":36,"tm_wday":24,"tm_min":4,"__size__":44},"EmscriptenWebGLContextAttributes":{"majorVersion":32,"stencil":8,"preserveDrawingBuffer":20,"failIfMajorPerformanceCaveat":28,"explicitSwapControl":44,"antialias":12,"depth":4,"minorVersion":36,"premultipliedAlpha":16,"enableExtensionsByDefault":40,"alpha":0,"preferLowPowerToHighPerformance":24,"__size__":48},"EmscriptenBatteryEvent":{"dischargingTime":8,"level":16,"charging":24,"chargingTime":0,"__size__":32},"protoent":{"p_aliases":4,"p_proto":8,"p_name":0,"__size__":12},"SDL_Surface":{"userdata":24,"locked":28,"clip_rect":36,"format":4,"h":12,"refcount":56,"map":52,"flags":0,"w":8,"pitch":16,"lock_data":32,"pixels":20,"__size__":60},"EmscriptenTouchEvent":{"touches":20,"shiftKey":8,"altKey":12,"metaKey":16,"ctrlKey":4,"__size__":1684,"numTouches":0},"EmscriptenFocusEvent":{"id":128,"nodeName":0,"__size__":256},"sockaddr_in6":{"sin6_family":0,"sin6_flowinfo":4,"sin6_scope_id":24,"sin6_addr":{"__in6_union":{"__s6_addr16":8,"__s6_addr":8,"__s6_addr32":8,"__size__":16},"__size__":16},"__size__":28,"sin6_port":2},"SDL_JoyAxisEvent":{"__size__":12,"type":0,"value":8,"which":4,"padding2":7,"padding1":6,"axis":5},"netent":{"n_name":0,"n_net":12,"n_addrtype":8,"n_aliases":4,"__size__":16},"SDL_PixelFormat":{"palette":4,"Gloss":29,"Bmask":20,"Bloss":30,"Rloss":28,"format":0,"Gshift":33,"Aloss":31,"BitsPerPixel":8,"refcount":36,"next":40,"padding":10,"Rmask":12,"Bshift":34,"Gmask":16,"BytesPerPixel":9,"Amask":24,"Rshift":32,"Ashift":35,"__size__":44},"SDL_JoyButtonEvent":{"type":0,"button":5,"state":6,"which":4,"padding1":7,"__size__":8},"EmscriptenPointerlockChangeEvent":{"id":132,"nodeName":4,"isActive":0,"__size__":260},"in_addr":{"s_addr":0,"__size__":4},"EmscriptenDeviceOrientationEvent":{"timestamp":0,"beta":16,"alpha":8,"__size__":40,"gamma":24,"absolute":32},"libc":{"global_locale":40,"__size__":64},"SDL_WindowEvent":{"data2":16,"type":0,"data1":12,"windowID":4,"__size__":20,"padding1":9,"event":8,"padding3":11,"padding2":10},"SDL_Keysym":{"scancode":0,"mod":8,"unicode":12,"sym":4,"__size__":16},"cmsghdr":{"cmsg_type":8,"cmsg_level":4,"cmsg_len":0,"__size__":12},"EmscriptenUiEvent":{"windowInnerWidth":12,"detail":0,"scrollLeft":32,"documentBodyClientHeight":8,"windowInnerHeight":16,"scrollTop":28,"windowOuterHeight":24,"windowOuterWidth":20,"documentBodyClientWidth":4,"__size__":36},"thread_profiler_block":{"threadStatus":0,"timeSpentInStatus":16,"currentStatusStartTime":8,"name":72,"__size__":104},"stat":{"st_rdev":28,"st_mtim":{"tv_sec":56,"tv_nsec":60,"__size__":8},"st_blocks":44,"st_atim":{"tv_sec":48,"tv_nsec":52,"__size__":8},"st_nlink":16,"__st_ino_truncated":8,"st_ctim":{"tv_sec":64,"tv_nsec":68,"__size__":8},"st_mode":12,"st_blksize":40,"__st_dev_padding":4,"st_dev":0,"st_size":36,"st_gid":24,"__st_rdev_padding":32,"st_uid":20,"st_ino":72,"__size__":76},"pollfd":{"fd":0,"events":4,"revents":6,"__size__":8},"WebVRPositionState":{"linearVelocity":{"y":56,"x":48,"z":64,"w":72,"__size__":32},"orientation":{"y":128,"x":120,"z":136,"w":144,"__size__":32},"timeStamp":0,"angularVelocity":{"y":160,"x":152,"z":168,"w":176,"__size__":32},"hasPosition":8,"angularAcceleration":{"y":192,"x":184,"z":200,"w":208,"__size__":32},"linearAcceleration":{"y":88,"x":80,"z":96,"w":104,"__size__":32},"hasOrientation":112,"position":{"y":24,"x":16,"z":32,"w":40,"__size__":32},"__size__":216},"dirent":{"d_name":11,"d_off":4,"d_ino":0,"d_reclen":8,"d_type":10,"__size__":268},"EmscriptenTouchPoint":{"clientX":12,"clientY":16,"identifier":0,"targetX":36,"targetY":40,"isChanged":28,"canvasY":48,"canvasX":44,"pageX":20,"pageY":24,"screenY":8,"screenX":4,"onTarget":32,"__size__":52},"EmscriptenDeviceMotionEvent":{"timestamp":0,"accelerationIncludingGravityZ":48,"accelerationIncludingGravityX":32,"accelerationIncludingGravityY":40,"accelerationY":16,"accelerationX":8,"rotationRateBeta":64,"accelerationZ":24,"rotationRateGamma":72,"rotationRateAlpha":56,"__size__":80},"SDL_AudioSpec":{"padding":10,"userdata":20,"format":4,"channels":6,"callback":16,"samples":8,"freq":0,"size":12,"silence":7,"__size__":24},"hostent":{"h_addrtype":8,"h_addr_list":16,"h_name":0,"__size__":20,"h_aliases":4,"h_length":12},"SDL_MouseWheelEvent":{"timestamp":4,"windowID":8,"which":12,"y":20,"x":16,"type":0,"__size__":24},"linger":{"l_onoff":0,"l_linger":4,"__size__":8},"SDL_version":{"major":0,"patch":2,"minor":1,"__size__":3},"statvfs":{"f_bsize":0,"f_bavail":16,"f_fsid":32,"f_favail":28,"f_files":20,"f_frsize":4,"f_blocks":8,"f_ffree":24,"f_bfree":12,"f_flag":40,"f_namemax":44,"__size__":72},"EmscriptenFullscreenChangeEvent":{"elementWidth":264,"screenWidth":272,"nodeName":8,"elementHeight":268,"fullscreenEnabled":4,"screenHeight":276,"isFullscreen":0,"id":136,"__size__":280},"EmscriptenWheelEvent":{"deltaX":72,"deltaY":80,"deltaZ":88,"deltaMode":96,"mouse":0,"__size__":104},"WebVRIntRect":{"y":4,"x":0,"height":12,"width":8,"__size__":16},"SDL_TouchFingerEvent":{"timestamp":4,"dy":36,"touchId":8,"pressure":40,"dx":32,"type":0,"y":28,"x":24,"fingerId":16,"__size__":48},"SDL_AudioCVT":{"len_ratio":32,"len_cvt":24,"rate_incr":8,"filters":40,"len":20,"needed":0,"filter_index":80,"src_format":4,"len_mult":28,"__size__":88,"buf":16,"dst_format":6},"WebVRPoint":{"y":8,"x":0,"z":16,"w":24,"__size__":32},"timeb":{"dstflag":8,"timezone":6,"time":0,"millitm":4,"__size__":12},"statfs":{"f_bsize":4,"f_bavail":16,"f_fsid":28,"f_files":20,"f_frsize":40,"f_namelen":36,"f_blocks":8,"f_ffree":24,"f_bfree":12,"f_flags":44,"__size__":64},"msghdr":{"msg_iov":8,"msg_iovlen":12,"msg_namelen":4,"msg_controllen":20,"msg_flags":24,"msg_name":0,"msg_control":16,"__size__":28},"WebVREyeParameters":{"currentFieldOfView":{"leftDegrees":152,"upDegrees":128,"downDegrees":144,"rightDegrees":136,"__size__":32},"recommendedFieldOfView":{"leftDegrees":88,"upDegrees":64,"downDegrees":80,"rightDegrees":72,"__size__":32},"eyeTranslation":{"y":104,"x":96,"z":112,"w":120,"__size__":32},"renderRect":{"y":164,"x":160,"height":172,"width":168,"__size__":16},"minimumFieldOfView":{"leftDegrees":24,"upDegrees":0,"downDegrees":16,"rightDegrees":8,"__size__":32},"maximumFieldOfView":{"leftDegrees":56,"upDegrees":32,"downDegrees":48,"rightDegrees":40,"__size__":32},"__size__":176},"SDL_Palette":{"ncolors":0,"colors":4,"version":8,"refcount":12,"__size__":16},"EmscriptenFullscreenStrategy":{"canvasResizedCallbackUserData":16,"canvasResolutionScaleMode":4,"scaleMode":0,"canvasResizedCallback":12,"filteringMode":8,"__size__":20},"EmscriptenGamepadEvent":{"index":1300,"analogButton":528,"timestamp":0,"numButtons":12,"mapping":1368,"digitalButton":1040,"connected":1296,"numAxes":8,"__size__":1432,"id":1304,"axis":16},"SDL_TextInputEvent":{"text":8,"windowID":4,"type":0,"__size__":40}},"defines":{"ETXTBSY":26,"EOF":-1,"EMSCRIPTEN_EVENT_MOUSEOVER":35,"ETOOMANYREFS":109,"ENAMETOOLONG":36,"ENOPKG":65,"UUID_TYPE_DCE_TIME":1,"_SC_XOPEN_LEGACY":129,"_SC_XOPEN_VERSION":89,"F_UNLCK":2,"_SC_BC_DIM_MAX":37,"EL3HLT":46,"S_IFDIR":16384,"EMSCRIPTEN_EVENT_KEYPRESS":1,"EINPROGRESS":115,"_SC_BARRIERS":133,"EMSCRIPTEN_EVENT_TOUCHMOVE":24,"SDL_AUDIO_ALLOW_FREQUENCY_CHANGE":1,"AUDIO_U8":8,"EAI_AGAIN":-3,"_PC_MAX_CANON":1,"ENOTSUP":95,"EFBIG":27,"O_CREAT":64,"EMSCRIPTEN_EVENT_POINTERLOCKERROR":38,"_SC_2_PBS_LOCATE":170,"EM_PROXIED_SETENV":113,"_CS_POSIX_V6_LP64_OFF64_LIBS":1126,"ENOLINK":67,"ABDAY_7":131078,"ABDAY_6":131077,"ABDAY_5":131076,"ABDAY_4":131075,"ABDAY_3":131074,"ABDAY_2":131073,"ABDAY_1":131072,"EL3RST":47,"YESEXPR":327680,"_SC_V6_ILP32_OFFBIG":177,"SDL_MINOR_VERSION":3,"EM_PROXIED_CLEARENV":112,"_SC_MEMLOCK":17,"ENOTUNIQ":76,"EMSCRIPTEN_RESULT_FAILED":-6,"ABMON_1":131086,"ELNRNG":48,"UUID_VARIANT_MICROSOFT":2,"EMSCRIPTEN_EVENT_TOUCHSTART":22,"ENOANO":55,"EMSCRIPTEN_EVENT_FOCUSIN":14,"EMSCRIPTEN_EVENT_MOUSEUP":6,"ENOPROTOOPT":92,"POLLIN":1,"S_IALLUGO":4095,"_SC_THREAD_KEYS_MAX":74,"EM_THREAD_STATUS_WAITPROXY":5,"O_RDWR":2,"EREMCHG":78,"EMSCRIPTEN_EVENT_GAMEPADDISCONNECTED":27,"_SC_2_PBS":168,"_SC_TRACE_INHERIT":183,"_SC_REGEXP":155,"_CS_POSIX_V6_LP64_OFF64_CFLAGS":1124,"_SC_DELAYTIMER_MAX":26,"S_IWUGO":146,"S_IFREG":32768,"F_GETLK64":12,"O_DIRECTORY":65536,"EM_PROXIED_UTIMES":13,"POLLHUP":16,"S_IFMT":61440,"F_SETLK64":13,"_SC_XOPEN_CRYPT":92,"_SC_CLOCK_SELECTION":137,"_PC_CHOWN_RESTRICTED":6,"E2BIG":7,"ABMON_3":131088,"AM_STR":131110,"SDL_AUDIO_MASK_ENDIAN":4096,"ALT_DIGITS":131119,"EHOSTDOWN":112,"EBFONT":59,"ENOTEMPTY":39,"AUDIO_S16":32784,"TIOCGPGRP":21519,"EBUSY":16,"_SC_MQ_PRIO_MAX":28,"_SC_PAGE_SIZE":30,"EADDRINUSE":98,"ENOTSOCK":88,"PM_STR":131111,"O_WRONLY":1,"_SC_STREAM_MAX":5,"ABMON_9":131094,"ELIBACC":79,"S_IFIFO":4096,"EDQUOT":122,"EAI_SYSTEM":-11,"ENOENT":2,"_SC_TIMERS":11,"O_SYNC":1052672,"SEEK_END":2,"EM_THREAD_STATUS_FINISHED":6,"_PC_REC_MIN_XFER_SIZE":16,"_PC_PATH_MAX":4,"_SC_SPORADIC_SERVER":160,"ECOMM":70,"_SC_NPROCESSORS_ONLN":84,"_CS_POSIX_V6_LPBIG_OFFBIG_LIBS":1130,"_PC_MAX_INPUT":2,"_SC_VERSION":29,"TCGETS":21505,"_SC_CLK_TCK":2,"ABMON_2":131087,"EXFULL":54,"ABMON_7":131092,"ABMON_6":131091,"ABMON_5":131090,"ABMON_4":131089,"ENOTDIR":20,"ABMON_8":131093,"_SC_AIO_MAX":24,"ERA":131116,"EM_PROXIED_UNSETENV":114,"_SC_THREAD_PRIO_INHERIT":80,"_PC_2_SYMLINKS":20,"_SC_XBS5_LP64_OFF64":127,"EMSCRIPTEN_EVENT_BATTERYLEVELCHANGE":30,"ENETRESET":102,"EAFNOSUPPORT":97,"MON_2":131099,"MON_3":131100,"MON_1":131098,"EMSCRIPTEN_EVENT_DEVICEORIENTATION":16,"MON_7":131104,"MON_4":131101,"MON_5":131102,"_SC_SPAWN":159,"MON_8":131105,"MON_9":131106,"_CS_POSIX_V6_ILP32_OFF32_LDFLAGS":1117,"S_IFSOCK":49152,"S_IRUGO":292,"SOCK_DGRAM":2,"POLLERR":8,"EINVAL":22,"_CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS":1128,"POLLRDNORM":64,"AUDIO_F32SYS":33056,"_SC_TRACE_SYS_MAX":244,"AI_V4MAPPED":8,"AI_NUMERICHOST":4,"_CS_POSIX_V6_WIDTH_RESTRICTED_ENVS":1,"EHOSTUNREACH":113,"ENOCSI":50,"EPROTONOSUPPORT":93,"_SC_AIO_PRIO_DELTA_MAX":25,"_SC_MONOTONIC_CLOCK":149,"ETIME":62,"ENOTTY":25,"_SC_XOPEN_ENH_I18N":93,"EAI_SERVICE":-8,"EAGAIN":11,"F_SETLKW64":14,"EMSGSIZE":90,"ELIBEXEC":83,"_SC_MEMORY_PROTECTION":19,"EMSCRIPTEN_FULLSCREEN_SCALE_CENTER":3,"SDL_AUDIO_ALLOW_FORMAT_CHANGE":2,"ECANCELED":125,"_SC_SPIN_LOCKS":154,"_SC_XOPEN_SHM":94,"_PC_LINK_MAX":0,"TIOCSPGRP":21520,"EOPNOTSUPP":95,"EMSCRIPTEN_EVENT_MOUSEENTER":33,"EAI_FAIL":-4,"NOEXPR":327681,"_SC_FSYNC":15,"_SC_GETGR_R_SIZE_MAX":69,"EDESTADDRREQ":89,"EADDRNOTAVAIL":99,"AUDIO_S32SYS":32800,"_SC_TRACE_NAME_MAX":243,"_SC_BC_BASE_MAX":36,"EMSCRIPTEN_EVENT_CANVASRESIZED":37,"EPERM":1,"EAI_FAMILY":-6,"O_NOFOLLOW":131072,"SOCK_STREAM":1,"O_APPEND":1024,"_SC_XOPEN_STREAMS":246,"_SC_GETPW_R_SIZE_MAX":70,"MON_6":131103,"EPROTOTYPE":91,"_SC_CPUTIME":138,"EISCONN":106,"_SC_XBS5_ILP32_OFFBIG":126,"S_IFBLK":24576,"T_FMT_AMPM":131115,"SDL_PIXELFORMAT_RGBA8888":-2042224636,"F_SETLKW":14,"SDL_TOUCH_MOUSEID":-1,"EMSCRIPTEN_EVENT_SCROLL":11,"ELOOP":40,"_SC_OPEN_MAX":4,"_SC_2_FORT_RUN":50,"EMSCRIPTEN_EVENT_VISIBILITYCHANGE":21,"EREMOTE":66,"_SC_RE_DUP_MAX":44,"_SC_THREAD_PRIO_PROTECT":81,"_SC_2_PBS_CHECKPOINT":175,"_SC_2_PBS_TRACK":172,"MON_10":131107,"MON_11":131108,"MON_12":131109,"_SC_XBS5_LPBIG_OFFBIG":128,"_SC_THREAD_PROCESS_SHARED":82,"AF_INET":2,"_SC_SHARED_MEMORY_OBJECTS":22,"F_GETFD":1,"EMSCRIPTEN_EVENT_DEVICEMOTION":17,"SDL_MIX_MAXVOLUME":128,"_PC_ALLOC_SIZE_MIN":18,"TCSETS":21506,"ELIBMAX":82,"_SC_READER_WRITER_LOCKS":153,"EMULTIHOP":72,"IPPROTO_TCP":6,"_SC_PHYS_PAGES":85,"_SC_MEMLOCK_RANGE":18,"_SC_PRIORITY_SCHEDULING":10,"T_FMT":131114,"AI_ALL":16,"_PC_VDISABLE":8,"THOUSEP":65537,"_SC_TRACE_EVENT_FILTER":182,"ERA_T_FMT":131121,"_SC_THREAD_ATTR_STACKADDR":77,"_SC_THREAD_THREADS_MAX":76,"_SC_LOGIN_NAME_MAX":71,"_SC_2_C_BIND":47,"_PC_NO_TRUNC":7,"ECONNABORTED":103,"EMSCRIPTEN_RESULT_SUCCESS":0,"_SC_SHELL":157,"EFAULT":14,"O_LARGEFILE":32768,"_SC_V6_LP64_OFF64":178,"_CS_GNU_LIBC_VERSION":2,"ENODATA":61,"_SC_SEM_VALUE_MAX":33,"_SC_MQ_OPEN_MAX":27,"AI_ADDRCONFIG":32,"_SC_HOST_NAME_MAX":180,"_SC_THREAD_STACK_MIN":75,"_SC_TIMEOUTS":164,"POLLOUT":4,"_SC_IPV6":235,"_SC_CHILD_MAX":1,"EDOM":33,"_SC_2_PBS_MESSAGE":171,"EILSEQ":84,"UUID_VARIANT_DCE":1,"_SC_2_C_DEV":48,"_SC_TIMER_MAX":35,"FP_ZERO":2,"EPFNOSUPPORT":96,"ENONET":64,"ECHRNG":44,"_SC_THREADS":67,"_SC_REALTIME_SIGNALS":9,"CLOCKS_PER_SEC":1000000,"ERA_D_T_FMT":131120,"ESRCH":3,"D_FMT":131113,"POLLPRI":2,"_PC_ASYNC_IO":10,"DAY_2":131080,"DAY_3":131081,"DAY_1":131079,"DAY_6":131084,"DAY_7":131085,"DAY_4":131082,"DAY_5":131083,"_SC_SYNCHRONIZED_IO":14,"EL2HLT":51,"EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF":1,"IPPROTO_UDP":17,"_SC_MAPPED_FILES":16,"EL2NSYNC":45,"_SC_NGROUPS_MAX":3,"ENOMSG":42,"EISDIR":21,"_SC_SEMAPHORES":21,"AI_NUMERICSERV":1024,"EDEADLOCK":35,"EMSCRIPTEN_EVENT_WEBGLCONTEXTLOST":31,"EMSCRIPTEN_EVENT_BATTERYCHARGINGCHANGE":29,"AUDIO_F32LSB":33056,"_SC_COLL_WEIGHTS_MAX":40,"SO_ERROR":4,"ECONNRESET":104,"AT_SYMLINK_NOFOLLOW":256,"_SC_TRACE_LOG":184,"AUDIO_U16LSB":16,"ESTRPIPE":86,"ESHUTDOWN":108,"_PC_SOCK_MAXBUF":12,"_CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS":1129,"EDEADLK":35,"_CS_POSIX_V6_ILP32_OFF32_CFLAGS":1116,"EBADRQC":56,"_SC_THREAD_DESTRUCTOR_ITERATIONS":73,"_SC_TYPED_MEMORY_OBJECTS":165,"_SC_TRACE_EVENT_NAME_MAX":242,"_SC_BC_STRING_MAX":39,"_SC_2_SW_DEV":51,"FP_NAN":0,"F_SETOWN":8,"EMSCRIPTEN_EVENT_RESIZE":10,"_SC_ARG_MAX":0,"_SC_THREAD_PRIORITY_SCHEDULING":79,"F_GETLK":12,"EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF":2,"FIONREAD":21531,"_SC_THREAD_CPUTIME":139,"EMSCRIPTEN_EVENT_POINTERLOCKCHANGE":20,"EM_THREAD_STATUS_NOTSTARTED":0,"_CS_POSIX_V6_ILP32_OFF32_LIBS":1118,"EUNATCH":49,"AUDIO_S8":32776,"AUDIO_S32LSB":32800,"SDL_AUDIO_MASK_BITSIZE":255,"ERA_D_FMT":131118,"AUDIO_F32MSB":37152,"_CS_POSIX_V6_LP64_OFF64_LDFLAGS":1125,"FP_INFINITE":1,"ECHILD":10,"EAI_MEMORY":-10,"EM_PROXIED_FPATHCONF":46,"O_TRUNC":512,"ETIMEDOUT":110,"S_IRWXO":7,"EALREADY":114,"ENXIO":6,"NI_NUMERICHOST":1,"EMFILE":24,"F_GETOWN":9,"EMLINK":31,"F_SETFD":2,"ENFILE":23,"EM_PROXIED_SYSCONF":72,"EM_PROXIED_GETENV":111,"SDL_MAJOR_VERSION":1,"ENOMEM":12,"ENOSR":63,"SDL_AUDIO_ALLOW_ANY_CHANGE":7,"EOWNERDEAD":130,"_PC_PRIO_IO":11,"ELIBSCN":81,"_SC_V6_LPBIG_OFFBIG":179,"EM_PROXIED_CHROOT":37,"EMSCRIPTEN_EVENT_CLICK":4,"_SC_EXPR_NEST_MAX":42,"_CS_POSIX_V6_ILP32_OFFBIG_CFLAGS":1120,"EBADSLT":57,"AUDIO_S16MSB":36880,"S_ISVTX":512,"EMSCRIPTEN_RESULT_DEFERRED":1,"EMSCRIPTEN_RESULT_UNKNOWN_TARGET":-4,"S_IRWXUGO":511,"EM_PROXIED_TZSET":119,"_CS_GNU_LIBPTHREAD_VERSION":3,"_PC_REC_MAX_XFER_SIZE":15,"UUID_VARIANT_OTHER":3,"EMSCRIPTEN_EVENT_WEBGLCONTEXTRESTORED":32,"EM_PROXIED_PTHREAD_CREATE":137,"EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT":0,"RADIXCHAR":65536,"AF_UNSPEC":0,"ENOSTR":60,"W_OK":2,"AUDIO_S32":32800,"EACCES":13,"R_OK":4,"EM_HTML5_MEDIUM_STRING_LEN_BYTES":64,"_SC_V6_ILP32_OFF32":176,"EMSCRIPTEN_EVENT_FULLSCREENCHANGE":19,"EIO":5,"EMSCRIPTEN_RESULT_NOT_SUPPORTED":-1,"EM_PROXIED_CONFSTR":68,"_SC_SIGQUEUE_MAX":34,"EWOULDBLOCK":11,"AUDIO_U16SYS":16,"EMSCRIPTEN_EVENT_FOCUSOUT":15,"EAI_OVERFLOW":-12,"SDL_AUDIO_MASK_DATATYPE":256,"MAP_PRIVATE":2,"_SC_TZNAME_MAX":6,"_CS_PATH":0,"SEEK_SET":0,"EBADE":52,"EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED":-2,"INT_MAX":2147483647,"EMSCRIPTEN_EVENT_KEYDOWN":2,"EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH":1,"_SC_MESSAGE_PASSING":20,"_SC_THREAD_SAFE_FUNCTIONS":68,"_SC_SYMLOOP_MAX":173,"_PC_NAME_MAX":3,"O_EXCL":128,"_SC_TRACE_USER_EVENT_MAX":245,"_PC_REC_XFER_ALIGN":17,"EMSCRIPTEN_FULLSCREEN_SCALE_DEFAULT":0,"_SC_RAW_SOCKETS":236,"_SC_2_UPE":97,"EMSCRIPTEN_RESULT_NO_DATA":-7,"EMSCRIPTEN_EVENT_BLUR":12,"_SC_TTY_NAME_MAX":72,"_SC_RTSIG_MAX":31,"ESOCKTNOSUPPORT":94,"_SC_PRIORITIZED_IO":13,"_SC_XOPEN_UNIX":91,"CODESET":14,"EPIPE":32,"_PC_REC_INCR_XFER_SIZE":14,"F_SETLK":13,"_PC_FILESIZEBITS":13,"_SC_XBS5_ILP32_OFF32":125,"RAND_MAX":2147483647,"EM_PROXIED_SYSCALL":138,"ENOLCK":37,"EM_PROXIED_PUTENV":115,"AUDIO_U16":16,"EMSCRIPTEN_EVENT_MOUSELEAVE":34,"EMSCRIPTEN_EVENT_MOUSEOUT":36,"_PC_SYNC_IO":9,"EEXIST":17,"FP_NORMAL":4,"O_RDONLY":0,"_SC_SEM_NSEMS_MAX":32,"_SC_IOV_MAX":60,"EPROTO":71,"_SC_TRACE":181,"ESRMNT":69,"EM_HTML5_LONG_STRING_LEN_BYTES":128,"_CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS":1121,"INADDR_LOOPBACK":2130706433,"EXDEV":18,"TIOCGWINSZ":21523,"EM_THREAD_STATUS_RUNNING":1,"EMSCRIPTEN_EVENT_BEFOREUNLOAD":28,"EM_THREAD_STATUS_WAITFUTEX":3,"EMSCRIPTEN_RESULT_INVALID_TARGET":-3,"_SC_THREAD_SPORADIC_SERVER":161,"F_SETFL":4,"AI_PASSIVE":1,"ELIBBAD":80,"_SC_LINE_MAX":43,"D_T_FMT":131112,"ERANGE":34,"ESTALE":116,"F_DUPFD":0,"AUDIO_F32":33056,"CLOCK_MONOTONIC":1,"EMSCRIPTEN_EVENT_GAMEPADCONNECTED":26,"F_GETOWN_EX":16,"_SC_ASYNCHRONOUS_IO":12,"ENOTRECOVERABLE":131,"ENOBUFS":105,"EIDRM":43,"EMSCRIPTEN_EVENT_ORIENTATIONCHANGE":18,"CRNCYSTR":262159,"EINTR":4,"EADV":68,"ENOSYS":38,"_CS_POSIX_V6_ILP32_OFFBIG_LIBS":1122,"EM_PROXIED_UTIME":12,"F_GETFL":3,"S_IXUGO":73,"_SC_2_FORT_DEV":49,"SDL_COMPILEDVERSION":1300,"EBADMSG":74,"EUSERS":87,"CLOCK_REALTIME":0,"ENODEV":19,"AF_INET6":10,"_SC_ATEXIT_MAX":87,"_SC_SAVED_IDS":8,"SOL_SOCKET":1,"S_IFLNK":40960,"AUDIO_S16LSB":32784,"POLLNVAL":32,"EMSCRIPTEN_EVENT_TOUCHCANCEL":25,"EMSCRIPTEN_RESULT_INVALID_PARAM":-5,"EMSCRIPTEN_EVENT_MOUSEDOWN":5,"EM_THREAD_STATUS_SLEEPING":2,"_SC_JOB_CONTROL":7,"NI_NAMEREQD":8,"EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT":2,"EMSCRIPTEN_EVENT_MOUSEMOVE":8,"UUID_TYPE_DCE_RANDOM":4,"ENOTCONN":107,"_SC_ADVISORY_INFO":132,"ENETUNREACH":101,"_SC_XOPEN_REALTIME_THREADS":131,"_SC_2_LOCALEDEF":52,"_PC_SYMLINK_MAX":19,"X_OK":1,"EMSCRIPTEN_EVENT_KEYUP":3,"AI_CANONNAME":2,"UUID_VARIANT_NCS":0,"ESPIPE":29,"AUDIO_S32MSB":36896,"EMSCRIPTEN_EVENT_WHEEL":9,"SDL_AUDIO_ALLOW_CHANNELS_CHANGE":4,"_SC_XOPEN_REALTIME":130,"EAI_NONAME":-2,"_PC_PIPE_BUF":5,"EROFS":30,"EM_PROXIED_ATEXIT":110,"ECONNREFUSED":111,"_SC_2_PBS_ACCOUNTING":169,"EMSCRIPTEN_EVENT_FOCUS":13,"AUDIO_S16SYS":32784,"ENETDOWN":100,"ENOEXEC":8,"ENOSPC":28,"EBADF":9,"EAI_SOCKTYPE":-7,"EDOTDOT":73,"_SC_THREAD_ATTR_STACKSIZE":78,"EBADFD":77,"O_ACCMODE":2097155,"EBADR":53,"_SC_2_VERSION":46,"S_IFCHR":8192,"SDL_PATCHLEVEL":0,"ABMON_12":131097,"PTHREAD_KEYS_MAX":128,"ENOMEDIUM":123,"EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE":0,"AUDIO_U16MSB":4112,"EMSCRIPTEN_FULLSCREEN_FILTERING_BILINEAR":2,"_SC_2_CHAR_TERM":95,"EMSCRIPTEN_EVENT_TOUCHEND":23,"_SC_AIO_LISTIO_MAX":23,"_SC_BC_SCALE_MAX":38,"ENOTBLK":15,"EAI_BADFLAGS":-1,"EOVERFLOW":75,"EMSCRIPTEN_EVENT_DBLCLICK":7,"SDL_AUDIO_MASK_SIGNED":32768,"EMSCRIPTEN_FULLSCREEN_FILTERING_NEAREST":1,"ABMON_11":131096,"ABMON_10":131095,"AT_FDCWD":-100,"EM_HTML5_SHORT_STRING_LEN_BYTES":32}} \ No newline at end of file diff --git a/src/struct_info.json b/src/struct_info.json index d4cbfc1a5eb5c..853e39690712d 100644 --- a/src/struct_info.json +++ b/src/struct_info.json @@ -467,7 +467,8 @@ "F_GETOWN_EX", "F_SETFD", "O_EXCL", - "F_GETFL" + "F_GETFL", + "O_LARGEFILE" ], "structs": {} }, @@ -491,7 +492,8 @@ "TCGETS", "TCSETS", "TIOCGPGRP", - "TIOCSPGRP" + "TIOCSPGRP", + "TIOCGWINSZ" ], "structs": {} }, @@ -1485,7 +1487,17 @@ "tid", "pid", "canceldisable", - "cancelasync" + "cancelasync", + "locale" + ] + }, + "defines": [] + }, + { + "file": "../lib/libc/musl/src/internal/libc.h", + "structs": { + "libc": [ + "global_locale" ] }, "defines": [] diff --git a/system/include/emscripten/threading.h b/system/include/emscripten/threading.h index a23b240a124b4..6d97db5bff9a4 100644 --- a/system/include/emscripten/threading.h +++ b/system/include/emscripten/threading.h @@ -80,9 +80,9 @@ uint16_t emscripten_atomic_xor_u16(void/*uint16_t*/ *addr, uint16_t val); uint32_t emscripten_atomic_xor_u32(void/*uint32_t*/ *addr, uint32_t val); uint64_t emscripten_atomic_xor_u64(void/*uint64_t*/ *addr, uint64_t val); // Emulated with locks, very slow!! -int emscripten_futex_wait(void/*uint32_t*/ *addr, uint32_t val, double maxWaitMilliseconds); -int emscripten_futex_wake(void/*uint32_t*/ *addr, int count); -int emscripten_futex_wake_or_requeue(void/*uint32_t*/ *addr, int count, void/*uint32_t*/ *addr2, int cmpValue); +int emscripten_futex_wait(volatile void/*uint32_t*/ *addr, uint32_t val, double maxWaitMilliseconds); +int emscripten_futex_wake(volatile void/*uint32_t*/ *addr, int count); +int emscripten_futex_wake_or_requeue(volatile void/*uint32_t*/ *addr, int count, volatile void/*uint32_t*/ *addr2, int cmpValue); typedef union em_variant_val { diff --git a/system/include/libc/aio.h b/system/include/libc/aio.h index d9330ebeb9662..19bc28a9b19e0 100644 --- a/system/include/libc/aio.h +++ b/system/include/libc/aio.h @@ -21,7 +21,7 @@ struct aiocb { struct sigevent aio_sigevent; void *__td; int __lock[2]; - int __err; + volatile int __err; ssize_t __ret; off_t aio_offset; void *__next, *__prev; diff --git a/system/include/libc/alltypes.h.in b/system/include/libc/alltypes.h.in index c4ca5d5254a9d..6a9c105fb6c02 100644 --- a/system/include/libc/alltypes.h.in +++ b/system/include/libc/alltypes.h.in @@ -28,6 +28,7 @@ TYPEDEF _Int64 blkcnt_t; TYPEDEF unsigned _Int64 fsblkcnt_t; TYPEDEF unsigned _Int64 fsfilcnt_t; +TYPEDEF unsigned wint_t; TYPEDEF unsigned long wctype_t; TYPEDEF void * timer_t; @@ -58,6 +59,8 @@ TYPEDEF struct { unsigned __attr[2]; } pthread_rwlockattr_t; TYPEDEF struct _IO_FILE FILE; +TYPEDEF struct __mbstate_t { unsigned __opaque1, __opaque2; } mbstate_t; + TYPEDEF struct __locale_struct * locale_t; TYPEDEF struct __sigset_t { unsigned long __bits[128/sizeof(long)]; } sigset_t; diff --git a/system/include/libc/arpa/nameser.h b/system/include/libc/arpa/nameser.h index b9ee6659ea84d..581925a43367a 100644 --- a/system/include/libc/arpa/nameser.h +++ b/system/include/libc/arpa/nameser.h @@ -1,6 +1,11 @@ #ifndef _ARPA_NAMESER_H #define _ARPA_NAMESER_H +#ifdef __cplusplus +extern "C" { +#endif + +#include #include #define __NAMESER 19991006 @@ -48,6 +53,8 @@ extern const struct _ns_flagdata _ns_flagdata[]; #define ns_msg_end(handle) ((handle)._eom + 0) #define ns_msg_size(handle) ((handle)._eom - (handle)._msg) #define ns_msg_count(handle, section) ((handle)._counts[section] + 0) +#define ns_msg_getflag(handle, flag) \ + (((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift) typedef struct __ns_rr { char name[NS_MAXDNAME]; @@ -296,43 +303,20 @@ typedef enum __ns_cert_types { #define NS_OPT_DNSSEC_OK 0x8000U #define NS_OPT_NSID 3 -#define NS_GET16(s, cp) do { \ - register const unsigned char *t_cp = (const unsigned char *)(cp); \ - (s) = ((uint16_t)t_cp[0] << 8) \ - | ((uint16_t)t_cp[1]) \ - ; \ - (cp) += NS_INT16SZ; \ -} while (0) - -#define NS_GET32(l, cp) do { \ - register const unsigned char *t_cp = (const unsigned char *)(cp); \ - (l) = ((uint32_t)t_cp[0] << 24) \ - | ((uint32_t)t_cp[1] << 16) \ - | ((uint32_t)t_cp[2] << 8) \ - | ((uint32_t)t_cp[3]) \ - ; \ - (cp) += NS_INT32SZ; \ -} while (0) - -#define NS_PUT16(s, cp) do { \ - register uint16_t t_s = (uint16_t)(s); \ - register unsigned char *t_cp = (unsigned char *)(cp); \ - *t_cp++ = t_s >> 8; \ - *t_cp = t_s; \ - (cp) += NS_INT16SZ; \ -} while (0) - -#define NS_PUT32(l, cp) do { \ - register uint32_t t_l = (uint32_t)(l); \ - register unsigned char *t_cp = (unsigned char *)(cp); \ - *t_cp++ = t_l >> 24; \ - *t_cp++ = t_l >> 16; \ - *t_cp++ = t_l >> 8; \ - *t_cp = t_l; \ - (cp) += NS_INT32SZ; \ -} while (0) +#define NS_GET16(s, cp) (void)((s) = ns_get16(((cp)+=2)-2)) +#define NS_GET32(l, cp) (void)((l) = ns_get32(((cp)+=4)-4)) +#define NS_PUT16(s, cp) ns_put16((s), ((cp)+=2)-2) +#define NS_PUT32(l, cp) ns_put32((l), ((cp)+=4)-4) +unsigned ns_get16(const unsigned char *); +unsigned long ns_get32(const unsigned char *); +void ns_put16(unsigned, unsigned char *); +void ns_put32(unsigned long, unsigned char *); +int ns_initparse(const unsigned char *, int, ns_msg *); +int ns_parserr(ns_msg *, ns_sect, int, ns_rr *); +int ns_skiprr(const unsigned char *, const unsigned char *, ns_sect, int); +int ns_name_uncompress(const unsigned char *, const unsigned char *, const unsigned char *, char *, size_t); #define __BIND 19950621 @@ -464,4 +448,8 @@ typedef struct { #define PUTSHORT NS_PUT16 #define PUTLONG NS_PUT32 +#ifdef __cplusplus +} +#endif + #endif diff --git a/system/include/libc/assert.h b/system/include/libc/assert.h index fae53fc447b63..1ae0ea55d20df 100644 --- a/system/include/libc/assert.h +++ b/system/include/libc/assert.h @@ -8,11 +8,15 @@ #define assert(x) ((void)((x) || (__assert_fail(#x, __FILE__, __LINE__, __func__),0))) #endif +#if __STDC_VERSION__ >= 201112L && !defined(__cplusplus) +#define static_assert _Static_assert +#endif + #ifdef __cplusplus extern "C" { #endif -#if __EMSCRIPTEN__ +#ifdef __EMSCRIPTEN__ _Noreturn #endif void __assert_fail (const char *, const char *, int, const char *); diff --git a/system/include/libc/complex.h b/system/include/libc/complex.h index 13a45c57c200e..008b3c7e3b7d6 100644 --- a/system/include/libc/complex.h +++ b/system/include/libc/complex.h @@ -7,9 +7,9 @@ extern "C" { #define complex _Complex #ifdef __GNUC__ -#define _Complex_I (__extension__ 1.0fi) +#define _Complex_I (__extension__ (0.0f+1.0fi)) #else -#define _Complex_I 1.0fi +#define _Complex_I (0.0f+1.0fi) #endif #define I _Complex_I @@ -101,8 +101,9 @@ double creal(double complex); float crealf(float complex); long double creall(long double complex); +#ifndef __cplusplus #define __CIMAG(x, t) \ - ((union { _Complex t __z; t __xy[2]; }){(_Complex t)(x)}.__xy[1]) + (+(union { _Complex t __z; t __xy[2]; }){(_Complex t)(x)}.__xy[1]) #define creal(x) ((double)(x)) #define crealf(x) ((float)(x)) @@ -111,13 +112,20 @@ long double creall(long double complex); #define cimag(x) __CIMAG(x, double) #define cimagf(x) __CIMAG(x, float) #define cimagl(x) __CIMAG(x, long double) +#endif -#define __CMPLX(x, y, t) \ - ((union { _Complex t __z; t __xy[2]; }){.__xy = {(x),(y)}}.__z) - +#if __STDC_VERSION__ >= 201112L +#if defined(_Imaginary_I) +#define __CMPLX(x, y, t) ((t)(x) + _Imaginary_I*(t)(y)) +#elif defined(__clang__) +#define __CMPLX(x, y, t) (+(_Complex t){ (t)(x), (t)(y) }) +#else +#define __CMPLX(x, y, t) (__builtin_complex((t)(x), (t)(y))) +#endif #define CMPLX(x, y) __CMPLX(x, y, double) #define CMPLXF(x, y) __CMPLX(x, y, float) #define CMPLXL(x, y) __CMPLX(x, y, long double) +#endif #ifdef __cplusplus } diff --git a/system/include/libc/ctype.h b/system/include/libc/ctype.h index 8f0d16872e7a7..7936536f577c7 100644 --- a/system/include/libc/ctype.h +++ b/system/include/libc/ctype.h @@ -22,13 +22,20 @@ int isxdigit(int); int tolower(int); int toupper(int); -#define isalpha(a) ((((unsigned)(a)|32)-'a') < 26) -#define isdigit(a) (((unsigned)(a)-'0') < 10) -#define islower(a) (((unsigned)(a)-'a') < 26) -#define isupper(a) (((unsigned)(a)-'A') < 26) -#define isprint(a) (((unsigned)(a)-0x20) < 0x5f) -#define isgraph(a) (((unsigned)(a)-0x21) < 0x5e) +#ifndef __cplusplus +static __inline int __isspace(int _c) +{ + return _c == ' ' || (unsigned)_c-'\t' < 5; +} +#define isalpha(a) (0 ? isalpha(a) : (((unsigned)(a)|32)-'a') < 26) +#define isdigit(a) (0 ? isdigit(a) : ((unsigned)(a)-'0') < 10) +#define islower(a) (0 ? islower(a) : ((unsigned)(a)-'a') < 26) +#define isupper(a) (0 ? isupper(a) : ((unsigned)(a)-'A') < 26) +#define isprint(a) (0 ? isprint(a) : ((unsigned)(a)-0x20) < 0x5f) +#define isgraph(a) (0 ? isgraph(a) : ((unsigned)(a)-0x21) < 0x5e) +#define isspace(a) __isspace(a) +#endif #if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \ @@ -57,6 +64,7 @@ int isascii(int); int toascii(int); #define _tolower(a) ((a)|0x20) #define _toupper(a) ((a)&0x5f) +#define isascii(a) (0 ? isascii(a) : (unsigned)(a) < 128) #endif diff --git a/system/include/libc/dirent.h b/system/include/libc/dirent.h index 5aa8510bfd433..006a360e1c4c5 100644 --- a/system/include/libc/dirent.h +++ b/system/include/libc/dirent.h @@ -17,8 +17,7 @@ extern "C" { typedef struct __dirstream DIR; -struct dirent -{ +struct dirent { ino_t d_ino; off_t d_off; unsigned short d_reclen; diff --git a/system/include/libc/elf.h b/system/include/libc/elf.h index 4d8c0c8efd4e9..0721d63f73a17 100644 --- a/system/include/libc/elf.h +++ b/system/include/libc/elf.h @@ -209,9 +209,11 @@ typedef struct { #define EM_MN10300 89 #define EM_MN10200 90 #define EM_PJ 91 +#define EM_OR1K 92 #define EM_OPENRISC 92 #define EM_ARC_A5 93 #define EM_XTENSA 94 +#define EM_ALTERA_NIOS2 113 #define EM_AARCH64 183 #define EM_TILEPRO 188 #define EM_MICROBLAZE 189 @@ -316,10 +318,31 @@ typedef struct { #define SHF_GROUP (1 << 9) #define SHF_TLS (1 << 10) +#define SHF_COMPRESSED (1 << 11) #define SHF_MASKOS 0x0ff00000 #define SHF_MASKPROC 0xf0000000 #define SHF_ORDERED (1 << 30) -#define SHF_EXCLUDE (1 << 31) +#define SHF_EXCLUDE (1U << 31) + +typedef struct { + Elf32_Word ch_type; + Elf32_Word ch_size; + Elf32_Word ch_addralign; +} Elf32_Chdr; + +typedef struct { + Elf64_Word ch_type; + Elf64_Word ch_reserved; + Elf64_Xword ch_size; + Elf64_Xword ch_addralign; +} Elf64_Chdr; + +#define ELFCOMPRESS_ZLIB 1 +#define ELFCOMPRESS_LOOS 0x60000000 +#define ELFCOMPRESS_HIOS 0x6fffffff +#define ELFCOMPRESS_LOPROC 0x70000000 +#define ELFCOMPRESS_HIPROC 0x7fffffff + #define GRP_COMDAT 0x1 @@ -409,8 +432,7 @@ typedef struct { -typedef struct -{ +typedef struct { Elf32_Addr r_offset; Elf32_Word r_info; } Elf32_Rel; @@ -541,6 +563,7 @@ typedef struct { #define NT_ARM_TLS 0x401 #define NT_ARM_HW_BREAK 0x402 #define NT_ARM_HW_WATCH 0x403 +#define NT_ARM_SYSTEM_CALL 0x404 #define NT_METAG_CBUF 0x500 #define NT_METAG_RPIPE 0x501 #define NT_METAG_TLS 0x502 @@ -1020,7 +1043,8 @@ typedef struct { #define R_386_TLS_DESC_CALL 40 #define R_386_TLS_DESC 41 #define R_386_IRELATIVE 42 -#define R_386_NUM 43 +#define R_386_GOT32X 43 +#define R_386_NUM 44 @@ -1153,6 +1177,7 @@ typedef struct { #define EF_MIPS_64BIT_WHIRL 16 #define EF_MIPS_ABI2 32 #define EF_MIPS_ABI_ON32 64 +#define EF_MIPS_FP64 512 #define EF_MIPS_NAN2008 1024 #define EF_MIPS_ARCH 0xf0000000 @@ -1397,6 +1422,7 @@ typedef struct { #define PT_MIPS_REGINFO 0x70000000 #define PT_MIPS_RTPROC 0x70000001 #define PT_MIPS_OPTIONS 0x70000002 +#define PT_MIPS_ABIFLAGS 0x70000003 @@ -1460,7 +1486,8 @@ typedef struct { #define DT_MIPS_PLTGOT 0x70000032 #define DT_MIPS_RWPLT 0x70000034 -#define DT_MIPS_NUM 0x35 +#define DT_MIPS_RLD_MAP_REL 0x70000035 +#define DT_MIPS_NUM 0x36 @@ -1483,8 +1510,7 @@ typedef struct { -typedef struct -{ +typedef struct { Elf32_Word l_name; Elf32_Word l_time_stamp; Elf32_Word l_checksum; @@ -1492,8 +1518,7 @@ typedef struct Elf32_Word l_flags; } Elf32_Lib; -typedef struct -{ +typedef struct { Elf64_Word l_name; Elf64_Word l_time_stamp; Elf64_Word l_checksum; @@ -1516,7 +1541,73 @@ typedef struct typedef Elf32_Addr Elf32_Conflict; - +typedef struct { + Elf32_Half version; + unsigned char isa_level; + unsigned char isa_rev; + unsigned char gpr_size; + unsigned char cpr1_size; + unsigned char cpr2_size; + unsigned char fp_abi; + Elf32_Word isa_ext; + Elf32_Word ases; + Elf32_Word flags1; + Elf32_Word flags2; +} Elf_MIPS_ABIFlags_v0; + +#define MIPS_AFL_REG_NONE 0x00 +#define MIPS_AFL_REG_32 0x01 +#define MIPS_AFL_REG_64 0x02 +#define MIPS_AFL_REG_128 0x03 + +#define MIPS_AFL_ASE_DSP 0x00000001 +#define MIPS_AFL_ASE_DSPR2 0x00000002 +#define MIPS_AFL_ASE_EVA 0x00000004 +#define MIPS_AFL_ASE_MCU 0x00000008 +#define MIPS_AFL_ASE_MDMX 0x00000010 +#define MIPS_AFL_ASE_MIPS3D 0x00000020 +#define MIPS_AFL_ASE_MT 0x00000040 +#define MIPS_AFL_ASE_SMARTMIPS 0x00000080 +#define MIPS_AFL_ASE_VIRT 0x00000100 +#define MIPS_AFL_ASE_MSA 0x00000200 +#define MIPS_AFL_ASE_MIPS16 0x00000400 +#define MIPS_AFL_ASE_MICROMIPS 0x00000800 +#define MIPS_AFL_ASE_XPA 0x00001000 +#define MIPS_AFL_ASE_MASK 0x00001fff + +#define MIPS_AFL_EXT_XLR 1 +#define MIPS_AFL_EXT_OCTEON2 2 +#define MIPS_AFL_EXT_OCTEONP 3 +#define MIPS_AFL_EXT_LOONGSON_3A 4 +#define MIPS_AFL_EXT_OCTEON 5 +#define MIPS_AFL_EXT_5900 6 +#define MIPS_AFL_EXT_4650 7 +#define MIPS_AFL_EXT_4010 8 +#define MIPS_AFL_EXT_4100 9 +#define MIPS_AFL_EXT_3900 10 +#define MIPS_AFL_EXT_10000 11 +#define MIPS_AFL_EXT_SB1 12 +#define MIPS_AFL_EXT_4111 13 +#define MIPS_AFL_EXT_4120 14 +#define MIPS_AFL_EXT_5400 15 +#define MIPS_AFL_EXT_5500 16 +#define MIPS_AFL_EXT_LOONGSON_2E 17 +#define MIPS_AFL_EXT_LOONGSON_2F 18 + +#define MIPS_AFL_FLAGS1_ODDSPREG 1 + +enum +{ + Val_GNU_MIPS_ABI_FP_ANY = 0, + Val_GNU_MIPS_ABI_FP_DOUBLE = 1, + Val_GNU_MIPS_ABI_FP_SINGLE = 2, + Val_GNU_MIPS_ABI_FP_SOFT = 3, + Val_GNU_MIPS_ABI_FP_OLD_64 = 4, + Val_GNU_MIPS_ABI_FP_XX = 5, + Val_GNU_MIPS_ABI_FP_64 = 6, + Val_GNU_MIPS_ABI_FP_64A = 7, + Val_GNU_MIPS_ABI_FP_MAX = 7 +}; @@ -1857,7 +1948,8 @@ typedef Elf32_Addr Elf32_Conflict; #define R_PPC_GOT_DTPREL16_LO 92 #define R_PPC_GOT_DTPREL16_HI 93 #define R_PPC_GOT_DTPREL16_HA 94 - +#define R_PPC_TLSGD 95 +#define R_PPC_TLSLD 96 #define R_PPC_EMB_NADDR32 101 @@ -1900,7 +1992,10 @@ typedef Elf32_Addr Elf32_Conflict; #define DT_PPC_GOT (DT_LOPROC + 0) -#define DT_PPC_NUM 1 +#define DT_PPC_OPT (DT_LOPROC + 1) +#define DT_PPC_NUM 2 + +#define PPC_OPT_TLS 1 #define R_PPC64_NONE R_PPC_NONE @@ -2013,6 +2108,15 @@ typedef Elf32_Addr Elf32_Conflict; #define R_PPC64_DTPREL16_HIGHERA 104 #define R_PPC64_DTPREL16_HIGHEST 105 #define R_PPC64_DTPREL16_HIGHESTA 106 +#define R_PPC64_TLSGD 107 +#define R_PPC64_TLSLD 108 +#define R_PPC64_TOCSAVE 109 +#define R_PPC64_ADDR16_HIGH 110 +#define R_PPC64_ADDR16_HIGHA 111 +#define R_PPC64_TPREL16_HIGH 112 +#define R_PPC64_TPREL16_HIGHA 113 +#define R_PPC64_DTPREL16_HIGH 114 +#define R_PPC64_DTPREL16_HIGHA 115 #define R_PPC64_JMP_IREL 247 @@ -2022,14 +2126,20 @@ typedef Elf32_Addr Elf32_Conflict; #define R_PPC64_REL16_HI 251 #define R_PPC64_REL16_HA 252 +#define EF_PPC64_ABI 3 #define DT_PPC64_GLINK (DT_LOPROC + 0) #define DT_PPC64_OPD (DT_LOPROC + 1) #define DT_PPC64_OPDSZ (DT_LOPROC + 2) -#define DT_PPC64_NUM 3 - +#define DT_PPC64_OPT (DT_LOPROC + 3) +#define DT_PPC64_NUM 4 +#define PPC64_OPT_TLS 1 +#define PPC64_OPT_MULTI_TOC 2 +#define STO_PPC64_LOCAL_BIT 5 +#define STO_PPC64_LOCAL_MASK 0xe0 +#define PPC64_LOCAL_ENTRY_OFFSET(x) (1 << (((x)&0xe0)>>5) & 0xfc) #define EF_ARM_RELEXEC 0x01 @@ -2089,8 +2199,17 @@ typedef Elf32_Addr Elf32_Conflict; #define SHT_ARM_PREEMPTMAP (SHT_LOPROC + 2) #define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) - #define R_AARCH64_NONE 0 +#define R_AARCH64_P32_ABS32 1 +#define R_AARCH64_P32_COPY 180 +#define R_AARCH64_P32_GLOB_DAT 181 +#define R_AARCH64_P32_JUMP_SLOT 182 +#define R_AARCH64_P32_RELATIVE 183 +#define R_AARCH64_P32_TLS_DTPMOD 184 +#define R_AARCH64_P32_TLS_DTPREL 185 +#define R_AARCH64_P32_TLS_TPREL 186 +#define R_AARCH64_P32_TLSDESC 187 +#define R_AARCH64_P32_IRELATIVE 188 #define R_AARCH64_ABS64 257 #define R_AARCH64_ABS32 258 #define R_AARCH64_ABS16 259 @@ -2208,8 +2327,11 @@ typedef Elf32_Addr Elf32_Conflict; #define R_AARCH64_GLOB_DAT 1025 #define R_AARCH64_JUMP_SLOT 1026 #define R_AARCH64_RELATIVE 1027 +#define R_AARCH64_TLS_DTPMOD 1028 #define R_AARCH64_TLS_DTPMOD64 1028 +#define R_AARCH64_TLS_DTPREL 1029 #define R_AARCH64_TLS_DTPREL64 1029 +#define R_AARCH64_TLS_TPREL 1030 #define R_AARCH64_TLS_TPREL64 1030 #define R_AARCH64_TLSDESC 1031 @@ -2459,7 +2581,28 @@ typedef Elf32_Addr Elf32_Conflict; #define R_IA64_LTOFF_DTPREL22 0xba - +#define EF_SH_MACH_MASK 0x1f +#define EF_SH_UNKNOWN 0x0 +#define EF_SH1 0x1 +#define EF_SH2 0x2 +#define EF_SH3 0x3 +#define EF_SH_DSP 0x4 +#define EF_SH3_DSP 0x5 +#define EF_SH4AL_DSP 0x6 +#define EF_SH3E 0x8 +#define EF_SH4 0x9 +#define EF_SH2E 0xb +#define EF_SH4A 0xc +#define EF_SH2A 0xd +#define EF_SH4_NOFPU 0x10 +#define EF_SH4A_NOFPU 0x11 +#define EF_SH4_NOMMU_NOFPU 0x12 +#define EF_SH2A_NOFPU 0x13 +#define EF_SH3_NOMMU 0x14 +#define EF_SH2A_SH4_NOFPU 0x15 +#define EF_SH2A_SH3_NOFPU 0x16 +#define EF_SH2A_SH4 0x17 +#define EF_SH2A_SH3E 0x18 #define R_SH_NONE 0 #define R_SH_DIR32 1 @@ -2498,6 +2641,14 @@ typedef Elf32_Addr Elf32_Conflict; #define R_SH_RELATIVE 165 #define R_SH_GOTOFF 166 #define R_SH_GOTPC 167 +#define R_SH_GOT20 201 +#define R_SH_GOTOFF20 202 +#define R_SH_GOTFUNCDESC 203 +#define R_SH_GOTFUNCDEST20 204 +#define R_SH_GOTOFFFUNCDESC 205 +#define R_SH_GOTOFFFUNCDEST20 206 +#define R_SH_FUNCDESC 207 +#define R_SH_FUNCDESC_VALUE 208 #define R_SH_NUM 256 @@ -2657,7 +2808,9 @@ typedef Elf32_Addr Elf32_Conflict; #define R_X86_64_TLSDESC 36 #define R_X86_64_IRELATIVE 37 #define R_X86_64_RELATIVE64 38 -#define R_X86_64_NUM 39 +#define R_X86_64_GOTPCRELX 41 +#define R_X86_64_REX_GOTPCRELX 42 +#define R_X86_64_NUM 43 @@ -2775,6 +2928,91 @@ typedef Elf32_Addr Elf32_Conflict; #define R_MICROBLAZE_TLSGOTTPREL32 28 #define R_MICROBLAZE_TLSTPREL32 29 +#define DT_NIOS2_GP 0x70000002 + +#define R_NIOS2_NONE 0 +#define R_NIOS2_S16 1 +#define R_NIOS2_U16 2 +#define R_NIOS2_PCREL16 3 +#define R_NIOS2_CALL26 4 +#define R_NIOS2_IMM5 5 +#define R_NIOS2_CACHE_OPX 6 +#define R_NIOS2_IMM6 7 +#define R_NIOS2_IMM8 8 +#define R_NIOS2_HI16 9 +#define R_NIOS2_LO16 10 +#define R_NIOS2_HIADJ16 11 +#define R_NIOS2_BFD_RELOC_32 12 +#define R_NIOS2_BFD_RELOC_16 13 +#define R_NIOS2_BFD_RELOC_8 14 +#define R_NIOS2_GPREL 15 +#define R_NIOS2_GNU_VTINHERIT 16 +#define R_NIOS2_GNU_VTENTRY 17 +#define R_NIOS2_UJMP 18 +#define R_NIOS2_CJMP 19 +#define R_NIOS2_CALLR 20 +#define R_NIOS2_ALIGN 21 +#define R_NIOS2_GOT16 22 +#define R_NIOS2_CALL16 23 +#define R_NIOS2_GOTOFF_LO 24 +#define R_NIOS2_GOTOFF_HA 25 +#define R_NIOS2_PCREL_LO 26 +#define R_NIOS2_PCREL_HA 27 +#define R_NIOS2_TLS_GD16 28 +#define R_NIOS2_TLS_LDM16 29 +#define R_NIOS2_TLS_LDO16 30 +#define R_NIOS2_TLS_IE16 31 +#define R_NIOS2_TLS_LE16 32 +#define R_NIOS2_TLS_DTPMOD 33 +#define R_NIOS2_TLS_DTPREL 34 +#define R_NIOS2_TLS_TPREL 35 +#define R_NIOS2_COPY 36 +#define R_NIOS2_GLOB_DAT 37 +#define R_NIOS2_JUMP_SLOT 38 +#define R_NIOS2_RELATIVE 39 +#define R_NIOS2_GOTOFF 40 +#define R_NIOS2_CALL26_NOAT 41 +#define R_NIOS2_GOT_LO 42 +#define R_NIOS2_GOT_HA 43 +#define R_NIOS2_CALL_LO 44 +#define R_NIOS2_CALL_HA 45 + +#define R_OR1K_NONE 0 +#define R_OR1K_32 1 +#define R_OR1K_16 2 +#define R_OR1K_8 3 +#define R_OR1K_LO_16_IN_INSN 4 +#define R_OR1K_HI_16_IN_INSN 5 +#define R_OR1K_INSN_REL_26 6 +#define R_OR1K_GNU_VTENTRY 7 +#define R_OR1K_GNU_VTINHERIT 8 +#define R_OR1K_32_PCREL 9 +#define R_OR1K_16_PCREL 10 +#define R_OR1K_8_PCREL 11 +#define R_OR1K_GOTPC_HI16 12 +#define R_OR1K_GOTPC_LO16 13 +#define R_OR1K_GOT16 14 +#define R_OR1K_PLT26 15 +#define R_OR1K_GOTOFF_HI16 16 +#define R_OR1K_GOTOFF_LO16 17 +#define R_OR1K_COPY 18 +#define R_OR1K_GLOB_DAT 19 +#define R_OR1K_JMP_SLOT 20 +#define R_OR1K_RELATIVE 21 +#define R_OR1K_TLS_GD_HI16 22 +#define R_OR1K_TLS_GD_LO16 23 +#define R_OR1K_TLS_LDM_HI16 24 +#define R_OR1K_TLS_LDM_LO16 25 +#define R_OR1K_TLS_LDO_HI16 26 +#define R_OR1K_TLS_LDO_LO16 27 +#define R_OR1K_TLS_IE_HI16 28 +#define R_OR1K_TLS_IE_LO16 29 +#define R_OR1K_TLS_LE_HI16 30 +#define R_OR1K_TLS_LE_LO16 31 +#define R_OR1K_TLS_TPOFF 32 +#define R_OR1K_TLS_DTPOFF 33 +#define R_OR1K_TLS_DTPMOD 34 + #ifdef __cplusplus } #endif diff --git a/system/include/libc/errno.h b/system/include/libc/errno.h index 0361b33ad348a..93f5f6ecb6c35 100644 --- a/system/include/libc/errno.h +++ b/system/include/libc/errno.h @@ -9,9 +9,6 @@ extern "C" { #include -#ifdef __GNUC__ -__attribute__((const)) -#endif int *__errno_location(void); #define errno (*__errno_location()) diff --git a/system/include/libc/fcntl.h b/system/include/libc/fcntl.h index 2d8fa6e4d3730..e683e4dc6873f 100644 --- a/system/include/libc/fcntl.h +++ b/system/include/libc/fcntl.h @@ -21,8 +21,7 @@ extern "C" { #include -struct flock -{ +struct flock { short l_type; short l_whence; off_t l_start; @@ -37,15 +36,18 @@ int openat(int, const char *, int, ...); int posix_fadvise(int, off_t, off_t, int); int posix_fallocate(int, off_t, off_t); -#define O_SEARCH 010000000 -#define O_EXEC 010000000 -#define O_PATH 010000000 +#define O_SEARCH O_PATH +#define O_EXEC O_PATH #define O_ACCMODE (03|O_SEARCH) #define O_RDONLY 00 #define O_WRONLY 01 #define O_RDWR 02 +#define F_OFD_GETLK 36 +#define F_OFD_SETLK 37 +#define F_OFD_SETLKW 38 + #define F_DUPFD_CLOEXEC 1030 #define F_RDLCK 0 @@ -117,6 +119,13 @@ int posix_fallocate(int, off_t, off_t); #define F_CANCELLK 1029 #define F_SETPIPE_SZ 1031 #define F_GETPIPE_SZ 1032 +#define F_ADD_SEALS 1033 +#define F_GET_SEALS 1034 + +#define F_SEAL_SEAL 0x0001 +#define F_SEAL_SHRINK 0x0002 +#define F_SEAL_GROW 0x0004 +#define F_SEAL_WRITE 0x0008 #define DN_ACCESS 0x00000001 #define DN_MODIFY 0x00000002 diff --git a/system/include/libc/features.h b/system/include/libc/features.h index 294c61dd6056e..3cc3e57933e1a 100644 --- a/system/include/libc/features.h +++ b/system/include/libc/features.h @@ -1,10 +1,14 @@ #ifndef _FEATURES_H #define _FEATURES_H -#ifdef _ALL_SOURCE +#if defined(_ALL_SOURCE) && !defined(_GNU_SOURCE) #define _GNU_SOURCE 1 #endif +#if defined(_DEFAULT_SOURCE) && !defined(_BSD_SOURCE) +#define _BSD_SOURCE 1 +#endif + #if !defined(_POSIX_SOURCE) && !defined(_POSIX_C_SOURCE) \ && !defined(_XOPEN_SOURCE) && !defined(_GNU_SOURCE) \ && !defined(_BSD_SOURCE) && !defined(__STRICT_ANSI__) diff --git a/system/include/libc/float.h b/system/include/libc/float.h index 2b2ad399de0f6..713aadb906d95 100644 --- a/system/include/libc/float.h +++ b/system/include/libc/float.h @@ -1,6 +1,13 @@ #ifndef _FLOAT_H #define _FLOAT_H +#ifdef __cplusplus +extern "C" { +#endif + +int __flt_rounds(void); +#define FLT_ROUNDS (__flt_rounds()) + #define FLT_RADIX 2 #define FLT_TRUE_MIN 1.40129846432481707092e-45F @@ -11,8 +18,10 @@ #define FLT_MANT_DIG 24 #define FLT_MIN_EXP (-125) #define FLT_MAX_EXP 128 +#define FLT_HAS_SUBNORM 1 #define FLT_DIG 6 +#define FLT_DECIMAL_DIG 9 #define FLT_MIN_10_EXP (-37) #define FLT_MAX_10_EXP 38 @@ -24,11 +33,20 @@ #define DBL_MANT_DIG 53 #define DBL_MIN_EXP (-1021) #define DBL_MAX_EXP 1024 +#define DBL_HAS_SUBNORM 1 #define DBL_DIG 15 +#define DBL_DECIMAL_DIG 17 #define DBL_MIN_10_EXP (-307) #define DBL_MAX_10_EXP 308 +#define LDBL_HAS_SUBNORM 1 +#define LDBL_DECIMAL_DIG DECIMAL_DIG + #include +#ifdef __cplusplus +} +#endif + #endif diff --git a/system/include/libc/fmtmsg.h b/system/include/libc/fmtmsg.h new file mode 100644 index 0000000000000..d944b06f8d2db --- /dev/null +++ b/system/include/libc/fmtmsg.h @@ -0,0 +1,47 @@ +#ifndef _FMTMSG_H +#define _FMTMSG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MM_HARD 1 +#define MM_SOFT 2 +#define MM_FIRM 4 + +#define MM_APPL 8 +#define MM_UTIL 16 +#define MM_OPSYS 32 + +#define MM_RECOVER 64 +#define MM_NRECOV 128 + +#define MM_PRINT 256 +#define MM_CONSOLE 512 + +#define MM_NULLMC 0L + +#define MM_HALT 1 +#define MM_ERROR 2 +#define MM_WARNING 3 +#define MM_INFO 4 +#define MM_NOSEV 0 + +#define MM_OK 0 +#define MM_NOTOK (-1) +#define MM_NOMSG 1 +#define MM_NOCON 4 + +#define MM_NULLLBL ((char*)0) +#define MM_NULLTXT ((char*)0) +#define MM_NULLACT ((char*)0) +#define MM_NULLTAG ((char*)0) +#define MM_NULLSEV 0 + +int fmtmsg(long, const char *, int, const char *, const char *, const char *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/system/include/libc/ftw.h b/system/include/libc/ftw.h index c8eadbc9dda72..b15c062a8389e 100644 --- a/system/include/libc/ftw.h +++ b/system/include/libc/ftw.h @@ -21,8 +21,7 @@ extern "C" { #define FTW_CHDIR 4 #define FTW_DEPTH 8 -struct FTW -{ +struct FTW { int base; int level; }; diff --git a/system/include/libc/getopt.h b/system/include/libc/getopt.h index c1d0df928f749..35cbd358b5285 100644 --- a/system/include/libc/getopt.h +++ b/system/include/libc/getopt.h @@ -9,8 +9,7 @@ int getopt(int, char * const [], const char *); extern char *optarg; extern int optind, opterr, optopt, optreset; -struct option -{ +struct option { const char *name; int has_arg; int *flag; diff --git a/system/include/libc/glob.h b/system/include/libc/glob.h index 9fbbaa65ea204..76f6c1c68a235 100644 --- a/system/include/libc/glob.h +++ b/system/include/libc/glob.h @@ -39,6 +39,7 @@ void globfree(glob_t *); #if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) #define glob64 glob #define globfree64 globfree +#define glob64_t glob_t #endif #ifdef __cplusplus diff --git a/system/include/libc/grp.h b/system/include/libc/grp.h index b331d3264c0f1..358181bf139a2 100644 --- a/system/include/libc/grp.h +++ b/system/include/libc/grp.h @@ -16,8 +16,7 @@ extern "C" { #include -struct group -{ +struct group { char *gr_name; char *gr_passwd; gid_t gr_gid; diff --git a/system/include/libc/libintl.h b/system/include/libc/libintl.h index a2dada675dceb..6a707bf0f0011 100644 --- a/system/include/libc/libintl.h +++ b/system/include/libc/libintl.h @@ -8,16 +8,24 @@ extern "C" { #define __USE_GNU_GETTEXT 1 #define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 1 : -1) -char *gettext(const char *); -char *dgettext(const char *, const char *); -char *dcgettext(const char *, const char *, int); -char *ngettext(const char *, const char *, unsigned long); -char *dngettext(const char *, const char *, const char *, unsigned long); -char *dcngettext(const char *, const char *, const char *, unsigned long, int); +#if __GNUC__ >= 3 +#define __fa(n) __attribute__ ((__format_arg__ (n))) +#else +#define __fa(n) +#endif + +char *gettext(const char *) __fa(1); +char *dgettext(const char *, const char *) __fa(2); +char *dcgettext(const char *, const char *, int) __fa(2); +char *ngettext(const char *, const char *, unsigned long) __fa(1) __fa(2); +char *dngettext(const char *, const char *, const char *, unsigned long) __fa(2) __fa(3); +char *dcngettext(const char *, const char *, const char *, unsigned long, int) __fa(2) __fa(3); char *textdomain(const char *); char *bindtextdomain (const char *, const char *); char *bind_textdomain_codeset(const char *, const char *); +#undef __fa + #ifdef __cplusplus } #endif diff --git a/system/include/libc/malloc.h b/system/include/libc/malloc.h index e69de29bb2d1d..35f8b19c2c340 100644 --- a/system/include/libc/malloc.h +++ b/system/include/libc/malloc.h @@ -0,0 +1,25 @@ +#ifndef _MALLOC_H +#define _MALLOC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_size_t + +#include + +void *malloc (size_t); +void *calloc (size_t, size_t); +void *realloc (void *, size_t); +void free (void *); +void *valloc (size_t); +void *memalign(size_t, size_t); + +size_t malloc_usable_size(void *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/system/include/libc/mntent.h b/system/include/libc/mntent.h index d03c414a2b069..3492a1d6daa25 100644 --- a/system/include/libc/mntent.h +++ b/system/include/libc/mntent.h @@ -20,8 +20,7 @@ extern "C" { #define MNTOPT_NOSUID "nosuid" #define MNTOPT_NOAUTO "noauto" -struct mntent -{ +struct mntent { char *mnt_fsname; char *mnt_dir; char *mnt_type; diff --git a/system/include/libc/net/if.h b/system/include/libc/net/if.h index 3f4fc09273883..1a4059d60f680 100644 --- a/system/include/libc/net/if.h +++ b/system/include/libc/net/if.h @@ -9,8 +9,7 @@ extern "C" { #define IF_NAMESIZE 16 -struct if_nameindex -{ +struct if_nameindex { unsigned int if_index; char *if_name; }; diff --git a/system/include/libc/netdb.h b/system/include/libc/netdb.h index dfc70e2bf28ab..967ca211f9dab 100644 --- a/system/include/libc/netdb.h +++ b/system/include/libc/netdb.h @@ -13,8 +13,7 @@ extern "C" { #include #endif -struct addrinfo -{ +struct addrinfo { int ai_flags; int ai_family; int ai_socktype; @@ -41,7 +40,7 @@ struct addrinfo #define NI_NOFQDN 0x04 #define NI_NAMEREQD 0x08 #define NI_DGRAM 0x10 -/*#define NI_NUMERICSCOPE */ +#define NI_NUMERICSCOPE 0x100 #define EAI_BADFLAGS -1 #define EAI_NONAME -2 @@ -62,16 +61,14 @@ const char *gai_strerror(int); /* Legacy functions follow (marked OBsolete in SUS) */ -struct netent -{ +struct netent { char *n_name; char **n_aliases; int n_addrtype; uint32_t n_net; }; -struct hostent -{ +struct hostent { char *h_name; char **h_aliases; int h_addrtype; @@ -80,16 +77,14 @@ struct hostent }; #define h_addr h_addr_list[0] -struct servent -{ +struct servent { char *s_name; char **s_aliases; int s_port; char *s_proto; }; -struct protoent -{ +struct protoent { char *p_name; char **p_aliases; int p_proto; @@ -122,9 +117,6 @@ struct protoent *getprotobynumber (int); || (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE+0 < 700) struct hostent *gethostbyname (const char *); struct hostent *gethostbyaddr (const void *, socklen_t, int); -#ifdef __GNUC__ -__attribute__((const)) -#endif int *__h_errno_location(void); #define h_errno (*__h_errno_location()) #define HOST_NOT_FOUND 1 diff --git a/system/include/libc/netinet/ether.h b/system/include/libc/netinet/ether.h index d64c9ef598bd2..eec7e53ca497a 100644 --- a/system/include/libc/netinet/ether.h +++ b/system/include/libc/netinet/ether.h @@ -1,6 +1,10 @@ #ifndef _NETINET_ETHER_H #define _NETINET_ETHER_H +#ifdef __cplusplus +extern "C" { +#endif + #include char *ether_ntoa (const struct ether_addr *); @@ -11,4 +15,8 @@ int ether_line(const char *, struct ether_addr *, char *); int ether_ntohost(char *, const struct ether_addr *); int ether_hostton(const char *, struct ether_addr *); +#ifdef __cplusplus +} +#endif + #endif diff --git a/system/include/libc/netinet/if_ether.h b/system/include/libc/netinet/if_ether.h index 34f9be55c9f21..4c2322b3153b5 100644 --- a/system/include/libc/netinet/if_ether.h +++ b/system/include/libc/netinet/if_ether.h @@ -39,11 +39,11 @@ #define ETH_P_PAUSE 0x8808 #define ETH_P_SLOW 0x8809 #define ETH_P_WCCP 0x883E -#define ETH_P_PPP_DISC 0x8863 -#define ETH_P_PPP_SES 0x8864 #define ETH_P_MPLS_UC 0x8847 #define ETH_P_MPLS_MC 0x8848 #define ETH_P_ATMMPOA 0x884c +#define ETH_P_PPP_DISC 0x8863 +#define ETH_P_PPP_SES 0x8864 #define ETH_P_LINK_CTL 0x886c #define ETH_P_ATMFATE 0x8884 #define ETH_P_PAE 0x888E @@ -51,6 +51,7 @@ #define ETH_P_8021AD 0x88A8 #define ETH_P_802_EX1 0x88B5 #define ETH_P_TIPC 0x88CA +#define ETH_P_MACSEC 0x88E5 #define ETH_P_8021AH 0x88E7 #define ETH_P_MVRP 0x88F5 #define ETH_P_1588 0x88F7 @@ -58,6 +59,8 @@ #define ETH_P_FCOE 0x8906 #define ETH_P_TDLS 0x890D #define ETH_P_FIP 0x8914 +#define ETH_P_80221 0x8917 +#define ETH_P_LOOPBACK 0x9000 #define ETH_P_QINQ1 0x9100 #define ETH_P_QINQ2 0x9200 #define ETH_P_QINQ3 0x9300 diff --git a/system/include/libc/netinet/in.h b/system/include/libc/netinet/in.h index ee6e19fbdaf5b..f6bb77b1fb09c 100644 --- a/system/include/libc/netinet/in.h +++ b/system/include/libc/netinet/in.h @@ -13,16 +13,14 @@ typedef uint16_t in_port_t; typedef uint32_t in_addr_t; struct in_addr { in_addr_t s_addr; }; -struct sockaddr_in -{ +struct sockaddr_in { sa_family_t sin_family; in_port_t sin_port; struct in_addr sin_addr; uint8_t sin_zero[8]; }; -struct in6_addr -{ +struct in6_addr { union { uint8_t __s6_addr[16]; uint16_t __s6_addr16[8]; @@ -33,8 +31,7 @@ struct in6_addr #define s6_addr16 __in6_union.__s6_addr16 #define s6_addr32 __in6_union.__s6_addr32 -struct sockaddr_in6 -{ +struct sockaddr_in6 { sa_family_t sin6_family; in_port_t sin6_port; uint32_t sin6_flowinfo; @@ -42,8 +39,7 @@ struct sockaddr_in6 uint32_t sin6_scope_id; }; -struct ipv6_mreq -{ +struct ipv6_mreq { struct in6_addr ipv6mr_multiaddr; unsigned ipv6mr_interface; }; @@ -103,6 +99,7 @@ uint16_t ntohs(uint16_t); #define IPPROTO_SCTP 132 #define IPPROTO_MH 135 #define IPPROTO_UDPLITE 136 +#define IPPROTO_MPLS 137 #define IPPROTO_RAW 255 #define IPPROTO_MAX 256 @@ -198,6 +195,9 @@ uint16_t ntohs(uint16_t); #define IP_ORIGDSTADDR 20 #define IP_RECVORIGDSTADDR IP_ORIGDSTADDR #define IP_MINTTL 21 +#define IP_NODEFRAG 22 +#define IP_CHECKSUM 23 +#define IP_BIND_ADDRESS_NO_PORT 24 #define IP_MULTICAST_IF 32 #define IP_MULTICAST_TTL 33 #define IP_MULTICAST_LOOP 34 @@ -218,13 +218,13 @@ uint16_t ntohs(uint16_t); #define IP_PMTUDISC_DO 2 #define IP_PMTUDISC_PROBE 3 #define IP_PMTUDISC_INTERFACE 4 +#define IP_PMTUDISC_OMIT 5 #define IP_DEFAULT_MULTICAST_TTL 1 #define IP_DEFAULT_MULTICAST_LOOP 1 #define IP_MAX_MEMBERSHIPS 20 -struct ip_opts -{ +struct ip_opts { struct in_addr ip_dst; char ip_opts[40]; }; @@ -242,14 +242,12 @@ struct ip_opts #define MCAST_EXCLUDE 0 #define MCAST_INCLUDE 1 -struct ip_mreq -{ +struct ip_mreq { struct in_addr imr_multiaddr; struct in_addr imr_interface; }; -struct ip_mreqn -{ +struct ip_mreqn { struct in_addr imr_multiaddr; struct in_addr imr_address; int imr_ifindex; @@ -294,21 +292,18 @@ struct group_filter { (sizeof(struct group_filter) - sizeof(struct sockaddr_storage) \ + (numsrc) * sizeof(struct sockaddr_storage)) -struct in_pktinfo -{ +struct in_pktinfo { int ipi_ifindex; struct in_addr ipi_spec_dst; struct in_addr ipi_addr; }; -struct in6_pktinfo -{ +struct in6_pktinfo { struct in6_addr ipi6_addr; unsigned ipi6_ifindex; }; -struct ip6_mtuinfo -{ +struct ip6_mtuinfo { struct sockaddr_in6 ip6m_addr; uint32_t ip6m_mtu; }; @@ -339,6 +334,7 @@ struct ip6_mtuinfo #define IPV6_LEAVE_ANYCAST 28 #define IPV6_IPSEC_POLICY 34 #define IPV6_XFRM_POLICY 35 +#define IPV6_HDRINCL 36 #define IPV6_RECVPKTINFO 49 #define IPV6_PKTINFO 50 @@ -351,9 +347,18 @@ struct ip6_mtuinfo #define IPV6_RTHDR 57 #define IPV6_RECVDSTOPTS 58 #define IPV6_DSTOPTS 59 - +#define IPV6_RECVPATHMTU 60 +#define IPV6_PATHMTU 61 +#define IPV6_DONTFRAG 62 #define IPV6_RECVTCLASS 66 #define IPV6_TCLASS 67 +#define IPV6_AUTOFLOWLABEL 70 +#define IPV6_ADDR_PREFERENCES 72 +#define IPV6_MINHOPCOUNT 73 +#define IPV6_ORIGDSTADDR 74 +#define IPV6_RECVORIGDSTADDR IPV6_ORIGDSTADDR +#define IPV6_TRANSPARENT 75 +#define IPV6_UNICAST_IF 76 #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP #define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP @@ -364,6 +369,16 @@ struct ip6_mtuinfo #define IPV6_PMTUDISC_WANT 1 #define IPV6_PMTUDISC_DO 2 #define IPV6_PMTUDISC_PROBE 3 +#define IPV6_PMTUDISC_INTERFACE 4 +#define IPV6_PMTUDISC_OMIT 5 + +#define IPV6_PREFER_SRC_TMP 0x0001 +#define IPV6_PREFER_SRC_PUBLIC 0x0002 +#define IPV6_PREFER_SRC_PUBTMP_DEFAULT 0x0100 +#define IPV6_PREFER_SRC_COA 0x0004 +#define IPV6_PREFER_SRC_HOME 0x0400 +#define IPV6_PREFER_SRC_CGA 0x0008 +#define IPV6_PREFER_SRC_NONCGA 0x0800 #define IPV6_RTHDR_LOOSE 0 #define IPV6_RTHDR_STRICT 1 diff --git a/system/include/libc/netinet/ip.h b/system/include/libc/netinet/ip.h index 411874146f92a..d7fa8d5e4e9b2 100644 --- a/system/include/libc/netinet/ip.h +++ b/system/include/libc/netinet/ip.h @@ -104,6 +104,18 @@ struct ip_timestamp { #define IPTOS_DSCP_AF43 0x98 #define IPTOS_DSCP_EF 0xb8 +#define IPTOS_CLASS_MASK 0xe0 +#define IPTOS_CLASS(x) ((x) & IPTOS_CLASS_MASK) +#define IPTOS_CLASS_CS0 0x00 +#define IPTOS_CLASS_CS1 0x20 +#define IPTOS_CLASS_CS2 0x40 +#define IPTOS_CLASS_CS3 0x60 +#define IPTOS_CLASS_CS4 0x80 +#define IPTOS_CLASS_CS5 0xa0 +#define IPTOS_CLASS_CS6 0xc0 +#define IPTOS_CLASS_CS7 0xe0 +#define IPTOS_CLASS_DEFAULT IPTOS_CLASS_CS0 + #define IPTOS_TOS_MASK 0x1E #define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK) #define IPTOS_LOWDELAY 0x10 diff --git a/system/include/libc/netinet/tcp.h b/system/include/libc/netinet/tcp.h index d3db0421b8587..9ea64c451ce47 100644 --- a/system/include/libc/netinet/tcp.h +++ b/system/include/libc/netinet/tcp.h @@ -27,6 +27,9 @@ #define TCP_FASTOPEN 23 #define TCP_TIMESTAMP 24 #define TCP_NOTSENT_LOWAT 25 +#define TCP_CC_INFO 26 +#define TCP_SAVE_SYN 27 +#define TCP_SAVED_SYN 28 #define TCP_ESTABLISHED 1 #define TCP_SYN_SENT 2 @@ -41,7 +44,20 @@ #define TCP_CLOSING 11 #if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define TCPOPT_EOL 0 +#define TCPOPT_NOP 1 +#define TCPOPT_MAXSEG 2 +#define TCPOPT_WINDOW 3 +#define TCPOPT_SACK_PERMITTED 4 +#define TCPOPT_SACK 5 +#define TCPOPT_TIMESTAMP 8 +#define TCPOLEN_SACK_PERMITTED 2 +#define TCPOLEN_WINDOW 3 +#define TCPOLEN_MAXSEG 4 +#define TCPOLEN_TIMESTAMP 10 + #define SOL_TCP 6 + #include #include #include @@ -129,8 +145,7 @@ struct tcphdr { #define TCP_CA_Recovery 3 #define TCP_CA_Loss 4 -struct tcp_info -{ +struct tcp_info { uint8_t tcpi_state; uint8_t tcpi_ca_state; uint8_t tcpi_retransmits; @@ -162,12 +177,21 @@ struct tcp_info uint32_t tcpi_rcv_rtt; uint32_t tcpi_rcv_space; uint32_t tcpi_total_retrans; + uint64_t tcpi_pacing_rate; + uint64_t tcpi_max_pacing_rate; + uint64_t tcpi_bytes_acked; + uint64_t tcpi_bytes_received; + uint32_t tcpi_segs_out; + uint32_t tcpi_segs_in; + uint32_t tcpi_notsent_bytes; + uint32_t tcpi_min_rtt; + uint32_t tcpi_data_segs_in; + uint32_t tcpi_data_segs_out; }; #define TCP_MD5SIG_MAXKEYLEN 80 -struct tcp_md5sig -{ +struct tcp_md5sig { struct sockaddr_storage tcpm_addr; uint16_t __tcpm_pad1; uint16_t tcpm_keylen; diff --git a/system/include/libc/netpacket/packet.h b/system/include/libc/netpacket/packet.h index fa53712f44799..f2210ce81678d 100644 --- a/system/include/libc/netpacket/packet.h +++ b/system/include/libc/netpacket/packet.h @@ -32,10 +32,27 @@ struct packet_mreq { #define PACKET_RECV_OUTPUT 3 #define PACKET_RX_RING 5 #define PACKET_STATISTICS 6 +#define PACKET_COPY_THRESH 7 +#define PACKET_AUXDATA 8 +#define PACKET_ORIGDEV 9 +#define PACKET_VERSION 10 +#define PACKET_HDRLEN 11 +#define PACKET_RESERVE 12 +#define PACKET_TX_RING 13 +#define PACKET_LOSS 14 +#define PACKET_VNET_HDR 15 +#define PACKET_TX_TIMESTAMP 16 +#define PACKET_TIMESTAMP 17 +#define PACKET_FANOUT 18 +#define PACKET_TX_HAS_OFF 19 +#define PACKET_QDISC_BYPASS 20 +#define PACKET_ROLLOVER_STATS 21 +#define PACKET_FANOUT_DATA 22 #define PACKET_MR_MULTICAST 0 #define PACKET_MR_PROMISC 1 #define PACKET_MR_ALLMULTI 2 +#define PACKET_MR_UNICAST 3 #ifdef __cplusplus } diff --git a/system/include/libc/poll.h b/system/include/libc/poll.h index 7af737222f643..daccc760bb26a 100644 --- a/system/include/libc/poll.h +++ b/system/include/libc/poll.h @@ -28,8 +28,7 @@ extern "C" { typedef unsigned long nfds_t; -struct pollfd -{ +struct pollfd { int fd; short events; short revents; diff --git a/system/include/libc/pthread.h b/system/include/libc/pthread.h index 0e92c283380c5..378ae2922ca8f 100644 --- a/system/include/libc/pthread.h +++ b/system/include/libc/pthread.h @@ -63,6 +63,7 @@ extern "C" { #define PTHREAD_CANCEL_ENABLE 0 #define PTHREAD_CANCEL_DISABLE 1 +#define PTHREAD_CANCEL_MASKED 2 #define PTHREAD_CANCEL_DEFERRED 0 #define PTHREAD_CANCEL_ASYNCHRONOUS 1 @@ -78,13 +79,12 @@ int pthread_detach(pthread_t); _Noreturn void pthread_exit(void *); int pthread_join(pthread_t, void **); -#ifdef __GNUC__ -__attribute__((const)) -#endif pthread_t pthread_self(void); int pthread_equal(pthread_t, pthread_t); +#ifndef __cplusplus #define pthread_equal(x,y) ((x)==(y)) +#endif int pthread_setcancelstate(int, int *); int pthread_setcanceltype(int, int *); @@ -221,6 +221,8 @@ struct cpu_set_t; int pthread_getaffinity_np(pthread_t, size_t, struct cpu_set_t *); int pthread_setaffinity_np(pthread_t, size_t, const struct cpu_set_t *); int pthread_getattr_np(pthread_t, pthread_attr_t *); +int pthread_tryjoin_np(pthread_t, void **); +int pthread_timedjoin_np(pthread_t, void **, const struct timespec *); #endif #ifdef __cplusplus diff --git a/system/include/libc/pwd.h b/system/include/libc/pwd.h index 55d9d42d379e9..07a5871d722ef 100644 --- a/system/include/libc/pwd.h +++ b/system/include/libc/pwd.h @@ -17,8 +17,7 @@ extern "C" { #include -struct passwd -{ +struct passwd { char *pw_name; char *pw_passwd; uid_t pw_uid; diff --git a/system/include/libc/sched.h b/system/include/libc/sched.h index 024667573634d..af82d6c9bd27b 100644 --- a/system/include/libc/sched.h +++ b/system/include/libc/sched.h @@ -38,6 +38,7 @@ int sched_yield(void); #define SCHED_RR 2 #define SCHED_BATCH 3 #define SCHED_IDLE 5 +#define SCHED_DEADLINE 6 #define SCHED_RESET_ON_FORK 0x40000000 #ifdef _GNU_SOURCE @@ -58,6 +59,7 @@ int sched_yield(void); #define CLONE_DETACHED 0x00400000 #define CLONE_UNTRACED 0x00800000 #define CLONE_CHILD_SETTID 0x01000000 +#define CLONE_NEWCGROUP 0x02000000 #define CLONE_NEWUTS 0x04000000 #define CLONE_NEWIPC 0x08000000 #define CLONE_NEWUSER 0x10000000 @@ -75,6 +77,7 @@ void free(void *); typedef struct cpu_set_t { unsigned long __bits[128/sizeof(long)]; } cpu_set_t; int __sched_cpucount(size_t, const cpu_set_t *); +int sched_getcpu(void); int sched_getaffinity(pid_t, size_t, cpu_set_t *); int sched_setaffinity(pid_t, size_t, const cpu_set_t *); diff --git a/system/include/libc/search.h b/system/include/libc/search.h index 27f6107200d66..02e407e3c2aba 100644 --- a/system/include/libc/search.h +++ b/system/include/libc/search.h @@ -22,6 +22,18 @@ int hcreate(size_t); void hdestroy(void); ENTRY *hsearch(ENTRY, ACTION); +#ifdef _GNU_SOURCE +struct hsearch_data { + struct __tab *__tab; + unsigned int __unused1; + unsigned int __unused2; +}; + +int hcreate_r(size_t, struct hsearch_data *); +void hdestroy_r(struct hsearch_data *); +int hsearch_r(ENTRY, ACTION, ENTRY **, struct hsearch_data *); +#endif + void insque(void *, void *); void remque(void *); diff --git a/system/include/libc/semaphore.h b/system/include/libc/semaphore.h index 20d46f0de2a70..277c47d6f7425 100644 --- a/system/include/libc/semaphore.h +++ b/system/include/libc/semaphore.h @@ -15,7 +15,7 @@ extern "C" { #define SEM_FAILED ((sem_t *)0) typedef struct { - int __val[4*sizeof(long)/sizeof(int)]; + volatile int __val[4*sizeof(long)/sizeof(int)]; } sem_t; int sem_close(sem_t *); diff --git a/system/include/libc/setjmp.h b/system/include/libc/setjmp.h index 0da27de6e5c67..2d43abf84f54a 100644 --- a/system/include/libc/setjmp.h +++ b/system/include/libc/setjmp.h @@ -33,7 +33,6 @@ int setjmp (jmp_buf); _Noreturn void longjmp (jmp_buf, int); #define setjmp setjmp -#define longjmp longjmp #ifdef __cplusplus } diff --git a/system/include/libc/signal.h b/system/include/libc/signal.h index 3fb21b2ad641d..a16094c515694 100644 --- a/system/include/libc/signal.h +++ b/system/include/libc/signal.h @@ -27,8 +27,6 @@ extern "C" { #include -#define SIG_HOLD ((void (*)(int)) 2) - #define SIG_BLOCK 0 #define SIG_UNBLOCK 1 #define SIG_SETMASK 2 @@ -43,6 +41,18 @@ extern "C" { #define SI_USER 0 #define SI_KERNEL 128 +typedef struct sigaltstack stack_t; + +#endif + +#include + +#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \ + || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \ + || defined(_BSD_SOURCE) + +#define SIG_HOLD ((void (*)(int)) 2) + #define FPE_INTDIV 1 #define FPE_INTOVF 2 #define FPE_FLTDIV 3 @@ -63,6 +73,8 @@ extern "C" { #define SEGV_MAPERR 1 #define SEGV_ACCERR 2 +#define SEGV_BNDERR 3 +#define SEGV_PKUERR 4 #define BUS_ADRALN 1 #define BUS_ADRERR 2 @@ -77,34 +89,48 @@ extern "C" { #define CLD_STOPPED 5 #define CLD_CONTINUED 6 -typedef struct sigaltstack stack_t; - union sigval { int sival_int; void *sival_ptr; }; typedef struct { +#ifdef __SI_SWAP_ERRNO_CODE + int si_signo, si_code, si_errno; +#else int si_signo, si_errno, si_code; +#endif union { char __pad[128 - 2*sizeof(int) - sizeof(long)]; struct { - pid_t si_pid; - uid_t si_uid; - union sigval si_sigval; - } __rt; - struct { - unsigned int si_timer1, si_timer2; - } __timer; - struct { - pid_t si_pid; - uid_t si_uid; - int si_status; - clock_t si_utime, si_stime; - } __sigchld; + union { + struct { + pid_t si_pid; + uid_t si_uid; + } __piduid; + struct { + int si_timerid; + int si_overrun; + } __timer; + } __first; + union { + union sigval si_value; + struct { + int si_status; + clock_t si_utime, si_stime; + } __sigchld; + } __second; + } __si_common; struct { void *si_addr; short si_addr_lsb; + union { + struct { + void *si_lower; + void *si_upper; + } __addr_bnd; + unsigned si_pkey; + } __first; } __sigfault; struct { long si_band; @@ -117,20 +143,23 @@ typedef struct { } __sigsys; } __si_fields; } siginfo_t; -#define si_pid __si_fields.__sigchld.si_pid -#define si_uid __si_fields.__sigchld.si_uid -#define si_status __si_fields.__sigchld.si_status -#define si_utime __si_fields.__sigchld.si_utime -#define si_stime __si_fields.__sigchld.si_stime -#define si_value __si_fields.__rt.si_sigval +#define si_pid __si_fields.__si_common.__first.__piduid.si_pid +#define si_uid __si_fields.__si_common.__first.__piduid.si_uid +#define si_status __si_fields.__si_common.__second.__sigchld.si_status +#define si_utime __si_fields.__si_common.__second.__sigchld.si_utime +#define si_stime __si_fields.__si_common.__second.__sigchld.si_stime +#define si_value __si_fields.__si_common.__second.si_value #define si_addr __si_fields.__sigfault.si_addr #define si_addr_lsb __si_fields.__sigfault.si_addr_lsb +#define si_lower __si_fields.__sigfault.__first.__addr_bnd.si_lower +#define si_upper __si_fields.__sigfault.__first.__addr_bnd.si_upper +#define si_pkey __si_fields.__sigfault.__first.si_pkey #define si_band __si_fields.__sigpoll.si_band #define si_fd __si_fields.__sigpoll.si_fd -#define si_timer1 __si_fields.__timer.si_timer1 -#define si_timer2 __si_fields.__timer.si_timer2 -#define si_ptr __si_fields.__rt.si_sigval.sival_ptr -#define si_int __si_fields.__rt.si_sigval.sival_int +#define si_timerid __si_fields.__si_common.__first.__timer.si_timerid +#define si_overrun __si_fields.__si_common.__first.__timer.si_overrun +#define si_ptr si_value.sival_ptr +#define si_int si_value.sival_int #define si_call_addr __si_fields.__sigsys.si_call_addr #define si_syscall __si_fields.__sigsys.si_syscall #define si_arch __si_fields.__sigsys.si_arch @@ -191,7 +220,7 @@ void psignal(int, const char *); #endif -#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) +#if defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE) || defined(_GNU_SOURCE) int killpg(pid_t, int); int sigaltstack(const stack_t *__restrict, stack_t *__restrict); int sighold(int); @@ -210,8 +239,6 @@ void (*sigset(int, void (*)(int)))(int); #define POLL_HUP 6 #define SS_ONSTACK 1 #define SS_DISABLE 2 -#define MINSIGSTKSZ 2048 -#define SIGSTKSZ 8192 #endif #if defined(_BSD_SOURCE) || defined(_GNU_SOURCE) @@ -230,8 +257,6 @@ int sigandset(sigset_t *, const sigset_t *, const sigset_t *); #define SA_ONESHOT SA_RESETHAND #endif -#include - #define SIG_ERR ((void (*)(int))-1) #define SIG_DFL ((void (*)(int)) 0) #define SIG_IGN ((void (*)(int)) 1) diff --git a/system/include/libc/stdalign.h b/system/include/libc/stdalign.h index b6e50aebdbfd6..2cc94be3f6d7e 100644 --- a/system/include/libc/stdalign.h +++ b/system/include/libc/stdalign.h @@ -1,6 +1,8 @@ #ifndef _STDALIGN_H #define _STDALIGN_H +#ifndef __cplusplus + /* this whole header only works in C11 or with compiler extensions */ #if __STDC_VERSION__ < 201112L && defined( __GNUC__) #define _Alignas(t) __attribute__((__aligned__(t))) @@ -9,6 +11,9 @@ #define alignas _Alignas #define alignof _Alignof + +#endif + #define __alignas_is_defined 1 #define __alignof_is_defined 1 diff --git a/system/include/libc/stdc-predef.h b/system/include/libc/stdc-predef.h new file mode 100644 index 0000000000000..f8cd4b8911366 --- /dev/null +++ b/system/include/libc/stdc-predef.h @@ -0,0 +1,10 @@ +#ifndef _STDC_PREDEF_H +#define _STDC_PREDEF_H + +#define __STDC_ISO_10646__ 201206L + +#if !defined(__GCC_IEC_559) || __GCC_IEC_559 > 0 +#define __STDC_IEC_559__ 1 +#endif + +#endif diff --git a/system/include/libc/stddef.h b/system/include/libc/stddef.h index 0a329190c17c4..bd753853503d9 100644 --- a/system/include/libc/stddef.h +++ b/system/include/libc/stddef.h @@ -10,6 +10,9 @@ #define __NEED_ptrdiff_t #define __NEED_size_t #define __NEED_wchar_t +#if __STDC_VERSION__ >= 201112L || __cplusplus >= 201103L +#define __NEED_max_align_t +#endif #include diff --git a/system/include/libc/stdint.h b/system/include/libc/stdint.h index 518d05b9d179e..a2968197dbe23 100644 --- a/system/include/libc/stdint.h +++ b/system/include/libc/stdint.h @@ -47,8 +47,8 @@ typedef uint64_t uint_least64_t; #define UINT8_MAX (0xff) #define UINT16_MAX (0xffff) -#define UINT32_MAX (0xffffffff) -#define UINT64_MAX (0xffffffffffffffff) +#define UINT32_MAX (0xffffffffu) +#define UINT64_MAX (0xffffffffffffffffu) #define INT_FAST8_MIN INT8_MIN #define INT_FAST64_MIN INT64_MIN diff --git a/system/include/libc/stdlib.h b/system/include/libc/stdlib.h index f034c6e502b37..d2c911fcd7a3f 100644 --- a/system/include/libc/stdlib.h +++ b/system/include/libc/stdlib.h @@ -76,7 +76,8 @@ size_t wcstombs (char *__restrict, const wchar_t *__restrict, size_t); #define EXIT_FAILURE 1 #define EXIT_SUCCESS 0 -#define MB_CUR_MAX ((size_t)+4) +size_t __ctype_get_mb_cur_max(void); +#define MB_CUR_MAX (__ctype_get_mb_cur_max()) #define RAND_MAX (0x7fffffff) @@ -114,9 +115,6 @@ long int random (void); void srandom (unsigned int); char *initstate (unsigned int, char *, size_t); char *setstate (char *); -#endif - -#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) int putenv (char *); int posix_openpt (int); int grantpt (int); @@ -144,12 +142,12 @@ int mkostemps (char *, int, int); void *valloc (size_t); void *memalign(size_t, size_t); int getloadavg(double *, int); +int clearenv(void); #define WCOREDUMP(s) ((s) & 0x80) #define WIFCONTINUED(s) ((s) == 0xffff) #endif #ifdef _GNU_SOURCE -int clearenv(void); int ptsname_r(int, char *, size_t); char *ecvt(double, int, int *, int *); char *fcvt(double, int, int *, int *); diff --git a/system/include/libc/stdnoreturn.h b/system/include/libc/stdnoreturn.h index 60d924a070e4c..5c6aeeb008cd8 100644 --- a/system/include/libc/stdnoreturn.h +++ b/system/include/libc/stdnoreturn.h @@ -1,5 +1,7 @@ #ifndef _STDNORETURN_H #define _STDNORETURN_H +#ifndef __cplusplus #include #define noreturn _Noreturn #endif +#endif diff --git a/system/include/libc/strings.h b/system/include/libc/strings.h index 2b7e086cc8ac4..db0960b4eb87a 100644 --- a/system/include/libc/strings.h +++ b/system/include/libc/strings.h @@ -20,7 +20,11 @@ char *index (const char *, int); char *rindex (const char *, int); #endif +#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE) int ffs (int); +int ffsl (long); +int ffsll (long long); +#endif int strcasecmp (const char *, const char *); int strncasecmp (const char *, const char *, size_t); diff --git a/system/include/libc/sys/acct.h b/system/include/libc/sys/acct.h index ee576c4ab39ff..9b0ba36fbe93a 100644 --- a/system/include/libc/sys/acct.h +++ b/system/include/libc/sys/acct.h @@ -14,8 +14,7 @@ extern "C" { typedef uint16_t comp_t; -struct acct -{ +struct acct { char ac_flag; uint16_t ac_uid; uint16_t ac_gid; @@ -36,8 +35,7 @@ struct acct }; -struct acct_v3 -{ +struct acct_v3 { char ac_flag; char ac_version; uint16_t ac_tty; diff --git a/system/include/libc/sys/auxv.h b/system/include/libc/sys/auxv.h new file mode 100644 index 0000000000000..6dcf9adc2c4e8 --- /dev/null +++ b/system/include/libc/sys/auxv.h @@ -0,0 +1,16 @@ +#ifndef _SYS_AUXV_H +#define _SYS_AUXV_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +unsigned long getauxval(unsigned long); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/system/include/libc/sys/epoll.h b/system/include/libc/sys/epoll.h index 1f0312e59ee21..ffe2311f97d3a 100644 --- a/system/include/libc/sys/epoll.h +++ b/system/include/libc/sys/epoll.h @@ -28,6 +28,7 @@ enum EPOLL_EVENTS { __EPOLL_DUMMY }; #define EPOLLERR 0x008 #define EPOLLHUP 0x010 #define EPOLLRDHUP 0x2000 +#define EPOLLEXCLUSIVE (1U<<28) #define EPOLLWAKEUP (1U<<29) #define EPOLLONESHOT (1U<<30) #define EPOLLET (1U<<31) diff --git a/system/include/libc/sys/mman.h b/system/include/libc/sys/mman.h index a34448a6e5c4f..8a5149c980b37 100644 --- a/system/include/libc/sys/mman.h +++ b/system/include/libc/sys/mman.h @@ -16,6 +16,66 @@ extern "C" { #include +#define MAP_FAILED ((void *) -1) + +#define MAP_SHARED 0x01 +#define MAP_PRIVATE 0x02 +#define MAP_TYPE 0x0f +#define MAP_FIXED 0x10 +#define MAP_ANON 0x20 +#define MAP_ANONYMOUS MAP_ANON +#define MAP_NORESERVE 0x4000 +#define MAP_GROWSDOWN 0x0100 +#define MAP_DENYWRITE 0x0800 +#define MAP_EXECUTABLE 0x1000 +#define MAP_LOCKED 0x2000 +#define MAP_POPULATE 0x8000 +#define MAP_NONBLOCK 0x10000 +#define MAP_STACK 0x20000 +#define MAP_HUGETLB 0x40000 +#define MAP_FILE 0 + +#define PROT_NONE 0 +#define PROT_READ 1 +#define PROT_WRITE 2 +#define PROT_EXEC 4 +#define PROT_GROWSDOWN 0x01000000 +#define PROT_GROWSUP 0x02000000 + +#define MS_ASYNC 1 +#define MS_INVALIDATE 2 +#define MS_SYNC 4 + +#define MCL_CURRENT 1 +#define MCL_FUTURE 2 +#define MCL_ONFAULT 4 + +#define POSIX_MADV_NORMAL 0 +#define POSIX_MADV_RANDOM 1 +#define POSIX_MADV_SEQUENTIAL 2 +#define POSIX_MADV_WILLNEED 3 +#define POSIX_MADV_DONTNEED 4 + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define MADV_NORMAL 0 +#define MADV_RANDOM 1 +#define MADV_SEQUENTIAL 2 +#define MADV_WILLNEED 3 +#define MADV_DONTNEED 4 +#define MADV_FREE 8 +#define MADV_REMOVE 9 +#define MADV_DONTFORK 10 +#define MADV_DOFORK 11 +#define MADV_MERGEABLE 12 +#define MADV_UNMERGEABLE 13 +#define MADV_HUGEPAGE 14 +#define MADV_NOHUGEPAGE 15 +#define MADV_DONTDUMP 16 +#define MADV_DODUMP 17 +#define MADV_HWPOISON 100 +#define MADV_SOFT_OFFLINE 101 +#endif + #include void *mmap (void *, size_t, int, int, int, off_t); @@ -32,11 +92,14 @@ int mlockall (int); int munlockall (void); #ifdef _GNU_SOURCE +#define MREMAP_MAYMOVE 1 +#define MREMAP_FIXED 2 void *mremap (void *, size_t, size_t, int, ...); int remap_file_pages (void *, size_t, int, size_t, int); #endif #if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define MLOCK_ONFAULT 0x01 int madvise (void *, size_t, int); int mincore (void *, size_t, unsigned char *); #endif diff --git a/system/include/libc/sys/mount.h b/system/include/libc/sys/mount.h index 1e1907f481630..6674e657754ea 100644 --- a/system/include/libc/sys/mount.h +++ b/system/include/libc/sys/mount.h @@ -46,12 +46,13 @@ extern "C" { #define MS_KERNMOUNT (1<<22) #define MS_I_VERSION (1<<23) #define MS_STRICTATIME (1<<24) +#define MS_LAZYTIME (1<<25) #define MS_NOSEC (1<<28) #define MS_BORN (1<<29) #define MS_ACTIVE (1<<30) #define MS_NOUSER (1U<<31) -#define MS_RMT_MASK (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_I_VERSION) +#define MS_RMT_MASK (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_I_VERSION|MS_LAZYTIME) #define MS_MGC_VAL 0xc0ed0000 #define MS_MGC_MSK 0xffff0000 diff --git a/system/include/libc/sys/prctl.h b/system/include/libc/sys/prctl.h index d41ff0f6180d8..24f4f8bdfb74c 100644 --- a/system/include/libc/sys/prctl.h +++ b/system/include/libc/sys/prctl.h @@ -5,6 +5,8 @@ extern "C" { #endif +#include + #define PR_SET_PDEATHSIG 1 #define PR_GET_PDEATHSIG 2 #define PR_GET_DUMPABLE 3 @@ -80,6 +82,25 @@ extern "C" { #define PR_SET_MM_ENV_END 11 #define PR_SET_MM_AUXV 12 #define PR_SET_MM_EXE_FILE 13 +#define PR_SET_MM_MAP 14 +#define PR_SET_MM_MAP_SIZE 15 + +struct prctl_mm_map { + uint64_t start_code; + uint64_t end_code; + uint64_t start_data; + uint64_t end_data; + uint64_t start_brk; + uint64_t brk; + uint64_t start_stack; + uint64_t arg_start; + uint64_t arg_end; + uint64_t env_start; + uint64_t env_end; + uint64_t *auxv; + uint32_t auxv_size; + uint32_t exe_fd; +}; #define PR_SET_PTRACER 0x59616d61 #define PR_SET_PTRACER_ANY (-1UL) @@ -92,6 +113,23 @@ extern "C" { #define PR_GET_TID_ADDRESS 40 +#define PR_SET_THP_DISABLE 41 +#define PR_GET_THP_DISABLE 42 + +#define PR_MPX_ENABLE_MANAGEMENT 43 +#define PR_MPX_DISABLE_MANAGEMENT 44 + +#define PR_SET_FP_MODE 45 +#define PR_GET_FP_MODE 46 +#define PR_FP_MODE_FR (1 << 0) +#define PR_FP_MODE_FRE (1 << 1) + +#define PR_CAP_AMBIENT 47 +#define PR_CAP_AMBIENT_IS_SET 1 +#define PR_CAP_AMBIENT_RAISE 2 +#define PR_CAP_AMBIENT_LOWER 3 +#define PR_CAP_AMBIENT_CLEAR_ALL 4 + int prctl (int, ...); #ifdef __cplusplus diff --git a/system/include/libc/sys/procfs.h b/system/include/libc/sys/procfs.h index f7936c43233ee..e23bf1ad6b9f6 100644 --- a/system/include/libc/sys/procfs.h +++ b/system/include/libc/sys/procfs.h @@ -33,8 +33,7 @@ struct elf_prstatus { #define ELF_PRARGSZ 80 -struct elf_prpsinfo - { +struct elf_prpsinfo { char pr_state; char pr_sname; char pr_zomb; diff --git a/system/include/libc/sys/ptrace.h b/system/include/libc/sys/ptrace.h index a133e66a17644..d9d4540874425 100644 --- a/system/include/libc/sys/ptrace.h +++ b/system/include/libc/sys/ptrace.h @@ -39,6 +39,7 @@ extern "C" { #define PTRACE_PEEKSIGINFO 0x4209 #define PTRACE_GETSIGMASK 0x420a #define PTRACE_SETSIGMASK 0x420b +#define PTRACE_SECCOMP_GET_FILTER 0x420c #define PT_READ_I PTRACE_PEEKTEXT #define PT_READ_D PTRACE_PEEKDATA @@ -72,7 +73,8 @@ extern "C" { #define PTRACE_O_TRACEEXIT 0x00000040 #define PTRACE_O_TRACESECCOMP 0x00000080 #define PTRACE_O_EXITKILL 0x00100000 -#define PTRACE_O_MASK 0x001000ff +#define PTRACE_O_SUSPEND_SECCOMP 0x00200000 +#define PTRACE_O_MASK 0x003000ff #define PTRACE_EVENT_FORK 1 #define PTRACE_EVENT_VFORK 2 diff --git a/system/include/libc/sys/quota.h b/system/include/libc/sys/quota.h index a06f335ae3844..3ed73785df4c6 100644 --- a/system/include/libc/sys/quota.h +++ b/system/include/libc/sys/quota.h @@ -57,8 +57,7 @@ extern "C" { #define QIF_TIMES (QIF_BTIME | QIF_ITIME) #define QIF_ALL (QIF_LIMITS | QIF_USAGE | QIF_TIMES) -struct dqblk -{ +struct dqblk { uint64_t dqb_bhardlimit; uint64_t dqb_bsoftlimit; uint64_t dqb_curspace; @@ -87,8 +86,7 @@ struct dqblk #define IIF_FLAGS 4 #define IIF_ALL (IIF_BGRACE | IIF_IGRACE | IIF_FLAGS) -struct dqinfo -{ +struct dqinfo { uint64_t dqi_bgrace; uint64_t dqi_igrace; uint32_t dqi_flags; diff --git a/system/include/libc/sys/resource.h b/system/include/libc/sys/resource.h index 58392d64ba8f0..70d793d563f58 100644 --- a/system/include/libc/sys/resource.h +++ b/system/include/libc/sys/resource.h @@ -19,14 +19,12 @@ extern "C" { typedef unsigned long long rlim_t; -struct rlimit -{ +struct rlimit { rlim_t rlim_cur; rlim_t rlim_max; }; -struct rusage -{ +struct rusage { struct timeval ru_utime; struct timeval ru_stime; /* linux extentions, but useful */ @@ -68,7 +66,8 @@ int prlimit(pid_t, int, const struct rlimit *, struct rlimit *); #define PRIO_USER 2 #define RUSAGE_SELF 0 -#define RUSAGE_CHILDREN 1 +#define RUSAGE_CHILDREN (-1) +#define RUSAGE_THREAD 1 #define RLIM_INFINITY (~0ULL) #define RLIM_SAVED_CUR RLIM_INFINITY @@ -96,6 +95,9 @@ int prlimit(pid_t, int, const struct rlimit *, struct rlimit *); #define RLIM_NLIMITS RLIMIT_NLIMITS #if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#define RLIM64_INFINITY RLIM_INFINITY +#define RLIM64_SAVED_CUR RLIM_SAVED_CUR +#define RLIM64_SAVED_MAX RLIM_SAVED_MAX #define getrlimit64 getrlimit #define setrlimit64 setrlimit #define rlimit64 rlimit diff --git a/system/include/libc/sys/select.h b/system/include/libc/sys/select.h index e25257d2f33b9..d34cbf10d9cc9 100644 --- a/system/include/libc/sys/select.h +++ b/system/include/libc/sys/select.h @@ -19,8 +19,7 @@ extern "C" { typedef unsigned long fd_mask; -typedef struct -{ +typedef struct { unsigned long fds_bits[FD_SETSIZE / 8 / sizeof(long)]; } fd_set; diff --git a/system/include/libc/sys/socket.h b/system/include/libc/sys/socket.h index 8e8c9e9261b9d..59ab1e2ff9518 100644 --- a/system/include/libc/sys/socket.h +++ b/system/include/libc/sys/socket.h @@ -20,16 +20,24 @@ extern "C" { #include #ifdef _GNU_SOURCE -struct ucred -{ +struct ucred { pid_t pid; uid_t uid; gid_t gid; }; + +struct mmsghdr { + struct msghdr msg_hdr; + unsigned int msg_len; +}; + +struct timespec; + +int sendmmsg (int, struct mmsghdr *, unsigned int, unsigned int); +int recvmmsg (int, struct mmsghdr *, unsigned int, unsigned int, struct timespec *); #endif -struct linger -{ +struct linger { int l_onoff; int l_linger; }; @@ -85,6 +93,7 @@ struct linger #define PF_WANPIPE 25 #define PF_LLC 26 #define PF_IB 27 +#define PF_MPLS 28 #define PF_CAN 29 #define PF_TIPC 30 #define PF_BLUETOOTH 31 @@ -97,7 +106,8 @@ struct linger #define PF_ALG 38 #define PF_NFC 39 #define PF_VSOCK 40 -#define PF_MAX 41 +#define PF_KCM 41 +#define PF_MAX 42 #define AF_UNSPEC PF_UNSPEC #define AF_LOCAL PF_LOCAL @@ -130,6 +140,7 @@ struct linger #define AF_WANPIPE PF_WANPIPE #define AF_LLC PF_LLC #define AF_IB PF_IB +#define AF_MPLS PF_MPLS #define AF_CAN PF_CAN #define AF_TIPC PF_TIPC #define AF_BLUETOOTH PF_BLUETOOTH @@ -142,6 +153,7 @@ struct linger #define AF_ALG PF_ALG #define AF_NFC PF_NFC #define AF_VSOCK PF_VSOCK +#define AF_KCM PF_KCM #define AF_MAX PF_MAX #ifndef SO_DEBUG @@ -166,8 +178,11 @@ struct linger #define SO_SNDLOWAT 19 #define SO_RCVTIMEO 20 #define SO_SNDTIMEO 21 +#define SO_ACCEPTCONN 30 #define SO_SNDBUFFORCE 32 #define SO_RCVBUFFORCE 33 +#define SO_PROTOCOL 38 +#define SO_DOMAIN 39 #endif #define SO_SECURITY_AUTHENTICATION 22 @@ -184,7 +199,6 @@ struct linger #define SO_TIMESTAMP 29 #define SCM_TIMESTAMP SO_TIMESTAMP -#define SO_ACCEPTCONN 30 #define SO_PEERSEC 31 #define SO_PASSSEC 34 #define SO_TIMESTAMPNS 35 @@ -192,8 +206,6 @@ struct linger #define SO_MARK 36 #define SO_TIMESTAMPING 37 #define SCM_TIMESTAMPING SO_TIMESTAMPING -#define SO_PROTOCOL 38 -#define SO_DOMAIN 39 #define SO_RXQ_OVFL 40 #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS @@ -203,6 +215,13 @@ struct linger #define SO_SELECT_ERR_QUEUE 45 #define SO_BUSY_POLL 46 #define SO_MAX_PACING_RATE 47 +#define SO_BPF_EXTENSIONS 48 +#define SO_INCOMING_CPU 49 +#define SO_ATTACH_BPF 50 +#define SO_DETACH_BPF SO_DETACH_FILTER +#define SO_ATTACH_REUSEPORT_CBPF 51 +#define SO_ATTACH_REUSEPORT_EBPF 52 +#define SO_CNX_ADVICE 53 #ifndef SOL_SOCKET #define SOL_SOCKET 1 @@ -219,6 +238,21 @@ struct linger #define SOL_ATM 264 #define SOL_AAL 265 #define SOL_IRDA 266 +#define SOL_NETBEUI 267 +#define SOL_LLC 268 +#define SOL_DCCP 269 +#define SOL_NETLINK 270 +#define SOL_TIPC 271 +#define SOL_RXRPC 272 +#define SOL_PPPOL2TP 273 +#define SOL_BLUETOOTH 274 +#define SOL_PNPIPE 275 +#define SOL_RDS 276 +#define SOL_IUCV 277 +#define SOL_CAIF 278 +#define SOL_ALG 279 +#define SOL_NFC 280 +#define SOL_KCM 281 #define SOMAXCONN 128 @@ -239,6 +273,8 @@ struct linger #define MSG_NOSIGNAL 0x4000 #define MSG_MORE 0x8000 #define MSG_WAITFORONE 0x10000 +#define MSG_BATCH 0x40000 +#define MSG_FASTOPEN 0x20000000 #define MSG_CMSG_CLOEXEC 0x40000000 #define __CMSG_LEN(cmsg) (((cmsg)->cmsg_len + sizeof(long) - 1) & ~(long)(sizeof(long) - 1)) @@ -246,9 +282,9 @@ struct linger #define __MHDR_END(mhdr) ((unsigned char *)(mhdr)->msg_control + (mhdr)->msg_controllen) #define CMSG_DATA(cmsg) ((unsigned char *) (((struct cmsghdr *)(cmsg)) + 1)) -#define CMSG_NXTHDR(mhdr, cmsg) ((cmsg)->cmsg_len < sizeof (struct cmsghdr) ? (struct cmsghdr *)0 : \ - (__CMSG_NEXT(cmsg) + sizeof (struct cmsghdr) >= __MHDR_END(mhdr) ? (struct cmsghdr *)0 : \ - ((struct cmsghdr *)__CMSG_NEXT(cmsg)))) +#define CMSG_NXTHDR(mhdr, cmsg) ((cmsg)->cmsg_len < sizeof (struct cmsghdr) || \ + __CMSG_LEN(cmsg) + sizeof(struct cmsghdr) >= __MHDR_END(mhdr) - (unsigned char *)(cmsg) \ + ? 0 : (struct cmsghdr *)__CMSG_NEXT(cmsg)) #define CMSG_FIRSTHDR(mhdr) ((size_t) (mhdr)->msg_controllen >= sizeof (struct cmsghdr) ? (struct cmsghdr *) (mhdr)->msg_control : (struct cmsghdr *) 0) #define CMSG_ALIGN(len) (((len) + sizeof (size_t) - 1) & (size_t) ~(sizeof (size_t) - 1)) @@ -258,17 +294,15 @@ struct linger #define SCM_RIGHTS 0x01 #define SCM_CREDENTIALS 0x02 -struct sockaddr -{ +struct sockaddr { sa_family_t sa_family; char sa_data[14]; }; -struct sockaddr_storage -{ +struct sockaddr_storage { sa_family_t ss_family; + char __ss_padding[128-sizeof(long)-sizeof(sa_family_t)]; unsigned long __ss_align; - char __ss_padding[128-2*sizeof(unsigned long)]; }; int socket (int, int, int); diff --git a/system/include/libc/sys/stat.h b/system/include/libc/sys/stat.h index c6abab5a0c01f..82a649043dc8b 100644 --- a/system/include/libc/sys/stat.h +++ b/system/include/libc/sys/stat.h @@ -100,8 +100,9 @@ int lchmod(const char *, mode_t); #define fstat64 fstat #define lstat64 lstat #define fstatat64 fstatat -#define blksize64_t blksize_t #define blkcnt64_t blkcnt_t +#define fsblkcnt64_t fsblkcnt_t +#define fsfilcnt64_t fsfilcnt_t #define ino64_t ino_t #define off64_t off_t #endif diff --git a/system/include/libc/sys/time.h b/system/include/libc/sys/time.h index bfe1414e86fbc..e4b379aea8590 100644 --- a/system/include/libc/sys/time.h +++ b/system/include/libc/sys/time.h @@ -17,8 +17,7 @@ int gettimeofday (struct timeval *__restrict, void *__restrict); #define ITIMER_VIRTUAL 1 #define ITIMER_PROF 2 -struct itimerval -{ +struct itimerval { struct timeval it_interval; struct timeval it_value; }; diff --git a/system/include/libc/sys/timerfd.h b/system/include/libc/sys/timerfd.h index df645fe8aef56..9724d903472c5 100644 --- a/system/include/libc/sys/timerfd.h +++ b/system/include/libc/sys/timerfd.h @@ -13,6 +13,8 @@ extern "C" { #define TFD_TIMER_ABSTIME 1 +struct itimerspec; + int timerfd_create(int, int); int timerfd_settime(int, int, const struct itimerspec *, struct itimerspec *); int timerfd_gettime(int, struct itimerspec *); diff --git a/system/include/libc/sys/times.h b/system/include/libc/sys/times.h index cc55e573fd4b8..80a50522d75d9 100644 --- a/system/include/libc/sys/times.h +++ b/system/include/libc/sys/times.h @@ -8,8 +8,7 @@ extern "C" { #define __NEED_clock_t #include -struct tms -{ +struct tms { clock_t tms_utime; clock_t tms_stime; clock_t tms_cutime; diff --git a/system/include/libc/sys/types.h b/system/include/libc/sys/types.h index 27170f6443b85..75e489c57345a 100644 --- a/system/include/libc/sys/types.h +++ b/system/include/libc/sys/types.h @@ -20,11 +20,6 @@ extern "C" { #define __NEED_timer_t #define __NEED_clockid_t -#define __NEED_int8_t -#define __NEED_int16_t -#define __NEED_int32_t -#define __NEED_int64_t - #define __NEED_blkcnt_t #define __NEED_fsblkcnt_t #define __NEED_fsfilcnt_t @@ -49,19 +44,22 @@ extern "C" { #define __NEED_pthread_key_t #define __NEED_pthread_once_t #define __NEED_useconds_t -#define __NEED_u_int64_t #if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define __NEED_int8_t +#define __NEED_int16_t +#define __NEED_int32_t +#define __NEED_int64_t +#define __NEED_u_int64_t #define __NEED_register_t #endif #include +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) typedef unsigned char u_int8_t; typedef unsigned short u_int16_t; typedef unsigned u_int32_t; - -#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) typedef char *caddr_t; typedef unsigned char u_char; typedef unsigned short u_short, ushort; @@ -75,7 +73,6 @@ typedef unsigned long long u_quad_t; #endif #if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) -#define blksize64_t blksize_t #define blkcnt64_t blkcnt_t #define fsblkcnt64_t fsblkcnt_t #define fsfilcnt64_t fsfilcnt_t @@ -87,5 +84,3 @@ typedef unsigned long long u_quad_t; } #endif #endif - - diff --git a/system/include/libc/sys/un.h b/system/include/libc/sys/un.h index 7494f1a382ed0..1a3193ad208de 100644 --- a/system/include/libc/sys/un.h +++ b/system/include/libc/sys/un.h @@ -14,8 +14,7 @@ extern "C" { #include -struct sockaddr_un -{ +struct sockaddr_un { sa_family_t sun_family; char sun_path[108]; }; diff --git a/system/include/libc/sys/utsname.h b/system/include/libc/sys/utsname.h index 6b9ea970970df..2c80fb5a2dfbd 100644 --- a/system/include/libc/sys/utsname.h +++ b/system/include/libc/sys/utsname.h @@ -7,8 +7,7 @@ extern "C" { #include -struct utsname -{ +struct utsname { char sysname[65]; char nodename[65]; char release[65]; diff --git a/system/include/libc/threads.h b/system/include/libc/threads.h new file mode 100644 index 0000000000000..017948261e9f8 --- /dev/null +++ b/system/include/libc/threads.h @@ -0,0 +1,87 @@ +#ifndef _THREADS_H +#define _THREADS_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +typedef unsigned long thrd_t; +#else +typedef struct __pthread *thrd_t; +#define thread_local _Thread_local +#endif + +typedef int once_flag; +typedef unsigned tss_t; +typedef int (*thrd_start_t)(void *); +typedef void (*tss_dtor_t)(void *); + +#define __NEED_cnd_t +#define __NEED_mtx_t + +#include + +#define TSS_DTOR_ITERATIONS 4 + +enum { + thrd_success = 0, + thrd_busy = 1, + thrd_error = 2, + thrd_nomem = 3, + thrd_timedout = 4, +}; + +enum { + mtx_plain = 0, + mtx_recursive = 1, + mtx_timed = 2, +}; + +#define ONCE_FLAG_INIT 0 + +int thrd_create(thrd_t *, thrd_start_t, void *); +_Noreturn void thrd_exit(int); + +int thrd_detach(thrd_t); +int thrd_join(thrd_t, int *); + +int thrd_sleep(const struct timespec *, struct timespec *); +void thrd_yield(void); + +thrd_t thrd_current(void); +int thrd_equal(thrd_t, thrd_t); +#ifndef __cplusplus +#define thrd_equal(A, B) ((A) == (B)) +#endif + +void call_once(once_flag *, void (*)(void)); + +int mtx_init(mtx_t *, int); +void mtx_destroy(mtx_t *); + +int mtx_lock(mtx_t *); +int mtx_timedlock(mtx_t *__restrict, const struct timespec *__restrict); +int mtx_trylock(mtx_t *); +int mtx_unlock(mtx_t *); + +int cnd_init(cnd_t *); +void cnd_destroy(cnd_t *); + +int cnd_broadcast(cnd_t *); +int cnd_signal(cnd_t *); + +int cnd_timedwait(cnd_t *__restrict, mtx_t *__restrict, const struct timespec *__restrict); +int cnd_wait(cnd_t *, mtx_t *); + +int tss_create(tss_t *, tss_dtor_t); +void tss_delete(tss_t key); + +int tss_set(tss_t, void *); +void *tss_get(tss_t); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/system/include/libc/time.h b/system/include/libc/time.h index dc8807063af91..a408679c2b0e0 100644 --- a/system/include/libc/time.h +++ b/system/include/libc/time.h @@ -17,11 +17,11 @@ extern "C" { #define __NEED_size_t #define __NEED_time_t #define __NEED_clock_t +#define __NEED_struct_timespec #if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \ || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \ || defined(_BSD_SOURCE) -#define __NEED_struct_timespec #define __NEED_clockid_t #define __NEED_timer_t #define __NEED_pid_t @@ -35,8 +35,7 @@ extern "C" { #define __tm_zone tm_zone #endif -struct tm -{ +struct tm { int tm_sec; int tm_min; int tm_hour; @@ -59,9 +58,11 @@ struct tm *gmtime (const time_t *); struct tm *localtime (const time_t *); char *asctime (const struct tm *); char *ctime (const time_t *); +int timespec_get(struct timespec *, int); #define CLOCKS_PER_SEC 1000000L +#define TIME_UTC 1 #if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \ || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \ @@ -76,8 +77,7 @@ char *ctime_r (const time_t *, char *); void tzset (void); -struct itimerspec -{ +struct itimerspec { struct timespec it_interval; struct timespec it_value; }; @@ -114,7 +114,7 @@ int timer_getoverrun (timer_t); #endif -#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) +#if defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE) || defined(_GNU_SOURCE) char *strptime (const char *__restrict, const char *__restrict, struct tm *__restrict); extern int daylight; extern long timezone; diff --git a/system/include/libc/uchar.h b/system/include/libc/uchar.h new file mode 100644 index 0000000000000..8dabf1ed9b8ee --- /dev/null +++ b/system/include/libc/uchar.h @@ -0,0 +1,27 @@ +#ifndef _UCHAR_H +#define _UCHAR_H + +#ifdef __cplusplus +extern "C" { +#else +typedef unsigned short char16_t; +typedef unsigned char32_t; +#endif + +#define __NEED_mbstate_t +#define __NEED_size_t + +#include +#include + +size_t c16rtomb(char *__restrict, char16_t, mbstate_t *__restrict); +size_t mbrtoc16(char16_t *__restrict, const char *__restrict, size_t, mbstate_t *__restrict); + +size_t c32rtomb(char *__restrict, char32_t, mbstate_t *__restrict); +size_t mbrtoc32(char32_t *__restrict, const char *__restrict, size_t, mbstate_t *__restrict); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/system/include/libc/unistd.h b/system/include/libc/unistd.h index 2ceef55a73326..c7cafaafbc046 100644 --- a/system/include/libc/unistd.h +++ b/system/include/libc/unistd.h @@ -140,9 +140,6 @@ int lockf(int, int, off_t); long gethostid(void); int nice(int); void sync(void); -#endif - -#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) pid_t setpgrp(void); char *crypt(const char *, const char *); void encrypt(char *, int); @@ -177,6 +174,8 @@ void endusershell(void); char *getusershell(void); int acct(const char *); /* XXX EMSCRIPTEN long syscall(long, ...); */ +int execvpe(const char *, char *const [], char *const []); +int issetugid(void); #endif #ifdef _GNU_SOURCE @@ -186,7 +185,7 @@ int setresgid(gid_t, gid_t, gid_t); int getresuid(uid_t *, uid_t *, uid_t *); int getresgid(gid_t *, gid_t *, gid_t *); char *get_current_dir_name(void); -void syncfs(int); +int syncfs(int); int euidaccess(const char *, int); int eaccess(const char *, int); #endif @@ -320,11 +319,9 @@ int eaccess(const char *, int); #define _SC_BC_SCALE_MAX 38 #define _SC_BC_STRING_MAX 39 #define _SC_COLL_WEIGHTS_MAX 40 -#define _SC_EQUIV_CLASS_MAX 41 #define _SC_EXPR_NEST_MAX 42 #define _SC_LINE_MAX 43 #define _SC_RE_DUP_MAX 44 -#define _SC_CHARCLASS_NAME_MAX 45 #define _SC_2_VERSION 46 #define _SC_2_C_BIND 47 #define _SC_2_C_DEV 48 @@ -332,21 +329,8 @@ int eaccess(const char *, int); #define _SC_2_FORT_RUN 50 #define _SC_2_SW_DEV 51 #define _SC_2_LOCALEDEF 52 -#define _SC_PII 53 -#define _SC_PII_XTI 54 -#define _SC_PII_SOCKET 55 -#define _SC_PII_INTERNET 56 -#define _SC_PII_OSI 57 -#define _SC_POLL 58 -#define _SC_SELECT 59 #define _SC_UIO_MAXIOV 60 /* !! */ #define _SC_IOV_MAX 60 -#define _SC_PII_INTERNET_STREAM 61 -#define _SC_PII_INTERNET_DGRAM 62 -#define _SC_PII_OSI_COTS 63 -#define _SC_PII_OSI_CLTS 64 -#define _SC_PII_OSI_M 65 -#define _SC_T_IOV_MAX 66 #define _SC_THREADS 67 #define _SC_THREAD_SAFE_FUNCTIONS 68 #define _SC_GETGR_R_SIZE_MAX 69 @@ -376,35 +360,11 @@ int eaccess(const char *, int); #define _SC_XOPEN_ENH_I18N 93 #define _SC_XOPEN_SHM 94 #define _SC_2_CHAR_TERM 95 -#define _SC_2_C_VERSION 96 #define _SC_2_UPE 97 #define _SC_XOPEN_XPG2 98 #define _SC_XOPEN_XPG3 99 #define _SC_XOPEN_XPG4 100 -#define _SC_CHAR_BIT 101 -#define _SC_CHAR_MAX 102 -#define _SC_CHAR_MIN 103 -#define _SC_INT_MAX 104 -#define _SC_INT_MIN 105 -#define _SC_LONG_BIT 106 -#define _SC_WORD_BIT 107 -#define _SC_MB_LEN_MAX 108 #define _SC_NZERO 109 -#define _SC_SSIZE_MAX 110 -#define _SC_SCHAR_MAX 111 -#define _SC_SCHAR_MIN 112 -#define _SC_SHRT_MAX 113 -#define _SC_SHRT_MIN 114 -#define _SC_UCHAR_MAX 115 -#define _SC_UINT_MAX 116 -#define _SC_ULONG_MAX 117 -#define _SC_USHRT_MAX 118 -#define _SC_NL_ARGMAX 119 -#define _SC_NL_LANGMAX 120 -#define _SC_NL_MSGMAX 121 -#define _SC_NL_NMAX 122 -#define _SC_NL_SETMAX 123 -#define _SC_NL_TEXTMAX 124 #define _SC_XBS5_ILP32_OFF32 125 #define _SC_XBS5_ILP32_OFFBIG 126 #define _SC_XBS5_LP64_OFF64 127 @@ -414,40 +374,19 @@ int eaccess(const char *, int); #define _SC_XOPEN_REALTIME_THREADS 131 #define _SC_ADVISORY_INFO 132 #define _SC_BARRIERS 133 -#define _SC_BASE 134 -#define _SC_C_LANG_SUPPORT 135 -#define _SC_C_LANG_SUPPORT_R 136 #define _SC_CLOCK_SELECTION 137 #define _SC_CPUTIME 138 #define _SC_THREAD_CPUTIME 139 -#define _SC_DEVICE_IO 140 -#define _SC_DEVICE_SPECIFIC 141 -#define _SC_DEVICE_SPECIFIC_R 142 -#define _SC_FD_MGMT 143 -#define _SC_FIFO 144 -#define _SC_PIPE 145 -#define _SC_FILE_ATTRIBUTES 146 -#define _SC_FILE_LOCKING 147 -#define _SC_FILE_SYSTEM 148 #define _SC_MONOTONIC_CLOCK 149 -#define _SC_MULTI_PROCESS 150 -#define _SC_SINGLE_PROCESS 151 -#define _SC_NETWORKING 152 #define _SC_READER_WRITER_LOCKS 153 #define _SC_SPIN_LOCKS 154 #define _SC_REGEXP 155 -#define _SC_REGEX_VERSION 156 #define _SC_SHELL 157 -#define _SC_SIGNALS 158 #define _SC_SPAWN 159 #define _SC_SPORADIC_SERVER 160 #define _SC_THREAD_SPORADIC_SERVER 161 -#define _SC_SYSTEM_DATABASE 162 -#define _SC_SYSTEM_DATABASE_R 163 #define _SC_TIMEOUTS 164 #define _SC_TYPED_MEMORY_OBJECTS 165 -#define _SC_USER_GROUPS 166 -#define _SC_USER_GROUPS_R 167 #define _SC_2_PBS 168 #define _SC_2_PBS_ACCOUNTING 169 #define _SC_2_PBS_LOCATE 170 diff --git a/system/include/libc/utime.h b/system/include/libc/utime.h index ec82e0f3f844f..dd5ff927c25d1 100644 --- a/system/include/libc/utime.h +++ b/system/include/libc/utime.h @@ -9,8 +9,7 @@ extern "C" { #include -struct utimbuf -{ +struct utimbuf { time_t actime; time_t modtime; }; diff --git a/system/include/libc/utmp.h b/system/include/libc/utmp.h index e9ba23e2de059..48a400d84dec3 100644 --- a/system/include/libc/utmp.h +++ b/system/include/libc/utmp.h @@ -22,7 +22,6 @@ struct lastlog { #define ut_name ut_user #define ut_addr ut_addr_v6[0] #define utmp utmpx -#define utmpname(x) (-1) #define e_exit __e_exit #define e_termination __e_termination @@ -34,6 +33,9 @@ struct utmp *pututline(const struct utmp *); void setutent(void); void updwtmp(const char *, const struct utmp *); +int utmpname(const char *); + +int login_tty(int); #define _PATH_UTMP "/dev/null/utmp" #define _PATH_WTMP "/dev/null/wtmp" diff --git a/system/include/libc/utmpx.h b/system/include/libc/utmpx.h index f0c3b01370c7b..9e5cc955eb1f8 100644 --- a/system/include/libc/utmpx.h +++ b/system/include/libc/utmpx.h @@ -14,8 +14,7 @@ extern "C" { #include -struct utmpx -{ +struct utmpx { short ut_type; pid_t ut_pid; char ut_line[32]; @@ -43,6 +42,7 @@ void setutxent(void); #define e_exit __e_exit #define e_termination __e_termination void updwtmpx(const char *, const struct utmpx *); +int utmpxname(const char *); #endif #define EMPTY 0 diff --git a/system/include/libc/wchar.h b/system/include/libc/wchar.h index 9fd967ccc365e..0167dce6b577a 100644 --- a/system/include/libc/wchar.h +++ b/system/include/libc/wchar.h @@ -12,6 +12,7 @@ extern "C" { #define __NEED_size_t #define __NEED_wchar_t #define __NEED_wint_t +#define __NEED_mbstate_t #if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \ || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE) @@ -42,11 +43,6 @@ extern "C" { #undef WEOF #define WEOF 0xffffffffU -typedef struct __mbstate_t -{ - unsigned __opaque1, __opaque2; -} mbstate_t; - wchar_t *wcscpy (wchar_t *__restrict, const wchar_t *__restrict); wchar_t *wcsncpy (wchar_t *__restrict, const wchar_t *__restrict, size_t); @@ -176,8 +172,11 @@ int iswctype(wint_t, wctype_t); wint_t towlower(wint_t); wint_t towupper(wint_t); wctype_t wctype(const char *); + +#ifndef __cplusplus #undef iswdigit -#define iswdigit(a) ((unsigned)(a)-'0' < 10) +#define iswdigit(a) (0 ? iswdigit(a) : ((unsigned)(a)-'0') < 10) +#endif #endif #ifdef __cplusplus diff --git a/system/include/libc/wctype.h b/system/include/libc/wctype.h index 3ac24f13841a7..bc2420d3fd847 100644 --- a/system/include/libc/wctype.h +++ b/system/include/libc/wctype.h @@ -43,8 +43,10 @@ wint_t towupper(wint_t); wctrans_t wctrans(const char *); wctype_t wctype(const char *); +#ifndef __cplusplus #undef iswdigit -#define iswdigit(a) (((unsigned)(a)-L'0') < 10) +#define iswdigit(a) (0 ? iswdigit(a) : ((unsigned)(a)-'0') < 10) +#endif #if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \ || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE) diff --git a/system/include/libc/wordexp.h b/system/include/libc/wordexp.h index d12081e80130c..5460002deec74 100644 --- a/system/include/libc/wordexp.h +++ b/system/include/libc/wordexp.h @@ -18,8 +18,7 @@ extern "C" { #define WRDE_SHOWERR 16 #define WRDE_UNDEF 32 -typedef struct -{ +typedef struct { size_t we_wordc; char **we_wordv; size_t we_offs; diff --git a/system/lib/libc/musl/COPYRIGHT b/system/lib/libc/musl/COPYRIGHT index a8a38a56305c7..f0ee3b78d8798 100644 --- a/system/lib/libc/musl/COPYRIGHT +++ b/system/lib/libc/musl/COPYRIGHT @@ -25,31 +25,54 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Authors/contributors include: +Alex Dowad +Alexander Monakov Anthony G. Basile Arvid Picciani Bobby Bingham Boris Brezillon +Brent Cook Chris Spiegel +Clément Vasseur +Daniel Micay +Denys Vlasenko Emil Renner Berthing +Felix Fietkau +Felix Janda +Gianluca Anzolin +Hauke Mehrtens Hiltjo Posthuma Isaac Dunham +Jaydeep Patil Jens Gustedt Jeremy Huntwork +Jo-Philipp Wich +Joakim Sindholt John Spencer +Josiah Worcester Justin Cormack +Khem Raj +Kylie McClain Luca Barbato Luka Perkov +M Farkas-Dyck (Strake) +Mahesh Bodapati Michael Forney +Natanael Copa Nicholas J. Kain orc Pascal Cuoq +Petr Hosek Pierre Carrier Rich Felker Richard Pennington +Shiz +sin Solar Designer -Strake +Stefan Kristiansson Szabolcs Nagy Timo Teräs +Trutz Behn Valentin Ochs William Haddon @@ -71,14 +94,14 @@ Copyright © 2008 Stephen L. Moshier and labelled as such in comments in the individual source files. All have been licensed under extremely permissive terms. -The ARM memcpy code (src/string/armel/memcpy.s) is Copyright © 2008 +The ARM memcpy code (src/string/arm/memcpy_el.S) is Copyright © 2008 The Android Open Source Project and is licensed under a two-clause BSD license. It was taken from Bionic libc, used on Android. -The implementation of DES for crypt (src/misc/crypt_des.c) is +The implementation of DES for crypt (src/crypt/crypt_des.c) is Copyright © 1994 David Burren. It is licensed under a BSD license. -The implementation of blowfish crypt (src/misc/crypt_blowfish.c) was +The implementation of blowfish crypt (src/crypt/crypt_blowfish.c) was originally written by Solar Designer and placed into the public domain. The code also comes with a fallback permissive license for use in jurisdictions that may not recognize the public domain. @@ -92,16 +115,17 @@ licensed under following terms: "Permission to use, copy, modify, and/or distribute this code for any purpose with or without fee is hereby granted. There is no warranty." -The x86_64 port was written by Nicholas J. Kain. Several files (crt) -were released into the public domain; others are licensed under the -standard MIT license terms at the top of this file. See individual -files for their copyright status. +The x86_64 port was written by Nicholas J. Kain and is licensed under +the standard MIT terms. The mips and microblaze ports were originally written by Richard Pennington for use in the ellcc project. The original code was adapted by Rich Felker for build system and code conventions during upstream integration. It is licensed under the standard MIT terms. +The mips64 port was contributed by Imagination Technologies and is +licensed under the standard MIT terms. + The powerpc port was also originally written by Richard Pennington, and later supplemented and integrated by John Spencer. It is licensed under the standard MIT terms. @@ -114,15 +138,26 @@ can be found in the git version control history of the project. The omission of copyright and license comments in each file is in the interest of source tree size. -All public header files (include/* and arch/*/bits/*) should be -treated as Public Domain as they intentionally contain no content -which can be covered by copyright. Some source modules may fall in -this category as well. If you believe that a file is so trivial that -it should be in the Public Domain, please contact the authors and -request an explicit statement releasing it from copyright. +In addition, permission is hereby granted for all public header files +(include/* and arch/*/bits/*) and crt files intended to be linked into +applications (crt/*, ldso/dlstart.c, and arch/*/crt_arch.h) to omit +the copyright notice and permission notice otherwise required by the +license, and to use these files without any requirement of +attribution. These files include substantial contributions from: + +Bobby Bingham +John Spencer +Nicholas J. Kain +Rich Felker +Richard Pennington +Stefan Kristiansson +Szabolcs Nagy -The following files are trivial, believed not to be copyrightable in -the first place, and hereby explicitly released to the Public Domain: +all of whom have explicitly granted such permission. -All public headers: include/*, arch/*/bits/* -Startup files: crt/* +This file previously contained text expressing a belief that most of +the files covered by the above exception were sufficiently trivial not +to be subject to copyright, resulting in confusion over whether it +negated the permissions granted in the license. In the spirit of +permissive licensing, and of not having licensing issues being an +obstacle to adoption, that text has been removed. diff --git a/system/lib/libc/musl/INSTALL b/system/lib/libc/musl/INSTALL index 9f295d5059a1e..526c3f62ed2d4 100644 --- a/system/lib/libc/musl/INSTALL +++ b/system/lib/libc/musl/INSTALL @@ -18,25 +18,18 @@ Build Prerequisites The only build-time prerequisites for musl are GNU Make and a freestanding C99 compiler toolchain targeting the desired instruction -set architecture and ABI, with support for gcc-style inline assembly, -weak aliases, and stand-alone assembly source files. +set architecture and ABI, with support for a minimal subset of "GNU C" +extensions consisting mainly of gcc-style inline assembly, weak +aliases, hidden visibility, and stand-alone assembly source files. + +GCC, LLVM/clang, Firm/cparser, and PCC have all successfully built +musl, but GCC is the most widely used/tested. Recent compiler (and +binutils) versions should be used if possible since some older +versions have bugs which affect musl. The system used to build musl does not need to be Linux-based, nor do the Linux kernel headers need to be available. -If support for dynamic linking is desired, some further requirements -are placed on the compiler and linker. In particular, the linker must -support the -Bsymbolic-functions option. - -At present, GCC 4.6 or later is the recommended compiler for building -musl. Any earlier version of GCC with full C99 support should also -work, but may be subject to minor floating point conformance issues on -i386 targets. Sufficiently recent versions of PCC and LLVM/clang are -also believed to work, but have not been tested as heavily; prior to -Fall 2012, both had known bugs that affected musl. Firm/cparser is -also believed to work but lacks support for producing shared -libraries. - Supported Targets @@ -50,12 +43,17 @@ and ABI combinations: the `cmpxchg` instruction is added * x86_64 + * ILP32 ABI (x32) is available as a separate arch but is still + experimental * ARM * EABI, standard or hard-float VFP variant * Little-endian default; big-endian variants also supported * Compiler toolchains only support armv4t and later +* AArch64 + * Little-endian default; big-endian variants also supported + * MIPS * ABI is o32 * Big-endian default; little-endian variants also supported @@ -64,6 +62,12 @@ and ABI combinations: * MIPS2 or later, or kernel emulation of ll/sc (standard in Linux) is required +* MIPS64 + * ABI is n64 (LP64) + * Big-endian default; little-endian variants also supported + * Default ABI variant uses FPU registers; alternate soft-float ABI + that does not use FPU registers or instructions is available + * PowerPC * Only 32-bit is supported * Compiler toolchain must provide 64-bit long double, not IBM @@ -71,21 +75,18 @@ and ABI combinations: * For dynamic linking, compiler toolchain must be configured for "secure PLT" variant +* SuperH (SH) + * Standard ELF ABI or FDPIC ABI (shared-text without MMU) + * Little-endian by default; big-engian variant also supported + * Full FPU ABI or soft-float ABI is supported, but the + single-precision-only FPU ABI is not + * Microblaze * Big-endian default; little-endian variants also supported * Soft-float * Requires support for lwx/swx instructions -The following additional targets are available for build, but may not -work correctly and may not yet have ABI stability: - -* SuperH (SH) - * Little-endian by default; big-engian variant also supported - * Full FPU ABI or soft-float ABI is supported, but the - single-precision-only FPU ABI is not supported (musl always - requires IEEE single and double to be supported) - -* x32 (x86_64 ILP32 ABI) +* OpenRISC 1000 (or1k) diff --git a/system/lib/libc/musl/Makefile b/system/lib/libc/musl/Makefile index 0ab0bfddb2364..8246b78f73b34 100644 --- a/system/lib/libc/musl/Makefile +++ b/system/lib/libc/musl/Makefile @@ -8,6 +8,7 @@ # Do not make changes here. # +srcdir = . exec_prefix = /usr/local bindir = $(exec_prefix)/bin @@ -16,138 +17,183 @@ includedir = $(prefix)/include libdir = $(prefix)/lib syslibdir = /lib -SRCS = $(sort $(wildcard src/*/*.c arch/$(ARCH)/src/*.c)) -OBJS = $(SRCS:.c=.o) -LOBJS = $(OBJS:.o=.lo) -GENH = include/bits/alltypes.h -GENH_INT = src/internal/version.h -IMPH = src/internal/stdio_impl.h src/internal/pthread_impl.h src/internal/libc.h - -LDFLAGS = +SRC_DIRS = $(addprefix $(srcdir)/,src/* crt ldso) +BASE_GLOBS = $(addsuffix /*.c,$(SRC_DIRS)) +ARCH_GLOBS = $(addsuffix /$(ARCH)/*.[csS],$(SRC_DIRS)) +BASE_SRCS = $(sort $(wildcard $(BASE_GLOBS))) +ARCH_SRCS = $(sort $(wildcard $(ARCH_GLOBS))) +BASE_OBJS = $(patsubst $(srcdir)/%,%.o,$(basename $(BASE_SRCS))) +ARCH_OBJS = $(patsubst $(srcdir)/%,%.o,$(basename $(ARCH_SRCS))) +REPLACED_OBJS = $(sort $(subst /$(ARCH)/,/,$(ARCH_OBJS))) +ALL_OBJS = $(addprefix obj/, $(filter-out $(REPLACED_OBJS), $(sort $(BASE_OBJS) $(ARCH_OBJS)))) + +LIBC_OBJS = $(filter obj/src/%,$(ALL_OBJS)) +LDSO_OBJS = $(filter obj/ldso/%,$(ALL_OBJS:%.o=%.lo)) +CRT_OBJS = $(filter obj/crt/%,$(ALL_OBJS)) + +AOBJS = $(LIBC_OBJS) +LOBJS = $(LIBC_OBJS:.o=.lo) +GENH = obj/include/bits/alltypes.h obj/include/bits/syscall.h +GENH_INT = obj/src/internal/version.h +IMPH = $(addprefix $(srcdir)/, src/internal/stdio_impl.h src/internal/pthread_impl.h src/internal/libc.h) + +LDFLAGS = +LDFLAGS_AUTO = LIBCC = -lgcc CPPFLAGS = -CFLAGS = -Os -pipe +CFLAGS = +CFLAGS_AUTO = -Os -pipe CFLAGS_C99FSE = -std=c99 -ffreestanding -nostdinc CFLAGS_ALL = $(CFLAGS_C99FSE) -CFLAGS_ALL += -D_XOPEN_SOURCE=700 -I./arch/$(ARCH) -I./src/internal -I./include -CFLAGS_ALL += $(CPPFLAGS) $(CFLAGS) -CFLAGS_ALL_STATIC = $(CFLAGS_ALL) -CFLAGS_ALL_SHARED = $(CFLAGS_ALL) -fPIC -DSHARED +CFLAGS_ALL += -D_XOPEN_SOURCE=700 -I$(srcdir)/arch/$(ARCH) -I$(srcdir)/arch/generic -Iobj/src/internal -I$(srcdir)/src/internal -Iobj/include -I$(srcdir)/include +CFLAGS_ALL += $(CPPFLAGS) $(CFLAGS_AUTO) $(CFLAGS) + +LDFLAGS_ALL = $(LDFLAGS_AUTO) $(LDFLAGS) AR = $(CROSS_COMPILE)ar RANLIB = $(CROSS_COMPILE)ranlib -INSTALL = ./tools/install.sh +INSTALL = $(srcdir)/tools/install.sh -ARCH_INCLUDES = $(wildcard arch/$(ARCH)/bits/*.h) -ALL_INCLUDES = $(sort $(wildcard include/*.h include/*/*.h) $(GENH) $(ARCH_INCLUDES:arch/$(ARCH)/%=include/%)) +ARCH_INCLUDES = $(wildcard $(srcdir)/arch/$(ARCH)/bits/*.h) +GENERIC_INCLUDES = $(wildcard $(srcdir)/arch/generic/bits/*.h) +INCLUDES = $(wildcard $(srcdir)/include/*.h $(srcdir)/include/*/*.h) +ALL_INCLUDES = $(sort $(INCLUDES:$(srcdir)/%=%) $(GENH:obj/%=%) $(ARCH_INCLUDES:$(srcdir)/arch/$(ARCH)/%=include/%) $(GENERIC_INCLUDES:$(srcdir)/arch/generic/%=include/%)) EMPTY_LIB_NAMES = m rt pthread crypt util xnet resolv dl EMPTY_LIBS = $(EMPTY_LIB_NAMES:%=lib/lib%.a) -CRT_LIBS = lib/crt1.o lib/Scrt1.o lib/crti.o lib/crtn.o +CRT_LIBS = $(addprefix lib/,$(notdir $(CRT_OBJS))) STATIC_LIBS = lib/libc.a SHARED_LIBS = lib/libc.so TOOL_LIBS = lib/musl-gcc.specs ALL_LIBS = $(CRT_LIBS) $(STATIC_LIBS) $(SHARED_LIBS) $(EMPTY_LIBS) $(TOOL_LIBS) -ALL_TOOLS = tools/musl-gcc +ALL_TOOLS = obj/musl-gcc + +WRAPCC_GCC = gcc +WRAPCC_CLANG = clang LDSO_PATHNAME = $(syslibdir)/ld-musl-$(ARCH)$(SUBARCH).so.1 -include config.mak +ifeq ($(ARCH),) + +all: + @echo "Please set ARCH in config.mak before running make." + @exit 1 + +else + all: $(ALL_LIBS) $(ALL_TOOLS) -install: install-libs install-headers install-tools +OBJ_DIRS = $(sort $(patsubst %/,%,$(dir $(ALL_LIBS) $(ALL_TOOLS) $(ALL_OBJS) $(GENH) $(GENH_INT))) obj/include) -clean: - rm -f crt/*.o - rm -f $(OBJS) - rm -f $(LOBJS) - rm -f $(ALL_LIBS) lib/*.[ao] lib/*.so - rm -f $(ALL_TOOLS) - rm -f $(GENH) $(GENH_INT) - rm -f include/bits +$(ALL_LIBS) $(ALL_TOOLS) $(ALL_OBJS) $(ALL_OBJS:%.o=%.lo) $(GENH) $(GENH_INT): | $(OBJ_DIRS) -distclean: clean - rm -f config.mak +$(OBJ_DIRS): + mkdir -p $@ + +obj/include/bits/alltypes.h: $(srcdir)/arch/$(ARCH)/bits/alltypes.h.in $(srcdir)/include/alltypes.h.in $(srcdir)/tools/mkalltypes.sed + sed -f $(srcdir)/tools/mkalltypes.sed $(srcdir)/arch/$(ARCH)/bits/alltypes.h.in $(srcdir)/include/alltypes.h.in > $@ + +obj/include/bits/syscall.h: $(srcdir)/arch/$(ARCH)/bits/syscall.h.in + cp $< $@ + sed -n -e s/__NR_/SYS_/p < $< >> $@ -include/bits: - @test "$(ARCH)" || { echo "Please set ARCH in config.mak before running make." ; exit 1 ; } - ln -sf ../arch/$(ARCH)/bits $@ +obj/src/internal/version.h: $(wildcard $(srcdir)/VERSION $(srcdir)/.git) + printf '#define VERSION "%s"\n' "$$(cd $(srcdir); sh tools/version.sh)" > $@ -include/bits/alltypes.h.in: include/bits +obj/src/internal/version.o obj/src/internal/version.lo: obj/src/internal/version.h -include/bits/alltypes.h: include/bits/alltypes.h.in include/alltypes.h.in tools/mkalltypes.sed - sed -f tools/mkalltypes.sed include/bits/alltypes.h.in include/alltypes.h.in > $@ +obj/crt/rcrt1.o obj/ldso/dlstart.lo obj/ldso/dynlink.lo: $(srcdir)/src/internal/dynlink.h $(srcdir)/arch/$(ARCH)/reloc.h -src/internal/version.h: $(wildcard VERSION .git) - printf '#define VERSION "%s"\n' "$$(sh tools/version.sh)" > $@ +obj/crt/crt1.o obj/crt/scrt1.o obj/crt/rcrt1.o obj/ldso/dlstart.lo: $(srcdir)/arch/$(ARCH)/crt_arch.h -src/internal/version.lo: src/internal/version.h +obj/crt/rcrt1.o: $(srcdir)/ldso/dlstart.c -src/ldso/dynlink.lo: arch/$(ARCH)/reloc.h +obj/crt/Scrt1.o obj/crt/rcrt1.o: CFLAGS_ALL += -fPIC -crt/crt1.o crt/Scrt1.o: $(wildcard arch/$(ARCH)/crt_arch.h) +obj/crt/$(ARCH)/crti.o: $(srcdir)/crt/$(ARCH)/crti.s -crt/Scrt1.o: CFLAGS += -fPIC +obj/crt/$(ARCH)/crtn.o: $(srcdir)/crt/$(ARCH)/crtn.s -OPTIMIZE_SRCS = $(wildcard $(OPTIMIZE_GLOBS:%=src/%)) -$(OPTIMIZE_SRCS:%.c=%.o) $(OPTIMIZE_SRCS:%.c=%.lo): CFLAGS += -O3 +OPTIMIZE_SRCS = $(wildcard $(OPTIMIZE_GLOBS:%=$(srcdir)/src/%)) +$(OPTIMIZE_SRCS:$(srcdir)/%.c=obj/%.o) $(OPTIMIZE_SRCS:$(srcdir)/%.c=obj/%.lo): CFLAGS += -O3 MEMOPS_SRCS = src/string/memcpy.c src/string/memmove.c src/string/memcmp.c src/string/memset.c -$(MEMOPS_SRCS:%.c=%.o) $(MEMOPS_SRCS:%.c=%.lo): CFLAGS += $(CFLAGS_MEMOPS) +$(MEMOPS_SRCS:%.c=obj/%.o) $(MEMOPS_SRCS:%.c=obj/%.lo): CFLAGS_ALL += $(CFLAGS_MEMOPS) + +NOSSP_SRCS = $(wildcard crt/*.c) \ + src/env/__libc_start_main.c src/env/__init_tls.c \ + src/env/__stack_chk_fail.c \ + src/thread/__set_thread_area.c src/thread/$(ARCH)/__set_thread_area.c \ + src/string/memset.c src/string/$(ARCH)/memset.c \ + src/string/memcpy.c src/string/$(ARCH)/memcpy.c \ + ldso/dlstart.c ldso/dynlink.c +$(NOSSP_SRCS:%.c=obj/%.o) $(NOSSP_SRCS:%.c=obj/%.lo): CFLAGS_ALL += $(CFLAGS_NOSSP) + +$(CRT_OBJS): CFLAGS_ALL += -DCRT + +$(LOBJS) $(LDSO_OBJS): CFLAGS_ALL += -fPIC -# This incantation ensures that changes to any subarch asm files will -# force the corresponding object file to be rebuilt, even if the implicit -# rule below goes indirectly through a .sub file. -define mkasmdep -$(dir $(patsubst %/,%,$(dir $(1))))$(notdir $(1:.s=.o)): $(1) -endef -$(foreach s,$(wildcard src/*/$(ARCH)*/*.s),$(eval $(call mkasmdep,$(s)))) +CC_CMD = $(CC) $(CFLAGS_ALL) -c -o $@ $< -%.o: $(ARCH)$(ASMSUBARCH)/%.sub - $(CC) $(CFLAGS_ALL_STATIC) -c -o $@ $(dir $<)$(shell cat $<) +# Choose invocation of assembler to be used +ifeq ($(ADD_CFI),yes) + AS_CMD = LC_ALL=C awk -f $(srcdir)/tools/add-cfi.common.awk -f $(srcdir)/tools/add-cfi.$(ARCH).awk $< | $(CC) $(CFLAGS_ALL) -x assembler -c -o $@ - +else + AS_CMD = $(CC_CMD) +endif -%.o: $(ARCH)/%.s - $(CC) $(CFLAGS_ALL_STATIC) -c -o $@ $< +obj/%.o: $(srcdir)/%.s + $(AS_CMD) -%.o: %.c $(GENH) $(IMPH) - $(CC) $(CFLAGS_ALL_STATIC) -c -o $@ $< +obj/%.o: $(srcdir)/%.S + $(CC_CMD) -%.lo: $(ARCH)$(ASMSUBARCH)/%.sub - $(CC) $(CFLAGS_ALL_SHARED) -c -o $@ $(dir $<)$(shell cat $<) +obj/%.o: $(srcdir)/%.c $(GENH) $(IMPH) + $(CC_CMD) -%.lo: $(ARCH)/%.s - $(CC) $(CFLAGS_ALL_SHARED) -c -o $@ $< +obj/%.lo: $(srcdir)/%.s + $(AS_CMD) -%.lo: %.c $(GENH) $(IMPH) - $(CC) $(CFLAGS_ALL_SHARED) -c -o $@ $< +obj/%.lo: $(srcdir)/%.S + $(CC_CMD) -lib/libc.so: $(LOBJS) - $(CC) $(CFLAGS_ALL_SHARED) $(LDFLAGS) -nostdlib -shared \ - -Wl,-e,_start -Wl,-Bsymbolic-functions \ - -o $@ $(LOBJS) $(LIBCC) +obj/%.lo: $(srcdir)/%.c $(GENH) $(IMPH) + $(CC_CMD) -lib/libc.a: $(OBJS) +lib/libc.so: $(LOBJS) $(LDSO_OBJS) + $(CC) $(CFLAGS_ALL) $(LDFLAGS_ALL) -nostdlib -shared \ + -Wl,-e,_dlstart -o $@ $(LOBJS) $(LDSO_OBJS) $(LIBCC) + +lib/libc.a: $(AOBJS) rm -f $@ - $(AR) rc $@ $(OBJS) + $(AR) rc $@ $(AOBJS) $(RANLIB) $@ $(EMPTY_LIBS): rm -f $@ $(AR) rc $@ -lib/%.o: crt/%.o +lib/%.o: obj/crt/$(ARCH)/%.o + cp $< $@ + +lib/%.o: obj/crt/%.o cp $< $@ -lib/musl-gcc.specs: tools/musl-gcc.specs.sh config.mak +lib/musl-gcc.specs: $(srcdir)/tools/musl-gcc.specs.sh config.mak sh $< "$(includedir)" "$(libdir)" "$(LDSO_PATHNAME)" > $@ -tools/musl-gcc: config.mak - printf '#!/bin/sh\nexec "$${REALGCC:-gcc}" "$$@" -specs "%s/musl-gcc.specs"\n' "$(libdir)" > $@ +obj/musl-gcc: config.mak + printf '#!/bin/sh\nexec "$${REALGCC:-$(WRAPCC_GCC)}" "$$@" -specs "%s/musl-gcc.specs"\n' "$(libdir)" > $@ + chmod +x $@ + +obj/%-clang: $(srcdir)/tools/%-clang.in config.mak + sed -e 's!@CC@!$(WRAPCC_CLANG)!g' -e 's!@PREFIX@!$(prefix)!g' -e 's!@INCDIR@!$(includedir)!g' -e 's!@LIBDIR@!$(libdir)!g' -e 's!@LDSO@!$(LDSO_PATHNAME)!g' $< > $@ chmod +x $@ -$(DESTDIR)$(bindir)/%: tools/% +$(DESTDIR)$(bindir)/%: obj/% $(INSTALL) -D $< $@ $(DESTDIR)$(libdir)/%.so: lib/%.so @@ -156,10 +202,16 @@ $(DESTDIR)$(libdir)/%.so: lib/%.so $(DESTDIR)$(libdir)/%: lib/% $(INSTALL) -D -m 644 $< $@ -$(DESTDIR)$(includedir)/bits/%: arch/$(ARCH)/bits/% +$(DESTDIR)$(includedir)/bits/%: $(srcdir)/arch/$(ARCH)/bits/% + $(INSTALL) -D -m 644 $< $@ + +$(DESTDIR)$(includedir)/bits/%: $(srcdir)/arch/generic/bits/% + $(INSTALL) -D -m 644 $< $@ + +$(DESTDIR)$(includedir)/bits/%: obj/include/bits/% $(INSTALL) -D -m 644 $< $@ -$(DESTDIR)$(includedir)/%: include/% +$(DESTDIR)$(includedir)/%: $(srcdir)/include/% $(INSTALL) -D -m 644 $< $@ $(DESTDIR)$(LDSO_PATHNAME): $(DESTDIR)$(libdir)/libc.so @@ -169,10 +221,22 @@ install-libs: $(ALL_LIBS:lib/%=$(DESTDIR)$(libdir)/%) $(if $(SHARED_LIBS),$(DEST install-headers: $(ALL_INCLUDES:include/%=$(DESTDIR)$(includedir)/%) -install-tools: $(ALL_TOOLS:tools/%=$(DESTDIR)$(bindir)/%) +install-tools: $(ALL_TOOLS:obj/%=$(DESTDIR)$(bindir)/%) + +install: install-libs install-headers install-tools + +musl-git-%.tar.gz: .git + git --git-dir=$(srcdir)/.git archive --format=tar.gz --prefix=$(patsubst %.tar.gz,%,$@)/ -o $@ $(patsubst musl-git-%.tar.gz,%,$@) +musl-%.tar.gz: .git + git --git-dir=$(srcdir)/.git archive --format=tar.gz --prefix=$(patsubst %.tar.gz,%,$@)/ -o $@ v$(patsubst musl-%.tar.gz,%,$@) +endif -.PRECIOUS: $(CRT_LIBS:lib/%=crt/%) +clean: + rm -rf obj lib + +distclean: clean + rm -f config.mak .PHONY: all clean install install-libs install-headers install-tools diff --git a/system/lib/libc/musl/README b/system/lib/libc/musl/README index dd61bd5a06f52..a30eb112750c1 100644 --- a/system/lib/libc/musl/README +++ b/system/lib/libc/musl/README @@ -10,7 +10,7 @@ usage, and correctness in the sense of standards conformance and safety. musl is built on the principle that these goals are best achieved through simple code that is easy to understand and maintain. -The 1.0 release series for musl features coverage for all interfaces +The 1.1 release series for musl features coverage for all interfaces defined in ISO C99 and POSIX 2008 base, along with a number of non-standardized interfaces for compatibility with Linux, BSD, and glibc functionality. diff --git a/system/lib/libc/musl/VERSION b/system/lib/libc/musl/VERSION index 90a27f9cea6e8..645377eea8d0f 100644 --- a/system/lib/libc/musl/VERSION +++ b/system/lib/libc/musl/VERSION @@ -1 +1 @@ -1.0.5 +1.1.15 diff --git a/system/lib/libc/musl/WHATSNEW b/system/lib/libc/musl/WHATSNEW index f47620834c6e8..be688cbb8ba15 100644 --- a/system/lib/libc/musl/WHATSNEW +++ b/system/lib/libc/musl/WHATSNEW @@ -1187,7 +1187,15 @@ arch-specific bugs fixed: -1.0.1 release notes +1.1.0 release notes + +new features: +- relro memory protection in dynamic linker +- malloc can now extend heap with mmap if brk fails +- vdso clock_gettime/gettimeofday/time acceleration on x86_64 +- thread/library-safe versions of search.h functions (nonstandard) +- getauxval function (nonstandard) +- sysconf extensions to query physical memory size bugs fixed: - floating point printf output corruption from carry into uninitialized slot @@ -1195,6 +1203,7 @@ bugs fixed: - printf %g failure to strip trailing zeros in some cases - search past end of haystack in memmem - off-by-one error in confstr return value +- crashes in some near-empty static programs that use stack protector - deadlock race in pthread_once - non-working clock_gettime fallback for old kernels @@ -1202,10 +1211,16 @@ arch-specific bugs fixed: - crash from missing syscall asm register clobbers on real microblaze kernel - crash in all nontrivial dynamic linker use on microblaze - incorrect rlimit constants on mips +- broken, possibly dangerous, use of getrlimit syscall on x32 in sysconf + +1.1.1 release notes -1.0.2 release notes +new features: +- new options --preload and --library-path to dynamic linker +- public execvpe function (nonstandard extension) +- iconv support for cp437 and cp850 bugs fixed: - false negatives with some periodic needles in strstr, wcsstr, and memmem @@ -1217,35 +1232,89 @@ bugs fixed: compatibility: - configure now detects serious constant-folding bug in gcc 4.9.0 - removed __yield symbol (unused) that clashed with some compilers +- improvements to sysconf's handling of unsupported/invalid arguments arch-specific bugs fixed: - misdetection of superh ABI variant by configure on gcc 3.x - missing SO_RCVBUFFORCE and SO_SNDBUFFORCE in mips socket.h +- build regression on armv6 and later with -mthumb + +1.1.2 release notes -1.0.3 release notes +new features: +- multi-protocol matches (tcp and udp) in getaddrinfo +- support for AI_V4MAPPED and AI_ALL flags to getaddrinfo +- reverse name lookups from /etc/hosts +- reverse service lookups from /etc/services +- support for service aliases in /etc/services +- ipsec and tunneling protocols to getprotoent-family functions +- res_send, res_mkquery, res_querydomain, and dn_comp functions +- ipv6 scope id handling for link-local scope addresses +- previously-unimplemented %C and %y in strptime now work +- vdso clock_gettime acceleration on i386 (new kernel feature) +- better O_CLOEXEC/SOCK_CLOEXEC fallbacks for old kernels bugs fixed: - buffer overflow in dns response parsing (CVE-2014-3484) - possible infinite loop in dns response parsing -- fix multiple validation issues in dns response label parsing - sendfile off_t 32/64-bit size mismatch - incorrect end pointer in some cases when wcsrtombs stops early - incorrect if_nametoindex return value when interface does not exist - dummy "ent" function aliases that possibly shadowed real ones +- tmpfile fd leak on memory exhaustion +- getaddrinfo returning EAI_NONAME for some transient failures arch-specific bugs fixed: - broken kernel side RLIM_INFINITY on mips +- incorrect syscall argument 6/7 types for pselect on x32 + + + +1.1.3 release notes + +new features: +- address sorting in getaddrinfo, etc. modeled on rfc 3484/6724 +- default timezone taken from /etc/localtime when $TZ is unset +- getopt double-colon extension for optional arguments +- support for TLSDESC-based (gnu2) TLS dialect on i386 and x86_64 +- sendmmsg/recvmmsg (linux-specific) +- fmtmsg (last mandatory XSI function that was missing) + +compatibility: +- treat dns rcode=2 as temporary failure, not negative result +- working thread-pointer for pre-2.6 kernels on i386 +- further ABI-compat symbols: __xmknod[at], __sysv_signal + +bugs fixed: +- memmem false positives/false negatives/crashes from invalid logic +- gethostby*_r not setting result pointer to null on failure +- aliasing violations in syscall.h SYSLOG_NAMES feature +- fanotify_mark syscall arguments wrong + +arch-specific bugs fixed: +- various subtle relocation bugs in powerpc and sh dynamic linker -1.0.4 release notes +1.1.4 release notes + +new features: +- experimental locale support for LC_MESSAGES and LC_TIME +- non-stub gettext family functions for message translation +- or1k (OpenRISC 1000) port +- syslog options LOG_CONS and LOG_PERROR +- issetugid function (from OpenBSD) +- improved if_nameindex and getifaddrs functions compatibility: - work around bug #61144 in gcc 4.9.0 and 4.9.1 +- support getauxval(AT_SECURE) even on kernels without AT_SECURE bugs fixed: +- empty dynamic linker error messages (regression in 1.1.3) +- if_nameindex omitted unconfigured and ipv6-only interfaces - incorrect return value for fwide function - failure of wide printf/scanf functions to set wide orientation - multiple issues in legacy function getpass @@ -1254,52 +1323,410 @@ bugs fixed: - crash in regexec for nonzero nmatch argument with REG_NOSUB - minor bugs in rarely-used nl_langinfo item lookups -- memmem false positives/false negatives/crashes from invalid logic -- gethostby*_r not setting result pointer to null on failure -- aliasing violations in syscall.h SYSLOG_NAMES feature -- fanotify_mark syscall arguments wrong - arch-specific bugs fixed: +- broken relocations in mips dynamic linker (regression in 1.1.3) - register state corruption in setjmp asm for microblaze - broken struct stat st_ino field on microblaze - broken struct stat st_dev field on big endian mips - broken asm register constraints in atomics on powerpc -- missing barriers in atomics on mips, powerpc, and microblaze +- missing barriers in atomics on mips, powerpc, microblaze, and sh -- TLS relocation bug in powerpc dynamic linker +1.1.5 release notes -1.0.5 release notes +new features: +- full C11 coverage (threads, UTF-16/32 API, timespec_get, etc.) +- malloc_usable_size function (nonstandard) +- support for new F_OFD_* fcntl operations (linux 3.15, POSIX-future) +- new _DEFAULT_SOURCE feature test macro to request default profile -compatibility: -- dynamic linker now honors DT_RUNPATH without DT_RPATH (new binutils) +performance: +- private-futex support +- redesigned cond var implementation with major performance improvement +- tweaked spinning in userspace before performing futex waits bugs fixed: -- stack-based buffer overflow in inet_pton (CVE-2015-1817) -- regcomp mishandling of high bytes after backslash -- regcomp miscompiled character class brace-repetitions -- use of uninitialized memory with application-provided thread stacks - failure of dn_expand to null-terminate name for crafted DNS packets +- corruption of cond var mutex state when switching mutexes +- use of uninitialized memory with application-provided thread stacks +- false ownership of orphaned mutexes due to tid reuse +- possible failure-to-wake for robust mutexes on owner death +- subtle errors in robust mutex unrecoverable status handling +- missing memory/compiler barrier spinning to obtain locks +- wrong behavior in various zero-length stdio operations - buffer overflow in swab with odd argument +- incorrect sequence generation in the rand48 family of prng functions +- missing cancellation check in non-wait paths of sem_wait, pthread_join - missing barrier in pthread_once fast path -- wordexp bad character checker mis-counted parentheses -- malloc init code could deadlock due to race condition -- getspnam_r returned results for partial username matches -- mishandling of negative non-whole-hour TZ offsets -- printf failed to report or stop on write errors -- syslog failed to check for connect error -- fchmodat was subject to fd leak race (missing O_CLOEXEC) -- fchmodat failed to report EOPNOTSUPP in race path -- wrong behavior in various zero-length stdio operations +- memory leak in regexec when input contains illegal sequence +- various parser bugs in regcomp - wrong return value on overflow in some strtoul-family functions -- incorrect sequence generation in the rand48 family of prng functions +- broken CPU_EQUAL macro in sched.h +- dlerror not working in static-linked programs +- mishandling of negative non-whole-hour TZ offsets +- incorrect case mappings for U+00DF +- namespace pollution via accidentally-non-static function named "dummy" +- missing __fpclassifyl and __signbitl definitions for ld64 archs + + + +1.1.6 release notes + +new features: +- getopt '-' flag for processing non-option arguments +- getopt_long argument permutation extension +- getopt_long abbreviated options +- ns_parserr and related DNS-packet-parsing functions +- fnmatch FNM_CASEFOLD extension +- support for translation of getopt error messages +- login_tty function (legacy) + +performance: +- efficient atomics on armv7+ targets +- pthread_once shrink-wrapping of fast path + +compatibility: +- baseline arm binaries now work on new cpus/kernels without kuser_helper +- dynamic linker now honors DT_RUNPATH without DT_RPATH (new binutils) +- arm asm is now compatible with clang's internal assembler +- suppress macro implementations of functions when headers are used in C++ +- increased message length limit for syslog + +bugs fixed: +- open ignored file creation mode argument for O_TMPFILE - wrong printf formatting for %#.0o with value zero +- missing private state for uchar.h functions (null ps pointer) - sched_getaffinity left uninitialized data in output bit array - wrong return values for pthread_getaffinity_np and pthread_setaffinity_np -- broken CPU_EQUAL macro in sched.h +- buggy handling of multibyte option chars with arguments in getopt +- printf failed to report or stop on write errors +- printf failed to honor '+' modifier when printing NANs +- wcsnrtombs returned the wrong value in one code path +- syslog failed to check for connect error +- multi-threaded set*id() had spurious failures from ugly workaround code +- various minor header conformance bugs (signedness, constant expressions, ...) arch-specific bugs fixed: +- on or1k, some syscalls with 64-bit arguments were broken (misaligned) - usage of sahf instruction on x86_64 crashed on some early cpu models + + + +1.1.7 release notes + +new features: +- alternate passwd/group backend support via nscd protocol +- masked cancellation mode extension (experimental) +- aio cancellation +- aarch64 port (experimental) + +performance: +- significant memset asm optimizations on i386 and x86_64 + +compatibility: +- suppress EINTR in semaphores for old kernels where futex restart is broken +- always set optarg in getopt_long +- support SOCK_RAW socket type in getaddrinfo +- report success instead of EINPROGRESS when close is interrupted + +bugs fixed: +- multithreaded set*id() was not async-signal safe, had various race bugs +- getspnam_r returned results for partial username matches +- wordexp bad character checker mis-counted parentheses +- close on fd with pending aio could lead to file corruption +- old aio implementation had numerous conformance bugs +- malloc init code could deadlock due to race condition +- pthread_exit did not disable cancellation +- pthread_cond_wait could wrongly consume signal on cancellation +- execvp wrongly stopped path search on EACCESS +- fsync, fdatasync, and msync were not honored as cancellation points +- fchmodat was subject to fd leak race (missing O_CLOEXEC) +- fchmodat failed to report EOPNOTSUPP in race path +- passwd/group lookup functions had various minor error-reporting bugs +- isatty had false-positives/device-state-corruption for OSS sound devices +- configure script failed to detect gcc with translated messages +- FLT_ROUNDS macro failed to reflect rounding mode changes in fenv + +arch-specific bugs fixed: - mips fesetenv did not handle FE_DFL_ENV - mips POLLWRNORM and POLLWRBAND macros had wrong values +- x32 pthread synchronization object type definitions were wrong +- powerpc minimum signal stack size was insufficient + + + +1.1.8 release notes + +bugs fixed: +- stack-based buffer overflow in inet_pton (CVE-2015-1817) +- regcomp crash/mem-corruption with illegal bytes after backslash +- regcomp wrongly allowed backrefs in ER +- regcomp miscompiled character class brace-repetitions +- regcomp wrongly processed \0 as an unmatchable backref +- new FLT_ROUNDS definition failed to work in C++ code + +arch-specific bugs fixed: +- aarch64 was missing max_align_t definition + + + +1.1.9 release notes + +new features: +- ability to protect libc code itself with stack protector +- sigsetjmp now restores signal mask after restoring context, not before +- thread-local dlerror status/messages +- dlerror messages are no longer truncated +- diagnostics for constraint violations with ctype.h macros + +optimizations: +- reduce cost of PIC on archs where PLT calls need a fixed GOT register +- spin locks no longer constantly invalidate cache lines while spinning +- code size reduction in static-linked TLS init + +bugs fixed: +- failure to process robust mutexes on detached-thread exit +- possible memory corruption due to robust mutex list on detached-thread exit +- crash on memory exhaustion in getgr* internals +- misaligned memory accesses in static binaries with low-alignment TLS blocks +- multiple cases of wrongful path search continuation after transient failure +- small memory leak on failure of dlopen with RPATH $ORIGIN +- several small math bugs related to exception flags with non-finite args +- mmap leak in sem_open failure path for link call +- duplocale clobbered new locale struct with memcpy of old +- futimes crashed with null timeval argument + +arch-specific bugs fixed: +- stack protector spuriously aborted after forking on x32 +- stack protector spuriously aborted with flockfile on powerpc +- theoretically-possible clobbering of syscall return value on mips +- random thread-pointer setup failure on sh (uninitialized return value) +- possible crash in dlsym on sh due to incorrectly-computed branch target +- broken fesetenv(FE_DFL_ENV) on mips +- dynamic linker name for sh ignored fpu/nofpu and endianness +- various minor aarch64 bugs +- dangling pointers in x32 syscall timespec fixup code + + + +1.1.10 release notes + +new features: +- fail-safe (allocation-free) C locale for newlocale to return +- all locale categories track requested locale name +- rcrt1.o start file for static PIE + +optimizations: +- inline atomics for sh4a +- removed heavy atomics from locale-related code paths +- removed global data accesses from CURRENT_LOCALE macro & callers +- dynamic linker stage 1 size reduction + +compatibility: +- better configure detection of unsupported compiler options +- support for more relocation types in libc.so, not currently used +- iconv_open accepts "" and "CHAR" as aliases for native (UTF-8) +- additional LFS64 macros in sys/resource.h + +regressions fixed: +- dynamic linker crash on NONE-type relocations (only mips affected) +- inability to build as thumb2 on arm +- failure to run under qemu-i386 user-level emulation +- inability to access globals from libc on powerpc +- PIE link errors in Scrt1.o under unusual usage on some archs + +other bugs fixed: +- failure of ungetc/ungetwc to work on FILE streams in EOF state +- possible null pointer dereference in gettext +- possible initial stack misalignment on mips with PIE + + + +1.1.11 release notes + +new features: +- byte-based C locale +- vdso clock_gettime on arm +- musl-clang wrapper +- sh2 nommu target support + +performance: +- major speed-up for dynamic linker symbol lookups with GNU hash + +compatibility: +- strverscmp now matches GNU behavior in corner cases +- empty TZ environment variable gives GMT rather than system default +- reconnection on syslog server socket loss (syslogd restart) +- mmap fallback in simple_malloc when brk fails +- support for %m and %s with null pointers in wide printf variants +- call frame information in i386 asm for improved debugger support + +bugs fixed: +- spurious errors from pwd/grp functions when nscd backend is absent +- possible invalid access on calloc with simple_malloc +- null pointer dereferences after calling uselocale((locale_t)0) +- erroneous support for cancellation in stdio caused data loss +- inconsistent handling of atexit called from atexit handler +- missing locking in error paths for ungetwc +- btowc mishandling of out-of-range non-EOF inputs +- negated return value of ns_skiprr, failure in related functions +- incorrect void return type for syncfs, missing error status +- possible failure of tempnam due to missing null termination +- negated tm_gmtoff field in struct tm +- off-by-one error in getsubopt leaving equals sign in value result + +arch-specific bugs fixed: +- soft deadlocks on i386/x86_64 due to missing barrier in internal locks +- regression in arm pre-v7 support for kernels with kuser helper removed +- runaway PC on mips detached thread exit (due to kernel regression) +- mismatched ABI for local-dynamic model TLS on mips and powerpc +- incorrect value of some SO_* constants on mips +- broken 64-bit syscall argument passing on aarch64 + + + +1.1.12 release notes + +new features: +- fdpic abi on sh2 for shareable text segment without mmu +- general fdpic elf support in dynamic linker +- CFI generation for x86_64 asm source files +- protection against silently building a libc.so with missing symbols + +compatibility: +- nl_langinfo(CODESET) now returns "ASCII" in byte-based C locale +- fixed build regression due to buggy .SECONDARY in some GNU make versions +- additional arm eabi functions needed by llvm arm backend +- added format argument attributes to gettext function prototypes +- static PIE no longer requires linking with -E/-rdynamic +- eliminated spurious protected-data warnings linking against libc.so +- avoided spurious fpu asm errors with some armhf toolchains + +bugs fixed: +- fclose of stdin/stdout caused deadlock at exit +- missing memory barrier in pthread_join +- open_[w]memstream produced no buffer when no writes took place +- uninitialized scopeid in address lookups from hosts file and ip literals +- ip literals for mismatching family (v4 vs v6) were queried as hostnames +- possible crash on OOM in regcomp +- incorrect contents in localeconv structure (-1 instead of CHAR_MAX) +- strftime mishandling of out-of-range struct tm members +- wrongful attribute((const)) on pthread_self and errno location function + +arch-specific bugs fixed: +- arm crt1 entry point failed to align stack pointer in some cases +- mips fesetround failed to actually set rounding mode +- i386 asm source CFI generation had multiple bugs + + + +1.1.13 release notes + +new features: +- out-of-tree builds +- search domains in resolv.conf +- sh arch supports j-core (j2) cas.l atomics +- dynamic linker includes arch/abi in output when run as a command +- header support for new kernel features through linux 4.4 +- mips vdso clock_gettime support +- regex BRE extensions: \|, \+, \? + +performance: +- improved atomics performance on all archs with ll/sc model +- atomic instructions are now inlined on armv6 +- use fpu sqrt for arm softfp abi on targets with vfp + +compatibility: +- getnameinfo now accepts sockaddr sizes larger than needed +- new default CFLAGS/LDFLAGS avoid entire classes of toolchain bugs +- explicit use of float_t/double_t avoids compiler float spill bugs +- i386 max_align_t definition now works with g++ 4.7's pseudo-c++11 +- all known protocols are added to protoent functions +- stub utmpname, utmpxname functions +- linker support for -Bsymbolic-functions is no longer mandatory +- regex parsing size limits increased +- malloc_usable_size now accepts null pointer input + +bugs fixed: +- potential single-byte heap overflow in getdelim +- mishandling of transient failure opening hosts, services, resolv.conf +- mremap was sometimes able to allocate objects larger than PTRDIFF_MAX +- nl_langinfo wrongly returned NULL instead of "" for invalid items +- out-of-bounds dynamic tls allocation due to pointer/index scaling error +- getifaddrs misreported point-to-point interface addresses +- tdelete left tsearch trees misbalanced +- tsearch crashed on allocation failure +- tsearch, tfind, and tdelete failed to handle null pointer input +- passing signal number 0 to sigaction resulted in a crash +- getdelim updated caller's size wrongly when realloc failed +- getdelim realloc strategy was wasteful +- if_nametoindex returned wrong value on failure +- missing ssp-suppression for some source files called from early-init +- various minor resolv.conf parsing bugs +- fwrite wrongly reported success on write errors in line-buffered flush +- fwrite and fread wrongly returned nmemb (not 0) when size was 0 + +nommu-specific bugs fix: +- failure to zero bss in FDPIC shared library loader +- unsafe writes to read-only file mapping in non-FDPIC library loader + +arch-specific bugs fixed: +- sh[eb]-nofpu-fdpic was using fpu-dependent setjmp/longjmp variants +- dynamic linker path file name was wrong for arm "softfp" targets +- mips siginfo_t and related macros were defined incorrectly +- possibly misaligned pointer globals on arm (from an asm source file) +- mips dynamic linker failed to provide info needed by debugger +- mips cancellation asm wrongly assumed validity of $gp register value + + + +1.1.14 release notes + +regressions fixed: +- treatment of empty string argument as error by puts and fputs +- make clean and distclean failure in unconfigured trees +- sh/fdpic dynamic linker entry point hang due to wrong code +- armhf (and arm softfp model) build failure with clang + +other bugs fixed: +- wrongly clamping (rather than failing) excessive rounds in crypt-sha* + + + +1.1.15 release notes + +new features: +- mips64 (full 64-bit and n32) port +- mips r6 isa support (subarch for mips, mips64, and mipsn32 archs) +- powerpc64 port +- powerpc (32-bit) soft-float ABI support (subarch) +- pthread_tryjoin_np and pthread_timedjoin_np (nonstandard extensions) +- header-level support for linux 4.5 and 4.6 features +- sched_getcpu (nonstandard extension) support, including vdso version +- __STDC_ISO_10646__, __STDC_IEC_559__ macros predefined via stdc-predef.h +- support for new elf/arch features in elf.h + +compatibility: +- configure now correctly chooses cross-prefix based on build/host/target +- abort now successfully terminates pid 1 in a container (or top-level) + +bugs fixed: +- memmem read past end of haystack, possible false positives or crashes +- buffer underflow (reverse-overflow) in ungetwc +- double-free under certain usage of putenv +- incorrect treatment by regcomp of * at start of BRE subexpression +- gethostbyname[2][_r] produced ip addresses in misaligned buffers +- looking up some invalid hostnames caused malformed dns queries +- lookups from hosts file were inconsistent with non-matching family +- missing h_length value in gethostbyaddr results +- a64l function produced wrong-signed results on 64-bit archs +- broken padding of string formats to width in wide printf variants +- wrong results for expf(-NAN) and exp2f(-NAN) +- wrong value for RUSAGE_CHILDREN prevented it from working +- abort failed to provide abnormal termination with SIGABRT blocked + +arch-specific bugs fixed: +- broken posix_fadvise on arm and powerpc (32-bit) +- thread structure/dtv corruption on powerpc at thread startup +- various wrong mips and powerpc ioctl and termios constant values diff --git a/system/lib/libc/musl/arch/emscripten/atomic.h b/system/lib/libc/musl/arch/emscripten/atomic_arch.h similarity index 81% rename from system/lib/libc/musl/arch/emscripten/atomic.h rename to system/lib/libc/musl/arch/emscripten/atomic_arch.h index 52cc54d1f78c4..d700042c7587f 100644 --- a/system/lib/libc/musl/arch/emscripten/atomic.h +++ b/system/lib/libc/musl/arch/emscripten/atomic_arch.h @@ -5,6 +5,7 @@ #include #include +#define a_ctz_l a_ctz_l static inline int a_ctz_l(unsigned long x) { if (x == 0) @@ -18,6 +19,7 @@ static inline int a_ctz_l(unsigned long x) return nTrailingZeros; } +#define a_ctz_64 a_ctz_64 static inline int a_ctz_64(uint64_t x) { uint32_t lo = (uint32_t)x; @@ -27,52 +29,62 @@ static inline int a_ctz_64(uint64_t x) return a_ctz_l((unsigned long)lo); } +#define a_and_64 a_and_64 static inline void a_and_64(volatile uint64_t *p, uint64_t v) { *p &= v; } +#define a_or_64 a_or_64 static inline void a_or_64(volatile uint64_t *p, uint64_t v) { *p |= v; } #ifdef __EMSCRIPTEN_PTHREADS__ +#define a_store_l a_store_l static inline void a_store_l(volatile void *p, long x) { emscripten_atomic_store_u32((void*)p, x); } +#define a_or_l a_or_l static inline void a_or_l(volatile void *p, long v) { emscripten_atomic_or_u32((void*)p, v); } +#define a_cas_p a_cas_p static inline void *a_cas_p(volatile void *p, void *t, void *s) { return (void*)emscripten_atomic_cas_u32(p, (uint32_t)t, (uint32_t)s); } +#define a_cas_l a_cas_l static inline long a_cas_l(volatile void *p, long t, long s) { return emscripten_atomic_cas_u32(p, t, s); } +#define a_cas a_cas static inline int a_cas(volatile int *p, int t, int s) { return emscripten_atomic_cas_u32(p, t, s); } +#define a_or a_or static inline void a_or(volatile void *p, int v) { emscripten_atomic_or_u32((void*)p, v); } +#define a_and a_and static inline void a_and(volatile void *p, int v) { emscripten_atomic_and_u32((void*)p, v); } +#define a_swap a_swap static inline int a_swap(volatile int *x, int v) { int old; @@ -82,36 +94,43 @@ static inline int a_swap(volatile int *x, int v) return old; } +#define a_fetch_add a_fetch_add static inline int a_fetch_add(volatile int *x, int v) { return emscripten_atomic_add_u32(x, v); } +#define a_inc a_inc static inline void a_inc(volatile int *x) { emscripten_atomic_add_u32((void*)x, 1); } +#define a_dec a_dec static inline void a_dec(volatile int *x) { emscripten_atomic_sub_u32((void*)x, 1); } +#define a_store a_store static inline void a_store(volatile int *p, int x) { emscripten_atomic_store_u32((void*)p, x); } #else // __EMSCRIPTEN_PTHREADS__ +#define a_store_l a_store_l static inline void a_store_l(volatile void *p, long x) { *(long*)p = x; } +#define a_or_l a_or_l static inline void a_or_l(volatile void *p, long v) { *(long*)p |= v; } +#define a_cas_p a_cas_p static inline void *a_cas_p(volatile void *p, void *t, void *s) { if (*(long*)p == t) @@ -119,6 +138,7 @@ static inline void *a_cas_p(volatile void *p, void *t, void *s) return t; } +#define a_cas_l a_cas_l static inline long a_cas_l(volatile void *p, long t, long s) { if (*(long*)p == t) @@ -126,6 +146,7 @@ static inline long a_cas_l(volatile void *p, long t, long s) return t; } +#define a_cas a_cas static inline int a_cas(volatile int *p, int t, int s) { if (*p == t) @@ -133,31 +154,37 @@ static inline int a_cas(volatile int *p, int t, int s) return t; } +#define a_or a_or static inline void a_or(volatile void *p, int v) { *(int*)p |= v; } +#define a_and a_and static inline void a_and(volatile void *p, int v) { *(int*)p &= v; } +#define a_inc a_inc static inline void a_inc(volatile int *x) { ++*x; } +#define a_dec a_dec static inline void a_dec(volatile int *x) { --*x; } +#define a_store a_store static inline void a_store(volatile int *p, int x) { *p = x; } +#define a_swap a_swap static inline int a_swap(volatile int *x, int v) { int old; @@ -166,16 +193,19 @@ static inline int a_swap(volatile int *x, int v) return old; } +#define a_fetch_add a_fetch_add static inline int a_fetch_add(volatile int *x, int v) { return __sync_fetch_and_add(x, v); } #endif +#define a_spin a_spin static inline void a_spin() { } +#define a_crash a_crash static inline void a_crash() { EM_ASM( abort() ); diff --git a/system/lib/libc/musl/arch/emscripten/bits/alltypes.h b/system/lib/libc/musl/arch/emscripten/bits/alltypes.h index c7d81094f9986..29f724fde6043 100644 --- a/system/lib/libc/musl/arch/emscripten/bits/alltypes.h +++ b/system/lib/libc/musl/arch/emscripten/bits/alltypes.h @@ -84,41 +84,44 @@ typedef long suseconds_t; #if defined(__NEED_pthread_attr_t) && !defined(__DEFINED_pthread_attr_t) #ifdef __EMSCRIPTEN__ -// For canvas transfer implementation in Emscripten, use an extra 10th control field +// For canvas transfer implementation in Emscripten, use an extra 11th control field // to pass a pointer to a string denoting the WebGL canvases to transfer. -typedef struct { union { int __i[10]; unsigned __s[10]; } __u; } pthread_attr_t; +typedef struct { union { int __i[11]; volatile int __vi[11]; unsigned __s[11]; } __u; } pthread_attr_t; #else -typedef struct { union { int __i[9]; unsigned __s[9]; } __u; } pthread_attr_t; +typedef struct { union { int __i[10]; volatile int __vi[10]; unsigned __s[10]; } __u; } pthread_attr_t; #endif #define __DEFINED_pthread_attr_t #endif #if defined(__NEED_pthread_mutex_t) && !defined(__DEFINED_pthread_mutex_t) #ifdef __EMSCRIPTEN__ -// For mutex implementation in Emscripten, need to use an extra seventh control field +// For mutex implementation in Emscripten, need to use an extra eighth control field // to hold a temporary futex wait & wake location, designated as mutex->_m_addr. -typedef struct { union { int __i[7]; void *__p[7]; } __u; } pthread_mutex_t; +typedef struct { union { int __i[8]; volatile int __vi[8]; volatile void *__p[8]; } __u; } pthread_mutex_t; #else -typedef struct { union { int __i[6]; void *__p[6]; } __u; } pthread_mutex_t; +typedef struct { union { int __i[7]; volatile int __vi[7]; volatile void *__p[7]; } __u; } pthread_mutex_t; #endif +typedef pthread_mutex_t mtx_t; #define __DEFINED_pthread_mutex_t #endif #if defined(__NEED_pthread_cond_t) && !defined(__DEFINED_pthread_cond_t) -typedef struct { union { int __i[12]; void *__p[12]; } __u; } pthread_cond_t; +typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12]; } __u; } pthread_cond_t; +typedef pthread_cond_t cnd_t; #define __DEFINED_pthread_cond_t #endif #if defined(__NEED_pthread_rwlock_t) && !defined(__DEFINED_pthread_rwlock_t) -typedef struct { union { int __i[8]; void *__p[8]; } __u; } pthread_rwlock_t; +typedef struct { union { int __i[8]; volatile int __vi[8]; void *__p[8]; } __u; } pthread_rwlock_t; #define __DEFINED_pthread_rwlock_t #endif #if defined(__NEED_pthread_barrier_t) && !defined(__DEFINED_pthread_barrier_t) -typedef struct { union { int __i[5]; void *__p[5]; } __u; } pthread_barrier_t; +typedef struct { union { int __i[5]; volatile int __vi[5]; void *__p[5]; } __u; } pthread_barrier_t; #define __DEFINED_pthread_barrier_t #endif + #if defined(__NEED_size_t) && !defined(__DEFINED_size_t) typedef unsigned _Addr size_t; #define __DEFINED_size_t @@ -256,6 +259,10 @@ typedef unsigned int fsfilcnt_t; #define __DEFINED_fsfilcnt_t #endif +#if defined(__NEED_wint_t) && !defined(__DEFINED_wint_t) +typedef unsigned wint_t; +#define __DEFINED_wint_t +#endif #if defined(__NEED_wctype_t) && !defined(__DEFINED_wctype_t) typedef unsigned long wctype_t; @@ -375,6 +382,12 @@ typedef struct _IO_FILE FILE; #endif +#if defined(__NEED_mbstate_t) && !defined(__DEFINED_mbstate_t) +typedef struct __mbstate_t { unsigned __opaque1, __opaque2; } mbstate_t; +#define __DEFINED_mbstate_t +#endif + + #if defined(__NEED_locale_t) && !defined(__DEFINED_locale_t) typedef struct __locale_struct * locale_t; #define __DEFINED_locale_t diff --git a/system/lib/libc/musl/arch/emscripten/bits/fcntl.h b/system/lib/libc/musl/arch/emscripten/bits/fcntl.h index 97bdfd610afa0..900601b1d7d99 100644 --- a/system/lib/libc/musl/arch/emscripten/bits/fcntl.h +++ b/system/lib/libc/musl/arch/emscripten/bits/fcntl.h @@ -15,6 +15,7 @@ #define O_DIRECT 040000 #define O_LARGEFILE 0100000 #define O_NOATIME 01000000 +#define O_PATH 010000000 #define O_TMPFILE 020000000 #define O_NDELAY O_NONBLOCK diff --git a/system/lib/libc/musl/arch/emscripten/bits/syscall.h b/system/lib/libc/musl/arch/emscripten/bits/syscall.h index e24bb5c9e2c9c..a6e10f0721bff 100644 --- a/system/lib/libc/musl/arch/emscripten/bits/syscall.h +++ b/system/lib/libc/musl/arch/emscripten/bits/syscall.h @@ -333,6 +333,7 @@ #define __NR_inotify_init1 332 #define __NR_preadv 333 #define __NR_pwritev 334 +#define __NR_recvmmsg 337 #define __NR_prlimit64 340 #define __NR_name_to_handle_at 341 #define __NR_open_by_handle_at 342 @@ -683,6 +684,7 @@ #define SYS_inotify_init1 332 #define SYS_preadv 333 #define SYS_pwritev 334 +#define SYS_recvmmsg 337 #define SYS_prlimit64 340 #define SYS_name_to_handle_at 341 #define SYS_open_by_handle_at 342 diff --git a/system/lib/libc/musl/arch/emscripten/syscall_arch.h b/system/lib/libc/musl/arch/emscripten/syscall_arch.h index 931599112aac7..81aa9a6a95072 100644 --- a/system/lib/libc/musl/arch/emscripten/syscall_arch.h +++ b/system/lib/libc/musl/arch/emscripten/syscall_arch.h @@ -88,6 +88,7 @@ long __syscall152(int which, ...); long __syscall153(int which, ...); long __syscall163(int which, ...); long __syscall168(int which, ...); +long __syscall178(int which, ...); long __syscall180(int which, ...); long __syscall181(int which, ...); long __syscall183(int which, ...); @@ -140,7 +141,11 @@ long __syscall330(int which, ...); long __syscall331(int which, ...); long __syscall333(int which, ...); long __syscall334(int which, ...); +long __syscall337(int which, ...); long __syscall340(int which, ...); +long __syscall345(int which, ...); + +#undef SYS_futimesat #ifdef __cplusplus } diff --git a/system/lib/libc/musl/configure b/system/lib/libc/musl/configure index f3ea041b69856..928455e7e9f5f 100755 --- a/system/lib/libc/musl/configure +++ b/system/lib/libc/musl/configure @@ -9,6 +9,9 @@ VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. +Configuration: + --srcdir=DIR source directory [detected] + Installation directories: --prefix=PREFIX main installation prefix [/usr/local/musl] --exec-prefix=EPREFIX installation prefix for executable files [PREFIX] @@ -22,12 +25,14 @@ Fine tuning of the installation directories: System types: --target=TARGET configure to run on target TARGET [detected] --host=HOST same as --target + --build=BUILD build system type; used only to infer cross-compiling Optional features: --enable-optimize=... optimize listed components for speed over size [auto] --enable-debug build with debugging information [disabled] --enable-warnings build with recommended warnings flags [disabled] - --enable-gcc-wrapper build musl-gcc toolchain wrapper [auto] + --enable-visibility use global visibility options to optimize PIC [auto] + --enable-wrapper=... build given musl toolchain wrapper [auto] --disable-shared inhibit building shared library [enabled] --disable-static inhibit building static library [enabled] @@ -79,7 +84,7 @@ fi tryflag () { printf "checking whether compiler accepts %s... " "$2" echo "typedef int x;" > "$tmpc" -if $CC "$2" -c -o /dev/null "$tmpc" >/dev/null 2>&1 ; then +if $CC $CFLAGS_TRY $2 -c -o /dev/null "$tmpc" >/dev/null 2>&1 ; then printf "yes\n" eval "$1=\"\${$1} \$2\"" eval "$1=\${$1# }" @@ -93,7 +98,7 @@ fi tryldflag () { printf "checking whether linker accepts %s... " "$2" echo "typedef int x;" > "$tmpc" -if $CC -nostdlib -shared "$2" -o /dev/null "$tmpc" >/dev/null 2>&1 ; then +if $CC $LDFLAGS_TRY -nostdlib -shared "$2" -o /dev/null "$tmpc" >/dev/null 2>&1 ; then printf "yes\n" eval "$1=\"\${$1} \$2\"" eval "$1=\${$1# }" @@ -111,25 +116,36 @@ fi CFLAGS_C99FSE= CFLAGS_AUTO= CFLAGS_MEMOPS= +CFLAGS_NOSSP= +CFLAGS_TRY= LDFLAGS_AUTO= +LDFLAGS_TRY= OPTIMIZE_GLOBS= +srcdir= prefix=/usr/local/musl exec_prefix='$(prefix)' bindir='$(exec_prefix)/bin' libdir='$(prefix)/lib' includedir='$(prefix)/include' syslibdir='/lib' +tools= +tool_libs= +build= target= optimize=auto debug=no warnings=no -shared=yes +visibility=auto +shared=auto static=yes wrapper=auto +gcc_wrapper=no +clang_wrapper=no for arg ; do case "$arg" in ---help) usage ;; +--help|-h) usage ;; +--srcdir=*) srcdir=${arg#*=} ;; --prefix=*) prefix=${arg#*=} ;; --exec-prefix=*) exec_prefix=${arg#*=} ;; --bindir=*) bindir=${arg#*=} ;; @@ -147,10 +163,18 @@ case "$arg" in --disable-debug|--enable-debug=no) debug=no ;; --enable-warnings|--enable-warnings=yes) warnings=yes ;; --disable-warnings|--enable-warnings=no) warnings=no ;; ---enable-gcc-wrapper|--enable-gcc-wrapper=yes) wrapper=yes ;; +--enable-visibility|--enable-visibility=yes) visibility=yes ;; +--disable-visibility|--enable-visibility=no) visibility=no ;; +--enable-wrapper|--enable-wrapper=yes) wrapper=detect ;; +--enable-wrapper=all) wrapper=yes ; gcc_wrapper=yes ; clang_wrapper=yes ;; +--enable-wrapper=gcc) wrapper=yes ; gcc_wrapper=yes ;; +--enable-wrapper=clang) wrapper=yes ; clang_wrapper=yes ;; +--disable-wrapper|--enable-wrapper=no) wrapper=no ;; +--enable-gcc-wrapper|--enable-gcc-wrapper=yes) wrapper=yes ; gcc_wrapper=yes ;; --disable-gcc-wrapper|--enable-gcc-wrapper=no) wrapper=no ;; ---enable-*|--disable-*|--with-*|--without-*|--*dir=*|--build=*) ;; +--enable-*|--disable-*|--with-*|--without-*|--*dir=*) ;; --host=*|--target=*) target=${arg#*=} ;; +--build=*) build=${arg#*=} ;; -* ) echo "$0: unknown option $arg" ;; CC=*) CC=${arg#*=} ;; CFLAGS=*) CFLAGS=${arg#*=} ;; @@ -159,14 +183,26 @@ LDFLAGS=*) LDFLAGS=${arg#*=} ;; CROSS_COMPILE=*) CROSS_COMPILE=${arg#*=} ;; LIBCC=*) LIBCC=${arg#*=} ;; *=*) ;; -*) target=$arg ;; +*) build=$arg ; target=$arg ;; esac done -for i in prefix exec_prefix bindir libdir includedir syslibdir ; do +for i in srcdir prefix exec_prefix bindir libdir includedir syslibdir ; do stripdir $i done +# +# Get the source dir for out-of-tree builds +# +if test -z "$srcdir" ; then +srcdir="${0%/configure}" +stripdir srcdir +fi +abs_builddir="$(pwd)" || fail "$0: cannot determine working directory" +abs_srcdir="$(cd $srcdir && pwd)" || fail "$0: invalid source directory $srcdir" +test "$abs_srcdir" = "$abs_builddir" && srcdir=. +test "$srcdir" != "." -a -f Makefile -a ! -h Makefile && fail "$0: Makefile already exists in the working directory" + # # Get a temp filename we can use # @@ -180,6 +216,15 @@ done set +C trap 'rm "$tmpc"' EXIT INT QUIT TERM HUP +# +# Check whether we are cross-compiling, and set a default +# CROSS_COMPILE prefix if none was provided. +# +test "$target" && \ +test "$target" != "$build" && \ +test -z "$CROSS_COMPILE" && \ +CROSS_COMPILE="$target-" + # # Find a C compiler to use # @@ -200,36 +245,59 @@ exit 1 fi # -# Need to know if the compiler is gcc to decide whether to build the -# musl-gcc wrapper, and for critical bug detection in some gcc versions. +# Figure out options to force errors on unknown flags. # -printf "checking whether compiler is gcc... " -if fnmatch '*gcc\ version*' "$($CC -v 2>&1)" ; then -cc_is_gcc=yes -else -cc_is_gcc=no +tryflag CFLAGS_TRY -Werror=unknown-warning-option +tryflag CFLAGS_TRY -Werror=unused-command-line-argument +tryldflag LDFLAGS_TRY -Werror=unknown-warning-option +tryldflag LDFLAGS_TRY -Werror=unused-command-line-argument + +# +# Need to know if the compiler is gcc or clang to decide which toolchain +# wrappers to build. +# +printf "checking for C compiler family... " +cc_ver="$(LC_ALL=C $CC -v 2>&1)" +cc_family=unknown +if fnmatch '*gcc\ version*' "$cc_ver" ; then +cc_family=gcc +elif fnmatch '*clang\ version*' "$cc_ver" ; then +cc_family=clang fi -echo "$cc_is_gcc" +echo "$cc_family" # -# Only build musl-gcc wrapper if toolchain does not already target musl +# Figure out toolchain wrapper to build # -if test "$wrapper" = auto ; then -printf "checking whether to build musl-gcc wrapper... " -if test "$cc_is_gcc" = yes ; then -wrapper=yes -while read line ; do -case "$line" in */ld-musl-*) wrapper=no ;; esac -done <" > "$tmpc" +echo "#if ! __GLIBC__" >> "$tmpc" +echo "#error no" >> "$tmpc" +echo "#endif" >> "$tmpc" +printf "checking for toolchain wrapper to build... " +if test "$wrapper" = auto && ! $CC -c -o /dev/null "$tmpc" >/dev/null 2>&1 ; then +echo "none" +elif test "$cc_family" = gcc ; then +gcc_wrapper=yes +echo "gcc" +elif test "$cc_family" = clang ; then +clang_wrapper=yes +echo "clang" else -wrapper=no +echo "none" +if test "$wrapper" = detect ; then +fail "$0: could not find an appropriate toolchain wrapper" +fi fi -echo "$wrapper" fi - +if test "$gcc_wrapper" = yes ; then +tools="$tools obj/musl-gcc" +tool_libs="$tool_libs lib/musl-gcc.specs" +fi +if test "$clang_wrapper" = yes ; then +tools="$tools obj/musl-clang obj/ld.musl-clang" +fi # # Find the target architecture @@ -243,13 +311,18 @@ printf "%s\n" "$target" # case "$target" in # Catch these early to simplify matching for 32-bit archs -mips64*|powerpc64*) fail "$0: unsupported target \"$target\"" ;; arm*) ARCH=arm ;; +aarch64*) ARCH=aarch64 ;; +i?86-nt32*) ARCH=nt32 ;; i?86*) ARCH=i386 ;; x86_64-x32*|x32*|x86_64*x32) ARCH=x32 ;; +x86_64-nt64*) ARCH=nt64 ;; x86_64*) ARCH=x86_64 ;; +mips64*) ARCH=mips64 ;; mips*) ARCH=mips ;; microblaze*) ARCH=microblaze ;; +or1k*) ARCH=or1k ;; +powerpc64*) ARCH=powerpc64 ;; powerpc*) ARCH=powerpc ;; sh[1-9bel-]*|sh|superh*) ARCH=sh ;; asmjs-unknown-emscripten) ARCH=emscripten ;; @@ -281,7 +354,7 @@ __attribute__((__may_alias__)) #endif x; EOF -if $CC $CFLAGS_C99FSE -I./arch/$ARCH -I./include $CPPFLAGS $CFLAGS \ +if $CC $CFLAGS_C99FSE $CPPFLAGS $CFLAGS \ -c -o /dev/null "$tmpc" >/dev/null 2>&1 ; then printf "no\n" else @@ -289,6 +362,20 @@ printf "yes\n" CFLAGS_C99FSE="$CFLAGS_C99FSE -D__may_alias__=" fi +# +# The GNU toolchain defaults to assuming unmarked files need an +# executable stack, potentially exposing vulnerabilities in programs +# linked with such object files. Fix this. +# +tryflag CFLAGS_C99FSE -Wa,--noexecstack + +# +# Check for options to disable stack protector, which needs to be +# disabled for a few early-bootstrap translation units. If not found, +# this is not an error; we assume the toolchain does not do ssp. +# +tryflag CFLAGS_NOSSP -fno-stack-protector + # # Check for options that may be needed to prevent the compiler from # generating self-referential versions of memcpy,, memmove, memcmp, @@ -299,12 +386,25 @@ fi # XXX EMSCRIPTEN tryflag CFLAGS_MEMOPS -fno-tree-loop-distribute-patterns # -# If debugging is explicitly enabled, don't auto-enable optimizations +# Enable debugging if requessted. +# +test "$debug" = yes && CFLAGS_AUTO=-g + +# +# Preprocess asm files to add extra debugging information if debug is +# enabled, our assembler supports the needed directives, and the +# preprocessing script has been written for our architecture. # -if test "$debug" = yes ; then -CFLAGS_AUTO=-g -test "$optimize" = auto && optimize=no +printf "checking whether we should preprocess assembly to add debugging information... " +if fnmatch '-g*|*\ -g*' "$CFLAGS_AUTO $CFLAGS" && + test -f "tools/add-cfi.$ARCH.awk" && + printf ".file 1 \"srcfile.s\"\n.line 1\n.cfi_startproc\n.cfi_endproc" | $CC -g -x assembler -c -o /dev/null 2>/dev/null - +then + ADD_CFI=yes +else + ADD_CFI=no fi +printf "%s\n" "$ADD_CFI" # # Possibly add a -O option to CFLAGS and select modules to optimize with @@ -370,21 +470,27 @@ tryflag CFLAGS_AUTO -fno-unwind-tables tryflag CFLAGS_AUTO -fno-asynchronous-unwind-tables # -# The GNU toolchain defaults to assuming unmarked files need an -# executable stack, potentially exposing vulnerabilities in programs -# linked with such object files. Fix this. +# Attempt to put each function and each data object in its own +# section. This both allows additional size optimizations at link +# time and works around a dangerous class of compiler/assembler bugs +# whereby relative address expressions are constant-folded by the +# assembler even when one or more of the symbols involved is +# replaceable. See gas pr 18561 and gcc pr 66609, 68178, etc. # -tryflag CFLAGS_AUTO -Wa,--noexecstack +tryflag CFLAGS_AUTO -ffunction-sections +tryflag CFLAGS_AUTO -fdata-sections # # On x86, make sure we don't have incompatible instruction set # extensions enabled by default. This is bad for making static binaries. # We cheat and use i486 rather than i386 because i386 really does not # work anyway (issues with atomic ops). +# Some build environments pass -march and -mtune options via CC, so +# check both CC and CFLAGS. # if test "$ARCH" = "i386" ; then -fnmatch '-march=*|*\ -march=*' "$CFLAGS" || tryldflag CFLAGS_AUTO -march=i486 -fnmatch '-mtune=*|*\ -mtune=*' "$CFLAGS" || tryldflag CFLAGS_AUTO -mtune=generic +fnmatch '-march=*|*\ -march=*' "$CC $CFLAGS" || tryldflag CFLAGS_AUTO -march=i486 +fnmatch '-mtune=*|*\ -mtune=*' "$CC $CFLAGS" || tryldflag CFLAGS_AUTO -mtune=generic fi # @@ -409,16 +515,76 @@ tryflag CFLAGS_AUTO -Wno-unknown-pragmas tryflag CFLAGS_AUTO -Wno-pointer-to-int-cast fi +if test "x$visibility" = xauto ; then +# This test checks toolchain support for several things: +# - the -include option +# - the attributes/pragmas used in vis.h +# - linking code that takes the address of protected symbols +# - gcc 3.x bug that wrongly claims declarations mismatch +printf "checking whether global visibility preinclude works... " +cat > "$tmpc" </dev/null 2>&1 ; then +visibility=yes +else +visibility=no +fi +printf "%s\n" "$visibility" +fi + +if test "x$visibility" = xyes ; then +CFLAGS_AUTO="$CFLAGS_AUTO -include vis.h" +CFLAGS_AUTO="${CFLAGS_AUTO# }" +fi + +# Determine if the compiler produces position-independent code (PIC) +# by default. If so, we don't need to compile separate object files +# for libc.a and libc.so. +if trycppif __PIC__ "$CFLAGS_C99FSE $CPPFLAGS $CFLAGS" ; then +pic_default=yes +else +pic_default=no +fi + +# Reduce space lost to padding for alignment purposes by sorting data +# objects according to their alignment reqirements. This approximates +# optimal packing. +tryldflag LDFLAGS_AUTO -Wl,--sort-section,alignment +tryldflag LDFLAGS_AUTO -Wl,--sort-common + +# When linking shared library, drop dummy weak definitions that were +# replaced by strong definitions from other translation units. +tryldflag LDFLAGS_AUTO -Wl,--gc-sections + # Some patched GCC builds have these defaults messed up... -tryflag CFLAGS_AUTO -fno-stack-protector tryldflag LDFLAGS_AUTO -Wl,--hash-style=both -# Disable dynamic linking if ld is broken and can't do -Bsymbolic-functions -LDFLAGS_DUMMY= -tryldflag LDFLAGS_DUMMY -Wl,-Bsymbolic-functions || { -printf "warning: disabling dynamic linking support\n" -shared=no -} +# Prevent linking if there are undefined symbols; if any exist, +# libc.so will crash at runtime during relocation processing. +# The common way this can happen is failure to link the compiler +# runtime library; implementation error is also a possibility. +tryldflag LDFLAGS_AUTO -Wl,--no-undefined + +# Avoid exporting symbols from compiler runtime libraries. They +# should be hidden anyway, but some toolchains including old gcc +# versions built without shared library support and pcc are broken. +tryldflag LDFLAGS_AUTO -Wl,--exclude-libs=ALL + +# Linking with -Bsymbolic-functions is no longer mandatory for +# the dynamic linker to work, but enable it if it works as +# a linking optimization. +tryldflag LDFLAGS_AUTO -Wl,-Bsymbolic-functions # Find compiler runtime library test -z "$LIBCC" && tryldflag LIBCC -lgcc && tryldflag LIBCC -lgcc_eh @@ -429,7 +595,7 @@ printf "using compiler runtime libraries: %s\n" "$LIBCC" # Figure out arch variants for archs with variants SUBARCH= -t="$CFLAGS_C99FSE $CPPFLAGS $CFLAGS_AUTO $CFLAGS" +t="$CFLAGS_C99FSE $CPPFLAGS $CFLAGS" if test "$ARCH" = "x86_64" ; then trycppif __ILP32__ "$t" && ARCH=x32 @@ -438,17 +604,56 @@ fi if test "$ARCH" = "arm" ; then trycppif __ARMEB__ "$t" && SUBARCH=${SUBARCH}eb trycppif __ARM_PCS_VFP "$t" && SUBARCH=${SUBARCH}hf +# Versions of clang up until at least 3.8 have the wrong constraint codes +# for floating point operands to inline asm. Detect this so the affected +# source files can just disable the asm. +if test "$cc_family" = clang ; then +printf "checking whether clang's vfp asm constraints work... " +echo 'float f(float x) { __asm__("":"+t"(x)); return x; }' > "$tmpc" +if $CC $CFLAGS_C99FSE $CPPFLAGS $CFLAGS -c -o /dev/null "$tmpc" >/dev/null 2>&1 ; then +printf "yes\n" +else +printf "no\n" +CFLAGS_AUTO="$CFLAGS_AUTO -DBROKEN_VFP_ASM" +CFLAGS_AUTO="${CFLAGS_AUTO# }" +fi +fi +fi + +if test "$ARCH" = "aarch64" ; then +trycppif __AARCH64EB__ "$t" && SUBARCH=${SUBARCH}_be fi if test "$ARCH" = "mips" ; then +trycppif "__mips_isa_rev >= 6" "$t" && SUBARCH=${SUBARCH}r6 trycppif "_MIPSEL || __MIPSEL || __MIPSEL__" "$t" && SUBARCH=${SUBARCH}el trycppif __mips_soft_float "$t" && SUBARCH=${SUBARCH}-sf fi +if test "$ARCH" = "mips64" ; then +trycppif "_MIPS_SIM != _ABI64" "$t" && ARCH=mipsn32 +trycppif "__mips_isa_rev >= 6" "$t" && SUBARCH=${SUBARCH}r6 +trycppif "_MIPSEL || __MIPSEL || __MIPSEL__" "$t" && SUBARCH=${SUBARCH}el +trycppif __mips_soft_float "$t" && SUBARCH=${SUBARCH}-sf +fi + +if test "$ARCH" = "powerpc" ; then +trycppif "__NO_FPRS__ && !_SOFT_FLOAT" "$t" && fail \ + "$0: error: compiler's floating point configuration is unsupported" +trycppif _SOFT_FLOAT "$t" && SUBARCH=${SUBARCH}-sf +fi + test "$ARCH" = "microblaze" && trycppif __MICROBLAZEEL__ "$t" \ && SUBARCH=${SUBARCH}el +if test "$ARCH" = "powerpc64" ; then +trycppif "_CALL_ELF == 2" "$t" || fail "$0: error: unsupported powerpc64 ABI" +trycppif __LITTLE_ENDIAN__ "$t" && SUBARCH=${SUBARCH}le +trycppif _SOFT_FLOAT "$t" && fail "$0: error: soft-float not supported on powerpc64" +fi + if test "$ARCH" = "sh" ; then +tryflag CFLAGS_AUTO -Wa,--isa=any trycppif __BIG_ENDIAN__ "$t" && SUBARCH=${SUBARCH}eb if trycppif "__SH_FPU_ANY__ || __SH4__" "$t" ; then # Some sh configurations are broken and replace double with float @@ -465,6 +670,9 @@ fi else SUBARCH=${SUBARCH}-nofpu fi +if trycppif __SH_FDPIC__ "$t" ; then +SUBARCH=${SUBARCH}-fdpic +fi fi test "$SUBARCH" \ @@ -488,14 +696,25 @@ echo '#include ' > "$tmpc" echo '#if LDBL_MANT_DIG == 53' >> "$tmpc" echo 'typedef char ldcheck[9-(int)sizeof(long double)];' >> "$tmpc" echo '#endif' >> "$tmpc" -if $CC $CFLAGS_C99FSE -I./arch/$ARCH -I./include $CPPFLAGS $CFLAGS \ - -c -o /dev/null "$tmpc" >/dev/null 2>&1 ; then +if $CC $CFLAGS_C99FSE \ + -I$srcdir/arch/$ARCH -I$srcdir/arch/generic -I$srcdir/include \ + $CPPFLAGS $CFLAGS -c -o /dev/null "$tmpc" >/dev/null 2>&1 ; then printf "yes\n" else printf "no\n" fail "$0: error: unsupported long double type" fi +# +# Some build systems globally pass in broken CFLAGS like -ffast-math +# for all packages. On recent GCC we can detect this and error out +# early rather than producing a seriously-broken math library. +# +if trycppif "__FAST_MATH__" \ + "$CFLAGS_C99FSE $CPPFLAGS $CFLAGS" ; then +fail "$0: error: compiler has broken floating point; check CFLAGS" +fi + printf "creating config.mak... " cmdline=$(quote "$0") @@ -511,6 +730,7 @@ cat << EOF ARCH = $ARCH SUBARCH = $SUBARCH ASMSUBARCH = $ASMSUBARCH +srcdir = $srcdir prefix = $prefix exec_prefix = $exec_prefix bindir = $bindir @@ -518,19 +738,28 @@ libdir = $libdir includedir = $includedir syslibdir = $syslibdir CC = $CC -CFLAGS = $CFLAGS_AUTO $CFLAGS +CFLAGS = $CFLAGS +CFLAGS_AUTO = $CFLAGS_AUTO CFLAGS_C99FSE = $CFLAGS_C99FSE CFLAGS_MEMOPS = $CFLAGS_MEMOPS +CFLAGS_NOSSP = $CFLAGS_NOSSP CPPFLAGS = $CPPFLAGS -LDFLAGS = $LDFLAGS_AUTO $LDFLAGS +LDFLAGS = $LDFLAGS +LDFLAGS_AUTO = $LDFLAGS_AUTO CROSS_COMPILE = $CROSS_COMPILE LIBCC = $LIBCC OPTIMIZE_GLOBS = $OPTIMIZE_GLOBS +ALL_TOOLS = $tools +TOOL_LIBS = $tool_libs +ADD_CFI = $ADD_CFI EOF test "x$static" = xno && echo "STATIC_LIBS =" test "x$shared" = xno && echo "SHARED_LIBS =" -test "x$wrapper" = xno && echo "ALL_TOOLS =" -test "x$wrapper" = xno && echo "TOOL_LIBS =" +test "x$cc_family" = xgcc && echo 'WRAPCC_GCC = $(CC)' +test "x$cc_family" = xclang && echo 'WRAPCC_CLANG = $(CC)' +test "x$pic_default" = xyes && echo 'AOBJS = $(LOBJS)' exec 1>&3 3>&- +test "$srcdir" = "." || ln -sf $srcdir/Makefile . + printf "done\n" diff --git a/system/lib/libc/musl/ldso/dlstart.c b/system/lib/libc/musl/ldso/dlstart.c new file mode 100644 index 0000000000000..4dbe17843ca27 --- /dev/null +++ b/system/lib/libc/musl/ldso/dlstart.c @@ -0,0 +1,148 @@ +#include +#include "dynlink.h" + +#ifndef START +#define START "_dlstart" +#endif + +#define SHARED + +#include "crt_arch.h" + +#ifndef GETFUNCSYM +#define GETFUNCSYM(fp, sym, got) do { \ + __attribute__((__visibility__("hidden"))) void sym(); \ + static void (*static_func_ptr)() = sym; \ + __asm__ __volatile__ ( "" : "+m"(static_func_ptr) : : "memory"); \ + *(fp) = static_func_ptr; } while(0) +#endif + +__attribute__((__visibility__("hidden"))) +void _dlstart_c(size_t *sp, size_t *dynv) +{ + size_t i, aux[AUX_CNT], dyn[DYN_CNT]; + size_t *rel, rel_size, base; + + int argc = *sp; + char **argv = (void *)(sp+1); + + for (i=argc+1; argv[i]; i++); + size_t *auxv = (void *)(argv+i+1); + + for (i=0; isegs; + } else { + /* If dynv is null, the entry point was started from loader + * that is not fdpic-aware. We can assume normal fixed- + * displacement ELF loading was performed, but when ldso was + * run as a command, finding the Ehdr is a heursitic: we + * have to assume Phdrs start in the first 4k of the file. */ + base = aux[AT_BASE]; + if (!base) base = aux[AT_PHDR] & -4096; + segs = &fakeseg; + segs[0].addr = base; + segs[0].p_vaddr = 0; + segs[0].p_memsz = -1; + Ehdr *eh = (void *)base; + Phdr *ph = (void *)(base + eh->e_phoff); + size_t phnum = eh->e_phnum; + size_t phent = eh->e_phentsize; + while (phnum-- && ph->p_type != PT_DYNAMIC) + ph = (void *)((size_t)ph + phent); + dynv = (void *)(base + ph->p_vaddr); + } +#endif + + for (i=0; i= segs[j].p_memsz; j++); + dyn[i] += segs[j].addr - segs[j].p_vaddr; + } + base = 0; + + const Sym *syms = (void *)dyn[DT_SYMTAB]; + + rel = (void *)dyn[DT_RELA]; + rel_size = dyn[DT_RELASZ]; + for (; rel_size; rel+=3, rel_size-=3*sizeof(size_t)) { + if (!IS_RELATIVE(rel[1], syms)) continue; + for (j=0; rel[0]-segs[j].p_vaddr >= segs[j].p_memsz; j++); + size_t *rel_addr = (void *) + (rel[0] + segs[j].addr - segs[j].p_vaddr); + if (R_TYPE(rel[1]) == REL_FUNCDESC_VAL) { + *rel_addr += segs[rel_addr[1]].addr + - segs[rel_addr[1]].p_vaddr + + syms[R_SYM(rel[1])].st_value; + rel_addr[1] = dyn[DT_PLTGOT]; + } else { + size_t val = syms[R_SYM(rel[1])].st_value; + for (j=0; val-segs[j].p_vaddr >= segs[j].p_memsz; j++); + *rel_addr = rel[2] + segs[j].addr - segs[j].p_vaddr + val; + } + } +#else + /* If the dynamic linker is invoked as a command, its load + * address is not available in the aux vector. Instead, compute + * the load address as the difference between &_DYNAMIC and the + * virtual address in the PT_DYNAMIC program header. */ + base = aux[AT_BASE]; + if (!base) { + size_t phnum = aux[AT_PHNUM]; + size_t phentsize = aux[AT_PHENT]; + Phdr *ph = (void *)aux[AT_PHDR]; + for (i=phnum; i--; ph = (void *)((char *)ph + phentsize)) { + if (ph->p_type == PT_DYNAMIC) { + base = (size_t)dynv - ph->p_vaddr; + break; + } + } + } + + /* MIPS uses an ugly packed form for GOT relocations. Since we + * can't make function calls yet and the code is tiny anyway, + * it's simply inlined here. */ + if (NEED_MIPS_GOT_RELOCS) { + size_t local_cnt = 0; + size_t *got = (void *)(base + dyn[DT_PLTGOT]); + for (i=0; dynv[i]; i+=2) if (dynv[i]==DT_MIPS_LOCAL_GOTNO) + local_cnt = dynv[i+1]; + for (i=0; i +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pthread_impl.h" +#include "libc.h" +#include "dynlink.h" + +static void error(const char *, ...); + +#define MAXP2(a,b) (-(-(a)&-(b))) +#define ALIGN(x,y) ((x)+(y)-1 & -(y)) + +struct debug { + int ver; + void *head; + void (*bp)(void); + int state; + void *base; +}; + +struct td_index { + size_t args[2]; + struct td_index *next; +}; + +struct dso { +#if DL_FDPIC + struct fdpic_loadmap *loadmap; +#else + unsigned char *base; +#endif + char *name; + size_t *dynv; + struct dso *next, *prev; + + Phdr *phdr; + int phnum; + size_t phentsize; + int refcnt; + Sym *syms; + uint32_t *hashtab; + uint32_t *ghashtab; + int16_t *versym; + char *strings; + unsigned char *map; + size_t map_len; + dev_t dev; + ino_t ino; + signed char global; + char relocated; + char constructed; + char kernel_mapped; + struct dso **deps, *needed_by; + char *rpath_orig, *rpath; + struct tls_module tls; + size_t tls_id; + size_t relro_start, relro_end; + void **new_dtv; + unsigned char *new_tls; + volatile int new_dtv_idx, new_tls_idx; + struct td_index *td_index; + struct dso *fini_next; + char *shortname; +#if DL_FDPIC + unsigned char *base; +#else + struct fdpic_loadmap *loadmap; +#endif + struct funcdesc { + void *addr; + size_t *got; + } *funcdescs; + size_t *got; + char buf[]; +}; + +struct symdef { + Sym *sym; + struct dso *dso; +}; + +int __init_tp(void *); +void __init_libc(char **, char *); +void *__copy_tls(unsigned char *); + +__attribute__((__visibility__("hidden"))) +const char *__libc_get_version(void); + +static struct builtin_tls { + char c; + struct pthread pt; + void *space[16]; +} builtin_tls[1]; +#define MIN_TLS_ALIGN offsetof(struct builtin_tls, pt) + +#define ADDEND_LIMIT 4096 +static size_t *saved_addends, *apply_addends_to; + +static struct dso ldso; +static struct dso *head, *tail, *fini_head; +static char *env_path, *sys_path; +static unsigned long long gencnt; +static int runtime; +static int ldd_mode; +static int ldso_fail; +static int noload; +static jmp_buf *rtld_fail; +static pthread_rwlock_t lock; +static struct debug debug; +static struct tls_module *tls_tail; +static size_t tls_cnt, tls_offset, tls_align = MIN_TLS_ALIGN; +static size_t static_tls_cnt; +static pthread_mutex_t init_fini_lock = { ._m_type = PTHREAD_MUTEX_RECURSIVE }; +static struct fdpic_loadmap *app_loadmap; +static struct fdpic_dummy_loadmap app_dummy_loadmap; + +struct debug *_dl_debug_addr = &debug; + +__attribute__((__visibility__("hidden"))) +void (*const __init_array_start)(void)=0, (*const __fini_array_start)(void)=0; + +__attribute__((__visibility__("hidden"))) +extern void (*const __init_array_end)(void), (*const __fini_array_end)(void); + +weak_alias(__init_array_start, __init_array_end); +weak_alias(__fini_array_start, __fini_array_end); + +static int dl_strcmp(const char *l, const char *r) +{ + for (; *l==*r && *l; l++, r++); + return *(unsigned char *)l - *(unsigned char *)r; +} +#define strcmp(l,r) dl_strcmp(l,r) + +/* Compute load address for a virtual address in a given dso. */ +#if DL_FDPIC +static void *laddr(const struct dso *p, size_t v) +{ + size_t j=0; + if (!p->loadmap) return p->base + v; + for (j=0; v-p->loadmap->segs[j].p_vaddr >= p->loadmap->segs[j].p_memsz; j++); + return (void *)(v - p->loadmap->segs[j].p_vaddr + p->loadmap->segs[j].addr); +} +#define fpaddr(p, v) ((void (*)())&(struct funcdesc){ \ + laddr(p, v), (p)->got }) +#else +#define laddr(p, v) (void *)((p)->base + (v)) +#define fpaddr(p, v) ((void (*)())laddr(p, v)) +#endif + +static void decode_vec(size_t *v, size_t *a, size_t cnt) +{ + size_t i; + for (i=0; i>24 & 0xf0; + } + return h & 0xfffffff; +} + +static uint32_t gnu_hash(const char *s0) +{ + const unsigned char *s = (void *)s0; + uint_fast32_t h = 5381; + for (; *s; s++) + h += h*32 + *s; + return h; +} + +static Sym *sysv_lookup(const char *s, uint32_t h, struct dso *dso) +{ + size_t i; + Sym *syms = dso->syms; + uint32_t *hashtab = dso->hashtab; + char *strings = dso->strings; + for (i=hashtab[2+h%hashtab[0]]; i; i=hashtab[2+hashtab[0]+i]) { + if ((!dso->versym || dso->versym[i] >= 0) + && (!strcmp(s, strings+syms[i].st_name))) + return syms+i; + } + return 0; +} + +static Sym *gnu_lookup(uint32_t h1, uint32_t *hashtab, struct dso *dso, const char *s) +{ + uint32_t nbuckets = hashtab[0]; + uint32_t *buckets = hashtab + 4 + hashtab[2]*(sizeof(size_t)/4); + uint32_t i = buckets[h1 % nbuckets]; + + if (!i) return 0; + + uint32_t *hashval = buckets + nbuckets + (i - hashtab[1]); + + for (h1 |= 1; ; i++) { + uint32_t h2 = *hashval++; + if ((h1 == (h2|1)) && (!dso->versym || dso->versym[i] >= 0) + && !strcmp(s, dso->strings + dso->syms[i].st_name)) + return dso->syms+i; + if (h2 & 1) break; + } + + return 0; +} + +static Sym *gnu_lookup_filtered(uint32_t h1, uint32_t *hashtab, struct dso *dso, const char *s, uint32_t fofs, size_t fmask) +{ + const size_t *bloomwords = (const void *)(hashtab+4); + size_t f = bloomwords[fofs & (hashtab[2]-1)]; + if (!(f & fmask)) return 0; + + f >>= (h1 >> hashtab[3]) % (8 * sizeof f); + if (!(f & 1)) return 0; + + return gnu_lookup(h1, hashtab, dso, s); +} + +#define OK_TYPES (1<next) { + Sym *sym; + if (!dso->global) continue; + if ((ght = dso->ghashtab)) { + if (!ghm) { + gh = gnu_hash(s); + int maskbits = 8 * sizeof ghm; + gho = gh / maskbits; + ghm = 1ul << gh % maskbits; + } + sym = gnu_lookup_filtered(gh, ght, dso, s, gho, ghm); + } else { + if (!h) h = sysv_hash(s); + sym = sysv_lookup(s, h, dso); + } + if (!sym) continue; + if (!sym->st_shndx) + if (need_def || (sym->st_info&0xf) == STT_TLS + || ARCH_SYM_REJECT_UND(sym)) + continue; + if (!sym->st_value) + if ((sym->st_info&0xf) != STT_TLS) + continue; + if (!(1<<(sym->st_info&0xf) & OK_TYPES)) continue; + if (!(1<<(sym->st_info>>4) & OK_BINDS)) continue; + + if (def.sym && sym->st_info>>4 == STB_WEAK) continue; + def.sym = sym; + def.dso = dso; + if (sym->st_info>>4 == STB_GLOBAL) break; + } + return def; +} + +__attribute__((__visibility__("hidden"))) +ptrdiff_t __tlsdesc_static(), __tlsdesc_dynamic(); + +static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stride) +{ + unsigned char *base = dso->base; + Sym *syms = dso->syms; + char *strings = dso->strings; + Sym *sym; + const char *name; + void *ctx; + int type; + int sym_index; + struct symdef def; + size_t *reloc_addr; + size_t sym_val; + size_t tls_val; + size_t addend; + int skip_relative = 0, reuse_addends = 0, save_slot = 0; + + if (dso == &ldso) { + /* Only ldso's REL table needs addend saving/reuse. */ + if (rel == apply_addends_to) + reuse_addends = 1; + skip_relative = 1; + } + + for (; rel_size; rel+=stride, rel_size-=stride*sizeof(size_t)) { + if (skip_relative && IS_RELATIVE(rel[1], dso->syms)) continue; + type = R_TYPE(rel[1]); + if (type == REL_NONE) continue; + sym_index = R_SYM(rel[1]); + reloc_addr = laddr(dso, rel[0]); + if (sym_index) { + sym = syms + sym_index; + name = strings + sym->st_name; + ctx = type==REL_COPY ? head->next : head; + def = (sym->st_info&0xf) == STT_SECTION + ? (struct symdef){ .dso = dso, .sym = sym } + : find_sym(ctx, name, type==REL_PLT); + if (!def.sym && (sym->st_shndx != SHN_UNDEF + || sym->st_info>>4 != STB_WEAK)) { + error("Error relocating %s: %s: symbol not found", + dso->name, name); + if (runtime) longjmp(*rtld_fail, 1); + continue; + } + } else { + sym = 0; + def.sym = 0; + def.dso = dso; + } + + if (stride > 2) { + addend = rel[2]; + } else if (type==REL_GOT || type==REL_PLT|| type==REL_COPY) { + addend = 0; + } else if (reuse_addends) { + /* Save original addend in stage 2 where the dso + * chain consists of just ldso; otherwise read back + * saved addend since the inline one was clobbered. */ + if (head==&ldso) + saved_addends[save_slot] = *reloc_addr; + addend = saved_addends[save_slot++]; + } else { + addend = *reloc_addr; + } + + sym_val = def.sym ? (size_t)laddr(def.dso, def.sym->st_value) : 0; + tls_val = def.sym ? def.sym->st_value : 0; + + switch(type) { + case REL_NONE: + break; + case REL_OFFSET: + addend -= (size_t)reloc_addr; + case REL_SYMBOLIC: + case REL_GOT: + case REL_PLT: + *reloc_addr = sym_val + addend; + break; + case REL_RELATIVE: + *reloc_addr = (size_t)base + addend; + break; + case REL_SYM_OR_REL: + if (sym) *reloc_addr = sym_val + addend; + else *reloc_addr = (size_t)base + addend; + break; + case REL_COPY: + memcpy(reloc_addr, (void *)sym_val, sym->st_size); + break; + case REL_OFFSET32: + *(uint32_t *)reloc_addr = sym_val + addend + - (size_t)reloc_addr; + break; + case REL_FUNCDESC: + *reloc_addr = def.sym ? (size_t)(def.dso->funcdescs + + (def.sym - def.dso->syms)) : 0; + break; + case REL_FUNCDESC_VAL: + if ((sym->st_info&0xf) == STT_SECTION) *reloc_addr += sym_val; + else *reloc_addr = sym_val; + reloc_addr[1] = def.sym ? (size_t)def.dso->got : 0; + break; + case REL_DTPMOD: + *reloc_addr = def.dso->tls_id; + break; + case REL_DTPOFF: + *reloc_addr = tls_val + addend - DTP_OFFSET; + break; +#ifdef TLS_ABOVE_TP + case REL_TPOFF: + *reloc_addr = tls_val + def.dso->tls.offset + TPOFF_K + addend; + break; +#else + case REL_TPOFF: + *reloc_addr = tls_val - def.dso->tls.offset + addend; + break; + case REL_TPOFF_NEG: + *reloc_addr = def.dso->tls.offset - tls_val + addend; + break; +#endif + case REL_TLSDESC: + if (stride<3) addend = reloc_addr[1]; + if (runtime && def.dso->tls_id >= static_tls_cnt) { + struct td_index *new = malloc(sizeof *new); + if (!new) { + error( + "Error relocating %s: cannot allocate TLSDESC for %s", + dso->name, sym ? name : "(local)" ); + longjmp(*rtld_fail, 1); + } + new->next = dso->td_index; + dso->td_index = new; + new->args[0] = def.dso->tls_id; + new->args[1] = tls_val + addend; + reloc_addr[0] = (size_t)__tlsdesc_dynamic; + reloc_addr[1] = (size_t)new; + } else { + reloc_addr[0] = (size_t)__tlsdesc_static; +#ifdef TLS_ABOVE_TP + reloc_addr[1] = tls_val + def.dso->tls.offset + + TPOFF_K + addend; +#else + reloc_addr[1] = tls_val - def.dso->tls.offset + + addend; +#endif + } + break; + default: + error("Error relocating %s: unsupported relocation type %d", + dso->name, type); + if (runtime) longjmp(*rtld_fail, 1); + continue; + } + } +} + +/* A huge hack: to make up for the wastefulness of shared libraries + * needing at least a page of dirty memory even if they have no global + * data, we reclaim the gaps at the beginning and end of writable maps + * and "donate" them to the heap by setting up minimal malloc + * structures and then freeing them. */ + +static void reclaim(struct dso *dso, size_t start, size_t end) +{ + size_t *a, *z; + if (start >= dso->relro_start && start < dso->relro_end) start = dso->relro_end; + if (end >= dso->relro_start && end < dso->relro_end) end = dso->relro_start; + start = start + 6*sizeof(size_t)-1 & -4*sizeof(size_t); + end = (end & -4*sizeof(size_t)) - 2*sizeof(size_t); + if (start>end || end-start < 4*sizeof(size_t)) return; + a = laddr(dso, start); + z = laddr(dso, end); + a[-2] = 1; + a[-1] = z[0] = end-start + 2*sizeof(size_t) | 1; + z[1] = 1; + free(a); +} + +static void reclaim_gaps(struct dso *dso) +{ + Phdr *ph = dso->phdr; + size_t phcnt = dso->phnum; + + if (DL_FDPIC) return; // FIXME + for (; phcnt--; ph=(void *)((char *)ph+dso->phentsize)) { + if (ph->p_type!=PT_LOAD) continue; + if ((ph->p_flags&(PF_R|PF_W))!=(PF_R|PF_W)) continue; + reclaim(dso, ph->p_vaddr & -PAGE_SIZE, ph->p_vaddr); + reclaim(dso, ph->p_vaddr+ph->p_memsz, + ph->p_vaddr+ph->p_memsz+PAGE_SIZE-1 & -PAGE_SIZE); + } +} + +static void *mmap_fixed(void *p, size_t n, int prot, int flags, int fd, off_t off) +{ + static int no_map_fixed; + char *q; + if (!no_map_fixed) { + q = mmap(p, n, prot, flags|MAP_FIXED, fd, off); + if (!DL_NOMMU_SUPPORT || q != MAP_FAILED || errno != EINVAL) + return q; + no_map_fixed = 1; + } + /* Fallbacks for MAP_FIXED failure on NOMMU kernels. */ + if (flags & MAP_ANONYMOUS) { + memset(p, 0, n); + return p; + } + ssize_t r; + if (lseek(fd, off, SEEK_SET) < 0) return MAP_FAILED; + for (q=p; n; q+=r, off+=r, n-=r) { + r = read(fd, q, n); + if (r < 0 && errno != EINTR) return MAP_FAILED; + if (!r) { + memset(q, 0, n); + break; + } + } + return p; +} + +static void unmap_library(struct dso *dso) +{ + if (dso->loadmap) { + size_t i; + for (i=0; iloadmap->nsegs; i++) { + if (!dso->loadmap->segs[i].p_memsz) + continue; + munmap((void *)dso->loadmap->segs[i].addr, + dso->loadmap->segs[i].p_memsz); + } + free(dso->loadmap); + } else if (dso->map && dso->map_len) { + munmap(dso->map, dso->map_len); + } +} + +static void *map_library(int fd, struct dso *dso) +{ + Ehdr buf[(896+sizeof(Ehdr))/sizeof(Ehdr)]; + void *allocated_buf=0; + size_t phsize; + size_t addr_min=SIZE_MAX, addr_max=0, map_len; + size_t this_min, this_max; + size_t nsegs = 0; + off_t off_start; + Ehdr *eh; + Phdr *ph, *ph0; + unsigned prot; + unsigned char *map=MAP_FAILED, *base; + size_t dyn=0; + size_t tls_image=0; + size_t i; + + ssize_t l = read(fd, buf, sizeof buf); + eh = buf; + if (l<0) return 0; + if (le_type != ET_DYN && eh->e_type != ET_EXEC)) + goto noexec; + phsize = eh->e_phentsize * eh->e_phnum; + if (phsize > sizeof buf - sizeof *eh) { + allocated_buf = malloc(phsize); + if (!allocated_buf) return 0; + l = pread(fd, allocated_buf, phsize, eh->e_phoff); + if (l < 0) goto error; + if (l != phsize) goto noexec; + ph = ph0 = allocated_buf; + } else if (eh->e_phoff + phsize > l) { + l = pread(fd, buf+1, phsize, eh->e_phoff); + if (l < 0) goto error; + if (l != phsize) goto noexec; + ph = ph0 = (void *)(buf + 1); + } else { + ph = ph0 = (void *)((char *)buf + eh->e_phoff); + } + for (i=eh->e_phnum; i; i--, ph=(void *)((char *)ph+eh->e_phentsize)) { + if (ph->p_type == PT_DYNAMIC) { + dyn = ph->p_vaddr; + } else if (ph->p_type == PT_TLS) { + tls_image = ph->p_vaddr; + dso->tls.align = ph->p_align; + dso->tls.len = ph->p_filesz; + dso->tls.size = ph->p_memsz; + } else if (ph->p_type == PT_GNU_RELRO) { + dso->relro_start = ph->p_vaddr & -PAGE_SIZE; + dso->relro_end = (ph->p_vaddr + ph->p_memsz) & -PAGE_SIZE; + } + if (ph->p_type != PT_LOAD) continue; + nsegs++; + if (ph->p_vaddr < addr_min) { + addr_min = ph->p_vaddr; + off_start = ph->p_offset; + prot = (((ph->p_flags&PF_R) ? PROT_READ : 0) | + ((ph->p_flags&PF_W) ? PROT_WRITE: 0) | + ((ph->p_flags&PF_X) ? PROT_EXEC : 0)); + } + if (ph->p_vaddr+ph->p_memsz > addr_max) { + addr_max = ph->p_vaddr+ph->p_memsz; + } + } + if (!dyn) goto noexec; + if (DL_FDPIC && !(eh->e_flags & FDPIC_CONSTDISP_FLAG)) { + dso->loadmap = calloc(1, sizeof *dso->loadmap + + nsegs * sizeof *dso->loadmap->segs); + if (!dso->loadmap) goto error; + dso->loadmap->nsegs = nsegs; + for (ph=ph0, i=0; ie_phentsize)) { + if (ph->p_type != PT_LOAD) continue; + prot = (((ph->p_flags&PF_R) ? PROT_READ : 0) | + ((ph->p_flags&PF_W) ? PROT_WRITE: 0) | + ((ph->p_flags&PF_X) ? PROT_EXEC : 0)); + map = mmap(0, ph->p_memsz + (ph->p_vaddr & PAGE_SIZE-1), + prot, MAP_PRIVATE, + fd, ph->p_offset & -PAGE_SIZE); + if (map == MAP_FAILED) { + unmap_library(dso); + goto error; + } + dso->loadmap->segs[i].addr = (size_t)map + + (ph->p_vaddr & PAGE_SIZE-1); + dso->loadmap->segs[i].p_vaddr = ph->p_vaddr; + dso->loadmap->segs[i].p_memsz = ph->p_memsz; + i++; + if (prot & PROT_WRITE) { + size_t brk = (ph->p_vaddr & PAGE_SIZE-1) + + ph->p_filesz; + size_t pgbrk = brk + PAGE_SIZE-1 & -PAGE_SIZE; + size_t pgend = brk + ph->p_memsz - ph->p_filesz + + PAGE_SIZE-1 & -PAGE_SIZE; + if (pgend > pgbrk && mmap_fixed(map+pgbrk, + pgend-pgbrk, prot, + MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, + -1, off_start) == MAP_FAILED) + goto error; + memset(map + brk, 0, pgbrk-brk); + } + } + map = (void *)dso->loadmap->segs[0].addr; + map_len = 0; + goto done_mapping; + } + addr_max += PAGE_SIZE-1; + addr_max &= -PAGE_SIZE; + addr_min &= -PAGE_SIZE; + off_start &= -PAGE_SIZE; + map_len = addr_max - addr_min + off_start; + /* The first time, we map too much, possibly even more than + * the length of the file. This is okay because we will not + * use the invalid part; we just need to reserve the right + * amount of virtual address space to map over later. */ + map = DL_NOMMU_SUPPORT + ? mmap((void *)addr_min, map_len, PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) + : mmap((void *)addr_min, map_len, prot, + MAP_PRIVATE, fd, off_start); + if (map==MAP_FAILED) goto error; + dso->map = map; + dso->map_len = map_len; + /* If the loaded file is not relocatable and the requested address is + * not available, then the load operation must fail. */ + if (eh->e_type != ET_DYN && addr_min && map!=(void *)addr_min) { + errno = EBUSY; + goto error; + } + base = map - addr_min; + dso->phdr = 0; + dso->phnum = 0; + for (ph=ph0, i=eh->e_phnum; i; i--, ph=(void *)((char *)ph+eh->e_phentsize)) { + if (ph->p_type != PT_LOAD) continue; + /* Check if the programs headers are in this load segment, and + * if so, record the address for use by dl_iterate_phdr. */ + if (!dso->phdr && eh->e_phoff >= ph->p_offset + && eh->e_phoff+phsize <= ph->p_offset+ph->p_filesz) { + dso->phdr = (void *)(base + ph->p_vaddr + + (eh->e_phoff-ph->p_offset)); + dso->phnum = eh->e_phnum; + dso->phentsize = eh->e_phentsize; + } + /* Reuse the existing mapping for the lowest-address LOAD */ + if ((ph->p_vaddr & -PAGE_SIZE) == addr_min && !DL_NOMMU_SUPPORT) + continue; + this_min = ph->p_vaddr & -PAGE_SIZE; + this_max = ph->p_vaddr+ph->p_memsz+PAGE_SIZE-1 & -PAGE_SIZE; + off_start = ph->p_offset & -PAGE_SIZE; + prot = (((ph->p_flags&PF_R) ? PROT_READ : 0) | + ((ph->p_flags&PF_W) ? PROT_WRITE: 0) | + ((ph->p_flags&PF_X) ? PROT_EXEC : 0)); + if (mmap_fixed(base+this_min, this_max-this_min, prot, MAP_PRIVATE|MAP_FIXED, fd, off_start) == MAP_FAILED) + goto error; + if (ph->p_memsz > ph->p_filesz) { + size_t brk = (size_t)base+ph->p_vaddr+ph->p_filesz; + size_t pgbrk = brk+PAGE_SIZE-1 & -PAGE_SIZE; + memset((void *)brk, 0, pgbrk-brk & PAGE_SIZE-1); + if (pgbrk-(size_t)base < this_max && mmap_fixed((void *)pgbrk, (size_t)base+this_max-pgbrk, prot, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) == MAP_FAILED) + goto error; + } + } + for (i=0; ((size_t *)(base+dyn))[i]; i+=2) + if (((size_t *)(base+dyn))[i]==DT_TEXTREL) { + if (mprotect(map, map_len, PROT_READ|PROT_WRITE|PROT_EXEC) + && errno != ENOSYS) + goto error; + break; + } +done_mapping: + dso->base = base; + dso->dynv = laddr(dso, dyn); + if (dso->tls.size) dso->tls.image = laddr(dso, tls_image); + if (!runtime) reclaim_gaps(dso); + free(allocated_buf); + return map; +noexec: + errno = ENOEXEC; +error: + if (map!=MAP_FAILED) unmap_library(dso); + free(allocated_buf); + return 0; +} + +static int path_open(const char *name, const char *s, char *buf, size_t buf_size) +{ + size_t l; + int fd; + for (;;) { + s += strspn(s, ":\n"); + l = strcspn(s, ":\n"); + if (l-1 >= INT_MAX) return -1; + if (snprintf(buf, buf_size, "%.*s/%s", (int)l, s, name) < buf_size) { + if ((fd = open(buf, O_RDONLY|O_CLOEXEC))>=0) return fd; + switch (errno) { + case ENOENT: + case ENOTDIR: + case EACCES: + case ENAMETOOLONG: + break; + default: + /* Any negative value but -1 will inhibit + * futher path search. */ + return -2; + } + } + s += l; + } +} + +static int fixup_rpath(struct dso *p, char *buf, size_t buf_size) +{ + size_t n, l; + const char *s, *t, *origin; + char *d; + if (p->rpath || !p->rpath_orig) return 0; + if (!strchr(p->rpath_orig, '$')) { + p->rpath = p->rpath_orig; + return 0; + } + n = 0; + s = p->rpath_orig; + while ((t=strchr(s, '$'))) { + if (strncmp(t, "$ORIGIN", 7) && strncmp(t, "${ORIGIN}", 9)) + return 0; + s = t+1; + n++; + } + if (n > SSIZE_MAX/PATH_MAX) return 0; + + if (p->kernel_mapped) { + /* $ORIGIN searches cannot be performed for the main program + * when it is suid/sgid/AT_SECURE. This is because the + * pathname is under the control of the caller of execve. + * For libraries, however, $ORIGIN can be processed safely + * since the library's pathname came from a trusted source + * (either system paths or a call to dlopen). */ + if (libc.secure) + return 0; + l = readlink("/proc/self/exe", buf, buf_size); + if (l == -1) switch (errno) { + case ENOENT: + case ENOTDIR: + case EACCES: + break; + default: + return -1; + } + if (l >= buf_size) + return 0; + buf[l] = 0; + origin = buf; + } else { + origin = p->name; + } + t = strrchr(origin, '/'); + l = t ? t-origin : 0; + p->rpath = malloc(strlen(p->rpath_orig) + n*l + 1); + if (!p->rpath) return -1; + + d = p->rpath; + s = p->rpath_orig; + while ((t=strchr(s, '$'))) { + memcpy(d, s, t-s); + d += t-s; + memcpy(d, origin, l); + d += l; + /* It was determined previously that the '$' is followed + * either by "ORIGIN" or "{ORIGIN}". */ + s = t + 7 + 2*(t[1]=='{'); + } + strcpy(d, s); + return 0; +} + +static void decode_dyn(struct dso *p) +{ + size_t dyn[DYN_CNT]; + decode_vec(p->dynv, dyn, DYN_CNT); + p->syms = laddr(p, dyn[DT_SYMTAB]); + p->strings = laddr(p, dyn[DT_STRTAB]); + if (dyn[0]&(1<hashtab = laddr(p, dyn[DT_HASH]); + if (dyn[0]&(1<rpath_orig = p->strings + dyn[DT_RPATH]; + if (dyn[0]&(1<rpath_orig = p->strings + dyn[DT_RUNPATH]; + if (dyn[0]&(1<got = laddr(p, dyn[DT_PLTGOT]); + if (search_vec(p->dynv, dyn, DT_GNU_HASH)) + p->ghashtab = laddr(p, *dyn); + if (search_vec(p->dynv, dyn, DT_VERSYM)) + p->versym = laddr(p, *dyn); +} + +static size_t count_syms(struct dso *p) +{ + if (p->hashtab) return p->hashtab[1]; + + size_t nsym, i; + uint32_t *buckets = p->ghashtab + 4 + (p->ghashtab[2]*sizeof(size_t)/4); + uint32_t *hashval; + for (i = nsym = 0; i < p->ghashtab[0]; i++) { + if (buckets[i] > nsym) + nsym = buckets[i]; + } + if (nsym) { + hashval = buckets + p->ghashtab[0] + (nsym - p->ghashtab[1]); + do nsym++; + while (!(*hashval++ & 1)); + } + return nsym; +} + +static void *dl_mmap(size_t n) +{ + void *p; + int prot = PROT_READ|PROT_WRITE, flags = MAP_ANONYMOUS|MAP_PRIVATE; +#ifdef SYS_mmap2 + p = (void *)__syscall(SYS_mmap2, 0, n, prot, flags, -1, 0); +#else + p = (void *)__syscall(SYS_mmap, 0, n, prot, flags, -1, 0); +#endif + return p == MAP_FAILED ? 0 : p; +} + +static void makefuncdescs(struct dso *p) +{ + static int self_done; + size_t nsym = count_syms(p); + size_t i, size = nsym * sizeof(*p->funcdescs); + + if (!self_done) { + p->funcdescs = dl_mmap(size); + self_done = 1; + } else { + p->funcdescs = malloc(size); + } + if (!p->funcdescs) { + if (!runtime) a_crash(); + error("Error allocating function descriptors for %s", p->name); + longjmp(*rtld_fail, 1); + } + for (i=0; isyms[i].st_info&0xf)==STT_FUNC && p->syms[i].st_shndx) { + p->funcdescs[i].addr = laddr(p, p->syms[i].st_value); + p->funcdescs[i].got = p->got; + } else { + p->funcdescs[i].addr = 0; + p->funcdescs[i].got = 0; + } + } +} + +static struct dso *load_library(const char *name, struct dso *needed_by) +{ + char buf[2*NAME_MAX+2]; + const char *pathname; + unsigned char *map; + struct dso *p, temp_dso = {0}; + int fd; + struct stat st; + size_t alloc_size; + int n_th = 0; + int is_self = 0; + + if (!*name) { + errno = EINVAL; + return 0; + } + + /* Catch and block attempts to reload the implementation itself */ + if (name[0]=='l' && name[1]=='i' && name[2]=='b') { + static const char *rp, reserved[] = + "c\0pthread\0rt\0m\0dl\0util\0xnet\0"; + char *z = strchr(name, '.'); + if (z) { + size_t l = z-name; + for (rp=reserved; *rp && strncmp(name+3, rp, l-3); rp+=strlen(rp)+1); + if (*rp) { + if (ldd_mode) { + /* Track which names have been resolved + * and only report each one once. */ + static unsigned reported; + unsigned mask = 1U<<(rp-reserved); + if (!(reported & mask)) { + reported |= mask; + dprintf(1, "\t%s => %s (%p)\n", + name, ldso.name, + ldso.base); + } + } + is_self = 1; + } + } + } + if (!strcmp(name, ldso.name)) is_self = 1; + if (is_self) { + if (!ldso.prev) { + tail->next = &ldso; + ldso.prev = tail; + tail = ldso.next ? ldso.next : &ldso; + } + return &ldso; + } + if (strchr(name, '/')) { + pathname = name; + fd = open(name, O_RDONLY|O_CLOEXEC); + } else { + /* Search for the name to see if it's already loaded */ + for (p=head->next; p; p=p->next) { + if (p->shortname && !strcmp(p->shortname, name)) { + p->refcnt++; + return p; + } + } + if (strlen(name) > NAME_MAX) return 0; + fd = -1; + if (env_path) fd = path_open(name, env_path, buf, sizeof buf); + for (p=needed_by; fd == -1 && p; p=p->needed_by) { + if (fixup_rpath(p, buf, sizeof buf) < 0) + fd = -2; /* Inhibit further search. */ + if (p->rpath) + fd = path_open(name, p->rpath, buf, sizeof buf); + } + if (fd == -1) { + if (!sys_path) { + char *prefix = 0; + size_t prefix_len; + if (ldso.name[0]=='/') { + char *s, *t, *z; + for (s=t=z=ldso.name; *s; s++) + if (*s=='/') z=t, t=s; + prefix_len = z-ldso.name; + if (prefix_len < PATH_MAX) + prefix = ldso.name; + } + if (!prefix) { + prefix = ""; + prefix_len = 0; + } + char etc_ldso_path[prefix_len + 1 + + sizeof "/etc/ld-musl-" LDSO_ARCH ".path"]; + snprintf(etc_ldso_path, sizeof etc_ldso_path, + "%.*s/etc/ld-musl-" LDSO_ARCH ".path", + (int)prefix_len, prefix); + FILE *f = fopen(etc_ldso_path, "rbe"); + if (f) { + if (getdelim(&sys_path, (size_t[1]){0}, 0, f) <= 0) { + free(sys_path); + sys_path = ""; + } + fclose(f); + } else if (errno != ENOENT) { + sys_path = ""; + } + } + if (!sys_path) sys_path = "/lib:/usr/local/lib:/usr/lib"; + fd = path_open(name, sys_path, buf, sizeof buf); + } + pathname = buf; + } + if (fd < 0) return 0; + if (fstat(fd, &st) < 0) { + close(fd); + return 0; + } + for (p=head->next; p; p=p->next) { + if (p->dev == st.st_dev && p->ino == st.st_ino) { + /* If this library was previously loaded with a + * pathname but a search found the same inode, + * setup its shortname so it can be found by name. */ + if (!p->shortname && pathname != name) + p->shortname = strrchr(p->name, '/')+1; + close(fd); + p->refcnt++; + return p; + } + } + map = noload ? 0 : map_library(fd, &temp_dso); + close(fd); + if (!map) return 0; + + /* Allocate storage for the new DSO. When there is TLS, this + * storage must include a reservation for all pre-existing + * threads to obtain copies of both the new TLS, and an + * extended DTV capable of storing an additional slot for + * the newly-loaded DSO. */ + alloc_size = sizeof *p + strlen(pathname) + 1; + if (runtime && temp_dso.tls.image) { + size_t per_th = temp_dso.tls.size + temp_dso.tls.align + + sizeof(void *) * (tls_cnt+3); + n_th = libc.threads_minus_1 + 1; + if (n_th > SSIZE_MAX / per_th) alloc_size = SIZE_MAX; + else alloc_size += n_th * per_th; + } + p = calloc(1, alloc_size); + if (!p) { + unmap_library(&temp_dso); + return 0; + } + memcpy(p, &temp_dso, sizeof temp_dso); + decode_dyn(p); + p->dev = st.st_dev; + p->ino = st.st_ino; + p->refcnt = 1; + p->needed_by = needed_by; + p->name = p->buf; + strcpy(p->name, pathname); + /* Add a shortname only if name arg was not an explicit pathname. */ + if (pathname != name) p->shortname = strrchr(p->name, '/')+1; + if (p->tls.image) { + p->tls_id = ++tls_cnt; + tls_align = MAXP2(tls_align, p->tls.align); +#ifdef TLS_ABOVE_TP + p->tls.offset = tls_offset + ( (tls_align-1) & + -(tls_offset + (uintptr_t)p->tls.image) ); + tls_offset += p->tls.size; +#else + tls_offset += p->tls.size + p->tls.align - 1; + tls_offset -= (tls_offset + (uintptr_t)p->tls.image) + & (p->tls.align-1); + p->tls.offset = tls_offset; +#endif + p->new_dtv = (void *)(-sizeof(size_t) & + (uintptr_t)(p->name+strlen(p->name)+sizeof(size_t))); + p->new_tls = (void *)(p->new_dtv + n_th*(tls_cnt+1)); + if (tls_tail) tls_tail->next = &p->tls; + else libc.tls_head = &p->tls; + tls_tail = &p->tls; + } + + tail->next = p; + p->prev = tail; + tail = p; + + if (DL_FDPIC) makefuncdescs(p); + + if (ldd_mode) dprintf(1, "\t%s => %s (%p)\n", name, pathname, p->base); + + return p; +} + +static void load_deps(struct dso *p) +{ + size_t i, ndeps=0; + struct dso ***deps = &p->deps, **tmp, *dep; + for (; p; p=p->next) { + for (i=0; p->dynv[i]; i+=2) { + if (p->dynv[i] != DT_NEEDED) continue; + dep = load_library(p->strings + p->dynv[i+1], p); + if (!dep) { + error("Error loading shared library %s: %m (needed by %s)", + p->strings + p->dynv[i+1], p->name); + if (runtime) longjmp(*rtld_fail, 1); + continue; + } + if (runtime) { + tmp = realloc(*deps, sizeof(*tmp)*(ndeps+2)); + if (!tmp) longjmp(*rtld_fail, 1); + tmp[ndeps++] = dep; + tmp[ndeps] = 0; + *deps = tmp; + } + } + } +} + +static void load_preload(char *s) +{ + int tmp; + char *z; + for (z=s; *z; s=z) { + for ( ; *s && (isspace(*s) || *s==':'); s++); + for (z=s; *z && !isspace(*z) && *z!=':'; z++); + tmp = *z; + *z = 0; + load_library(s, 0); + *z = tmp; + } +} + +static void make_global(struct dso *p) +{ + for (; p; p=p->next) p->global = 1; +} + +static void do_mips_relocs(struct dso *p, size_t *got) +{ + size_t i, j, rel[2]; + unsigned char *base = p->base; + i=0; search_vec(p->dynv, &i, DT_MIPS_LOCAL_GOTNO); + if (p==&ldso) { + got += i; + } else { + while (i--) *got++ += (size_t)base; + } + j=0; search_vec(p->dynv, &j, DT_MIPS_GOTSYM); + i=0; search_vec(p->dynv, &i, DT_MIPS_SYMTABNO); + Sym *sym = p->syms + j; + rel[0] = (unsigned char *)got - base; + for (i-=j; i; i--, sym++, rel[0]+=sizeof(size_t)) { + rel[1] = R_INFO(sym-p->syms, R_MIPS_JUMP_SLOT); + do_relocs(p, rel, sizeof rel, 2); + } +} + +static void reloc_all(struct dso *p) +{ + size_t dyn[DYN_CNT]; + for (; p; p=p->next) { + if (p->relocated) continue; + decode_vec(p->dynv, dyn, DYN_CNT); + if (NEED_MIPS_GOT_RELOCS) + do_mips_relocs(p, laddr(p, dyn[DT_PLTGOT])); + do_relocs(p, laddr(p, dyn[DT_JMPREL]), dyn[DT_PLTRELSZ], + 2+(dyn[DT_PLTREL]==DT_RELA)); + do_relocs(p, laddr(p, dyn[DT_REL]), dyn[DT_RELSZ], 2); + do_relocs(p, laddr(p, dyn[DT_RELA]), dyn[DT_RELASZ], 3); + + if (head != &ldso && p->relro_start != p->relro_end && + mprotect(laddr(p, p->relro_start), p->relro_end-p->relro_start, PROT_READ) + && errno != ENOSYS) { + error("Error relocating %s: RELRO protection failed: %m", + p->name); + if (runtime) longjmp(*rtld_fail, 1); + } + + p->relocated = 1; + } +} + +static void kernel_mapped_dso(struct dso *p) +{ + size_t min_addr = -1, max_addr = 0, cnt; + Phdr *ph = p->phdr; + for (cnt = p->phnum; cnt--; ph = (void *)((char *)ph + p->phentsize)) { + if (ph->p_type == PT_DYNAMIC) { + p->dynv = laddr(p, ph->p_vaddr); + } else if (ph->p_type == PT_GNU_RELRO) { + p->relro_start = ph->p_vaddr & -PAGE_SIZE; + p->relro_end = (ph->p_vaddr + ph->p_memsz) & -PAGE_SIZE; + } + if (ph->p_type != PT_LOAD) continue; + if (ph->p_vaddr < min_addr) + min_addr = ph->p_vaddr; + if (ph->p_vaddr+ph->p_memsz > max_addr) + max_addr = ph->p_vaddr+ph->p_memsz; + } + min_addr &= -PAGE_SIZE; + max_addr = (max_addr + PAGE_SIZE-1) & -PAGE_SIZE; + p->map = p->base + min_addr; + p->map_len = max_addr - min_addr; + p->kernel_mapped = 1; +} + +void __libc_exit_fini() +{ + struct dso *p; + size_t dyn[DYN_CNT]; + for (p=fini_head; p; p=p->fini_next) { + if (!p->constructed) continue; + decode_vec(p->dynv, dyn, DYN_CNT); + if (dyn[0] & (1<prev) { + if (p->constructed) continue; + p->constructed = 1; + decode_vec(p->dynv, dyn, DYN_CNT); + if (dyn[0] & ((1<fini_next = fini_head; + fini_head = p; + } +#ifndef NO_LEGACY_INITFINI + if ((dyn[0] & (1<dtv[0]) { + __restore_sigs(&set); + return (char *)self->dtv[v[0]]+v[1]+DTP_OFFSET; + } + + /* This is safe without any locks held because, if the caller + * is able to request the Nth entry of the DTV, the DSO list + * must be valid at least that far out and it was synchronized + * at program startup or by an already-completed call to dlopen. */ + struct dso *p; + for (p=head; p->tls_id != v[0]; p=p->next); + + /* Get new DTV space from new DSO if needed */ + if (v[0] > (size_t)self->dtv[0]) { + void **newdtv = p->new_dtv + + (v[0]+1)*a_fetch_add(&p->new_dtv_idx,1); + memcpy(newdtv, self->dtv, + ((size_t)self->dtv[0]+1) * sizeof(void *)); + newdtv[0] = (void *)v[0]; + self->dtv = self->dtv_copy = newdtv; + } + + /* Get new TLS memory from all new DSOs up to the requested one */ + unsigned char *mem; + for (p=head; ; p=p->next) { + if (!p->tls_id || self->dtv[p->tls_id]) continue; + mem = p->new_tls + (p->tls.size + p->tls.align) + * a_fetch_add(&p->new_tls_idx,1); + mem += ((uintptr_t)p->tls.image - (uintptr_t)mem) + & (p->tls.align-1); + self->dtv[p->tls_id] = mem; + memcpy(mem, p->tls.image, p->tls.len); + if (p->tls_id == v[0]) break; + } + __restore_sigs(&set); + return mem + v[1] + DTP_OFFSET; +} + +static void update_tls_size() +{ + libc.tls_cnt = tls_cnt; + libc.tls_align = tls_align; + libc.tls_size = ALIGN( + (1+tls_cnt) * sizeof(void *) + + tls_offset + + sizeof(struct pthread) + + tls_align * 2, + tls_align); +} + +/* Stage 1 of the dynamic linker is defined in dlstart.c. It calls the + * following stage 2 and stage 3 functions via primitive symbolic lookup + * since it does not have access to their addresses to begin with. */ + +/* Stage 2 of the dynamic linker is called after relative relocations + * have been processed. It can make function calls to static functions + * and access string literals and static data, but cannot use extern + * symbols. Its job is to perform symbolic relocations on the dynamic + * linker itself, but some of the relocations performed may need to be + * replaced later due to copy relocations in the main program. */ + +__attribute__((__visibility__("hidden"))) +void __dls2(unsigned char *base, size_t *sp) +{ + if (DL_FDPIC) { + void *p1 = (void *)sp[-2]; + void *p2 = (void *)sp[-1]; + if (!p1) { + size_t *auxv, aux[AUX_CNT]; + for (auxv=sp+1+*sp+1; *auxv; auxv++); auxv++; + decode_vec(auxv, aux, AUX_CNT); + if (aux[AT_BASE]) ldso.base = (void *)aux[AT_BASE]; + else ldso.base = (void *)(aux[AT_PHDR] & -4096); + } + app_loadmap = p2 ? p1 : 0; + ldso.loadmap = p2 ? p2 : p1; + ldso.base = laddr(&ldso, 0); + } else { + ldso.base = base; + } + Ehdr *ehdr = (void *)ldso.base; + ldso.name = ldso.shortname = "libc.so"; + ldso.global = 1; + ldso.phnum = ehdr->e_phnum; + ldso.phdr = laddr(&ldso, ehdr->e_phoff); + ldso.phentsize = ehdr->e_phentsize; + kernel_mapped_dso(&ldso); + decode_dyn(&ldso); + + if (DL_FDPIC) makefuncdescs(&ldso); + + /* Prepare storage for to save clobbered REL addends so they + * can be reused in stage 3. There should be very few. If + * something goes wrong and there are a huge number, abort + * instead of risking stack overflow. */ + size_t dyn[DYN_CNT]; + decode_vec(ldso.dynv, dyn, DYN_CNT); + size_t *rel = laddr(&ldso, dyn[DT_REL]); + size_t rel_size = dyn[DT_RELSZ]; + size_t symbolic_rel_cnt = 0; + apply_addends_to = rel; + for (; rel_size; rel+=2, rel_size-=2*sizeof(size_t)) + if (!IS_RELATIVE(rel[1], ldso.syms)) symbolic_rel_cnt++; + if (symbolic_rel_cnt >= ADDEND_LIMIT) a_crash(); + size_t addends[symbolic_rel_cnt+1]; + saved_addends = addends; + + head = &ldso; + reloc_all(&ldso); + + ldso.relocated = 0; + + /* Call dynamic linker stage-3, __dls3, looking it up + * symbolically as a barrier against moving the address + * load across the above relocation processing. */ + struct symdef dls3_def = find_sym(&ldso, "__dls3", 0); + if (DL_FDPIC) ((stage3_func)&ldso.funcdescs[dls3_def.sym-ldso.syms])(sp); + else ((stage3_func)laddr(&ldso, dls3_def.sym->st_value))(sp); +} + +/* Stage 3 of the dynamic linker is called with the dynamic linker/libc + * fully functional. Its job is to load (if not already loaded) and + * process dependencies and relocations for the main application and + * transfer control to its entry point. */ + +_Noreturn void __dls3(size_t *sp) +{ + static struct dso app, vdso; + size_t aux[AUX_CNT], *auxv; + size_t i; + char *env_preload=0; + size_t vdso_base; + int argc = *sp; + char **argv = (void *)(sp+1); + char **argv_orig = argv; + char **envp = argv+argc+1; + + /* Find aux vector just past environ[] and use it to initialize + * global data that may be needed before we can make syscalls. */ + __environ = envp; + for (i=argc+1; argv[i]; i++); + libc.auxv = auxv = (void *)(argv+i+1); + decode_vec(auxv, aux, AUX_CNT); + __hwcap = aux[AT_HWCAP]; + libc.page_size = aux[AT_PAGESZ]; + libc.secure = ((aux[0]&0x7800)!=0x7800 || aux[AT_UID]!=aux[AT_EUID] + || aux[AT_GID]!=aux[AT_EGID] || aux[AT_SECURE]); + + /* Setup early thread pointer in builtin_tls for ldso/libc itself to + * use during dynamic linking. If possible it will also serve as the + * thread pointer at runtime. */ + libc.tls_size = sizeof builtin_tls; + libc.tls_align = tls_align; + if (__init_tp(__copy_tls((void *)builtin_tls)) < 0) { + a_crash(); + } + + /* Only trust user/env if kernel says we're not suid/sgid */ + if (!libc.secure) { + env_path = getenv("LD_LIBRARY_PATH"); + env_preload = getenv("LD_PRELOAD"); + } + + /* If the main program was already loaded by the kernel, + * AT_PHDR will point to some location other than the dynamic + * linker's program headers. */ + if (aux[AT_PHDR] != (size_t)ldso.phdr) { + size_t interp_off = 0; + size_t tls_image = 0; + /* Find load address of the main program, via AT_PHDR vs PT_PHDR. */ + Phdr *phdr = app.phdr = (void *)aux[AT_PHDR]; + app.phnum = aux[AT_PHNUM]; + app.phentsize = aux[AT_PHENT]; + for (i=aux[AT_PHNUM]; i; i--, phdr=(void *)((char *)phdr + aux[AT_PHENT])) { + if (phdr->p_type == PT_PHDR) + app.base = (void *)(aux[AT_PHDR] - phdr->p_vaddr); + else if (phdr->p_type == PT_INTERP) + interp_off = (size_t)phdr->p_vaddr; + else if (phdr->p_type == PT_TLS) { + tls_image = phdr->p_vaddr; + app.tls.len = phdr->p_filesz; + app.tls.size = phdr->p_memsz; + app.tls.align = phdr->p_align; + } + } + if (DL_FDPIC) app.loadmap = app_loadmap; + if (app.tls.size) app.tls.image = laddr(&app, tls_image); + if (interp_off) ldso.name = laddr(&app, interp_off); + if ((aux[0] & (1UL<= 3 && !strcmp(ldname+l-3, "ldd")) ldd_mode = 1; + argv++; + while (argv[0] && argv[0][0]=='-' && argv[0][1]=='-') { + char *opt = argv[0]+2; + *argv++ = (void *)-1; + if (!*opt) { + break; + } else if (!memcmp(opt, "list", 5)) { + ldd_mode = 1; + } else if (!memcmp(opt, "library-path", 12)) { + if (opt[12]=='=') env_path = opt+13; + else if (opt[12]) *argv = 0; + else if (*argv) env_path = *argv++; + } else if (!memcmp(opt, "preload", 7)) { + if (opt[7]=='=') env_preload = opt+8; + else if (opt[7]) *argv = 0; + else if (*argv) env_preload = *argv++; + } else { + argv[0] = 0; + } + } + argv[-1] = (void *)(argc - (argv-argv_orig)); + if (!argv[0]) { + dprintf(2, "musl libc (" LDSO_ARCH ")\n" + "Version %s\n" + "Dynamic Program Loader\n" + "Usage: %s [options] [--] pathname%s\n", + __libc_get_version(), ldname, + ldd_mode ? "" : " [args]"); + _exit(1); + } + fd = open(argv[0], O_RDONLY); + if (fd < 0) { + dprintf(2, "%s: cannot load %s: %s\n", ldname, argv[0], strerror(errno)); + _exit(1); + } + runtime = 1; + Ehdr *ehdr = (void *)map_library(fd, &app); + if (!ehdr) { + dprintf(2, "%s: %s: Not a valid dynamic program\n", ldname, argv[0]); + _exit(1); + } + runtime = 0; + close(fd); + ldso.name = ldname; + app.name = argv[0]; + aux[AT_ENTRY] = (size_t)laddr(&app, ehdr->e_entry); + /* Find the name that would have been used for the dynamic + * linker had ldd not taken its place. */ + if (ldd_mode) { + for (i=0; insegs = 1; + app.loadmap->segs[0].addr = (size_t)app.map; + app.loadmap->segs[0].p_vaddr = (size_t)app.map + - (size_t)app.base; + app.loadmap->segs[0].p_memsz = app.map_len; + } + argv[-3] = (void *)app.loadmap; + } + + /* Attach to vdso, if provided by the kernel */ + if (search_vec(auxv, &vdso_base, AT_SYSINFO_EHDR)) { + Ehdr *ehdr = (void *)vdso_base; + Phdr *phdr = vdso.phdr = (void *)(vdso_base + ehdr->e_phoff); + vdso.phnum = ehdr->e_phnum; + vdso.phentsize = ehdr->e_phentsize; + for (i=ehdr->e_phnum; i; i--, phdr=(void *)((char *)phdr + ehdr->e_phentsize)) { + if (phdr->p_type == PT_DYNAMIC) + vdso.dynv = (void *)(vdso_base + phdr->p_offset); + if (phdr->p_type == PT_LOAD) + vdso.base = (void *)(vdso_base - phdr->p_vaddr + phdr->p_offset); + } + vdso.name = ""; + vdso.shortname = "linux-gate.so.1"; + vdso.global = 1; + vdso.relocated = 1; + decode_dyn(&vdso); + vdso.prev = &ldso; + ldso.next = &vdso; + } + + /* Initial dso chain consists only of the app. */ + head = tail = &app; + + /* Donate unused parts of app and library mapping to malloc */ + reclaim_gaps(&app); + reclaim_gaps(&ldso); + + /* Load preload/needed libraries, add their symbols to the global + * namespace, and perform all remaining relocations. */ + if (env_preload) load_preload(env_preload); + load_deps(&app); + make_global(&app); + + for (i=0; app.dynv[i]; i+=2) { + if (!DT_DEBUG_INDIRECT && app.dynv[i]==DT_DEBUG) + app.dynv[i+1] = (size_t)&debug; + if (DT_DEBUG_INDIRECT && app.dynv[i]==DT_DEBUG_INDIRECT) { + size_t *ptr = (size_t *) app.dynv[i+1]; + *ptr = (size_t)&debug; + } + } + + /* The main program must be relocated LAST since it may contin + * copy relocations which depend on libraries' relocations. */ + reloc_all(app.next); + reloc_all(&app); + + update_tls_size(); + if (libc.tls_size > sizeof builtin_tls || tls_align > MIN_TLS_ALIGN) { + void *initial_tls = calloc(libc.tls_size, 1); + if (!initial_tls) { + dprintf(2, "%s: Error getting %zu bytes thread-local storage: %m\n", + argv[0], libc.tls_size); + _exit(127); + } + if (__init_tp(__copy_tls(initial_tls)) < 0) { + a_crash(); + } + } else { + size_t tmp_tls_size = libc.tls_size; + pthread_t self = __pthread_self(); + /* Temporarily set the tls size to the full size of + * builtin_tls so that __copy_tls will use the same layout + * as it did for before. Then check, just to be safe. */ + libc.tls_size = sizeof builtin_tls; + if (__copy_tls((void*)builtin_tls) != self) a_crash(); + libc.tls_size = tmp_tls_size; + } + static_tls_cnt = tls_cnt; + + if (ldso_fail) _exit(127); + if (ldd_mode) _exit(0); + + /* Switch to runtime mode: any further failures in the dynamic + * linker are a reportable failure rather than a fatal startup + * error. */ + runtime = 1; + + debug.ver = 1; + debug.bp = dl_debug_state; + debug.head = head; + debug.base = ldso.base; + debug.state = 0; + _dl_debug_state(); + + errno = 0; + + CRTJMP((void *)aux[AT_ENTRY], argv-1); + for(;;); +} + +void *dlopen(const char *file, int mode) +{ + struct dso *volatile p, *orig_tail, *next; + struct tls_module *orig_tls_tail; + size_t orig_tls_cnt, orig_tls_offset, orig_tls_align; + size_t i; + int cs; + jmp_buf jb; + + if (!file) return head; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + pthread_rwlock_wrlock(&lock); + __inhibit_ptc(); + + p = 0; + orig_tls_tail = tls_tail; + orig_tls_cnt = tls_cnt; + orig_tls_offset = tls_offset; + orig_tls_align = tls_align; + orig_tail = tail; + noload = mode & RTLD_NOLOAD; + + rtld_fail = &jb; + if (setjmp(*rtld_fail)) { + /* Clean up anything new that was (partially) loaded */ + if (p && p->deps) for (i=0; p->deps[i]; i++) + if (p->deps[i]->global < 0) + p->deps[i]->global = 0; + for (p=orig_tail->next; p; p=next) { + next = p->next; + while (p->td_index) { + void *tmp = p->td_index->next; + free(p->td_index); + p->td_index = tmp; + } + free(p->funcdescs); + if (p->rpath != p->rpath_orig) + free(p->rpath); + free(p->deps); + unmap_library(p); + free(p); + } + if (!orig_tls_tail) libc.tls_head = 0; + tls_tail = orig_tls_tail; + tls_cnt = orig_tls_cnt; + tls_offset = orig_tls_offset; + tls_align = orig_tls_align; + tail = orig_tail; + tail->next = 0; + p = 0; + goto end; + } else p = load_library(file, head); + + if (!p) { + error(noload ? + "Library %s is not already loaded" : + "Error loading shared library %s: %m", + file); + goto end; + } + + /* First load handling */ + if (!p->deps) { + load_deps(p); + if (p->deps) for (i=0; p->deps[i]; i++) + if (!p->deps[i]->global) + p->deps[i]->global = -1; + if (!p->global) p->global = -1; + reloc_all(p); + if (p->deps) for (i=0; p->deps[i]; i++) + if (p->deps[i]->global < 0) + p->deps[i]->global = 0; + if (p->global < 0) p->global = 0; + } + + if (mode & RTLD_GLOBAL) { + if (p->deps) for (i=0; p->deps[i]; i++) + p->deps[i]->global = 1; + p->global = 1; + } + + update_tls_size(); + _dl_debug_state(); + orig_tail = tail; +end: + __release_ptc(); + if (p) gencnt++; + pthread_rwlock_unlock(&lock); + if (p) do_init_fini(orig_tail); + pthread_setcancelstate(cs, 0); + return p; +} + +__attribute__((__visibility__("hidden"))) +int __dl_invalid_handle(void *h) +{ + struct dso *p; + for (p=head; p; p=p->next) if (h==p) return 0; + error("Invalid library handle %p", (void *)h); + return 1; +} + +static void *addr2dso(size_t a) +{ + struct dso *p; + size_t i; + if (DL_FDPIC) for (p=head; p; p=p->next) { + i = count_syms(p); + if (a-(size_t)p->funcdescs < i*sizeof(*p->funcdescs)) + return p; + } + for (p=head; p; p=p->next) { + if (DL_FDPIC && p->loadmap) { + for (i=0; iloadmap->nsegs; i++) { + if (a-p->loadmap->segs[i].p_vaddr + < p->loadmap->segs[i].p_memsz) + return p; + } + } else { + if (a-(size_t)p->map < p->map_len) + return p; + } + } + return 0; +} + +void *__tls_get_addr(size_t *); + +static void *do_dlsym(struct dso *p, const char *s, void *ra) +{ + size_t i; + uint32_t h = 0, gh = 0, *ght; + Sym *sym; + if (p == head || p == RTLD_DEFAULT || p == RTLD_NEXT) { + if (p == RTLD_DEFAULT) { + p = head; + } else if (p == RTLD_NEXT) { + p = addr2dso((size_t)ra); + if (!p) p=head; + p = p->next; + } + struct symdef def = find_sym(p, s, 0); + if (!def.sym) goto failed; + if ((def.sym->st_info&0xf) == STT_TLS) + return __tls_get_addr((size_t []){def.dso->tls_id, def.sym->st_value}); + if (DL_FDPIC && (def.sym->st_info&0xf) == STT_FUNC) + return def.dso->funcdescs + (def.sym - def.dso->syms); + return laddr(def.dso, def.sym->st_value); + } + if (__dl_invalid_handle(p)) + return 0; + if ((ght = p->ghashtab)) { + gh = gnu_hash(s); + sym = gnu_lookup(gh, ght, p, s); + } else { + h = sysv_hash(s); + sym = sysv_lookup(s, h, p); + } + if (sym && (sym->st_info&0xf) == STT_TLS) + return __tls_get_addr((size_t []){p->tls_id, sym->st_value}); + if (DL_FDPIC && sym && sym->st_shndx && (sym->st_info&0xf) == STT_FUNC) + return p->funcdescs + (sym - p->syms); + if (sym && sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES)) + return laddr(p, sym->st_value); + if (p->deps) for (i=0; p->deps[i]; i++) { + if ((ght = p->deps[i]->ghashtab)) { + if (!gh) gh = gnu_hash(s); + sym = gnu_lookup(gh, ght, p->deps[i], s); + } else { + if (!h) h = sysv_hash(s); + sym = sysv_lookup(s, h, p->deps[i]); + } + if (sym && (sym->st_info&0xf) == STT_TLS) + return __tls_get_addr((size_t []){p->deps[i]->tls_id, sym->st_value}); + if (DL_FDPIC && sym && sym->st_shndx && (sym->st_info&0xf) == STT_FUNC) + return p->deps[i]->funcdescs + (sym - p->deps[i]->syms); + if (sym && sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES)) + return laddr(p->deps[i], sym->st_value); + } +failed: + error("Symbol not found: %s", s); + return 0; +} + +int dladdr(const void *addr, Dl_info *info) +{ + struct dso *p; + Sym *sym, *bestsym; + uint32_t nsym; + char *strings; + void *best = 0; + + pthread_rwlock_rdlock(&lock); + p = addr2dso((size_t)addr); + pthread_rwlock_unlock(&lock); + + if (!p) return 0; + + sym = p->syms; + strings = p->strings; + nsym = count_syms(p); + + if (DL_FDPIC) { + size_t idx = ((size_t)addr-(size_t)p->funcdescs) + / sizeof(*p->funcdescs); + if (idx < nsym && (sym[idx].st_info&0xf) == STT_FUNC) { + best = p->funcdescs + idx; + bestsym = sym + idx; + } + } + + if (!best) for (; nsym; nsym--, sym++) { + if (sym->st_value + && (1<<(sym->st_info&0xf) & OK_TYPES) + && (1<<(sym->st_info>>4) & OK_BINDS)) { + void *symaddr = laddr(p, sym->st_value); + if (symaddr > addr || symaddr < best) + continue; + best = symaddr; + bestsym = sym; + if (addr == symaddr) + break; + } + } + + if (!best) return 0; + + if (DL_FDPIC && (bestsym->st_info&0xf) == STT_FUNC) + best = p->funcdescs + (bestsym - p->syms); + + info->dli_fname = p->name; + info->dli_fbase = p->base; + info->dli_sname = strings + bestsym->st_name; + info->dli_saddr = best; + + return 1; +} + +__attribute__((__visibility__("hidden"))) +void *__dlsym(void *restrict p, const char *restrict s, void *restrict ra) +{ + void *res; + pthread_rwlock_rdlock(&lock); + res = do_dlsym(p, s, ra); + pthread_rwlock_unlock(&lock); + return res; +} + +int dl_iterate_phdr(int(*callback)(struct dl_phdr_info *info, size_t size, void *data), void *data) +{ + struct dso *current; + struct dl_phdr_info info; + int ret = 0; + for(current = head; current;) { + info.dlpi_addr = (uintptr_t)current->base; + info.dlpi_name = current->name; + info.dlpi_phdr = current->phdr; + info.dlpi_phnum = current->phnum; + info.dlpi_adds = gencnt; + info.dlpi_subs = 0; + info.dlpi_tls_modid = current->tls_id; + info.dlpi_tls_data = current->tls.image; + + ret = (callback)(&info, sizeof (info), data); + + if (ret != 0) break; + + pthread_rwlock_rdlock(&lock); + current = current->next; + pthread_rwlock_unlock(&lock); + } + return ret; +} + +__attribute__((__visibility__("hidden"))) +void __dl_vseterr(const char *, va_list); + +static void error(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + if (!runtime) { + vdprintf(2, fmt, ap); + dprintf(2, "\n"); + ldso_fail = 1; + va_end(ap); + return; + } + __dl_vseterr(fmt, ap); + va_end(ap); +} diff --git a/system/lib/libc/musl/src/aio/aio.c b/system/lib/libc/musl/src/aio/aio.c new file mode 100644 index 0000000000000..aafd8e8cb7786 --- /dev/null +++ b/system/lib/libc/musl/src/aio/aio.c @@ -0,0 +1,379 @@ +#include +#include +#include +#include +#include +#include +#include +#include "syscall.h" +#include "atomic.h" +#include "libc.h" +#include "pthread_impl.h" + +/* The following is a threads-based implementation of AIO with minimal + * dependence on implementation details. Most synchronization is + * performed with pthread primitives, but atomics and futex operations + * are used for notification in a couple places where the pthread + * primitives would be inefficient or impractical. + * + * For each fd with outstanding aio operations, an aio_queue structure + * is maintained. These are reference-counted and destroyed by the last + * aio worker thread to exit. Accessing any member of the aio_queue + * structure requires a lock on the aio_queue. Adding and removing aio + * queues themselves requires a write lock on the global map object, + * a 4-level table mapping file descriptor numbers to aio queues. A + * read lock on the map is used to obtain locks on existing queues by + * excluding destruction of the queue by a different thread while it is + * being locked. + * + * Each aio queue has a list of active threads/operations. Presently there + * is a one to one relationship between threads and operations. The only + * members of the aio_thread structure which are accessed by other threads + * are the linked list pointers, op (which is immutable), running (which + * is updated atomically), and err (which is synchronized via running), + * so no locking is necessary. Most of the other other members are used + * for sharing data between the main flow of execution and cancellation + * cleanup handler. + * + * Taking any aio locks requires having all signals blocked. This is + * necessary because aio_cancel is needed by close, and close is required + * to be async-signal safe. All aio worker threads run with all signals + * blocked permanently. + */ + +struct aio_args { + struct aiocb *cb; + int op; + int err; + sem_t sem; +}; + +struct aio_thread { + pthread_t td; + struct aiocb *cb; + struct aio_thread *next, *prev; + struct aio_queue *q; + volatile int running; + int err, op; + ssize_t ret; +}; + +struct aio_queue { + int fd, seekable, append, ref, init; + pthread_mutex_t lock; + pthread_cond_t cond; + struct aio_thread *head; +}; + +static pthread_rwlock_t maplock = PTHREAD_RWLOCK_INITIALIZER; +static struct aio_queue *****map; +static volatile int aio_fd_cnt; +volatile int __aio_fut; + +static struct aio_queue *__aio_get_queue(int fd, int need) +{ + if (fd < 0) return 0; + int a=fd>>24; + unsigned char b=fd>>16, c=fd>>8, d=fd; + struct aio_queue *q = 0; + pthread_rwlock_rdlock(&maplock); + if ((!map || !map[a] || !map[a][b] || !map[a][b][c] || !(q=map[a][b][c][d])) && need) { + pthread_rwlock_unlock(&maplock); + pthread_rwlock_wrlock(&maplock); + if (!map) map = calloc(sizeof *map, (-1U/2+1)>>24); + if (!map) goto out; + if (!map[a]) map[a] = calloc(sizeof **map, 256); + if (!map[a]) goto out; + if (!map[a][b]) map[a][b] = calloc(sizeof ***map, 256); + if (!map[a][b]) goto out; + if (!map[a][b][c]) map[a][b][c] = calloc(sizeof ****map, 256); + if (!map[a][b][c]) goto out; + if (!(q = map[a][b][c][d])) { + map[a][b][c][d] = q = calloc(sizeof *****map, 1); + if (q) { + q->fd = fd; + pthread_mutex_init(&q->lock, 0); + pthread_cond_init(&q->cond, 0); + a_inc(&aio_fd_cnt); + } + } + } + if (q) pthread_mutex_lock(&q->lock); +out: + pthread_rwlock_unlock(&maplock); + return q; +} + +static void __aio_unref_queue(struct aio_queue *q) +{ + if (q->ref > 1) { + q->ref--; + pthread_mutex_unlock(&q->lock); + return; + } + + /* This is potentially the last reference, but a new reference + * may arrive since we cannot free the queue object without first + * taking the maplock, which requires releasing the queue lock. */ + pthread_mutex_unlock(&q->lock); + pthread_rwlock_wrlock(&maplock); + pthread_mutex_lock(&q->lock); + if (q->ref == 1) { + int fd=q->fd; + int a=fd>>24; + unsigned char b=fd>>16, c=fd>>8, d=fd; + map[a][b][c][d] = 0; + a_dec(&aio_fd_cnt); + pthread_rwlock_unlock(&maplock); + pthread_mutex_unlock(&q->lock); + free(q); + } else { + q->ref--; + pthread_rwlock_unlock(&maplock); + pthread_mutex_unlock(&q->lock); + } +} + +static void cleanup(void *ctx) +{ + struct aio_thread *at = ctx; + struct aio_queue *q = at->q; + struct aiocb *cb = at->cb; + struct sigevent sev = cb->aio_sigevent; + + /* There are four potential types of waiters we could need to wake: + * 1. Callers of aio_cancel/close. + * 2. Callers of aio_suspend with a single aiocb. + * 3. Callers of aio_suspend with a list. + * 4. AIO worker threads waiting for sequenced operations. + * Types 1-3 are notified via atomics/futexes, mainly for AS-safety + * considerations. Type 4 is notified later via a cond var. */ + + cb->__ret = at->ret; + if (a_swap(&at->running, 0) < 0) + __wake(&at->running, -1, 1); + if (a_swap(&cb->__err, at->err) != EINPROGRESS) + __wake(&cb->__err, -1, 1); + if (a_swap(&__aio_fut, 0)) + __wake(&__aio_fut, -1, 1); + + pthread_mutex_lock(&q->lock); + + if (at->next) at->next->prev = at->prev; + if (at->prev) at->prev->next = at->next; + else q->head = at->next; + + /* Signal aio worker threads waiting for sequenced operations. */ + pthread_cond_broadcast(&q->cond); + + __aio_unref_queue(q); + + if (sev.sigev_notify == SIGEV_SIGNAL) { + siginfo_t si = { + .si_signo = sev.sigev_signo, + .si_value = sev.sigev_value, + .si_code = SI_ASYNCIO, + .si_pid = getpid(), + .si_uid = getuid() + }; + __syscall(SYS_rt_sigqueueinfo, si.si_pid, si.si_signo, &si); + } + if (sev.sigev_notify == SIGEV_THREAD) { + a_store(&__pthread_self()->cancel, 0); + sev.sigev_notify_function(sev.sigev_value); + } +} + +static void *io_thread_func(void *ctx) +{ + struct aio_thread at, *p; + + struct aio_args *args = ctx; + struct aiocb *cb = args->cb; + int fd = cb->aio_fildes; + int op = args->op; + void *buf = (void *)cb->aio_buf; + size_t len = cb->aio_nbytes; + off_t off = cb->aio_offset; + + struct aio_queue *q = __aio_get_queue(fd, 1); + ssize_t ret; + + args->err = q ? 0 : EAGAIN; + sem_post(&args->sem); + if (!q) return 0; + + at.op = op; + at.running = 1; + at.ret = -1; + at.err = ECANCELED; + at.q = q; + at.td = __pthread_self(); + at.cb = cb; + at.prev = 0; + if ((at.next = q->head)) at.next->prev = &at; + q->head = &at; + q->ref++; + + if (!q->init) { + int seekable = lseek(fd, 0, SEEK_CUR) >= 0; + q->seekable = seekable; + q->append = !seekable || (fcntl(fd, F_GETFL) & O_APPEND); + q->init = 1; + } + + pthread_cleanup_push(cleanup, &at); + + /* Wait for sequenced operations. */ + if (op!=LIO_READ && (op!=LIO_WRITE || q->append)) { + for (;;) { + for (p=at.next; p && p->op!=LIO_WRITE; p=p->next); + if (!p) break; + pthread_cond_wait(&q->cond, &q->lock); + } + } + + pthread_mutex_unlock(&q->lock); + + switch (op) { + case LIO_WRITE: + ret = q->append ? write(fd, buf, len) : pwrite(fd, buf, len, off); + break; + case LIO_READ: + ret = !q->seekable ? read(fd, buf, len) : pread(fd, buf, len, off); + break; + case O_SYNC: + ret = fsync(fd); + break; + case O_DSYNC: + ret = fdatasync(fd); + break; + } + at.ret = ret; + at.err = ret<0 ? errno : 0; + + pthread_cleanup_pop(1); + + return 0; +} + +static int submit(struct aiocb *cb, int op) +{ + int ret = 0; + pthread_attr_t a; + sigset_t allmask, origmask; + pthread_t td; + struct aio_args args = { .cb = cb, .op = op }; + sem_init(&args.sem, 0, 0); + + if (cb->aio_sigevent.sigev_notify == SIGEV_THREAD) { + if (cb->aio_sigevent.sigev_notify_attributes) + a = *cb->aio_sigevent.sigev_notify_attributes; + else + pthread_attr_init(&a); + } else { + pthread_attr_init(&a); + pthread_attr_setstacksize(&a, PTHREAD_STACK_MIN); + pthread_attr_setguardsize(&a, 0); + } + pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED); + sigfillset(&allmask); + pthread_sigmask(SIG_BLOCK, &allmask, &origmask); + cb->__err = EINPROGRESS; + if (pthread_create(&td, &a, io_thread_func, &args)) { + errno = EAGAIN; + ret = -1; + } + pthread_sigmask(SIG_SETMASK, &origmask, 0); + + if (!ret) { + while (sem_wait(&args.sem)); + if (args.err) { + errno = args.err; + ret = -1; + } + } + + return ret; +} + +int aio_read(struct aiocb *cb) +{ + return submit(cb, LIO_READ); +} + +int aio_write(struct aiocb *cb) +{ + return submit(cb, LIO_WRITE); +} + +int aio_fsync(int op, struct aiocb *cb) +{ + if (op != O_SYNC && op != O_DSYNC) { + errno = EINVAL; + return -1; + } + return submit(cb, op); +} + +ssize_t aio_return(struct aiocb *cb) +{ + return cb->__ret; +} + +int aio_error(const struct aiocb *cb) +{ + a_barrier(); + return cb->__err & 0x7fffffff; +} + +int aio_cancel(int fd, struct aiocb *cb) +{ + sigset_t allmask, origmask; + int ret = AIO_ALLDONE; + struct aio_thread *p; + struct aio_queue *q; + + /* Unspecified behavior case. Report an error. */ + if (cb && fd != cb->aio_fildes) { + errno = EINVAL; + return -1; + } + + sigfillset(&allmask); + pthread_sigmask(SIG_BLOCK, &allmask, &origmask); + + if (!(q = __aio_get_queue(fd, 0))) { + if (fcntl(fd, F_GETFD) < 0) ret = -1; + goto done; + } + + for (p = q->head; p; p = p->next) { + if (cb && cb != p->cb) continue; + /* Transition target from running to running-with-waiters */ + if (a_cas(&p->running, 1, -1)) { + pthread_cancel(p->td); + __wait(&p->running, 0, -1, 1); + if (p->err == ECANCELED) ret = AIO_CANCELED; + } + } + + pthread_mutex_unlock(&q->lock); +done: + pthread_sigmask(SIG_SETMASK, &origmask, 0); + return ret; +} + +int __aio_close(int fd) +{ + a_barrier(); + if (aio_fd_cnt) aio_cancel(fd, 0); + return fd; +} + +LFS64(aio_cancel); +LFS64(aio_error); +LFS64(aio_fsync); +LFS64(aio_read); +LFS64(aio_write); +LFS64(aio_return); diff --git a/system/lib/libc/musl/src/aio/aio_suspend.c b/system/lib/libc/musl/src/aio/aio_suspend.c index 39a1d3a228c8d..08fb5ddcf1a7b 100644 --- a/system/lib/libc/musl/src/aio/aio_suspend.c +++ b/system/lib/libc/musl/src/aio/aio_suspend.c @@ -1,57 +1,79 @@ #include #include +#include +#include "atomic.h" +#include "libc.h" #include "pthread_impl.h" -/* Due to the requirement that aio_suspend be async-signal-safe, we cannot - * use any locks, wait queues, etc. that would make it more efficient. The - * only obviously-correct algorithm is to generate a wakeup every time any - * aio operation finishes and have aio_suspend re-evaluate the completion - * status of each aiocb it was waiting on. */ - -static volatile int seq; - -void __aio_wake(void) -{ - a_inc(&seq); - __wake(&seq, -1, 1); -} +extern volatile int __aio_fut; int aio_suspend(const struct aiocb *const cbs[], int cnt, const struct timespec *ts) { - int i, last, first=1, ret=0; + int i, tid = 0, ret, expect = 0; struct timespec at; + volatile int dummy_fut, *pfut; + int nzcnt = 0; + const struct aiocb *cb = 0; + + pthread_testcancel(); if (cnt<0) { errno = EINVAL; return -1; } - for (;;) { - last = seq; + for (i=0; i__err != EINPROGRESS) - return 0; + if (ts) { + clock_gettime(CLOCK_MONOTONIC, &at); + at.tv_sec += ts->tv_sec; + if ((at.tv_nsec += ts->tv_nsec) >= 1000000000) { + at.tv_nsec -= 1000000000; + at.tv_sec++; } + } - if (first && ts) { - clock_gettime(CLOCK_MONOTONIC, &at); - at.tv_sec += ts->tv_sec; - if ((at.tv_nsec += ts->tv_nsec) >= 1000000000) { - at.tv_nsec -= 1000000000; - at.tv_sec++; - } - first = 0; - } + for (;;) { + for (i=0; i__err; + expect = EINPROGRESS | 0x80000000; + a_cas(pfut, EINPROGRESS, expect); + break; + default: + pfut = &__aio_fut; + if (!tid) tid = __pthread_self()->tid; + expect = a_cas(pfut, 0, tid); + if (!expect) expect = tid; + /* Need to recheck the predicate before waiting. */ + for (i=0; isigev_signo, .si_value = sev->sigev_value, .si_code = SI_ASYNCIO, - .si_pid = __pthread_self()->pid, + .si_pid = getpid(), .si_uid = getuid() }; __syscall(SYS_rt_sigqueueinfo, si.si_pid, si.si_signo, &si); @@ -141,3 +141,4 @@ int lio_listio(int mode, struct aiocb *restrict const *restrict cbs, int cnt, st return 0; } +LFS64(lio_listio); diff --git a/system/lib/libc/musl/src/complex/ctanh.c b/system/lib/libc/musl/src/complex/ctanh.c index 0461050d73301..3ba3a8997d803 100644 --- a/system/lib/libc/musl/src/complex/ctanh.c +++ b/system/lib/libc/musl/src/complex/ctanh.c @@ -101,11 +101,13 @@ double complex ctanh(double complex z) } /* + * ctanh(+-0 + i NAN) = +-0 + i NaN + * ctanh(+-0 +- i Inf) = +-0 + i NaN * ctanh(x + i NAN) = NaN + i NaN * ctanh(x +- i Inf) = NaN + i NaN */ if (!isfinite(y)) - return CMPLX(y - y, y - y); + return CMPLX(x ? y - y : x, y - y); /* * ctanh(+-huge + i +-y) ~= +-1 +- i 2sin(2y)/exp(2x), using the diff --git a/system/lib/libc/musl/src/complex/ctanhf.c b/system/lib/libc/musl/src/complex/ctanhf.c index a7e1a5fc0dccf..72b76da075cf8 100644 --- a/system/lib/libc/musl/src/complex/ctanhf.c +++ b/system/lib/libc/musl/src/complex/ctanhf.c @@ -50,7 +50,7 @@ float complex ctanhf(float complex z) } if (!isfinite(y)) - return CMPLXF(y - y, y - y); + return CMPLXF(ix ? y - y : x, y - y); if (ix >= 0x41300000) { /* x >= 11 */ float exp_mx = expf(-fabsf(x)); diff --git a/system/lib/libc/musl/src/conf/legacy.c b/system/lib/libc/musl/src/conf/legacy.c new file mode 100644 index 0000000000000..f1d9e3253cf64 --- /dev/null +++ b/system/lib/libc/musl/src/conf/legacy.c @@ -0,0 +1,22 @@ +#include +#include + +int get_nprocs_conf() +{ + return sysconf(_SC_NPROCESSORS_CONF); +} + +int get_nprocs() +{ + return sysconf(_SC_NPROCESSORS_ONLN); +} + +long get_phys_pages() +{ + return sysconf(_SC_PHYS_PAGES); +} + +long get_avphys_pages() +{ + return sysconf(_SC_AVPHYS_PAGES); +} diff --git a/system/lib/libc/musl/src/conf/sysconf.c b/system/lib/libc/musl/src/conf/sysconf.c index 12e8136825d14..b8b761d01a315 100644 --- a/system/lib/libc/musl/src/conf/sysconf.c +++ b/system/lib/libc/musl/src/conf/sysconf.c @@ -3,18 +3,28 @@ #include #include #include +#include #include "syscall.h" #include "libc.h" -#define VER (-2) -#define OFLOW (-3) -#define CPUCNT (-4) +#define JT(x) (-256|(x)) +#define VER JT(1) +#define JT_ARG_MAX JT(2) +#define JT_MQ_PRIO_MAX JT(3) +#define JT_PAGE_SIZE JT(4) +#define JT_SEM_VALUE_MAX JT(5) +#define JT_NPROCESSORS_CONF JT(6) +#define JT_NPROCESSORS_ONLN JT(7) +#define JT_PHYS_PAGES JT(8) +#define JT_AVPHYS_PAGES JT(9) +#define JT_ZERO JT(10) + #define RLIM(x) (-32768|(RLIMIT_ ## x)) long sysconf(int name) { static const short values[] = { - [_SC_ARG_MAX] = OFLOW, + [_SC_ARG_MAX] = JT_ARG_MAX, [_SC_CHILD_MAX] = RLIM(NPROC), [_SC_CLK_TCK] = 100, [_SC_NGROUPS_MAX] = 32, @@ -39,15 +49,15 @@ long sysconf(int name) [_SC_SHARED_MEMORY_OBJECTS] = VER, [_SC_AIO_LISTIO_MAX] = -1, [_SC_AIO_MAX] = -1, - [_SC_AIO_PRIO_DELTA_MAX] = 0, /* ?? */ + [_SC_AIO_PRIO_DELTA_MAX] = JT_ZERO, /* ?? */ [_SC_DELAYTIMER_MAX] = _POSIX_DELAYTIMER_MAX, [_SC_MQ_OPEN_MAX] = -1, - [_SC_MQ_PRIO_MAX] = OFLOW, + [_SC_MQ_PRIO_MAX] = JT_MQ_PRIO_MAX, [_SC_VERSION] = VER, - [_SC_PAGE_SIZE] = OFLOW, + [_SC_PAGE_SIZE] = JT_PAGE_SIZE, [_SC_RTSIG_MAX] = _NSIG - 1 - 31 - 3, [_SC_SEM_NSEMS_MAX] = SEM_NSEMS_MAX, - [_SC_SEM_VALUE_MAX] = OFLOW, + [_SC_SEM_VALUE_MAX] = JT_SEM_VALUE_MAX, [_SC_SIGQUEUE_MAX] = -1, [_SC_TIMER_MAX] = -1, [_SC_BC_BASE_MAX] = _POSIX2_BC_BASE_MAX, @@ -55,11 +65,9 @@ long sysconf(int name) [_SC_BC_SCALE_MAX] = _POSIX2_BC_SCALE_MAX, [_SC_BC_STRING_MAX] = _POSIX2_BC_STRING_MAX, [_SC_COLL_WEIGHTS_MAX] = COLL_WEIGHTS_MAX, - [_SC_EQUIV_CLASS_MAX] = -1, /* ?? */ [_SC_EXPR_NEST_MAX] = -1, [_SC_LINE_MAX] = -1, [_SC_RE_DUP_MAX] = RE_DUP_MAX, - [_SC_CHARCLASS_NAME_MAX] = -1, /* ?? */ [_SC_2_VERSION] = VER, [_SC_2_C_BIND] = VER, [_SC_2_C_DEV] = -1, @@ -67,20 +75,7 @@ long sysconf(int name) [_SC_2_FORT_RUN] = -1, [_SC_2_SW_DEV] = -1, [_SC_2_LOCALEDEF] = -1, - [_SC_PII] = -1, /* ????????? */ - [_SC_PII_XTI] = -1, - [_SC_PII_SOCKET] = -1, - [_SC_PII_INTERNET] = -1, - [_SC_PII_OSI] = -1, - [_SC_POLL] = 1, - [_SC_SELECT] = 1, [_SC_IOV_MAX] = IOV_MAX, - [_SC_PII_INTERNET_STREAM] = -1, - [_SC_PII_INTERNET_DGRAM] = -1, - [_SC_PII_OSI_COTS] = -1, - [_SC_PII_OSI_CLTS] = -1, - [_SC_PII_OSI_M] = -1, - [_SC_T_IOV_MAX] = -1, [_SC_THREADS] = VER, [_SC_THREAD_SAFE_FUNCTIONS] = VER, [_SC_GETGR_R_SIZE_MAX] = -1, @@ -97,10 +92,10 @@ long sysconf(int name) [_SC_THREAD_PRIO_INHERIT] = -1, [_SC_THREAD_PRIO_PROTECT] = -1, [_SC_THREAD_PROCESS_SHARED] = VER, - [_SC_NPROCESSORS_CONF] = CPUCNT, - [_SC_NPROCESSORS_ONLN] = CPUCNT, - [_SC_PHYS_PAGES] = -1, - [_SC_AVPHYS_PAGES] = -1, + [_SC_NPROCESSORS_CONF] = JT_NPROCESSORS_CONF, + [_SC_NPROCESSORS_ONLN] = JT_NPROCESSORS_ONLN, + [_SC_PHYS_PAGES] = JT_PHYS_PAGES, + [_SC_AVPHYS_PAGES] = JT_AVPHYS_PAGES, [_SC_ATEXIT_MAX] = -1, [_SC_PASS_MAX] = -1, [_SC_XOPEN_VERSION] = _XOPEN_VERSION, @@ -110,89 +105,44 @@ long sysconf(int name) [_SC_XOPEN_ENH_I18N] = 1, [_SC_XOPEN_SHM] = 1, [_SC_2_CHAR_TERM] = -1, - [_SC_2_C_VERSION] = -1, [_SC_2_UPE] = -1, [_SC_XOPEN_XPG2] = -1, [_SC_XOPEN_XPG3] = -1, [_SC_XOPEN_XPG4] = -1, - [_SC_CHAR_BIT] = -1, - [_SC_CHAR_MAX] = -1, - [_SC_CHAR_MIN] = -1, - [_SC_INT_MAX] = -1, - [_SC_INT_MIN] = -1, - [_SC_LONG_BIT] = -1, - [_SC_WORD_BIT] = -1, - [_SC_MB_LEN_MAX] = -1, [_SC_NZERO] = NZERO, - [_SC_SSIZE_MAX] = -1, - [_SC_SCHAR_MAX] = -1, - [_SC_SCHAR_MIN] = -1, - [_SC_SHRT_MAX] = -1, - [_SC_SHRT_MIN] = -1, - [_SC_UCHAR_MAX] = -1, - [_SC_UINT_MAX] = -1, - [_SC_ULONG_MAX] = -1, - [_SC_USHRT_MAX] = -1, - [_SC_NL_ARGMAX] = -1, - [_SC_NL_LANGMAX] = -1, - [_SC_NL_MSGMAX] = -1, - [_SC_NL_NMAX] = -1, - [_SC_NL_SETMAX] = -1, - [_SC_NL_TEXTMAX] = -1, [_SC_XBS5_ILP32_OFF32] = -1, - [_SC_XBS5_ILP32_OFFBIG] = 2*(sizeof(long)==4)-1, - [_SC_XBS5_LP64_OFF64] = 2*(sizeof(long)==8)-1, + [_SC_XBS5_ILP32_OFFBIG] = sizeof(long)==4 ? 1 : JT_ZERO, + [_SC_XBS5_LP64_OFF64] = sizeof(long)==8 ? 1 : JT_ZERO, [_SC_XBS5_LPBIG_OFFBIG] = -1, [_SC_XOPEN_LEGACY] = -1, [_SC_XOPEN_REALTIME] = -1, [_SC_XOPEN_REALTIME_THREADS] = -1, [_SC_ADVISORY_INFO] = VER, [_SC_BARRIERS] = VER, - [_SC_BASE] = -1, - [_SC_C_LANG_SUPPORT] = -1, - [_SC_C_LANG_SUPPORT_R] = -1, [_SC_CLOCK_SELECTION] = VER, [_SC_CPUTIME] = VER, [_SC_THREAD_CPUTIME] = VER, - [_SC_DEVICE_IO] = -1, - [_SC_DEVICE_SPECIFIC] = -1, - [_SC_DEVICE_SPECIFIC_R] = -1, - [_SC_FD_MGMT] = -1, - [_SC_FIFO] = -1, - [_SC_PIPE] = -1, - [_SC_FILE_ATTRIBUTES] = -1, - [_SC_FILE_LOCKING] = -1, - [_SC_FILE_SYSTEM] = -1, [_SC_MONOTONIC_CLOCK] = VER, - [_SC_MULTI_PROCESS] = -1, - [_SC_SINGLE_PROCESS] = -1, - [_SC_NETWORKING] = -1, [_SC_READER_WRITER_LOCKS] = VER, [_SC_SPIN_LOCKS] = VER, [_SC_REGEXP] = 1, - [_SC_REGEX_VERSION] = -1, [_SC_SHELL] = 1, - [_SC_SIGNALS] = -1, [_SC_SPAWN] = VER, [_SC_SPORADIC_SERVER] = -1, [_SC_THREAD_SPORADIC_SERVER] = -1, - [_SC_SYSTEM_DATABASE] = -1, - [_SC_SYSTEM_DATABASE_R] = -1, [_SC_TIMEOUTS] = VER, [_SC_TYPED_MEMORY_OBJECTS] = -1, - [_SC_USER_GROUPS] = -1, - [_SC_USER_GROUPS_R] = -1, [_SC_2_PBS] = -1, [_SC_2_PBS_ACCOUNTING] = -1, [_SC_2_PBS_LOCATE] = -1, [_SC_2_PBS_MESSAGE] = -1, [_SC_2_PBS_TRACK] = -1, [_SC_SYMLOOP_MAX] = SYMLOOP_MAX, - [_SC_STREAMS] = 0, + [_SC_STREAMS] = JT_ZERO, [_SC_2_PBS_CHECKPOINT] = -1, [_SC_V6_ILP32_OFF32] = -1, - [_SC_V6_ILP32_OFFBIG] = 2*(sizeof(long)==4)-1, - [_SC_V6_LP64_OFF64] = 2*(sizeof(long)==8)-1, + [_SC_V6_ILP32_OFFBIG] = sizeof(long)==4 ? 1 : JT_ZERO, + [_SC_V6_LP64_OFF64] = sizeof(long)==8 ? 1 : JT_ZERO, [_SC_V6_LPBIG_OFFBIG] = -1, [_SC_HOST_NAME_MAX] = HOST_NAME_MAX, [_SC_TRACE] = -1, @@ -203,40 +153,63 @@ long sysconf(int name) [_SC_IPV6] = VER, [_SC_RAW_SOCKETS] = VER, [_SC_V7_ILP32_OFF32] = -1, - [_SC_V7_ILP32_OFFBIG] = 2*(sizeof(long)==4)-1, - [_SC_V7_LP64_OFF64] = 2*(sizeof(long)==8)-1, + [_SC_V7_ILP32_OFFBIG] = sizeof(long)==4 ? 1 : JT_ZERO, + [_SC_V7_LP64_OFF64] = sizeof(long)==8 ? 1 : JT_ZERO, [_SC_V7_LPBIG_OFFBIG] = -1, [_SC_SS_REPL_MAX] = -1, [_SC_TRACE_EVENT_NAME_MAX] = -1, [_SC_TRACE_NAME_MAX] = -1, [_SC_TRACE_SYS_MAX] = -1, [_SC_TRACE_USER_EVENT_MAX] = -1, - [_SC_XOPEN_STREAMS] = 0, + [_SC_XOPEN_STREAMS] = JT_ZERO, [_SC_THREAD_ROBUST_PRIO_INHERIT] = -1, [_SC_THREAD_ROBUST_PRIO_PROTECT] = -1, }; - if (name > sizeof(values)/sizeof(values[0])) { + + if (name >= sizeof(values)/sizeof(values[0]) || !values[name]) { errno = EINVAL; return -1; - } else if (values[name] == VER) { + } else if (values[name] >= -1) { + return values[name]; + } else if (values[name] < -256) { + struct rlimit lim; + getrlimit(values[name]&16383, &lim); + return lim.rlim_cur > LONG_MAX ? LONG_MAX : lim.rlim_cur; + } + + switch ((unsigned char)values[name]) { + case VER & 255: return _POSIX_VERSION; - } else if (values[name] == OFLOW) { - if (name == _SC_ARG_MAX) return ARG_MAX; - if (name == _SC_SEM_VALUE_MAX) return SEM_VALUE_MAX; - if (name == _SC_MQ_PRIO_MAX) return MQ_PRIO_MAX; - /* name == _SC_PAGE_SIZE */ + case JT_ARG_MAX & 255: + return ARG_MAX; + case JT_MQ_PRIO_MAX & 255: + return MQ_PRIO_MAX; + case JT_PAGE_SIZE & 255: return PAGE_SIZE; - } else if (values[name] == CPUCNT) { + case JT_SEM_VALUE_MAX & 255: + return SEM_VALUE_MAX; + case JT_NPROCESSORS_CONF & 255: + case JT_NPROCESSORS_ONLN & 255: ; unsigned char set[128] = {1}; int i, cnt; __syscall(SYS_sched_getaffinity, 0, sizeof set, set); for (i=cnt=0; i LONG_MAX) ? LONG_MAX : mem; + case JT_ZERO & 255: + return 0; } return values[name]; } diff --git a/system/lib/libc/musl/src/crypt/crypt_sha256.c b/system/lib/libc/musl/src/crypt/crypt_sha256.c index d5f0b786df252..e885dc68e3c5b 100644 --- a/system/lib/libc/musl/src/crypt/crypt_sha256.c +++ b/system/lib/libc/musl/src/crypt/crypt_sha256.c @@ -230,7 +230,7 @@ static char *sha256crypt(const char *key, const char *setting, char *output) if (u < ROUNDS_MIN) r = ROUNDS_MIN; else if (u > ROUNDS_MAX) - r = ROUNDS_MAX; + return 0; else r = u; /* needed when rounds is zero prefixed or out of bounds */ diff --git a/system/lib/libc/musl/src/crypt/crypt_sha512.c b/system/lib/libc/musl/src/crypt/crypt_sha512.c index 1294e98be78f5..39970cafe8715 100644 --- a/system/lib/libc/musl/src/crypt/crypt_sha512.c +++ b/system/lib/libc/musl/src/crypt/crypt_sha512.c @@ -252,7 +252,7 @@ static char *sha512crypt(const char *key, const char *setting, char *output) if (u < ROUNDS_MIN) r = ROUNDS_MIN; else if (u > ROUNDS_MAX) - r = ROUNDS_MAX; + return 0; else r = u; /* needed when rounds is zero prefixed or out of bounds */ diff --git a/system/lib/libc/musl/src/ctype/__ctype_get_mb_cur_max.c b/system/lib/libc/musl/src/ctype/__ctype_get_mb_cur_max.c index d235f4da3e752..8e946fc12bcfc 100644 --- a/system/lib/libc/musl/src/ctype/__ctype_get_mb_cur_max.c +++ b/system/lib/libc/musl/src/ctype/__ctype_get_mb_cur_max.c @@ -1,6 +1,7 @@ -#include +#include +#include "locale_impl.h" size_t __ctype_get_mb_cur_max() { - return 4; + return MB_CUR_MAX; } diff --git a/system/lib/libc/musl/src/ctype/isalnum.c b/system/lib/libc/musl/src/ctype/isalnum.c index e3d2cf0b4ee32..2214936f2bde5 100644 --- a/system/lib/libc/musl/src/ctype/isalnum.c +++ b/system/lib/libc/musl/src/ctype/isalnum.c @@ -1,6 +1,14 @@ #include +#include "libc.h" int isalnum(int c) { return isalpha(c) || isdigit(c); } + +int __isalnum_l(int c, locale_t l) +{ + return isalnum(c); +} + +weak_alias(__isalnum_l, isalnum_l); diff --git a/system/lib/libc/musl/src/ctype/isalpha.c b/system/lib/libc/musl/src/ctype/isalpha.c index 53e115c29df71..f155d3aa97048 100644 --- a/system/lib/libc/musl/src/ctype/isalpha.c +++ b/system/lib/libc/musl/src/ctype/isalpha.c @@ -1,7 +1,15 @@ #include +#include "libc.h" #undef isalpha int isalpha(int c) { return ((unsigned)c|32)-'a' < 26; } + +int __isalpha_l(int c, locale_t l) +{ + return isalpha(c); +} + +weak_alias(__isalpha_l, isalpha_l); diff --git a/system/lib/libc/musl/src/ctype/isascii.c b/system/lib/libc/musl/src/ctype/isascii.c index 3af0a10d4f097..54ad3bf028a67 100644 --- a/system/lib/libc/musl/src/ctype/isascii.c +++ b/system/lib/libc/musl/src/ctype/isascii.c @@ -1,4 +1,5 @@ #include +#undef isascii int isascii(int c) { diff --git a/system/lib/libc/musl/src/ctype/isblank.c b/system/lib/libc/musl/src/ctype/isblank.c index 957400b2bbe2a..299120e96df19 100644 --- a/system/lib/libc/musl/src/ctype/isblank.c +++ b/system/lib/libc/musl/src/ctype/isblank.c @@ -1,6 +1,14 @@ #include +#include "libc.h" int isblank(int c) { return (c == ' ' || c == '\t'); } + +int __isblank_l(int c, locale_t l) +{ + return isblank(c); +} + +weak_alias(__isblank_l, isblank_l); diff --git a/system/lib/libc/musl/src/ctype/iscntrl.c b/system/lib/libc/musl/src/ctype/iscntrl.c index 92ed7f0e9adcb..cb4114a060208 100644 --- a/system/lib/libc/musl/src/ctype/iscntrl.c +++ b/system/lib/libc/musl/src/ctype/iscntrl.c @@ -1,6 +1,14 @@ #include +#include "libc.h" int iscntrl(int c) { return (unsigned)c < 0x20 || c == 0x7f; } + +int __iscntrl_l(int c, locale_t l) +{ + return iscntrl(c); +} + +weak_alias(__iscntrl_l, iscntrl_l); diff --git a/system/lib/libc/musl/src/ctype/isdigit.c b/system/lib/libc/musl/src/ctype/isdigit.c index 0bc82a6d76d8e..4d8a103e612e2 100644 --- a/system/lib/libc/musl/src/ctype/isdigit.c +++ b/system/lib/libc/musl/src/ctype/isdigit.c @@ -1,7 +1,15 @@ #include +#include "libc.h" #undef isdigit int isdigit(int c) { return (unsigned)c-'0' < 10; } + +int __isdigit_l(int c, locale_t l) +{ + return isdigit(c); +} + +weak_alias(__isdigit_l, isdigit_l); diff --git a/system/lib/libc/musl/src/ctype/isgraph.c b/system/lib/libc/musl/src/ctype/isgraph.c index 98979d1e898b9..a0aae08aabe69 100644 --- a/system/lib/libc/musl/src/ctype/isgraph.c +++ b/system/lib/libc/musl/src/ctype/isgraph.c @@ -1,4 +1,15 @@ +#include +#include "libc.h" +#undef isgraph + int isgraph(int c) { return (unsigned)c-0x21 < 0x5e; } + +int __isgraph_l(int c, locale_t l) +{ + return isgraph(c); +} + +weak_alias(__isgraph_l, isgraph_l); diff --git a/system/lib/libc/musl/src/ctype/islower.c b/system/lib/libc/musl/src/ctype/islower.c index d72fb212f2459..02640213e5f65 100644 --- a/system/lib/libc/musl/src/ctype/islower.c +++ b/system/lib/libc/musl/src/ctype/islower.c @@ -1,7 +1,15 @@ #include +#include "libc.h" #undef islower int islower(int c) { return (unsigned)c-'a' < 26; } + +int __islower_l(int c, locale_t l) +{ + return islower(c); +} + +weak_alias(__islower_l, islower_l); diff --git a/system/lib/libc/musl/src/ctype/isprint.c b/system/lib/libc/musl/src/ctype/isprint.c index 504e66ed127f7..067275fa03e79 100644 --- a/system/lib/libc/musl/src/ctype/isprint.c +++ b/system/lib/libc/musl/src/ctype/isprint.c @@ -1,4 +1,15 @@ +#include +#include "libc.h" +#undef isprint + int isprint(int c) { return (unsigned)c-0x20 < 0x5f; } + +int __isprint_l(int c, locale_t l) +{ + return isprint(c); +} + +weak_alias(__isprint_l, isprint_l); diff --git a/system/lib/libc/musl/src/ctype/ispunct.c b/system/lib/libc/musl/src/ctype/ispunct.c index fc455352b5148..e772d76a03f20 100644 --- a/system/lib/libc/musl/src/ctype/ispunct.c +++ b/system/lib/libc/musl/src/ctype/ispunct.c @@ -1,6 +1,14 @@ #include +#include "libc.h" int ispunct(int c) { return isgraph(c) && !isalnum(c); } + +int __ispunct_l(int c, locale_t l) +{ + return ispunct(c); +} + +weak_alias(__ispunct_l, ispunct_l); diff --git a/system/lib/libc/musl/src/ctype/isspace.c b/system/lib/libc/musl/src/ctype/isspace.c index 8e535aa1dc59e..231e90793ddd3 100644 --- a/system/lib/libc/musl/src/ctype/isspace.c +++ b/system/lib/libc/musl/src/ctype/isspace.c @@ -1,6 +1,15 @@ #include +#include "libc.h" +#undef isspace int isspace(int c) { return c == ' ' || (unsigned)c-'\t' < 5; } + +int __isspace_l(int c, locale_t l) +{ + return isspace(c); +} + +weak_alias(__isspace_l, isspace_l); diff --git a/system/lib/libc/musl/src/ctype/isupper.c b/system/lib/libc/musl/src/ctype/isupper.c index f09d88c57c34a..68c36f4a424f2 100644 --- a/system/lib/libc/musl/src/ctype/isupper.c +++ b/system/lib/libc/musl/src/ctype/isupper.c @@ -1,7 +1,15 @@ #include +#include "libc.h" #undef isupper int isupper(int c) { return (unsigned)c-'A' < 26; } + +int __isupper_l(int c, locale_t l) +{ + return isupper(c); +} + +weak_alias(__isupper_l, isupper_l); diff --git a/system/lib/libc/musl/src/ctype/iswalnum.c b/system/lib/libc/musl/src/ctype/iswalnum.c index 35dbe02cf3cb3..a6082da437867 100644 --- a/system/lib/libc/musl/src/ctype/iswalnum.c +++ b/system/lib/libc/musl/src/ctype/iswalnum.c @@ -1,7 +1,14 @@ -#include #include +#include "libc.h" int iswalnum(wint_t wc) { return iswdigit(wc) || iswalpha(wc); } + +int __iswalnum_l(wint_t c, locale_t l) +{ + return iswalnum(c); +} + +weak_alias(__iswalnum_l, iswalnum_l); diff --git a/system/lib/libc/musl/src/ctype/iswalpha.c b/system/lib/libc/musl/src/ctype/iswalpha.c index d558faef47954..00f9d81f5a789 100644 --- a/system/lib/libc/musl/src/ctype/iswalpha.c +++ b/system/lib/libc/musl/src/ctype/iswalpha.c @@ -1,4 +1,5 @@ #include +#include "libc.h" static const unsigned char table[] = { #include "alpha.h" @@ -12,3 +13,10 @@ int iswalpha(wint_t wc) return 1; return 0; } + +int __iswalpha_l(wint_t c, locale_t l) +{ + return iswalpha(c); +} + +weak_alias(__iswalpha_l, iswalpha_l); diff --git a/system/lib/libc/musl/src/ctype/iswblank.c b/system/lib/libc/musl/src/ctype/iswblank.c index bc6196f290f9a..d9b33ef472d64 100644 --- a/system/lib/libc/musl/src/ctype/iswblank.c +++ b/system/lib/libc/musl/src/ctype/iswblank.c @@ -1,8 +1,15 @@ -#include #include #include +#include "libc.h" int iswblank(wint_t wc) { return isblank(wc); } + +int __iswblank_l(wint_t c, locale_t l) +{ + return iswblank(c); +} + +weak_alias(__iswblank_l, iswblank_l); diff --git a/system/lib/libc/musl/src/ctype/iswcntrl.c b/system/lib/libc/musl/src/ctype/iswcntrl.c index 93942b0874c5e..daace82a375f4 100644 --- a/system/lib/libc/musl/src/ctype/iswcntrl.c +++ b/system/lib/libc/musl/src/ctype/iswcntrl.c @@ -1,5 +1,5 @@ -#include #include +#include "libc.h" int iswcntrl(wint_t wc) { @@ -8,3 +8,10 @@ int iswcntrl(wint_t wc) || (unsigned)(wc-0x2028) < 2 || (unsigned)(wc-0xfff9) < 3; } + +int __iswcntrl_l(wint_t c, locale_t l) +{ + return iswcntrl(c); +} + +weak_alias(__iswcntrl_l, iswcntrl_l); diff --git a/system/lib/libc/musl/src/ctype/iswctype.c b/system/lib/libc/musl/src/ctype/iswctype.c index d917975b90a2a..3d9c2cc7c2d07 100644 --- a/system/lib/libc/musl/src/ctype/iswctype.c +++ b/system/lib/libc/musl/src/ctype/iswctype.c @@ -1,6 +1,6 @@ -#include #include #include +#include "libc.h" #define WCTYPE_ALNUM 1 #define WCTYPE_ALPHA 2 @@ -61,3 +61,16 @@ wctype_t wctype(const char *s) return i; return 0; } + +int __iswctype_l(wint_t c, wctype_t t, locale_t l) +{ + return iswctype(c, t); +} + +wctype_t __wctype_l(const char *s, locale_t l) +{ + return wctype(s); +} + +weak_alias(__iswctype_l, iswctype_l); +weak_alias(__wctype_l, wctype_l); diff --git a/system/lib/libc/musl/src/ctype/iswdigit.c b/system/lib/libc/musl/src/ctype/iswdigit.c index 0487145fabb17..ed9a88e740ad3 100644 --- a/system/lib/libc/musl/src/ctype/iswdigit.c +++ b/system/lib/libc/musl/src/ctype/iswdigit.c @@ -1,5 +1,5 @@ -#include #include +#include "libc.h" #undef iswdigit @@ -7,3 +7,10 @@ int iswdigit(wint_t wc) { return (unsigned)wc-'0' < 10; } + +int __iswdigit_l(wint_t c, locale_t l) +{ + return iswdigit(c); +} + +weak_alias(__iswdigit_l, iswdigit_l); diff --git a/system/lib/libc/musl/src/ctype/iswgraph.c b/system/lib/libc/musl/src/ctype/iswgraph.c index fdc978535b1e7..0ea5ca3a4d57e 100644 --- a/system/lib/libc/musl/src/ctype/iswgraph.c +++ b/system/lib/libc/musl/src/ctype/iswgraph.c @@ -1,7 +1,15 @@ #include +#include "libc.h" int iswgraph(wint_t wc) { /* ISO C defines this function as: */ return !iswspace(wc) && iswprint(wc); } + +int __iswgraph_l(wint_t c, locale_t l) +{ + return iswgraph(c); +} + +weak_alias(__iswgraph_l, iswgraph_l); diff --git a/system/lib/libc/musl/src/ctype/iswlower.c b/system/lib/libc/musl/src/ctype/iswlower.c index 438fe26a5dac1..79df44a3d64e5 100644 --- a/system/lib/libc/musl/src/ctype/iswlower.c +++ b/system/lib/libc/musl/src/ctype/iswlower.c @@ -1,6 +1,14 @@ #include +#include "libc.h" int iswlower(wint_t wc) { - return towupper(wc) != wc || wc == 0xdf; + return towupper(wc) != wc; } + +int __iswlower_l(wint_t c, locale_t l) +{ + return iswlower(c); +} + +weak_alias(__iswlower_l, iswlower_l); diff --git a/system/lib/libc/musl/src/ctype/iswprint.c b/system/lib/libc/musl/src/ctype/iswprint.c index 333f19c2b272a..69856e0d8e3a3 100644 --- a/system/lib/libc/musl/src/ctype/iswprint.c +++ b/system/lib/libc/musl/src/ctype/iswprint.c @@ -1,4 +1,5 @@ #include +#include "libc.h" /* Consider all legal codepoints as printable except for: * - C0 and C1 control characters @@ -17,3 +18,10 @@ int iswprint(wint_t wc) return 0; return 1; } + +int __iswprint_l(wint_t c, locale_t l) +{ + return iswprint(c); +} + +weak_alias(__iswprint_l, iswprint_l); diff --git a/system/lib/libc/musl/src/ctype/iswpunct.c b/system/lib/libc/musl/src/ctype/iswpunct.c index 16e8703b55cdc..d88010463c9f8 100644 --- a/system/lib/libc/musl/src/ctype/iswpunct.c +++ b/system/lib/libc/musl/src/ctype/iswpunct.c @@ -1,4 +1,5 @@ #include +#include "libc.h" static const unsigned char table[] = { #include "punct.h" @@ -10,3 +11,10 @@ int iswpunct(wint_t wc) return (table[table[wc>>8]*32+((wc&255)>>3)]>>(wc&7))&1; return 0; } + +int __iswpunct_l(wint_t c, locale_t l) +{ + return iswpunct(c); +} + +weak_alias(__iswpunct_l, iswpunct_l); diff --git a/system/lib/libc/musl/src/ctype/iswspace.c b/system/lib/libc/musl/src/ctype/iswspace.c index b0c0ae18cf225..75ae7e8ee3657 100644 --- a/system/lib/libc/musl/src/ctype/iswspace.c +++ b/system/lib/libc/musl/src/ctype/iswspace.c @@ -1,6 +1,6 @@ #include #include -#include +#include "libc.h" /* Our definition of whitespace is the Unicode White_Space property, * minus non-breaking spaces (U+00A0, U+2007, and U+202F) and script- @@ -16,3 +16,10 @@ int iswspace(wint_t wc) }; return wc && wcschr(spaces, wc); } + +int __iswspace_l(wint_t c, locale_t l) +{ + return iswspace(c); +} + +weak_alias(__iswspace_l, iswspace_l); diff --git a/system/lib/libc/musl/src/ctype/iswupper.c b/system/lib/libc/musl/src/ctype/iswupper.c index eae59a75d9419..6e1e029c49029 100644 --- a/system/lib/libc/musl/src/ctype/iswupper.c +++ b/system/lib/libc/musl/src/ctype/iswupper.c @@ -1,6 +1,14 @@ #include +#include "libc.h" int iswupper(wint_t wc) { return towlower(wc) != wc; } + +int __iswupper_l(wint_t c, locale_t l) +{ + return iswupper(c); +} + +weak_alias(__iswupper_l, iswupper_l); diff --git a/system/lib/libc/musl/src/ctype/iswxdigit.c b/system/lib/libc/musl/src/ctype/iswxdigit.c index 229a469f028e9..1e27f1f0f9d82 100644 --- a/system/lib/libc/musl/src/ctype/iswxdigit.c +++ b/system/lib/libc/musl/src/ctype/iswxdigit.c @@ -1,7 +1,14 @@ -#include #include +#include "libc.h" int iswxdigit(wint_t wc) { return (unsigned)(wc-'0') < 10 || (unsigned)((wc|32)-'a') < 6; } + +int __iswxdigit_l(wint_t c, locale_t l) +{ + return iswxdigit(c); +} + +weak_alias(__iswxdigit_l, iswxdigit_l); diff --git a/system/lib/libc/musl/src/ctype/isxdigit.c b/system/lib/libc/musl/src/ctype/isxdigit.c index ae68a3dc9249b..0e9152a7b0166 100644 --- a/system/lib/libc/musl/src/ctype/isxdigit.c +++ b/system/lib/libc/musl/src/ctype/isxdigit.c @@ -1,6 +1,14 @@ #include +#include "libc.h" int isxdigit(int c) { return isdigit(c) || ((unsigned)c|32)-'a' < 6; } + +int __isxdigit_l(int c, locale_t l) +{ + return isxdigit(c); +} + +weak_alias(__isxdigit_l, isxdigit_l); diff --git a/system/lib/libc/musl/src/ctype/tolower.c b/system/lib/libc/musl/src/ctype/tolower.c index b56f3c5094a24..362d6b2becdeb 100644 --- a/system/lib/libc/musl/src/ctype/tolower.c +++ b/system/lib/libc/musl/src/ctype/tolower.c @@ -1,7 +1,15 @@ #include +#include "libc.h" int tolower(int c) { if (isupper(c)) return c | 32; return c; } + +int __tolower_l(int c, locale_t l) +{ + return tolower(c); +} + +weak_alias(__tolower_l, tolower_l); diff --git a/system/lib/libc/musl/src/ctype/toupper.c b/system/lib/libc/musl/src/ctype/toupper.c index 1799f0307789a..bbf4e06e815c6 100644 --- a/system/lib/libc/musl/src/ctype/toupper.c +++ b/system/lib/libc/musl/src/ctype/toupper.c @@ -1,7 +1,15 @@ #include +#include "libc.h" int toupper(int c) { if (islower(c)) return c & 0x5f; return c; } + +int __toupper_l(int c, locale_t l) +{ + return toupper(c); +} + +weak_alias(__toupper_l, toupper_l); diff --git a/system/lib/libc/musl/src/ctype/towctrans.c b/system/lib/libc/musl/src/ctype/towctrans.c index 2842d690e7dfb..6af618758bcb8 100644 --- a/system/lib/libc/musl/src/ctype/towctrans.c +++ b/system/lib/libc/musl/src/ctype/towctrans.c @@ -1,6 +1,5 @@ -#include #include -#include +#include "libc.h" #define CASEMAP(u1,u2,l) { (u1), (l)-(u1), (u2)-(u1)+1 } #define CASELACE(u1,u2) CASEMAP((u1),(u2),(u1)+1) @@ -152,7 +151,6 @@ static const unsigned short pairs[][2] = { { 0x03f7, 0x03f8 }, { 0x03fa, 0x03fb }, { 0x1e60, 0x1e9b }, - { 0xdf, 0xdf }, { 0x1e9e, 0xdf }, { 0x1f59, 0x1f51 }, @@ -266,3 +264,16 @@ wint_t towlower(wint_t wc) { return __towcase(wc, 1); } + +wint_t __towupper_l(wint_t c, locale_t l) +{ + return towupper(c); +} + +wint_t __towlower_l(wint_t c, locale_t l) +{ + return towlower(c); +} + +weak_alias(__towupper_l, towupper_l); +weak_alias(__towlower_l, towlower_l); diff --git a/system/lib/libc/musl/src/ctype/wctrans.c b/system/lib/libc/musl/src/ctype/wctrans.c index 739869d059e4a..b1b1265481c7d 100644 --- a/system/lib/libc/musl/src/ctype/wctrans.c +++ b/system/lib/libc/musl/src/ctype/wctrans.c @@ -1,5 +1,6 @@ #include #include +#include "libc.h" wctrans_t wctrans(const char *class) { @@ -14,3 +15,16 @@ wint_t towctrans(wint_t wc, wctrans_t trans) if (trans == (wctrans_t)2) return towlower(wc); return wc; } + +wctrans_t __wctrans_l(const char *s, locale_t l) +{ + return wctrans(s); +} + +wint_t __towctrans_l(wint_t c, wctrans_t t, locale_t l) +{ + return towctrans(c, t); +} + +weak_alias(__wctrans_l, wctrans_l); +weak_alias(__towctrans_l, towctrans_l); diff --git a/system/lib/libc/musl/src/dirent/__dirent.h b/system/lib/libc/musl/src/dirent/__dirent.h index 45509e19c3de2..32871baf51a1f 100644 --- a/system/lib/libc/musl/src/dirent/__dirent.h +++ b/system/lib/libc/musl/src/dirent/__dirent.h @@ -4,6 +4,6 @@ struct __dirstream off_t tell; int buf_pos; int buf_end; - int lock[2]; + volatile int lock[2]; char buf[2048]; }; diff --git a/system/lib/libc/musl/src/dirent/versionsort.c b/system/lib/libc/musl/src/dirent/versionsort.c index 9769610518eb3..410cb703456f3 100644 --- a/system/lib/libc/musl/src/dirent/versionsort.c +++ b/system/lib/libc/musl/src/dirent/versionsort.c @@ -1,8 +1,12 @@ #define _GNU_SOURCE #include #include +#include "libc.h" int versionsort(const struct dirent **a, const struct dirent **b) { return strverscmp((*a)->d_name, (*b)->d_name); } + +#undef versionsort64 +LFS64(versionsort); diff --git a/system/lib/libc/musl/src/env/__init_tls.c b/system/lib/libc/musl/src/env/__init_tls.c index 5c1768111ba55..0107a545f282a 100644 --- a/system/lib/libc/musl/src/env/__init_tls.c +++ b/system/lib/libc/musl/src/env/__init_tls.c @@ -2,71 +2,82 @@ #include #include #include +#include #include "pthread_impl.h" #include "libc.h" #include "atomic.h" +#include "syscall.h" -#ifndef SHARED +int __init_tp(void *p) +{ + pthread_t td = p; + td->self = td; + int r = __set_thread_area(TP_ADJ(p)); + if (r < 0) return -1; + if (!r) libc.can_do_threads = 1; + td->tid = __syscall(SYS_set_tid_address, &td->tid); + td->locale = &libc.global_locale; + td->robust_list.head = &td->robust_list.head; + return 0; +} -struct tls_image { - void *image; - size_t len, size, align; -} __static_tls ATTR_LIBC_VISIBILITY; +static struct builtin_tls { + char c; + struct pthread pt; + void *space[16]; +} builtin_tls[1]; +#define MIN_TLS_ALIGN offsetof(struct builtin_tls, pt) -#define T __static_tls +static struct tls_module main_tls; void *__copy_tls(unsigned char *mem) { pthread_t td; - if (!T.image) return mem; - void **dtv = (void *)mem; - dtv[0] = (void *)1; + struct tls_module *p; + size_t i; + void **dtv; + #ifdef TLS_ABOVE_TP - mem += sizeof(void *) * 2; - mem += -((uintptr_t)mem + sizeof(struct pthread)) & (T.align-1); + dtv = (void **)(mem + libc.tls_size) - (libc.tls_cnt + 1); + + mem += -((uintptr_t)mem + sizeof(struct pthread)) & (libc.tls_align-1); td = (pthread_t)mem; mem += sizeof(struct pthread); + + for (i=1, p=libc.tls_head; p; i++, p=p->next) { + dtv[i] = mem + p->offset; + memcpy(dtv[i], p->image, p->len); + } #else + dtv = (void **)mem; + mem += libc.tls_size - sizeof(struct pthread); - mem -= (uintptr_t)mem & (T.align-1); + mem -= (uintptr_t)mem & (libc.tls_align-1); td = (pthread_t)mem; - mem -= T.size; + + for (i=1, p=libc.tls_head; p; i++, p=p->next) { + dtv[i] = mem - p->offset; + memcpy(dtv[i], p->image, p->len); + } #endif - td->dtv = dtv; - dtv[1] = mem; - memcpy(mem, T.image, T.len); + dtv[0] = (void *)libc.tls_cnt; + td->dtv = td->dtv_copy = dtv; return td; } -void *__tls_get_addr(size_t *v) -{ - return (char *)__pthread_self()->dtv[1]+v[1]; -} - -static void *simple(void *p) -{ - *(void **)p = p; - return __set_thread_area(TP_ADJ(p)) ? 0 : p; -} - -weak_alias(simple, __install_initial_tls); - -void *__mmap(void *, size_t, int, int, int, off_t); - #if ULONG_MAX == 0xffffffff typedef Elf32_Phdr Phdr; #else typedef Elf64_Phdr Phdr; #endif -void __init_tls(size_t *aux) +static void static_init_tls(size_t *aux) { - unsigned char *p, *mem; + unsigned char *p; size_t n; Phdr *phdr, *tls_phdr=0; size_t base = 0; - - libc.tls_size = sizeof(struct pthread); + void *mem; for (p=(void *)aux[AT_PHDR],n=aux[AT_PHNUM]; n; n--,p+=aux[AT_PHENT]) { phdr = (void *)p; @@ -75,22 +86,46 @@ void __init_tls(size_t *aux) if (phdr->p_type == PT_TLS) tls_phdr = phdr; } - if (!tls_phdr) return; - T.image = (void *)(base + tls_phdr->p_vaddr); - T.len = tls_phdr->p_filesz; - T.size = tls_phdr->p_memsz; - T.align = tls_phdr->p_align; + if (tls_phdr) { + main_tls.image = (void *)(base + tls_phdr->p_vaddr); + main_tls.len = tls_phdr->p_filesz; + main_tls.size = tls_phdr->p_memsz; + main_tls.align = tls_phdr->p_align; + libc.tls_cnt = 1; + libc.tls_head = &main_tls; + } - T.size += (-T.size - (uintptr_t)T.image) & (T.align-1); - if (T.align < 4*sizeof(size_t)) T.align = 4*sizeof(size_t); + main_tls.size += (-main_tls.size - (uintptr_t)main_tls.image) + & (main_tls.align-1); + if (main_tls.align < MIN_TLS_ALIGN) main_tls.align = MIN_TLS_ALIGN; +#ifndef TLS_ABOVE_TP + main_tls.offset = main_tls.size; +#endif - libc.tls_size = 2*sizeof(void *)+T.size+T.align+sizeof(struct pthread); + libc.tls_align = main_tls.align; + libc.tls_size = 2*sizeof(void *) + sizeof(struct pthread) + + main_tls.size + main_tls.align + + MIN_TLS_ALIGN-1 & -MIN_TLS_ALIGN; - mem = __mmap(0, libc.tls_size, PROT_READ|PROT_WRITE, - MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); - if (!__install_initial_tls(__copy_tls(mem))) a_crash(); -} -#else -void __init_tls(size_t *auxv) { } + if (libc.tls_size > sizeof builtin_tls) { +#ifndef SYS_mmap2 +#define SYS_mmap2 SYS_mmap #endif + mem = (void *)__syscall( + SYS_mmap2, + 0, libc.tls_size, PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); + /* -4095...-1 cast to void * will crash on dereference anyway, + * so don't bloat the init code checking for error codes and + * explicitly calling a_crash(). */ + } else { + mem = builtin_tls; + } + + /* Failure to initialize thread pointer is always fatal. */ + if (__init_tp(__copy_tls(mem)) < 0) + a_crash(); +} + +weak_alias(static_init_tls, __init_tls); diff --git a/system/lib/libc/musl/src/env/__libc_start_main.c b/system/lib/libc/musl/src/env/__libc_start_main.c index 73d4932788d4a..5c79be28f0b5c 100644 --- a/system/lib/libc/musl/src/env/__libc_start_main.c +++ b/system/lib/libc/musl/src/env/__libc_start_main.c @@ -1,21 +1,23 @@ #include +#include +#include +#include +#include "syscall.h" +#include "atomic.h" #include "libc.h" void __init_tls(size_t *); -void __init_security(size_t *); -void __init_ldso_ctors(void); -#ifndef SHARED -static void dummy() {} +static void dummy(void) {} weak_alias(dummy, _init); -extern void (*const __init_array_start)() __attribute__((weak)); -extern void (*const __init_array_end)() __attribute__((weak)); -#endif -#define AUX_CNT 38 +__attribute__((__weak__, __visibility__("hidden"))) +extern void (*const __init_array_start)(void), (*const __init_array_end)(void); -extern size_t __hwcap, __sysinfo; -extern char *__progname, *__progname_full; +static void dummy1(void *p) {} +weak_alias(dummy1, __init_ssp); + +#define AUX_CNT 38 void __init_libc(char **envp, char *pn) { @@ -34,22 +36,41 @@ void __init_libc(char **envp, char *pn) } __init_tls(aux); - __init_security(aux); + __init_ssp((void *)aux[AT_RANDOM]); + + if (aux[AT_UID]==aux[AT_EUID] && aux[AT_GID]==aux[AT_EGID] + && !aux[AT_SECURE]) return; + + struct pollfd pfd[3] = { {.fd=0}, {.fd=1}, {.fd=2} }; +#ifdef SYS_poll + __syscall(SYS_poll, pfd, 3, 0); +#else + __syscall(SYS_ppoll, pfd, 3, &(struct timespec){0}, 0, _NSIG/8); +#endif + for (i=0; i<3; i++) if (pfd[i].revents&POLLNVAL) + if (__sys_open("/dev/null", O_RDWR)<0) + a_crash(); + libc.secure = 1; } -int __libc_start_main(int (*main)(int,char **,char **), int argc, char **argv) +static void libc_start_init(void) { - char **envp = argv+argc+1; - -#ifndef SHARED - __init_libc(envp, argv[0]); _init(); uintptr_t a = (uintptr_t)&__init_array_start; for (; a<(uintptr_t)&__init_array_end; a+=sizeof(void(*)())) (*(void (**)())a)(); -#endif +} + +weak_alias(libc_start_init, __libc_start_init); + +int __libc_start_main(int (*main)(int,char **,char **), int argc, char **argv) +{ + char **envp = argv+argc+1; + + __init_libc(envp, argv[0]); + __libc_start_init(); - /* Pass control to to application */ + /* Pass control to the application */ exit(main(argc, argv, envp)); return 0; } diff --git a/system/lib/libc/musl/src/env/__reset_tls.c b/system/lib/libc/musl/src/env/__reset_tls.c index 28c4405efe4c2..677e57f58b45c 100644 --- a/system/lib/libc/musl/src/env/__reset_tls.c +++ b/system/lib/libc/musl/src/env/__reset_tls.c @@ -1,22 +1,16 @@ -#ifndef SHARED - #include #include "pthread_impl.h" #include "libc.h" -extern struct tls_image { - void *image; - size_t len, size, align; -} __static_tls ATTR_LIBC_VISIBILITY; - -#define T __static_tls - void __reset_tls() { - if (!T.size) return; pthread_t self = __pthread_self(); - memcpy(self->dtv[1], T.image, T.len); - memset((char *)self->dtv[1]+T.len, 0, T.size-T.len); + struct tls_module *p; + size_t i, n = (size_t)self->dtv[0]; + if (n) for (p=libc.tls_head, i=1; i<=n; i++, p=p->next) { + if (!self->dtv[i]) continue; + memcpy(self->dtv[i], p->image, p->len); + memset((char *)self->dtv[i]+p->len, 0, + p->size - p->len); + } } - -#endif diff --git a/system/lib/libc/musl/src/env/__stack_chk_fail.c b/system/lib/libc/musl/src/env/__stack_chk_fail.c index daa1b0783a890..4de82fd9d2f39 100644 --- a/system/lib/libc/musl/src/env/__stack_chk_fail.c +++ b/system/lib/libc/musl/src/env/__stack_chk_fail.c @@ -1,21 +1,23 @@ #include #include #include "pthread_impl.h" -#include "atomic.h" uintptr_t __stack_chk_guard; void __init_ssp(void *entropy) { - pthread_t self = __pthread_self_init(); - uintptr_t canary; - if (entropy) memcpy(&canary, entropy, sizeof canary); - else canary = (uintptr_t)&canary * 1103515245; - a_cas_l(&__stack_chk_guard, 0, canary); - self->canary = __stack_chk_guard; + if (entropy) memcpy(&__stack_chk_guard, entropy, sizeof(uintptr_t)); + else __stack_chk_guard = (uintptr_t)&__stack_chk_guard * 1103515245; + + __pthread_self()->CANARY = __stack_chk_guard; } void __stack_chk_fail(void) { a_crash(); } + +__attribute__((__visibility__("hidden"))) +void __stack_chk_fail_local(void); + +weak_alias(__stack_chk_fail, __stack_chk_fail_local); diff --git a/system/lib/libc/musl/src/env/putenv.c b/system/lib/libc/musl/src/env/putenv.c index 4042869b500f1..7153042669da8 100644 --- a/system/lib/libc/musl/src/env/putenv.c +++ b/system/lib/libc/musl/src/env/putenv.c @@ -30,6 +30,7 @@ int __putenv(char *s, int a) } } else { free(__env_map[j]); + __env_map[j] = s; } } } diff --git a/system/lib/libc/musl/src/errno/__errno_location.c b/system/lib/libc/musl/src/errno/__errno_location.c index 3e92d7c7a89ab..7172a1be39dbb 100644 --- a/system/lib/libc/musl/src/errno/__errno_location.c +++ b/system/lib/libc/musl/src/errno/__errno_location.c @@ -2,7 +2,5 @@ int *__errno_location(void) { - static int e; - if (libc.main_thread) return __pthread_self()->errno_ptr; - return &e; + return &__pthread_self()->errno_val; } diff --git a/system/lib/libc/musl/src/errno/strerror.c b/system/lib/libc/musl/src/errno/strerror.c index b5559cbe3312f..24c94d3742d4e 100644 --- a/system/lib/libc/musl/src/errno/strerror.c +++ b/system/lib/libc/musl/src/errno/strerror.c @@ -1,5 +1,7 @@ #include #include +#include "locale_impl.h" +#include "libc.h" #define E(a,b) ((unsigned char)a), static const unsigned char errid[] = { @@ -12,7 +14,7 @@ static const char errmsg[] = #include "__strerror.h" ; -char *strerror(int e) +char *__strerror_l(int e, locale_t loc) { const char *s; int i; @@ -24,5 +26,12 @@ char *strerror(int e) } for (i=0; errid[i] && errid[i] != e; i++); for (s=errmsg; i; s++, i--) for (; *s; s++); - return (char *)s; + return (char *)LCTRANS(s, LC_MESSAGES, loc); +} + +char *strerror(int e) +{ + return __strerror_l(e, CURRENT_LOCALE); } + +weak_alias(__strerror_l, strerror_l); diff --git a/system/lib/libc/musl/src/exit/abort.c b/system/lib/libc/musl/src/exit/abort.c index 203dd35cb99d2..ecc0f735aaee7 100644 --- a/system/lib/libc/musl/src/exit/abort.c +++ b/system/lib/libc/musl/src/exit/abort.c @@ -1,10 +1,14 @@ #include #include #include "syscall.h" +#include "pthread_impl.h" +#include "atomic.h" _Noreturn void abort(void) { raise(SIGABRT); + __block_all_sigs(0); + a_crash(); raise(SIGKILL); - for (;;); + _Exit(127); } diff --git a/system/lib/libc/musl/src/exit/at_quick_exit.c b/system/lib/libc/musl/src/exit/at_quick_exit.c index 85c3d26ef4fcc..34541badad445 100644 --- a/system/lib/libc/musl/src/exit/at_quick_exit.c +++ b/system/lib/libc/musl/src/exit/at_quick_exit.c @@ -5,7 +5,7 @@ static void (*funcs[COUNT])(void); static int count; -static int lock[2]; +static volatile int lock[2]; void __funcs_on_quick_exit() { diff --git a/system/lib/libc/musl/src/exit/atexit.c b/system/lib/libc/musl/src/exit/atexit.c index 89ff4ff35a30e..2b58b8bbf7416 100644 --- a/system/lib/libc/musl/src/exit/atexit.c +++ b/system/lib/libc/musl/src/exit/atexit.c @@ -12,18 +12,16 @@ static struct fl void *a[COUNT]; } builtin, *head; -static int lock[2]; +static int slot; +static volatile int lock[2]; void __funcs_on_exit() { - int i; void (*func)(void *), *arg; LOCK(lock); - for (; head; head=head->next) for (i=COUNT-1; i>=0; i--) { - if (!head->f[i]) continue; - func = head->f[i]; - arg = head->a[i]; - head->f[i] = 0; + for (; head; head=head->next, slot=COUNT) while(slot-->0) { + func = head->f[slot]; + arg = head->a[slot]; UNLOCK(lock); func(arg); LOCK(lock); @@ -36,15 +34,13 @@ void __cxa_finalize(void *dso) int __cxa_atexit(void (*func)(void *), void *arg, void *dso) { - int i; - LOCK(lock); /* Defer initialization of head so it can be in BSS */ if (!head) head = &builtin; /* If the current function list is full, add a new one */ - if (head->f[COUNT-1]) { + if (slot==COUNT) { struct fl *new_fl = calloc(sizeof(struct fl), 1); if (!new_fl) { UNLOCK(lock); @@ -52,12 +48,13 @@ int __cxa_atexit(void (*func)(void *), void *arg, void *dso) } new_fl->next = head; head = new_fl; + slot = 0; } /* Append function to the list. */ - for (i=0; if[i]; i++); - head->f[i] = func; - head->a[i] = arg; + head->f[slot] = func; + head->a[slot] = arg; + slot++; UNLOCK(lock); return 0; diff --git a/system/lib/libc/musl/src/exit/exit.c b/system/lib/libc/musl/src/exit/exit.c index f8e7668907499..bf7835a15cd2d 100644 --- a/system/lib/libc/musl/src/exit/exit.c +++ b/system/lib/libc/musl/src/exit/exit.c @@ -1,8 +1,6 @@ #include #include #include "libc.h" -#include "atomic.h" -#include "syscall.h" static void dummy() { @@ -12,31 +10,25 @@ static void dummy() * as a consequence of linking either __toread.c or __towrite.c. */ weak_alias(dummy, __funcs_on_exit); weak_alias(dummy, __stdio_exit); - -#ifndef SHARED weak_alias(dummy, _fini); -extern void (*const __fini_array_start)() __attribute__((weak)); -extern void (*const __fini_array_end)() __attribute__((weak)); -#endif - -_Noreturn void exit(int code) -{ - static int lock; - /* If more than one thread calls exit, hang until _Exit ends it all */ - while (a_swap(&lock, 1)) __syscall(SYS_pause); +__attribute__((__weak__, __visibility__("hidden"))) +extern void (*const __fini_array_start)(void), (*const __fini_array_end)(void); - __funcs_on_exit(); - -#ifndef SHARED +static void libc_exit_fini(void) +{ uintptr_t a = (uintptr_t)&__fini_array_end; for (; a>(uintptr_t)&__fini_array_start; a-=sizeof(void(*)())) (*(void (**)())(a-sizeof(void(*)())))(); _fini(); -#endif +} - __stdio_exit(); +weak_alias(libc_exit_fini, __libc_exit_fini); +_Noreturn void exit(int code) +{ + __funcs_on_exit(); + __libc_exit_fini(); + __stdio_exit(); _Exit(code); - for(;;); } diff --git a/system/lib/libc/musl/src/exit/quick_exit.c b/system/lib/libc/musl/src/exit/quick_exit.c index 1175d80cc49d3..ada91348bf659 100644 --- a/system/lib/libc/musl/src/exit/quick_exit.c +++ b/system/lib/libc/musl/src/exit/quick_exit.c @@ -1,6 +1,4 @@ #include -#include "syscall.h" -#include "atomic.h" #include "libc.h" static void dummy() { } @@ -8,8 +6,6 @@ weak_alias(dummy, __funcs_on_quick_exit); _Noreturn void quick_exit(int code) { - static int lock; - while (a_swap(&lock, 1)) __syscall(SYS_pause); __funcs_on_quick_exit(); _Exit(code); } diff --git a/system/lib/libc/musl/src/fcntl/fcntl.c b/system/lib/libc/musl/src/fcntl/fcntl.c index 2c4f5351b38b6..ce615d0e5dcce 100644 --- a/system/lib/libc/musl/src/fcntl/fcntl.c +++ b/system/lib/libc/musl/src/fcntl/fcntl.c @@ -39,7 +39,6 @@ int fcntl(int fd, int cmd, ...) } switch (cmd) { case F_SETLK: - case F_SETLKW: case F_GETLK: case F_GETOWN_EX: case F_SETOWN_EX: diff --git a/system/lib/libc/musl/src/fcntl/open.c b/system/lib/libc/musl/src/fcntl/open.c index be442089a894a..3928a6e6696f0 100644 --- a/system/lib/libc/musl/src/fcntl/open.c +++ b/system/lib/libc/musl/src/fcntl/open.c @@ -5,12 +5,20 @@ int open(const char *filename, int flags, ...) { - mode_t mode; - va_list ap; - va_start(ap, flags); - mode = va_arg(ap, mode_t); - va_end(ap); - return syscall_cp(SYS_open, filename, flags|O_LARGEFILE, mode); + mode_t mode = 0; + + if ((flags & O_CREAT) || (flags & O_TMPFILE) == O_TMPFILE) { + va_list ap; + va_start(ap, flags); + mode = va_arg(ap, mode_t); + va_end(ap); + } + + int fd = __sys_open_cp(filename, flags, mode); + if (fd>=0 && (flags & O_CLOEXEC)) + __syscall(SYS_fcntl, fd, F_SETFD, FD_CLOEXEC); + + return __syscall_ret(fd); } LFS64(open); diff --git a/system/lib/libc/musl/src/fcntl/posix_fadvise.c b/system/lib/libc/musl/src/fcntl/posix_fadvise.c index 2aa4d51125a84..c1a0ef5a2079d 100644 --- a/system/lib/libc/musl/src/fcntl/posix_fadvise.c +++ b/system/lib/libc/musl/src/fcntl/posix_fadvise.c @@ -4,9 +4,12 @@ int posix_fadvise(int fd, off_t base, off_t len, int advice) { -#ifndef __EMSCRIPTEN__ - return -(__syscall)(SYS_fadvise, fd, __SYSCALL_LL_O(base), - __SYSCALL_LL_E(len), advice); +#if defined(SYSCALL_FADVISE_6_ARG) + /* Some archs, at least arm and powerpc, have the syscall + * arguments reordered to avoid needing 7 argument registers + * due to 64-bit argument alignment. */ + return -__syscall(SYS_fadvise, fd, advice, + __SYSCALL_LL_E(base), __SYSCALL_LL_E(len)); #else return -__syscall(SYS_fadvise, fd, __SYSCALL_LL_O(base), __SYSCALL_LL_E(len), advice); diff --git a/system/lib/libc/musl/src/fenv/__flt_rounds.c b/system/lib/libc/musl/src/fenv/__flt_rounds.c new file mode 100644 index 0000000000000..ec0b3689e5ca2 --- /dev/null +++ b/system/lib/libc/musl/src/fenv/__flt_rounds.c @@ -0,0 +1,19 @@ +#include +#include + +int __flt_rounds() +{ + switch (fegetround()) { +#ifdef FE_TOWARDZERO + case FE_TOWARDZERO: return 0; +#endif + case FE_TONEAREST: return 1; +#ifdef FE_UPWARD + case FE_UPWARD: return 2; +#endif +#ifdef FE_DOWNWARD + case FE_DOWNWARD: return 3; +#endif + } + return -1; +} diff --git a/system/lib/libc/musl/src/internal/atomic.h b/system/lib/libc/musl/src/internal/atomic.h new file mode 100644 index 0000000000000..6f37d252cfec3 --- /dev/null +++ b/system/lib/libc/musl/src/internal/atomic.h @@ -0,0 +1,293 @@ +#ifndef _ATOMIC_H +#define _ATOMIC_H + +#include + +#include "atomic_arch.h" + +#ifdef a_ll + +#ifndef a_pre_llsc +#define a_pre_llsc() +#endif + +#ifndef a_post_llsc +#define a_post_llsc() +#endif + +#ifndef a_cas +#define a_cas a_cas +static inline int a_cas(volatile int *p, int t, int s) +{ + int old; + a_pre_llsc(); + do old = a_ll(p); + while (old==t && !a_sc(p, s)); + a_post_llsc(); + return old; +} +#endif + +#ifndef a_swap +#define a_swap a_swap +static inline int a_swap(volatile int *p, int v) +{ + int old; + a_pre_llsc(); + do old = a_ll(p); + while (!a_sc(p, v)); + a_post_llsc(); + return old; +} +#endif + +#ifndef a_fetch_add +#define a_fetch_add a_fetch_add +static inline int a_fetch_add(volatile int *p, int v) +{ + int old; + a_pre_llsc(); + do old = a_ll(p); + while (!a_sc(p, (unsigned)old + v)); + a_post_llsc(); + return old; +} +#endif + +#ifndef a_fetch_and +#define a_fetch_and a_fetch_and +static inline int a_fetch_and(volatile int *p, int v) +{ + int old; + a_pre_llsc(); + do old = a_ll(p); + while (!a_sc(p, old & v)); + a_post_llsc(); + return old; +} +#endif + +#ifndef a_fetch_or +#define a_fetch_or a_fetch_or +static inline int a_fetch_or(volatile int *p, int v) +{ + int old; + a_pre_llsc(); + do old = a_ll(p); + while (!a_sc(p, old | v)); + a_post_llsc(); + return old; +} +#endif + +#endif + +#ifdef a_ll_p + +#ifndef a_cas_p +#define a_cas_p a_cas_p +static inline void *a_cas_p(volatile void *p, void *t, void *s) +{ + void *old; + a_pre_llsc(); + do old = a_ll_p(p); + while (old==t && !a_sc_p(p, s)); + a_post_llsc(); + return old; +} +#endif + +#endif + +#ifndef a_cas +#error missing definition of a_cas +#endif + +#ifndef a_swap +#define a_swap a_swap +static inline int a_swap(volatile int *p, int v) +{ + int old; + do old = *p; + while (a_cas(p, old, v) != old); + return old; +} +#endif + +#ifndef a_fetch_add +#define a_fetch_add a_fetch_add +static inline int a_fetch_add(volatile int *p, int v) +{ + int old; + do old = *p; + while (a_cas(p, old, (unsigned)old+v) != old); + return old; +} +#endif + +#ifndef a_fetch_and +#define a_fetch_and a_fetch_and +static inline int a_fetch_and(volatile int *p, int v) +{ + int old; + do old = *p; + while (a_cas(p, old, old&v) != old); + return old; +} +#endif +#ifndef a_fetch_or +#define a_fetch_or a_fetch_or +static inline int a_fetch_or(volatile int *p, int v) +{ + int old; + do old = *p; + while (a_cas(p, old, old|v) != old); + return old; +} +#endif + +#ifndef a_and +#define a_and a_and +static inline void a_and(volatile int *p, int v) +{ + a_fetch_and(p, v); +} +#endif + +#ifndef a_or +#define a_or a_or +static inline void a_or(volatile int *p, int v) +{ + a_fetch_or(p, v); +} +#endif + +#ifndef a_inc +#define a_inc a_inc +static inline void a_inc(volatile int *p) +{ + a_fetch_add(p, 1); +} +#endif + +#ifndef a_dec +#define a_dec a_dec +static inline void a_dec(volatile int *p) +{ + a_fetch_add(p, -1); +} +#endif + +#ifndef a_store +#define a_store a_store +static inline void a_store(volatile int *p, int v) +{ +#ifdef a_barrier + a_barrier(); + *p = v; + a_barrier(); +#else + a_swap(p, v); +#endif +} +#endif + +#ifndef a_barrier +#define a_barrier a_barrier +static void a_barrier() +{ + volatile int tmp = 0; + a_cas(&tmp, 0, 0); +} +#endif + +#ifndef a_spin +#define a_spin a_barrier +#endif + +#ifndef a_and_64 +#define a_and_64 a_and_64 +static inline void a_and_64(volatile uint64_t *p, uint64_t v) +{ + union { uint64_t v; uint32_t r[2]; } u = { v }; + if (u.r[0]+1) a_and((int *)p, u.r[0]); + if (u.r[1]+1) a_and((int *)p+1, u.r[1]); +} +#endif + +#ifndef a_or_64 +#define a_or_64 a_or_64 +static inline void a_or_64(volatile uint64_t *p, uint64_t v) +{ + union { uint64_t v; uint32_t r[2]; } u = { v }; + if (u.r[0]) a_or((int *)p, u.r[0]); + if (u.r[1]) a_or((int *)p+1, u.r[1]); +} +#endif + +#ifndef a_cas_p +typedef char a_cas_p_undefined_but_pointer_not_32bit[-sizeof(char) == 0xffffffff ? 1 : -1]; +#define a_cas_p a_cas_p +static inline void *a_cas_p(volatile void *p, void *t, void *s) +{ + return (void *)a_cas((volatile int *)p, (int)t, (int)s); +} +#endif + +#ifndef a_or_l +#define a_or_l a_or_l +static inline void a_or_l(volatile void *p, long v) +{ + if (sizeof(long) == sizeof(int)) a_or(p, v); + else a_or_64(p, v); +} +#endif + +#ifndef a_crash +#define a_crash a_crash +static inline void a_crash() +{ + *(volatile char *)0=0; +} +#endif + +#ifndef a_ctz_64 +#define a_ctz_64 a_ctz_64 +static inline int a_ctz_64(uint64_t x) +{ + static const char debruijn64[64] = { + 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28, + 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11, + 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10, + 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12 + }; + static const char debruijn32[32] = { + 0, 1, 23, 2, 29, 24, 19, 3, 30, 27, 25, 11, 20, 8, 4, 13, + 31, 22, 28, 18, 26, 10, 7, 12, 21, 17, 9, 6, 16, 5, 15, 14 + }; + if (sizeof(long) < 8) { + uint32_t y = x; + if (!y) { + y = x>>32; + return 32 + debruijn32[(y&-y)*0x076be629 >> 27]; + } + return debruijn32[(y&-y)*0x076be629 >> 27]; + } + return debruijn64[(x&-x)*0x022fdd63cc95386dull >> 58]; +} +#endif + +#ifndef a_ctz_l +#define a_ctz_l a_ctz_l +static inline int a_ctz_l(unsigned long x) +{ + static const char debruijn32[32] = { + 0, 1, 23, 2, 29, 24, 19, 3, 30, 27, 25, 11, 20, 8, 4, 13, + 31, 22, 28, 18, 26, 10, 7, 12, 21, 17, 9, 6, 16, 5, 15, 14 + }; + if (sizeof(long) == 8) return a_ctz_64(x); + return debruijn32[(x&-x)*0x076be629 >> 27]; +} +#endif + +#endif diff --git a/system/lib/libc/musl/src/internal/dynlink.h b/system/lib/libc/musl/src/internal/dynlink.h new file mode 100644 index 0000000000000..5717627a53575 --- /dev/null +++ b/system/lib/libc/musl/src/internal/dynlink.h @@ -0,0 +1,98 @@ +#ifndef _INTERNAL_RELOC_H +#define _INTERNAL_RELOC_H + +#include +#include +#include + +#if UINTPTR_MAX == 0xffffffff +typedef Elf32_Ehdr Ehdr; +typedef Elf32_Phdr Phdr; +typedef Elf32_Sym Sym; +#define R_TYPE(x) ((x)&255) +#define R_SYM(x) ((x)>>8) +#define R_INFO ELF32_R_INFO +#else +typedef Elf64_Ehdr Ehdr; +typedef Elf64_Phdr Phdr; +typedef Elf64_Sym Sym; +#define R_TYPE(x) ((x)&0x7fffffff) +#define R_SYM(x) ((x)>>32) +#define R_INFO ELF64_R_INFO +#endif + +/* These enum constants provide unmatchable default values for + * any relocation type the arch does not use. */ +enum { + REL_NONE = 0, + REL_SYMBOLIC = -100, + REL_GOT, + REL_PLT, + REL_RELATIVE, + REL_OFFSET, + REL_OFFSET32, + REL_COPY, + REL_SYM_OR_REL, + REL_DTPMOD, + REL_DTPOFF, + REL_TPOFF, + REL_TPOFF_NEG, + REL_TLSDESC, + REL_FUNCDESC, + REL_FUNCDESC_VAL, +}; + +struct fdpic_loadseg { + uintptr_t addr, p_vaddr, p_memsz; +}; + +struct fdpic_loadmap { + unsigned short version, nsegs; + struct fdpic_loadseg segs[]; +}; + +struct fdpic_dummy_loadmap { + unsigned short version, nsegs; + struct fdpic_loadseg segs[1]; +}; + +#include "reloc.h" + +#ifndef FDPIC_CONSTDISP_FLAG +#define FDPIC_CONSTDISP_FLAG 0 +#endif + +#ifndef DL_FDPIC +#define DL_FDPIC 0 +#endif + +#ifndef DL_NOMMU_SUPPORT +#define DL_NOMMU_SUPPORT 0 +#endif + +#if !DL_FDPIC +#define IS_RELATIVE(x,s) ( \ + (R_TYPE(x) == REL_RELATIVE) || \ + (R_TYPE(x) == REL_SYM_OR_REL && !R_SYM(x)) ) +#else +#define IS_RELATIVE(x,s) ( ( \ + (R_TYPE(x) == REL_FUNCDESC_VAL) || \ + (R_TYPE(x) == REL_SYMBOLIC) ) \ + && (((s)[R_SYM(x)].st_info & 0xf) == STT_SECTION) ) +#endif + +#ifndef NEED_MIPS_GOT_RELOCS +#define NEED_MIPS_GOT_RELOCS 0 +#endif + +#ifndef DT_DEBUG_INDIRECT +#define DT_DEBUG_INDIRECT 0 +#endif + +#define AUX_CNT 32 +#define DYN_CNT 32 + +typedef void (*stage2_func)(unsigned char *, size_t *); +typedef _Noreturn void (*stage3_func)(size_t *); + +#endif diff --git a/system/lib/libc/musl/src/internal/fdpic_crt.h b/system/lib/libc/musl/src/internal/fdpic_crt.h new file mode 100644 index 0000000000000..7eb50c6bd12a3 --- /dev/null +++ b/system/lib/libc/musl/src/internal/fdpic_crt.h @@ -0,0 +1,28 @@ +#include + +__attribute__((__visibility__("hidden"))) +void *__fdpic_fixup(void *map, uintptr_t *a, uintptr_t *z) +{ + /* If map is a null pointer, the program was loaded by a + * non-FDPIC-aware ELF loader, and fixups are not needed, + * but the value for the GOT pointer is. */ + if (!map) return (void *)z[-1]; + + struct { + unsigned short version, nsegs; + struct fdpic_loadseg { + uintptr_t addr, p_vaddr, p_memsz; + } segs[]; + } *lm = map; + int nsegs = lm->nsegs, rseg = 0, vseg = 0; + for (;;) { + while (*a-lm->segs[rseg].p_vaddr >= lm->segs[rseg].p_memsz) + if (++rseg == nsegs) rseg = 0; + uintptr_t *r = (uintptr_t *) + (*a + lm->segs[rseg].addr - lm->segs[rseg].p_vaddr); + if (++a == z) return r; + while (*r-lm->segs[vseg].p_vaddr >= lm->segs[vseg].p_memsz) + if (++vseg == nsegs) vseg = 0; + *r += lm->segs[vseg].addr - lm->segs[vseg].p_vaddr; + } +} diff --git a/system/lib/libc/musl/src/internal/floatscan.c b/system/lib/libc/musl/src/internal/floatscan.c index f6e331d45d52d..eef70df9d6bc0 100644 --- a/system/lib/libc/musl/src/internal/floatscan.c +++ b/system/lib/libc/musl/src/internal/floatscan.c @@ -15,12 +15,20 @@ #define LD_B1B_MAX 9007199, 254740991 #define KMAX 128 -#else /* LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 */ +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 #define LD_B1B_DIG 3 #define LD_B1B_MAX 18, 446744073, 709551615 #define KMAX 2048 +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 + +#define LD_B1B_DIG 4 +#define LD_B1B_MAX 10384593, 717069655, 257060992, 658440191 +#define KMAX 2048 + +#else +#error Unsupported long double representation #endif #define MASK (KMAX-1) diff --git a/system/lib/libc/musl/src/internal/futex.h b/system/lib/libc/musl/src/internal/futex.h index d7bf2b7d4aad4..cf4c79513e240 100644 --- a/system/lib/libc/musl/src/internal/futex.h +++ b/system/lib/libc/musl/src/internal/futex.h @@ -12,6 +12,8 @@ #define FUTEX_TRYLOCK_PI 8 #define FUTEX_WAIT_BITSET 9 +#define FUTEX_PRIVATE 128 + #define FUTEX_CLOCK_REALTIME 256 int __futex(volatile int *, int, int, void *); diff --git a/system/lib/libc/musl/src/internal/ksigaction.h b/system/lib/libc/musl/src/internal/ksigaction.h index 2eacabf1138e1..1d8d9646149b6 100644 --- a/system/lib/libc/musl/src/internal/ksigaction.h +++ b/system/lib/libc/musl/src/internal/ksigaction.h @@ -7,3 +7,5 @@ struct k_sigaction { void (*restorer)(void); unsigned mask[2]; }; + +void __restore(), __restore_rt(); diff --git a/system/lib/libc/musl/src/internal/libc.c b/system/lib/libc/musl/src/internal/libc.c index 942f6b4484368..8c4139c1f5e70 100644 --- a/system/lib/libc/musl/src/internal/libc.c +++ b/system/lib/libc/musl/src/internal/libc.c @@ -1,18 +1,6 @@ #include "libc.h" -#ifdef USE_LIBC_ACCESSOR -struct __libc *__libc_loc() -{ - static struct __libc __libc; - return &__libc; -} -#else struct __libc __libc; -#endif - -#ifdef BROKEN_VISIBILITY -__asm__(".hidden __libc"); -#endif size_t __hwcap; size_t __sysinfo; @@ -20,3 +8,10 @@ char *__progname=0, *__progname_full=0; weak_alias(__progname, program_invocation_short_name); weak_alias(__progname_full, program_invocation_name); + +#ifdef __EMSCRIPTEN__ +#include +struct __libc* EMSCRIPTEN_KEEPALIVE emscripten_get_global_libc() { + return &libc; +} +#endif diff --git a/system/lib/libc/musl/src/internal/libc.h b/system/lib/libc/musl/src/internal/libc.h index d625b56afc3ab..5e14518312c77 100644 --- a/system/lib/libc/musl/src/internal/libc.h +++ b/system/lib/libc/musl/src/internal/libc.h @@ -5,31 +5,35 @@ #include #include +struct __locale_map; + +struct __locale_struct { + const struct __locale_map *volatile cat[6]; +}; + +struct tls_module { + struct tls_module *next; + void *image; + size_t len, size, align, offset; +}; + struct __libc { - void *main_thread; + int can_do_threads; int threaded; int secure; - size_t *auxv; volatile int threads_minus_1; - int canceldisable; - FILE *ofl_head; - int ofl_lock[2]; - size_t tls_size; + size_t *auxv; + struct tls_module *tls_head; + size_t tls_size, tls_align, tls_cnt; size_t page_size; + struct __locale_struct global_locale; }; -extern size_t __hwcap; - #ifndef PAGE_SIZE #define PAGE_SIZE libc.page_size #endif -#if !defined(__PIC__) || (100*__GNUC__+__GNUC_MINOR__ >= 303 && !defined(__PCC__)) - #ifdef __PIC__ -#if __GNUC__ < 4 -#define BROKEN_VISIBILITY 1 -#endif #define ATTR_LIBC_VISIBILITY __attribute__((visibility("hidden"))) #else #define ATTR_LIBC_VISIBILITY @@ -38,15 +42,9 @@ extern size_t __hwcap; extern struct __libc __libc ATTR_LIBC_VISIBILITY; #define libc __libc -#else - -#define USE_LIBC_ACCESSOR -#define ATTR_LIBC_VISIBILITY -extern struct __libc *__libc_loc(void) __attribute__((const)); -#define libc (*__libc_loc()) - -#endif - +extern size_t __hwcap ATTR_LIBC_VISIBILITY; +extern size_t __sysinfo ATTR_LIBC_VISIBILITY; +extern char *__progname, *__progname_full; /* Designed to avoid any overhead in non-threaded processes */ void __lock(volatile int *) ATTR_LIBC_VISIBILITY; diff --git a/system/lib/libc/musl/src/internal/libm.h b/system/lib/libc/musl/src/internal/libm.h index d9ca4dd0c11b2..6a3aaed5610ed 100644 --- a/system/lib/libc/musl/src/internal/libm.h +++ b/system/lib/libc/musl/src/internal/libm.h @@ -42,6 +42,20 @@ union ldshape { uint64_t hi; } i2; }; +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __BIG_ENDIAN +union ldshape { + long double f; + struct { + uint16_t se; + uint16_t top; + uint32_t mid; + uint64_t lo; + } i; + struct { + uint64_t hi; + uint64_t lo; + } i2; +}; #else #error Unsupported long double representation #endif @@ -136,6 +150,18 @@ do { \ (d) = __u.f; \ } while (0) +#undef __CMPLX +#undef CMPLX +#undef CMPLXF +#undef CMPLXL + +#define __CMPLX(x, y, t) \ + ((union { _Complex t __z; t __xy[2]; }){.__xy = {(x),(y)}}.__z) + +#define CMPLX(x, y) __CMPLX(x, y, double) +#define CMPLXF(x, y) __CMPLX(x, y, float) +#define CMPLXL(x, y) __CMPLX(x, y, long double) + /* fdlibm kernel functions */ int __rem_pio2_large(double*,double*,int,int,int); diff --git a/system/lib/libc/musl/src/internal/locale_impl.h b/system/lib/libc/musl/src/internal/locale_impl.h index f41c6f24513c9..f5e4d9b4ae003 100644 --- a/system/lib/libc/musl/src/internal/locale_impl.h +++ b/system/lib/libc/musl/src/internal/locale_impl.h @@ -1,5 +1,40 @@ +#ifndef _LOCALE_IMPL_H +#define _LOCALE_IMPL_H + #include +#include +#include "libc.h" +#include "pthread_impl.h" + +#define LOCALE_NAME_MAX 15 -struct __locale_struct { - int dummy; +struct __locale_map { + const void *map; + size_t map_size; + char name[LOCALE_NAME_MAX+1]; + const struct __locale_map *next; }; + +extern const struct __locale_map __c_dot_utf8; +extern const struct __locale_struct __c_locale; +extern const struct __locale_struct __c_dot_utf8_locale; + +const struct __locale_map *__get_locale(int, const char *); +const char *__mo_lookup(const void *, size_t, const char *); +const char *__lctrans(const char *, const struct __locale_map *); +const char *__lctrans_cur(const char *); + +#define LCTRANS(msg, lc, loc) __lctrans(msg, (loc)->cat[(lc)]) +#define LCTRANS_CUR(msg) __lctrans_cur(msg) + +#define C_LOCALE ((locale_t)&__c_locale) +#define UTF8_LOCALE ((locale_t)&__c_dot_utf8_locale) + +#define CURRENT_LOCALE (__pthread_self()->locale) + +#define CURRENT_UTF8 (!!__pthread_self()->locale->cat[LC_CTYPE]) + +#undef MB_CUR_MAX +#define MB_CUR_MAX (CURRENT_UTF8 ? 4 : 1) + +#endif diff --git a/system/lib/libc/musl/src/internal/pthread_impl.h b/system/lib/libc/musl/src/internal/pthread_impl.h index c5169583beaf6..059206b52fdec 100644 --- a/system/lib/libc/musl/src/internal/pthread_impl.h +++ b/system/lib/libc/musl/src/internal/pthread_impl.h @@ -10,9 +10,8 @@ #include "atomic.h" #ifdef __EMSCRIPTEN__ #include -#else -#include "futex.h" #endif +#include "futex.h" #define pthread __pthread @@ -30,9 +29,9 @@ struct pthread { struct pthread *self; void **dtv, *unused1, *unused2; uintptr_t sysinfo; - uintptr_t canary; + uintptr_t canary, canary2; pid_t tid, pid; - int tsd_used, errno_val, *errno_ptr; + int tsd_used, errno_val; volatile int cancel, canceldisable, cancelasync; int detached; unsigned char *map_base; @@ -47,17 +46,22 @@ struct pthread { pthread_attr_t attr; volatile int dead; struct { - void **head; + volatile void *volatile head; long off; - void *pending; + volatile void *volatile pending; } robust_list; int unblock_cancel; - int timer_id; + volatile int timer_id; locale_t locale; - int killlock[2]; - int exitlock[2]; - int startlock[2]; + volatile int killlock[2]; + volatile int exitlock[2]; + volatile int startlock[2]; unsigned long sigmask[_NSIG/8/sizeof(long)]; + char *dlerror_buf; + int dlerror_flag; + void *stdio_locks; + uintptr_t canary_at_end; + void **dtv_copy; }; struct __timer { @@ -75,39 +79,47 @@ struct __timer { #define _a_policy __u.__i[3*__SU+2] #define _a_prio __u.__i[3*__SU+3] #define _m_type __u.__i[0] -#define _m_lock __u.__i[1] -#define _m_waiters __u.__i[2] +#define _m_lock __u.__vi[1] +#define _m_waiters __u.__vi[2] #define _m_prev __u.__p[3] #define _m_next __u.__p[4] #define _m_count __u.__i[5] #ifdef __EMSCRIPTEN__ -#define _m_addr __u.__i[6] +#define _m_addr __u.__i[7] #endif -#define _c_mutex __u.__p[0] -#define _c_seq __u.__i[2] -#define _c_waiters __u.__i[3] +#define _c_shared __u.__p[0] +#define _c_seq __u.__vi[2] +#define _c_waiters __u.__vi[3] #define _c_clock __u.__i[4] -#define _c_lock __u.__i[5] -#define _c_lockwait __u.__i[6] -#define _c_waiters2 __u.__i[7] -#define _c_destroy __u.__i[8] -#define _rw_lock __u.__i[0] -#define _rw_waiters __u.__i[1] +#define _c_lock __u.__vi[8] +#define _c_head __u.__p[1] +#define _c_tail __u.__p[5] +#define _rw_lock __u.__vi[0] +#define _rw_waiters __u.__vi[1] +#define _rw_shared __u.__i[2] #ifdef __EMSCRIPTEN__ // XXX Emscripten: The spec allows detecting when multiple write locks would deadlock, so use an extra field // _rw_wr_owner to record which thread owns the write lock in order to avoid hangs. // Points to the pthread that currently has the write lock. -#define _rw_wr_owner __u.__i[2] +#define _rw_wr_owner __u.__vi[3] #endif -#define _b_lock __u.__i[0] -#define _b_waiters __u.__i[1] +#define _b_lock __u.__vi[0] +#define _b_waiters __u.__vi[1] #define _b_limit __u.__i[2] -#define _b_count __u.__i[3] -#define _b_waiters2 __u.__i[4] +#define _b_count __u.__vi[3] +#define _b_waiters2 __u.__vi[4] #define _b_inst __u.__p[3] #include "pthread_arch.h" +#ifndef CANARY +#define CANARY canary +#endif + +#ifndef DTP_OFFSET +#define DTP_OFFSET 0 +#endif + #define SIGTIMER 32 #define SIGCANCEL 33 #define SIGSYNCCALL 34 @@ -129,19 +141,28 @@ int __libc_sigprocmask(int, const sigset_t *, sigset_t *); void __lock(volatile int *); void __unmapself(void *, size_t); -int __timedwait(volatile int *, int, clockid_t, const struct timespec *, void (*)(void *), void *, int); -void __wait(volatile int *, volatile int *, int, int); +void __vm_wait(void); +void __vm_lock(void); +void __vm_unlock(void); +int __timedwait(volatile int *, int, clockid_t, const struct timespec *, int); +int __timedwait_cp(volatile int *, int, clockid_t, const struct timespec *, int); +void __wait(volatile int *, volatile int *, int, int); +static inline void __wake(volatile void *addr, int cnt, int priv) +{ + if (priv) priv = 128; + if (cnt<0) cnt = INT_MAX; #ifdef __EMSCRIPTEN__ -#define __wake(addr, cnt, priv) emscripten_futex_wake((void*)addr, (cnt)<0?INT_MAX:(cnt)) + emscripten_futex_wake(addr, (cnt)<0?INT_MAX:(cnt)); #else -#define __wake(addr, cnt, priv) \ - __syscall(SYS_futex, addr, FUTEX_WAKE, (cnt)<0?INT_MAX:(cnt)) + __syscall(SYS_futex, addr, FUTEX_WAKE|priv, cnt) != -ENOSYS || + __syscall(SYS_futex, addr, FUTEX_WAKE, cnt); #endif +} -void __acquire_ptc(); -void __release_ptc(); -void __inhibit_ptc(); +void __acquire_ptc(void); +void __release_ptc(void); +void __inhibit_ptc(void); void __block_all_sigs(void *); void __block_app_sigs(void *); @@ -150,4 +171,12 @@ void __restore_sigs(void *); #define DEFAULT_STACK_SIZE 81920 #define DEFAULT_GUARD_SIZE PAGE_SIZE +#define __ATTRP_C11_THREAD ((void*)(uintptr_t)-1) + +#ifdef __EMSCRIPTEN__ +void __emscripten_init_pthread(pthread_t thread); +#if !__EMSCRIPTEN_PTHREADS__ +pthread_t __emscripten_pthread_stub(void); +#endif +#endif #endif diff --git a/system/lib/libc/musl/src/internal/stdio_impl.h b/system/lib/libc/musl/src/internal/stdio_impl.h index 79be9fdb0d49c..7cdf729de8e7e 100644 --- a/system/lib/libc/musl/src/internal/stdio_impl.h +++ b/system/lib/libc/musl/src/internal/stdio_impl.h @@ -38,14 +38,16 @@ struct _IO_FILE { short dummy3; signed char mode; signed char lbf; - int lock; - int waiters; + volatile int lock; + volatile int waiters; void *cookie; off_t off; char *getln_buf; void *mustbezero_2; unsigned char *shend; off_t shlim, shcnt; + FILE *prev_locked, *next_locked; + struct __locale_struct *locale; }; size_t __stdio_read(FILE *, unsigned char *, size_t); @@ -74,8 +76,9 @@ int __putc_unlocked(int, FILE *); FILE *__fdopen(int, const char *); int __fmodeflags(const char *); -#define OFLLOCK() LOCK(libc.ofl_lock) -#define OFLUNLOCK() UNLOCK(libc.ofl_lock) +FILE *__ofl_add(FILE *f); +FILE **__ofl_lock(void); +void __ofl_unlock(void); #define feof(f) ((f)->flags & F_EOF) #define ferror(f) ((f)->flags & F_ERR) @@ -83,7 +86,8 @@ int __fmodeflags(const char *); #define getc_unlocked(f) \ ( ((f)->rpos < (f)->rend) ? *(f)->rpos++ : __uflow((f)) ) -#define putc_unlocked(c, f) ( ((c)!=(f)->lbf && (f)->wpos<(f)->wend) \ +#define putc_unlocked(c, f) \ + ( ((unsigned char)(c)!=(f)->lbf && (f)->wpos<(f)->wend) \ ? *(f)->wpos++ = (c) : __overflow((f),(c)) ) /* Caller-allocated FILE * operations */ diff --git a/system/lib/libc/musl/src/internal/syscall.h b/system/lib/libc/musl/src/internal/syscall.h index 6f16a061f5a7a..4ff4ae0da42e8 100644 --- a/system/lib/libc/musl/src/internal/syscall.h +++ b/system/lib/libc/musl/src/internal/syscall.h @@ -8,26 +8,49 @@ #define SYSCALL_RLIM_INFINITY (~0ULL) #endif +#ifndef SYSCALL_MMAP2_UNIT +#define SYSCALL_MMAP2_UNIT 4096ULL +#endif + #ifndef __scc #define __scc(X) ((long) (X)) typedef long syscall_arg_t; #endif -#if defined(__PIC__) && (100*__GNUC__+__GNUC_MINOR__ >= 303) __attribute__((visibility("hidden"))) -#endif long __syscall_ret(unsigned long), __syscall(syscall_arg_t, ...), __syscall_cp(syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t); #ifndef __EMSCRIPTEN__ +#ifdef SYSCALL_NO_INLINE +#define __syscall0(n) (__syscall)(n) +#define __syscall1(n,a) (__syscall)(n,__scc(a)) +#define __syscall2(n,a,b) (__syscall)(n,__scc(a),__scc(b)) +#define __syscall3(n,a,b,c) (__syscall)(n,__scc(a),__scc(b),__scc(c)) +#define __syscall4(n,a,b,c,d) (__syscall)(n,__scc(a),__scc(b),__scc(c),__scc(d)) +#define __syscall5(n,a,b,c,d,e) (__syscall)(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e)) +#define __syscall6(n,a,b,c,d,e,f) (__syscall)(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e),__scc(f)) +#else #define __syscall1(n,a) __syscall1(n,__scc(a)) #define __syscall2(n,a,b) __syscall2(n,__scc(a),__scc(b)) #define __syscall3(n,a,b,c) __syscall3(n,__scc(a),__scc(b),__scc(c)) #define __syscall4(n,a,b,c,d) __syscall4(n,__scc(a),__scc(b),__scc(c),__scc(d)) #define __syscall5(n,a,b,c,d,e) __syscall5(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e)) #define __syscall6(n,a,b,c,d,e,f) __syscall6(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e),__scc(f)) +#endif #define __syscall7(n,a,b,c,d,e,f,g) (__syscall)(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e),__scc(f),__scc(g)) +#else // __EMSCRIPTEN__ +#define __syscall_emscripten(n, ...) __syscall##n(n, ##__VA_ARGS__) +#define __syscall_emscripten0(n) __syscall_emscripten(n) +#define __syscall_emscripten1(n,a) __syscall_emscripten(n,__scc(a)) +#define __syscall_emscripten2(n,a,b) __syscall_emscripten(n,__scc(a),__scc(b)) +#define __syscall_emscripten3(n,a,b,c) __syscall_emscripten(n,__scc(a),__scc(b),__scc(c)) +#define __syscall_emscripten4(n,a,b,c,d) __syscall_emscripten(n,__scc(a),__scc(b),__scc(c),__scc(d)) +#define __syscall_emscripten5(n,a,b,c,d,e) __syscall_emscripten(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e)) +#define __syscall_emscripten6(n,a,b,c,d,e,f) __syscall_emscripten(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e),__scc(f)) +#define __syscall_emscripten7(n,a,b,c,d,e,f,g) __syscall_emscripten(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e),__scc(f),__scc(g)) +#endif // __EMSCRIPTEN__ #define __SYSCALL_NARGS_X(a,b,c,d,e,f,g,h,n,...) n #define __SYSCALL_NARGS(...) __SYSCALL_NARGS_X(__VA_ARGS__,7,6,5,4,3,2,1,0,) @@ -35,11 +58,11 @@ long __syscall_ret(unsigned long), __syscall(syscall_arg_t, ...), #define __SYSCALL_CONCAT(a,b) __SYSCALL_CONCAT_X(a,b) #define __SYSCALL_DISP(b,...) __SYSCALL_CONCAT(b,__SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__) +#ifndef __EMSCRIPTEN__ #define __syscall(...) __SYSCALL_DISP(__syscall,__VA_ARGS__) -#else // __EMSCRIPTEN__ -#define __syscall_emscripten(n, ...) __syscall##n(n, ##__VA_ARGS__) -#define __syscall(n, ...) __syscall_emscripten(n, ##__VA_ARGS__) -#endif // __EMSCRIPTEN__ +#else +#define __syscall(...) __SYSCALL_DISP(__syscall_emscripten,__VA_ARGS__) +#endif #define syscall(...) __syscall_ret(__syscall(__VA_ARGS__)) @@ -58,11 +81,12 @@ long __syscall_ret(unsigned long), __syscall(syscall_arg_t, ...), #define __syscall_cp(...) __SYSCALL_DISP(__syscall_cp,__VA_ARGS__) #else // __EMSCRIPTEN__ #define __syscall_cp(...) __syscall(__VA_ARGS__) +#define SYSCALL_USE_SOCKETCALL #endif // __EMSCRIPTEN__ #define syscall_cp(...) __syscall_ret(__syscall_cp(__VA_ARGS__)) -#ifdef SYS_socket +#ifndef SYSCALL_USE_SOCKETCALL #define __socketcall(nm,a,b,c,d,e,f) syscall(SYS_##nm, a, b, c, d, e, f) #define __socketcall_cp(nm,a,b,c,d,e,f) syscall_cp(SYS_##nm, a, b, c, d, e, f) #else @@ -137,14 +161,26 @@ long __syscall_ret(unsigned long), __syscall(syscall_arg_t, ...), #ifdef SYS_stat64 #undef SYS_stat -#undef SYS_fstat -#undef SYS_lstat -#undef SYS_statfs -#undef SYS_fstatfs #define SYS_stat SYS_stat64 +#endif + +#ifdef SYS_fstat64 +#undef SYS_fstat #define SYS_fstat SYS_fstat64 +#endif + +#ifdef SYS_lstat64 +#undef SYS_lstat #define SYS_lstat SYS_lstat64 +#endif + +#ifdef SYS_statfs64 +#undef SYS_statfs #define SYS_statfs SYS_statfs64 +#endif + +#ifdef SYS_fstatfs64 +#undef SYS_fstatfs #define SYS_fstatfs SYS_fstatfs64 #endif @@ -176,6 +212,9 @@ long __syscall_ret(unsigned long), __syscall(syscall_arg_t, ...), #ifdef SYS_fadvise64_64 #undef SYS_fadvise #define SYS_fadvise SYS_fadvise64_64 +#elif defined(SYS_fadvise64) +#undef SYS_fadvise +#define SYS_fadvise SYS_fadvise64 #endif #ifdef SYS_sendfile64 @@ -183,4 +222,51 @@ long __syscall_ret(unsigned long), __syscall(syscall_arg_t, ...), #define SYS_sendfile SYS_sendfile64 #endif +/* socketcall calls */ + +#define __SC_socket 1 +#define __SC_bind 2 +#define __SC_connect 3 +#define __SC_listen 4 +#define __SC_accept 5 +#define __SC_getsockname 6 +#define __SC_getpeername 7 +#define __SC_socketpair 8 +#define __SC_send 9 +#define __SC_recv 10 +#define __SC_sendto 11 +#define __SC_recvfrom 12 +#define __SC_shutdown 13 +#define __SC_setsockopt 14 +#define __SC_getsockopt 15 +#define __SC_sendmsg 16 +#define __SC_recvmsg 17 +#define __SC_accept4 18 +#define __SC_recvmmsg 19 +#define __SC_sendmmsg 20 + +#ifndef __EMSCRIPTEN__ +#ifdef SYS_open +#define __sys_open2(x,pn,fl) __syscall2(SYS_open, pn, (fl)|O_LARGEFILE) +#define __sys_open3(x,pn,fl,mo) __syscall3(SYS_open, pn, (fl)|O_LARGEFILE, mo) +#define __sys_open_cp2(x,pn,fl) __syscall_cp2(SYS_open, pn, (fl)|O_LARGEFILE) +#define __sys_open_cp3(x,pn,fl,mo) __syscall_cp3(SYS_open, pn, (fl)|O_LARGEFILE, mo) +#else +#define __sys_open2(x,pn,fl) __syscall3(SYS_openat, AT_FDCWD, pn, (fl)|O_LARGEFILE) +#define __sys_open3(x,pn,fl,mo) __syscall4(SYS_openat, AT_FDCWD, pn, (fl)|O_LARGEFILE, mo) +#define __sys_open_cp2(x,pn,fl) __syscall_cp3(SYS_openat, AT_FDCWD, pn, (fl)|O_LARGEFILE) +#define __sys_open_cp3(x,pn,fl,mo) __syscall_cp4(SYS_openat, AT_FDCWD, pn, (fl)|O_LARGEFILE, mo) +#endif +#else // __EMSCRIPTEN__ +#define __sys_open2(x,pn,fl) __SYSCALL_CONCAT(__syscall, SYS_open)(SYS_open, __scc(pn), __scc((fl)|O_LARGEFILE)) +#define __sys_open3(x,pn,fl,mo) __SYSCALL_CONCAT(__syscall, SYS_open)(SYS_open, __scc(pn), __scc((fl)|O_LARGEFILE), __scc(mo)) +#define __sys_open_cp2(x,pn,fl) __SYSCALL_CONCAT(__syscall, SYS_open)(SYS_open, __scc(pn), __scc((fl)|O_LARGEFILE)) +#define __sys_open_cp3(x,pn,fl,mo) __SYSCALL_CONCAT(__syscall, SYS_open)(SYS_open, __scc(pn), __scc((fl)|O_LARGEFILE), __scc(mo)) +#endif +#define __sys_open(...) __SYSCALL_DISP(__sys_open,,__VA_ARGS__) +#define sys_open(...) __syscall_ret(__sys_open(__VA_ARGS__)) + +#define __sys_open_cp(...) __SYSCALL_DISP(__sys_open_cp,,__VA_ARGS__) +#define sys_open_cp(...) __syscall_ret(__sys_open_cp(__VA_ARGS__)) + #endif diff --git a/system/lib/libc/musl/src/internal/vdso.c b/system/lib/libc/musl/src/internal/vdso.c new file mode 100644 index 0000000000000..6ae0212e5c1ee --- /dev/null +++ b/system/lib/libc/musl/src/internal/vdso.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include "libc.h" +#include "syscall.h" + +#ifdef VDSO_USEFUL + +#if ULONG_MAX == 0xffffffff +typedef Elf32_Ehdr Ehdr; +typedef Elf32_Phdr Phdr; +typedef Elf32_Sym Sym; +typedef Elf32_Verdef Verdef; +typedef Elf32_Verdaux Verdaux; +#else +typedef Elf64_Ehdr Ehdr; +typedef Elf64_Phdr Phdr; +typedef Elf64_Sym Sym; +typedef Elf64_Verdef Verdef; +typedef Elf64_Verdaux Verdaux; +#endif + +static int checkver(Verdef *def, int vsym, const char *vername, char *strings) +{ + vsym &= 0x7fff; + for (;;) { + if (!(def->vd_flags & VER_FLG_BASE) + && (def->vd_ndx & 0x7fff) == vsym) + break; + if (def->vd_next == 0) + return 0; + def = (Verdef *)((char *)def + def->vd_next); + } + Verdaux *aux = (Verdaux *)((char *)def + def->vd_aux); + return !strcmp(vername, strings + aux->vda_name); +} + +#define OK_TYPES (1<e_phoff); + size_t *dynv=0, base=-1; + for (i=0; ie_phnum; i++, ph=(void *)((char *)ph+eh->e_phentsize)) { + if (ph->p_type == PT_LOAD) + base = (size_t)eh + ph->p_offset - ph->p_vaddr; + else if (ph->p_type == PT_DYNAMIC) + dynv = (void *)((char *)eh + ph->p_offset); + } + if (!dynv || base==(size_t)-1) return 0; + + char *strings = 0; + Sym *syms = 0; + uint32_t *hashtab = 0; + uint16_t *versym = 0; + Verdef *verdef = 0; + + for (i=0; dynv[i]; i+=2) { + void *p = (void *)(base + dynv[i+1]); + switch(dynv[i]) { + case DT_STRTAB: strings = p; break; + case DT_SYMTAB: syms = p; break; + case DT_HASH: hashtab = p; break; + case DT_VERSYM: versym = p; break; + case DT_VERDEF: verdef = p; break; + } + } + + if (!strings || !syms || !hashtab) return 0; + if (!verdef) versym = 0; + + for (i=0; i>4) & OK_BINDS)) continue; + if (!syms[i].st_shndx) continue; + if (strcmp(name, strings+syms[i].st_name)) continue; + if (versym && !checkver(verdef, versym[i], vername, strings)) + continue; + return (void *)(base + syms[i].st_value); + } + + return 0; +} + +#endif diff --git a/system/lib/libc/musl/src/internal/version.c b/system/lib/libc/musl/src/internal/version.c index 16554ba226663..dc044ec4129fb 100644 --- a/system/lib/libc/musl/src/internal/version.c +++ b/system/lib/libc/musl/src/internal/version.c @@ -1,12 +1,9 @@ -#ifdef SHARED - #include "version.h" static const char version[] = VERSION; +__attribute__((__visibility__("hidden"))) const char *__libc_get_version() { return version; } - -#endif diff --git a/system/lib/libc/musl/src/internal/version.h b/system/lib/libc/musl/src/internal/version.h new file mode 100644 index 0000000000000..adb0653cec045 --- /dev/null +++ b/system/lib/libc/musl/src/internal/version.h @@ -0,0 +1 @@ +#define VERSION "1.1.15" diff --git a/system/lib/libc/musl/src/internal/vis.h b/system/lib/libc/musl/src/internal/vis.h new file mode 100644 index 0000000000000..35855fc8ab9fb --- /dev/null +++ b/system/lib/libc/musl/src/internal/vis.h @@ -0,0 +1,27 @@ +/* This file is only used if enabled in the build system, in which case it is + * included automatically via command line options. It is not included + * explicitly by any source files or other headers. Its purpose is to + * override default visibilities to reduce the size and performance costs + * of position-independent code. */ + +#if !defined(CRT) && !defined(__ASSEMBLER__) + +/* Conceptually, all symbols should be protected, but some toolchains + * fail to support copy relocations for protected data, so exclude all + * exported data symbols. */ + +__attribute__((__visibility__("default"))) +extern struct _IO_FILE *const stdin, *const stdout, *const stderr; + +__attribute__((__visibility__("default"))) +extern int optind, opterr, optopt, optreset, __optreset, getdate_err, h_errno, daylight, __daylight, signgam, __signgam; + +__attribute__((__visibility__("default"))) +extern long timezone, __timezone; + +__attribute__((__visibility__("default"))) +extern char *optarg, **environ, **__environ, *tzname[2], *__tzname[2], *__progname, *__progname_full; + +#pragma GCC visibility push(protected) + +#endif diff --git a/system/lib/libc/musl/src/ldso/__dlsym.c b/system/lib/libc/musl/src/ldso/__dlsym.c new file mode 100644 index 0000000000000..99aafdf91b95c --- /dev/null +++ b/system/lib/libc/musl/src/ldso/__dlsym.c @@ -0,0 +1,13 @@ +#include +#include "libc.h" + +__attribute__((__visibility__("hidden"))) +void __dl_seterr(const char *, ...); + +static void *stub_dlsym(void *restrict p, const char *restrict s, void *restrict ra) +{ + __dl_seterr("Symbol not found: %s", s); + return 0; +} + +weak_alias(stub_dlsym, __dlsym); diff --git a/system/lib/libc/musl/src/ldso/dl_iterate_phdr.c b/system/lib/libc/musl/src/ldso/dl_iterate_phdr.c index 49b321a0203cb..c141fd9b4f27f 100644 --- a/system/lib/libc/musl/src/ldso/dl_iterate_phdr.c +++ b/system/lib/libc/musl/src/ldso/dl_iterate_phdr.c @@ -1,12 +1,10 @@ -#ifndef SHARED - #include #include #include "libc.h" #define AUX_CNT 38 -int dl_iterate_phdr(int(*callback)(struct dl_phdr_info *info, size_t size, void *data), void *data) +static int static_dl_iterate_phdr(int(*callback)(struct dl_phdr_info *info, size_t size, void *data), void *data) { unsigned char *p; ElfW(Phdr) *phdr, *tls_phdr=0; @@ -40,4 +38,5 @@ int dl_iterate_phdr(int(*callback)(struct dl_phdr_info *info, size_t size, void } return (callback)(&info, sizeof (info), data); } -#endif + +weak_alias(static_dl_iterate_phdr, dl_iterate_phdr); diff --git a/system/lib/libc/musl/src/ldso/dladdr.c b/system/lib/libc/musl/src/ldso/dladdr.c index 7ca718f4fbf4c..659ab91e8a679 100644 --- a/system/lib/libc/musl/src/ldso/dladdr.c +++ b/system/lib/libc/musl/src/ldso/dladdr.c @@ -1,9 +1,10 @@ #define _GNU_SOURCE #include +#include "libc.h" -int __dladdr(const void *, Dl_info *); - -int dladdr(const void *addr, Dl_info *info) +static int stub_dladdr(const void *addr, Dl_info *info) { - return __dladdr(addr, info); + return 0; } + +weak_alias(stub_dladdr, dladdr); diff --git a/system/lib/libc/musl/src/ldso/dlclose.c b/system/lib/libc/musl/src/ldso/dlclose.c new file mode 100644 index 0000000000000..0ef22319decea --- /dev/null +++ b/system/lib/libc/musl/src/ldso/dlclose.c @@ -0,0 +1,9 @@ +#include + +__attribute__((__visibility__("hidden"))) +int __dl_invalid_handle(void *); + +int dlclose(void *p) +{ + return __dl_invalid_handle(p); +} diff --git a/system/lib/libc/musl/src/ldso/dlerror.c b/system/lib/libc/musl/src/ldso/dlerror.c new file mode 100644 index 0000000000000..378f035647c52 --- /dev/null +++ b/system/lib/libc/musl/src/ldso/dlerror.c @@ -0,0 +1,64 @@ +#include +#include +#include +#include "pthread_impl.h" +#include "libc.h" + +char *dlerror() +{ + pthread_t self = __pthread_self(); + if (!self->dlerror_flag) return 0; + self->dlerror_flag = 0; + char *s = self->dlerror_buf; + if (s == (void *)-1) + return "Dynamic linker failed to allocate memory for error message"; + else + return s; +} + +void __dl_thread_cleanup(void) +{ + pthread_t self = __pthread_self(); + if (self->dlerror_buf != (void *)-1) + free(self->dlerror_buf); +} + +__attribute__((__visibility__("hidden"))) +void __dl_vseterr(const char *fmt, va_list ap) +{ + va_list ap2; + va_copy(ap2, ap); + pthread_t self = __pthread_self(); + if (self->dlerror_buf != (void *)-1) + free(self->dlerror_buf); + size_t len = vsnprintf(0, 0, fmt, ap2); + va_end(ap2); + char *buf = malloc(len+1); + if (buf) { + vsnprintf(buf, len+1, fmt, ap); + } else { + buf = (void *)-1; + } + self->dlerror_buf = buf; + self->dlerror_flag = 1; +} + +__attribute__((__visibility__("hidden"))) +void __dl_seterr(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + __dl_vseterr(fmt, ap); + va_end(ap); +} + +__attribute__((__visibility__("hidden"))) +int __dl_invalid_handle(void *); + +static int stub_invalid_handle(void *h) +{ + __dl_seterr("Invalid library handle %p", (void *)h); + return 1; +} + +weak_alias(stub_invalid_handle, __dl_invalid_handle); diff --git a/system/lib/libc/musl/src/ldso/dlinfo.c b/system/lib/libc/musl/src/ldso/dlinfo.c index 63d276d408e34..a173d1ac63ef1 100644 --- a/system/lib/libc/musl/src/ldso/dlinfo.c +++ b/system/lib/libc/musl/src/ldso/dlinfo.c @@ -1,9 +1,19 @@ #define _GNU_SOURCE #include -int __dlinfo(void *, int, void *); +__attribute__((__visibility__("hidden"))) +int __dl_invalid_handle(void *); + +__attribute__((__visibility__("hidden"))) +void __dl_seterr(const char *, ...); int dlinfo(void *dso, int req, void *res) { - return __dlinfo(dso, req, res); + if (__dl_invalid_handle(dso)) return -1; + if (req != RTLD_DI_LINKMAP) { + __dl_seterr("Unsupported request %d", req); + return -1; + } + *(struct link_map **)res = dso; + return 0; } diff --git a/system/lib/libc/musl/src/ldso/dlopen.c b/system/lib/libc/musl/src/ldso/dlopen.c new file mode 100644 index 0000000000000..dcdb439847d93 --- /dev/null +++ b/system/lib/libc/musl/src/ldso/dlopen.c @@ -0,0 +1,13 @@ +#include +#include "libc.h" + +__attribute__((__visibility__("hidden"))) +void __dl_seterr(const char *, ...); + +static void *stub_dlopen(const char *file, int mode) +{ + __dl_seterr("Dynamic loading not supported"); + return 0; +} + +weak_alias(stub_dlopen, dlopen); diff --git a/system/lib/libc/musl/src/ldso/tlsdesc.c b/system/lib/libc/musl/src/ldso/tlsdesc.c new file mode 100644 index 0000000000000..a2985cb64a20a --- /dev/null +++ b/system/lib/libc/musl/src/ldso/tlsdesc.c @@ -0,0 +1,12 @@ +#include +#include "libc.h" + +__attribute__((__visibility__("hidden"))) +ptrdiff_t __tlsdesc_static(), __tlsdesc_dynamic(); + +ptrdiff_t __tlsdesc_static() +{ + return 0; +} + +weak_alias(__tlsdesc_static, __tlsdesc_dynamic); diff --git a/system/lib/libc/musl/src/legacy/futimes.c b/system/lib/libc/musl/src/legacy/futimes.c index d81d83a962a86..1c19eb1fa1da1 100644 --- a/system/lib/libc/musl/src/legacy/futimes.c +++ b/system/lib/libc/musl/src/legacy/futimes.c @@ -5,6 +5,7 @@ int futimes(int fd, const struct timeval tv[2]) { struct timespec times[2]; + if (!tv) return futimens(fd, 0); times[0].tv_sec = tv[0].tv_sec; times[0].tv_nsec = tv[0].tv_usec * 1000; times[1].tv_sec = tv[1].tv_sec; diff --git a/system/lib/libc/musl/src/legacy/getloadavg.c b/system/lib/libc/musl/src/legacy/getloadavg.c index 43a8c9e36e1ef..ff06de0f8d165 100644 --- a/system/lib/libc/musl/src/legacy/getloadavg.c +++ b/system/lib/libc/musl/src/legacy/getloadavg.c @@ -1,18 +1,14 @@ #define _GNU_SOURCE #include -#include -#include +#include int getloadavg(double *a, int n) { - int i; - double b[3]; - FILE *f = fopen("/proc/loadavg", "rbe"); - if (!f) return -1; - i = fscanf(f, "%lf %lf %lf", b, b+1, b+2); - fclose(f); - if (n > i) n = i; - if (n < 0) return -1; - memcpy(a, b, n * sizeof *a); + struct sysinfo si; + if (n <= 0) return n ? -1 : 0; + sysinfo(&si); + if (n > 3) n = 3; + for (int i=0; i #include +#include #include "libc.h" void endutxent(void) @@ -34,6 +35,12 @@ void updwtmpx(const char *f, const struct utmpx *u) { } +int __utmpxname(const char *f) +{ + errno = ENOTSUP; + return -1; +} + weak_alias(endutxent, endutent); weak_alias(setutxent, setutent); weak_alias(getutxent, getutent); @@ -41,3 +48,5 @@ weak_alias(getutxid, getutid); weak_alias(getutxline, getutline); weak_alias(pututxline, pututline); weak_alias(updwtmpx, updwtmp); +weak_alias(__utmpxname, utmpname); +weak_alias(__utmpxname, utmpxname); diff --git a/system/lib/libc/musl/src/linux/epoll.c b/system/lib/libc/musl/src/linux/epoll.c index 030786d3ff993..deff5b101aade 100644 --- a/system/lib/libc/musl/src/linux/epoll.c +++ b/system/lib/libc/musl/src/linux/epoll.c @@ -1,15 +1,20 @@ #include #include +#include #include "syscall.h" int epoll_create(int size) { - return syscall(SYS_epoll_create, size); + return epoll_create1(0); } int epoll_create1(int flags) { - return syscall(SYS_epoll_create1, flags); + int r = __syscall(SYS_epoll_create1, flags); +#ifdef SYS_epoll_create + if (r==-ENOSYS && !flags) r = __syscall(SYS_epoll_create, 1); +#endif + return __syscall_ret(r); } int epoll_ctl(int fd, int op, int fd2, struct epoll_event *ev) @@ -19,10 +24,14 @@ int epoll_ctl(int fd, int op, int fd2, struct epoll_event *ev) int epoll_pwait(int fd, struct epoll_event *ev, int cnt, int to, const sigset_t *sigs) { - return syscall(SYS_epoll_pwait, fd, ev, cnt, to, sigs, _NSIG/8); + int r = __syscall(SYS_epoll_pwait, fd, ev, cnt, to, sigs, _NSIG/8); +#ifdef SYS_epoll_wait + if (r==-ENOSYS && !sigs) r = __syscall(SYS_epoll_wait, fd, ev, cnt, to); +#endif + return __syscall_ret(r); } int epoll_wait(int fd, struct epoll_event *ev, int cnt, int to) { - return syscall(SYS_epoll_wait, fd, ev, cnt, to); + return epoll_pwait(fd, ev, cnt, to, 0); } diff --git a/system/lib/libc/musl/src/linux/eventfd.c b/system/lib/libc/musl/src/linux/eventfd.c index 530664874f698..68e489c83647e 100644 --- a/system/lib/libc/musl/src/linux/eventfd.c +++ b/system/lib/libc/musl/src/linux/eventfd.c @@ -1,10 +1,15 @@ #include #include +#include #include "syscall.h" int eventfd(unsigned int count, int flags) { - return syscall(flags ? SYS_eventfd2 : SYS_eventfd, count, flags); + int r = __syscall(SYS_eventfd2, count, flags); +#ifdef SYS_eventfd + if (r==-ENOSYS && !flags) r = __syscall(SYS_eventfd, count); +#endif + return __syscall_ret(r); } int eventfd_read(int fd, eventfd_t *value) diff --git a/system/lib/libc/musl/src/linux/inotify.c b/system/lib/libc/musl/src/linux/inotify.c index a417c891fdf73..df5e48b31b7ea 100644 --- a/system/lib/libc/musl/src/linux/inotify.c +++ b/system/lib/libc/musl/src/linux/inotify.c @@ -1,13 +1,18 @@ #include +#include #include "syscall.h" int inotify_init() { - return syscall(SYS_inotify_init); + return inotify_init1(0); } int inotify_init1(int flags) { - return syscall(SYS_inotify_init1, flags); + int r = __syscall(SYS_inotify_init1, flags); +#ifdef SYS_inotify_init + if (r==-ENOSYS && !flags) r = __syscall(SYS_inotify_init); +#endif + return __syscall_ret(r); } int inotify_add_watch(int fd, const char *pathname, uint32_t mask) diff --git a/system/lib/libc/musl/src/linux/signalfd.c b/system/lib/libc/musl/src/linux/signalfd.c index da6bcedb3f905..4bf43326fe5a7 100644 --- a/system/lib/libc/musl/src/linux/signalfd.c +++ b/system/lib/libc/musl/src/linux/signalfd.c @@ -7,6 +7,7 @@ int signalfd(int fd, const sigset_t *sigs, int flags) { int ret = __syscall(SYS_signalfd4, fd, sigs, _NSIG/8, flags); +#ifdef SYS_signalfd if (ret != -ENOSYS) return __syscall_ret(ret); ret = __syscall(SYS_signalfd, fd, sigs, _NSIG/8); if (ret >= 0) { @@ -15,5 +16,6 @@ int signalfd(int fd, const sigset_t *sigs, int flags) if (flags & SFD_NONBLOCK) __syscall(SYS_fcntl, ret, F_SETFL, O_NONBLOCK); } +#endif return __syscall_ret(ret); } diff --git a/system/lib/libc/musl/src/linux/syncfs.c b/system/lib/libc/musl/src/linux/syncfs.c index fe2b8a70b24cd..bc7d301e51789 100644 --- a/system/lib/libc/musl/src/linux/syncfs.c +++ b/system/lib/libc/musl/src/linux/syncfs.c @@ -2,7 +2,7 @@ #include #include "syscall.h" -void syncfs(int fd) +int syncfs(int fd) { - __syscall(SYS_syncfs, fd); + return syscall(SYS_syncfs, fd); } diff --git a/system/lib/libc/musl/src/linux/sysinfo.c b/system/lib/libc/musl/src/linux/sysinfo.c index 7e64f330a184e..4b5a798d0683e 100644 --- a/system/lib/libc/musl/src/linux/sysinfo.c +++ b/system/lib/libc/musl/src/linux/sysinfo.c @@ -1,7 +1,10 @@ #include #include "syscall.h" +#include "libc.h" -int sysinfo(struct sysinfo *info) +int __lsysinfo(struct sysinfo *info) { return syscall(SYS_sysinfo, info); } + +weak_alias(__lsysinfo, sysinfo); diff --git a/system/lib/libc/musl/src/linux/utimes.c b/system/lib/libc/musl/src/linux/utimes.c index 70c0695f88a8e..b814c88b2fdef 100644 --- a/system/lib/libc/musl/src/linux/utimes.c +++ b/system/lib/libc/musl/src/linux/utimes.c @@ -1,7 +1,10 @@ #include +#include "fcntl.h" #include "syscall.h" +int __futimesat(int, const char *, const struct timeval [2]); + int utimes(const char *path, const struct timeval times[2]) { - return syscall(SYS_utimes, path, times); + return __futimesat(AT_FDCWD, path, times); } diff --git a/system/lib/libc/musl/src/locale/__lctrans.c b/system/lib/libc/musl/src/locale/__lctrans.c new file mode 100644 index 0000000000000..107fe14a3a36d --- /dev/null +++ b/system/lib/libc/musl/src/locale/__lctrans.c @@ -0,0 +1,20 @@ +#include +#include "locale_impl.h" +#include "libc.h" + +static const char *dummy(const char *msg, const struct __locale_map *lm) +{ + return msg; +} + +weak_alias(dummy, __lctrans_impl); + +const char *__lctrans(const char *msg, const struct __locale_map *lm) +{ + return __lctrans_impl(msg, lm); +} + +const char *__lctrans_cur(const char *msg) +{ + return __lctrans_impl(msg, CURRENT_LOCALE->cat[LC_MESSAGES]); +} diff --git a/system/lib/libc/musl/src/locale/__mo_lookup.c b/system/lib/libc/musl/src/locale/__mo_lookup.c new file mode 100644 index 0000000000000..d18ab7744246b --- /dev/null +++ b/system/lib/libc/musl/src/locale/__mo_lookup.c @@ -0,0 +1,42 @@ +#include +#include + +static inline uint32_t swapc(uint32_t x, int c) +{ + return c ? x>>24 | x>>8&0xff00 | x<<8&0xff0000 | x<<24 : x; +} + +const char *__mo_lookup(const void *p, size_t size, const char *s) +{ + const uint32_t *mo = p; + int sw = *mo - 0x950412de; + uint32_t b = 0, n = swapc(mo[2], sw); + uint32_t o = swapc(mo[3], sw); + uint32_t t = swapc(mo[4], sw); + if (n>=size/4 || o>=size-4*n || t>=size-4*n || ((o|t)%4)) + return 0; + o/=4; + t/=4; + for (;;) { + uint32_t ol = swapc(mo[o+2*(b+n/2)], sw); + uint32_t os = swapc(mo[o+2*(b+n/2)+1], sw); + if (os >= size || ol >= size-os || ((char *)p)[os+ol]) + return 0; + int sign = strcmp(s, (char *)p + os); + if (!sign) { + uint32_t tl = swapc(mo[t+2*(b+n/2)], sw); + uint32_t ts = swapc(mo[t+2*(b+n/2)+1], sw); + if (ts >= size || tl >= size-ts || ((char *)p)[ts+tl]) + return 0; + return (char *)p + ts; + } + else if (n == 1) return 0; + else if (sign < 0) + n /= 2; + else { + b += n/2; + n -= n/2; + } + } + return 0; +} diff --git a/system/lib/libc/musl/src/locale/bind_textdomain_codeset.c b/system/lib/libc/musl/src/locale/bind_textdomain_codeset.c new file mode 100644 index 0000000000000..5ebfd5e8a818f --- /dev/null +++ b/system/lib/libc/musl/src/locale/bind_textdomain_codeset.c @@ -0,0 +1,11 @@ +#include +#include +#include +#include + +char *bind_textdomain_codeset(const char *domainname, const char *codeset) +{ + if (codeset && strcasecmp(codeset, "UTF-8")) + errno = EINVAL; + return NULL; +} diff --git a/system/lib/libc/musl/src/locale/c_locale.c b/system/lib/libc/musl/src/locale/c_locale.c new file mode 100644 index 0000000000000..77ccf58736e72 --- /dev/null +++ b/system/lib/libc/musl/src/locale/c_locale.c @@ -0,0 +1,15 @@ +#include "locale_impl.h" +#include + +static const uint32_t empty_mo[] = { 0x950412de, 0, -1, -1, -1 }; + +const struct __locale_map __c_dot_utf8 = { + .map = empty_mo, + .map_size = sizeof empty_mo, + .name = "C.UTF-8" +}; + +const struct __locale_struct __c_locale = { 0 }; +const struct __locale_struct __c_dot_utf8_locale = { + .cat[LC_CTYPE] = &__c_dot_utf8 +}; diff --git a/system/lib/libc/musl/src/locale/codepages.h b/system/lib/libc/musl/src/locale/codepages.h index 35acd5a3eb583..ab146e89a4cb2 100644 --- a/system/lib/libc/musl/src/locale/codepages.h +++ b/system/lib/libc/musl/src/locale/codepages.h @@ -4,145 +4,148 @@ "iso88592\0" "\0\40" -"\0\124\0\211\22\0\40\1\6\0\0\230\101\206\32\177\0\60\110\40\0\130\40\311\22" -"\0\44\21\306\43\0\234\121\306\32\200\120\102\210\40\132\0\0\300\4\0\20\161\1\0" -"\35\0\160\2\0\51\0\0\300\7\41\60\1\5\0\0\130\1\0\0\136\320\1\200\35" -"\0\0\200\6\0\133\0\0\0\5\0\24\201\1\0\36\0\200\2\0\52\0\0\0\10\42\64\21\5\0" -"\0\134\1\0\0\137\324\1\300\35\0\0\220\106\44" +"\0\330\20\313\32\0\244\21\10\0\0\34\122\310\42\240\0\100\212\50\0\334\60\13\33" +"\0\250\41\10\54\0\40\142\10\43\241\324\122\312\50\173\0\0\0\15\0\224\201\3\0" +"\76\0\200\4\0\112\0\0\0\20\102\264\21\7\0\0\334\1\0\0\177\124\2\300\45" +"\0\0\220\10\0\174\0\0\100\15\0\230\221\3\0\77\0\220\4\0\113\0\0\100\20" +"\103\270\41\7\0\0\340\1\0\0\200\130\2\0\46\0\0\240\210\54" "iso88593\0" "\0\40" -"\0\324\0\11\0\0\4\60\3\0\0\364\100\106\13\77\0\20\100\40\0\330\0\0\0" -"\0\0\100\3\0\0\370\120\206\13\100\0\20\200\40\0\0\0\100\0\0\154\220\1\0" -"\0\0\0\0\0\0\0\0\0\0\1\0\0\0\0\0\274\0\0\0\53\0\0\0\0\0\310\41\6\0\0\0\0\100\0" -"\0\160\240\1\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\0\0\300\0\0\0\54\0\0\0\0" -"\0\314\61\106\44" +"\0\130\21\13\0\0\4\100\5\0\0\170\121\210\23\140\0\20\200\50\0\134\1\0\0" +"\0\0\120\5\0\0\174\141\310\23\141\0\20\300\50\0\0\0\100\0\0\360\240\3\0" +"\0\0\0\0\0\0\0\0\0\0\1\0\0\0\0\0\100\1\0\0\114\0\0\0\0\0\114\62\10\0" +"\0\0\0\100\0\0\364\260\3\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\0\0\104\1\0\0" +"\115\0\0\0\0\0\120\102\210\54" "iso88594\0" "\0\40" -"\0\124\60\4\27\0\334\140\4\0\0\230\61\102\14\154\0\60\10\0\0\130\40\111\27" -"\0\340\160\304\43\0\234\101\202\14\155\110\101\310\24\21\0\0\0\0\0\0\0\300\16" -"\35\0\160\2\0\45\0\0\100\16\41\70\101\105\20\0\0\0\0\0\0\340\1\0\0\0\270\1\7\0" -"\22\0\0\0\0\0\0\0\0\17\36\0\200\2\0\46\0\0\200\16\42\74\121\205\20\0\0\0\0\0" -"\0\344\1\0\0\0\274\21\107\44" +"\0\330\100\106\37\0\140\161\6\0\0\34\102\204\24\215\0\100\12\0\0\334\60\213\37" +"\0\144\201\6\54\0\40\122\304\24\216\314\121\12\35\62\0\0\0\0\0\0\0\0\27" +"\76\0\200\4\0\106\0\0\200\26\102\274\121\207\30\0\0\0\0\0\0\144\2\0\0" +"\0\74\22\11\0\63\0\0\0\0\0\0\0\100\27\77\0\220\4\0\107\0\0\300\26" +"\103\300\141\307\30\0\0\0\0\0\0\150\2\0\0\0\100\42\211\54" "iso88595\0" "\0\40" -"\0\210\63\16\71\345\230\163\16\72\351\250\263\16\73\355\0\340\316\73" -"\360\304\43\317\74\364\324\143\317\75\370\344\243\317\76\374\364\343\317\77" -"\0\5\44\320\100\4\25\144\320\101\10\45\244\320\102\14\65\344\320\103" -"\20\105\44\321\104\24\125\144\321\105\30\145\244\321\106\34\165\344\321\107" -"\40\205\44\322\110\44\225\144\322\111\50\245\244\322\112\54\265\344\322\113" -"\65\302\24\223\114\63\321\124\223\115\67\341\224\223\116\73\15\300\123\117" +"\0\14\104\120\101\6\35\204\120\102\12\55\304\120\103\16\1\360\20\104" +"\21\111\64\21\105\25\131\164\21\106\31\151\264\21\107\35\171\364\21\110" +"\41\211\64\22\111\45\231\164\22\112\51\251\264\22\113\55\271\364\22\114" +"\61\311\64\23\115\65\331\164\23\116\71\351\264\23\117\75\371\364\23\120" +"\101\11\65\24\121\105\31\165\24\122\111\51\265\24\123\115\71\365\24\124" +"\127\106\45\325\124\124\125\145\325\125\130\145\245\325\126\134\15\320\225\127" "iso88596\0" "\0\40" -"\0\4\20\100\0\0\4\20\100\0\1\4\20\100\0\163\1\20\100\0\1\4\20\100\0" -"\1\4\20\100\0\1\4\20\0\135\1\4\20\100\135\1\330\165\27\136\171\351\265\27\137" -"\175\371\365\27\140\201\11\66\30\141\205\31\166\30\142\211\51\266\30\143" -"\215\71\366\130\0\1\4\20\100\0\220\105\46\331\144\224\125\146\331\145" -"\230\145\246\331\146\234\165\346\331\147\240\205\46\132\0\1\4\20\100\0" -"\1\4\20\100\0\1\4\20\100\0" +"\0\4\20\100\0\0\4\20\100\0\1\4\20\100\0\224\1\20\100\0\1\4\20\100\0" +"\1\4\20\100\0\1\4\20\100\145\1\4\20\200\145\1\134\206\131\146" +"\232\155\306\131\147\236\175\6\132\150\242\215\106\132\151\246\235\206\132\152" +"\252\255\306\132\153\256\275\6\133\0\1\4\20\100\0\261\311\66\33\155" +"\265\331\166\33\156\271\351\266\33\157\275\371\366\33\160\301\11\67\134\0" +"\1\4\20\100\0\1\4\20\100\0\1\4\20\100\0" "iso88597\0" "\0\40" -"\0\220\130\42\0\63\322\10\0\0\0\0\240\11\0\0\0\20\200\210\0\0\0\0\0" -"\233\160\322\11\0\236\174\2\12\0\241\0\40\312\50\244\224\142\312\51" -"\250\244\242\312\52\254\264\342\312\53\260\304\42\313\54\264\324\22\200\55" -"\267\340\222\213\56\273\360\322\213\57\277\0\23\214\60\303\20\123\214\61" -"\307\40\223\214\62\313\60\323\214\63\317\100\23\215\64\323\120\123\215\65" -"\327\140\223\215\66\333\160\323\215\67\337\200\23\116\0" +"\0\24\151\44\0\124\126\11\0\0\0\0\260\13\0\0\0\20\300\220\0\0\0\0\0" +"\274\364\342\13\0\277\0\23\14\0\302\0\60\14\61\305\30\163\14\62" +"\311\50\263\14\63\315\70\363\14\64\321\110\63\15\65\325\130\23\300\65" +"\330\144\243\315\66\334\164\343\315\67\340\204\43\316\70\344\224\143\316\71" +"\350\244\243\316\72\354\264\343\316\73\360\304\43\317\74\364\324\143\317\75" +"\370\344\243\317\76\374\364\343\317\77\0\5\44\120\0" "iso88598\0" "\0\40" "\0\4\0\0\0\0\0\0\0\0\0\0\300\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\360\0\0" "\0\0\0\100\0\1\4\20\100\0\1\4\20\100\0\1\4\20\100\0\1\4\20\100\0\1\4\20\100\0" -"\1\4\20\100\0\1\4\20\100\0\1\4\20\300\210\123\121\125\225\125" -"\127\141\225\225\126\133\161\325\225\127\137\201\25\226\130" -"\143\221\125\226\131\147\241\225\226\132\153\261\325\126\0\1\170\370\141\0" +"\1\4\20\100\0\1\4\20\100\0\1\4\20\0\221\164\325\145\327\135" +"\170\345\245\327\136\174\365\345\327\137\200\5\46\330\140\204\25\146\330\141" +"\210\45\246\330\142\214\65\346\130\0\1\374\10\144\0" "iso88599\0" "\0\120" -"\55\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\364\100\6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" -"\0\0\0\0\0\56\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\370\120\6\0" +"\116\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\170\121\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" +"\0\0\0\0\0\117\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\174\141\10\0" "iso885910\0" "\0\40" -"\0\124\60\102\14\71\334\20\4\0\106\204\140\6\33\203\0\0\207\24" -"\0\130\100\202\14\72\340\40\4\0\107\210\160\106\33\204\210\30\307\24" -"\21\0\0\0\0\0\0\0\300\16\35\0\160\2\0\45\0\0\0\0\0\70\101\5\0\0\0\0\200\33" -"\0\340\1\0\0\0\0\0\0\0\22\0\0\0\0\0\0\0\0\17\36\0\200\2\0\46\0\0\0\0" -"\0\74\121\5\0\0\0\0\300\33\0\344\1\0\0\0\0\0\300\20" +"\0\330\100\204\24\132\140\41\6\0\147\10\161\110\43\244\0\20\311\34" +"\0\334\120\304\24\133\144\61\6\0\150\14\201\210\43\245\14\51\11\35\62\0\0\0\0" +"\0\0\0\0\27\76\0\200\4\0\106\0\0\0\0\0\274\121\7\0\0\0\0\300\43\0\144\2\0\0" +"\0\0\0\0\0\63\0\0\0\0\0\0\0\100\27\77\0\220\4\0\107\0\0\0\0\0\300\141\7\0" +"\0\0\0\0\44\0\150\2\0\0\0\0\0\0\31" "iso885911\0" "tis620\0" "\0\40" -"\0\274\6\133\154\262\315\106\133\155\266\335\206\133\156\272\355\306\133\157" -"\276\375\6\134\160\302\15\107\134\161\306\35\207\134\162\312\55\307\134\163" -"\316\75\7\135\164\322\115\107\135\165\326\135\207\135\166\332\155\307\135\167" -"\336\175\7\136\170\342\215\107\136\171\346\235\207\136\0\1\4\20\100\172" -"\352\255\307\136\173\356\275\7\137\174\362\315\107\137\175\366\335\207\137\176" -"\372\355\307\137\177\376\375\7\140\200\2\16\110\140\201\1\4\20\100\0" +"\0\100\27\235\164\323\121\127\235\165\327\141\227\235\166\333\161\327\235\167" +"\337\201\27\236\170\343\221\127\236\171\347\241\227\236\172" +"\353\261\327\236\173\357\301\27\237\174\363\321\127\237\175" +"\367\341\227\237\176\373\361\327\237\177\377\1\30\240\200\3\22\130\240\201" +"\7\42\230\140\0\1\4\20\200\202\13\62\330\240\203\17\102\30\241\204" +"\23\122\130\241\205\27\142\230\241\206\33\162\330\241\207\37\202\30\242\210" +"\43\222\130\242\211\1\4\20\100\0" "iso885913\0" "\0\40" -"\0\240\10\0\0\0\244\10\0\0\15\0\300\5\0\0\0\0\300\2\0\0\0\0\0\47\2\0\0\0" -"\20\0\320\5\0\0\0\0\200\3\25\354\20\301\5\0\0\160\302\10\35\0\360\107\11" -"\61\4\221\203\21\146\60\341\4\0\124\0\0\0\0\170\50\1\6\34\0\4\62\10\0" -"\26\360\40\1\6\0\0\200\2\11\36\0\0\210\11\62\10\241\303\21\147\64\361\4\0" -"\125\0\0\0\0\171\54\21\106\34\0\10\102\110\211" +"\0\44\11\0\0\0\50\11\0\0\15\0\320\7\0\0\0\0\300\2\0\0\0\0\0\110\2\0\0\0" +"\20\0\340\7\0\0\0\0\200\3\66\160\41\3\16\0\0\200\4\21\76\0\0\212\21" +"\122\210\241\305\31\207\264\361\6\0\165\0\0\0\0\231\254\21\110\44" +"\0\210\102\12\0\67\164\61\103\16\0\0\220\104\21\77\0\20\312\21" +"\123\214\261\5\32\210\270\1\7\0\166\0\0\0\0\232\260\41\210\44" +"\0\214\122\212\221" "iso885914\0" "\0\40" -"\0\30\170\40\0\33\160\200\40\0\24\2\140\141\202\32\2\0\200\37\12\56\370\2\14" -"\14\66\10\200\203\25\76\170\41\204\33\142\230\141\204\0\0\0\0\0\0\0\0\0\0" -"\0\0\0\0\0\0\0\0\0\0\172\0\0\0\0\0\0\0\200\204\0\0\0\0\0\0\0\300\7\0\0\0\0\0\0" -"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\173\0\0\0\0\0\0\0\300\204\0\0\0\0\0\0\0\320\7\0" +"\0\234\210\42\0\74\364\220\42\0\65\2\160\243\212\73\2\0\300\47" +"\53\262\10\105\24\55\272\10\300\213\66\302\210\143\214\74\346\250\243\214" +"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\233\0\0\0\0\0\0\0\300\214\0\0\0\0\0" +"\0\0\320\11\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\234\0\0\0\0\0\0\0\0\215" +"\0\0\0\0\0\0\0\340\11\0" "iso885915\0" "latin9\0" "\0\44" -"\63\2\140\6\0\147\0\0\0\0\0\0\0\0\0\0\0\0\0\0\203\0\0\0\0\204\0\0\0\0" -"\130\144\341\7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" +"\124\2\160\10\0\210\0\0\0\0\0\0\0\0\0\0\0\0\0\0\244\0\0\0\0\245\0\0\0\0" +"\171\350\361\11\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "iso885916\0" "\0\40" -"\0\124\140\201\22\63\246\150\6\0\147\0\240\10\0\177\0\0\110\40\0\0\320\301\22" -"\203\240\10\0\0\204\170\260\10\0\130\144\341\207\40\0\0\0\300\4\0\134\0\0\0" -"\0\0\0\0\0\0\0\0\0\0\41\60\1\0\0\0\130\1\0\30\166\0\0\0\0\0\234\300\10\0" -"\0\0\0\0\5\0\140\0\0\0\0\0\0\0\0\0\0\0\0\0\42\64\1\0\0\0\134\1\100\30" -"\167\0\0\0\0\0\240\320\10\0" +"\0\330\160\303\32\124\52\171\10\0\210\0\260\12\0\240\0\20\212\50\0\0\340\3\33" +"\244\44\11\0\0\245\374\300\12\0\171\350\361\311\50\0\0\0\0\15\0\340\0\0\0" +"\0\0\0\0\0\0\0\0\0\0\102\264\1\0\0\0\334\1\100\40\227\0\0\0\0\0\40\321\12\0" +"\0\0\0\100\15\0\344\0\0\0\0\0\0\0\0\0\0\0\0\0\103\270\1\0\0\0\340\1\200\40" +"\230\0\0\0\0\0\44\341\12\0" "cp1250\0" "windows1250\0" "\0\0" -"\63\6\140\142\0\51\266\250\342\212\1\270\150\306\213\140\250\61\310\37" -"\1\220\130\342\211\50\262\10\142\210\1\330\170\6\214\141\254\101\10\40" -"\0\74\2\211\22\0\124\0\0\0\0\0\100\6\0\0\0\0\100\40\0\0\40\311\22\0\0\0\0\0" -"\0\130\120\6\0\110\120\222\204\40\132\0\0\300\4\0\20\161\1\0\35\0\160\2\0" -"\51\0\0\300\7\41\60\1\5\0\0\130\1\0\0\136\320\1\200\35\0\0\200\6\0\133\0\0\0\5" -"\0\24\201\1\0\36\0\200\2\0\52\0\0\0\10\42\64\21\5\0\0\134\1\0\0" -"\137\324\1\300\35\0\0\220\106\44" +"\124\6\160\144\0\112\72\271\44\223\1\74\171\10\224\201\54\102\12\50" +"\1\24\151\44\222\111\66\31\244\220\1\140\211\110\224\202\60\122\112\50" +"\0\300\22\313\32\0\330\0\0\0\0\0\120\10\0\0\0\0\200\50\0\0\60\13\33\0\0\0\0\0" +"\0\334\140\10\0\151\324\242\306\50\173\0\0\0\15\0\224\201\3\0\76\0\200\4\0" +"\112\0\0\0\20\102\264\21\7\0\0\334\1\0\0\177\124\2\300\45\0\0\220\10\0" +"\174\0\0\100\15\0\230\221\3\0\77\0\220\4\0\113\0\0\100\20\103\270\41\7\0" +"\0\340\1\0\0\200\130\2\0\46\0\0\240\210\54" "cp1251\0" "windows1251\0" "\0\0" -"\343\220\143\242\114\51\266\250\342\212\63\272\250\316\213\353\264\303\316\73" -"\61\221\130\342\211\50\262\10\142\210\1\330\210\23\214\71\355\244\123\117" -"\0\270\303\123\72\0\370\4\0\0\342\0\120\16\0\0\0\0\0\72\0\0\160\116\115" -"\77\1\0\0\0\60\325\70\23\0\67\231\103\223\115\360\304\43\317\74" -"\364\324\143\317\75\370\344\243\317\76\374\364\343\317\77\0\5\44\320\100" -"\4\25\144\320\101\10\45\244\320\102\14\65\344\320\103\20\105\44\321\104" -"\24\125\144\321\105\30\145\244\321\106\34\165\344\321\107\40\205\44\322\110" -"\44\225\144\322\111\50\245\244\322\112\54\265\344\322\113" +"\4\25\164\344\124\112\72\271\44\223\124\76\271\20\224\14\71\324\20\104" +"\122\25\151\44\222\111\66\31\244\220\1\140\231\125\224\132\161\265\225\127" +"\0\74\324\225\102\0\174\5\0\0\3\1\140\20\0\0\0\0\100\102\0\0\200\220\125" +"\140\1\0\0\0\121\135\111\25\0\130\35\124\325\125\21\111\64\21\105" +"\25\131\164\21\106\31\151\264\21\107\35\171\364\21\110\41\211\64\22\111" +"\45\231\164\22\112\51\251\264\22\113\55\271\364\22\114\61\311\64\23\115" +"\65\331\164\23\116\71\351\264\23\117\75\371\364\23\120\101\11\65\24\121" +"\105\31\165\24\122\111\51\265\24\123\115\71\365\24\124" "cp1252\0" "windows1252\0" "\0\0" -"\63\6\140\142\41\51\266\250\342\212\216\270\150\306\213\130\4\60\110\0" -"\1\220\130\342\211\50\262\10\142\210\223\330\170\6\214\131\4\100\210\37" +"\124\6\160\244\51\112\72\271\44\223\257\74\171\10\224\171\4\100\112\0" +"\1\24\151\44\222\111\66\31\244\220\264\140\211\110\224\172\4\120\312\47" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" @@ -151,88 +154,112 @@ "cp1253\0" "windows1253\0" "\0\0" -"\63\6\140\142\41\51\266\250\342\212\1\270\30\300\213\1\4\20\100\0" -"\1\220\130\342\211\50\262\10\142\210\1\330\30\0\214\1\4\20\100\0" -"\0\160\322\11\0\0\0\0\0\0\0\0\20\0\0\0\0\0\200\210\0\0\0\0\0\233\0\0\0\0" -"\236\174\2\12\0\241\0\40\312\50\244\224\142\312\51\250\244\242\312\52" -"\254\264\342\312\53\260\304\42\313\54\264\324\22\200\55\267\340\222\213\56" -"\273\360\322\213\57\277\0\23\214\60\303\20\123\214\61\307\40\223\214\62" -"\313\60\323\214\63\317\100\23\215\64\323\120\123\215\65\327\140\223\215\66" -"\333\160\323\215\67\337\200\23\116\0" +"\124\6\160\244\51\112\72\271\44\223\1\74\31\0\224\1\4\20\100\0\1\24\151\44\222" +"\111\66\31\244\220\1\140\31\100\224\1\4\20\100\0\0\364\342\13\0\0\0\0\0\0" +"\0\0\20\0\0\0\0\0\300\220\0\0\0\0\0\274\0\0\0\0\277\0\23\14\0\302\0\60\14\61" +"\305\30\163\14\62\311\50\263\14\63\315\70\363\14\64\321\110\63\15\65" +"\325\130\23\300\65\330\144\243\315\66\334\164\343\315\67\340\204\43\316\70" +"\344\224\143\316\71\350\244\243\316\72\354\264\343\316\73\360\304\43\317\74" +"\364\324\143\317\75\370\344\243\317\76\374\364\343\317\77\0\5\44\120\0" "cp1254\0" "windows1254\0" "\0\0" -"\63\6\140\142\41\51\266\250\342\212\216\270\150\306\213\130\4\20\100\0" -"\1\220\130\342\211\50\262\10\142\210\223\330\170\6\214\131\4\20\200\37" +"\124\6\160\244\51\112\72\271\44\223\257\74\171\10\224\171\4\20\100\0" +"\1\24\151\44\222\111\66\31\244\220\264\140\211\110\224\172\4\20\300\47" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" -"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\55\0\0\0\0\0\0\0\0\0" -"\0\0\0\0\0\0\364\100\6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\56\0\0\0\0" -"\0\0\0\0\0\0\0\0\0\0\0\370\120\6\0" +"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\116\0\0\0\0\0\0\0\0\0" +"\0\0\0\0\0\0\170\121\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\117\0\0\0\0" +"\0\0\0\0\0\0\0\0\0\0\0\174\141\10\0" "cp1255\0" "windows1255\0" "\0\0" -"\63\6\140\142\41\51\266\250\342\212\216\270\30\300\213\1\4\20\100\0" -"\1\220\130\342\211\50\262\10\142\210\223\330\30\0\214\1\4\20\100\0\0\0\0\0\0" -"\61\2\0\0\0\0\0\300\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\360\0\0\0\0\0\0\0" -"\100\5\45\324\120\104\25\145\324\121\110\45\25\200\122\113\61\325\224\123" -"\117\101\25\225\124\156\275\5\127\134\162\5\20\100\0\1\4\20\100\0" -"\123\121\125\225\125\127\141\225\225\126\133\161\325\225\127" -"\137\201\25\226\130\143\221\125\226\131\147\241\225\226\132\153\261\325\126\0" -"\1\170\370\141\0" +"\124\6\160\244\51\112\72\271\44\223\257\74\31\0\224\1\4\20\100\0" +"\1\24\151\44\222\111\66\31\244\220\264\140\31\100\224\1\4\20\100\0\0\0\0\0\0" +"\122\2\0\0\0\0\0\300\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\360\0\0\0\0\0\0\0" +"\141\211\65\26\131\145\231\165\26\132\151\251\25\300\132\154\265\345\326\133" +"\160\305\45\327\134\217\101\26\231\144\223\5\20\100\0\1\4\20\100\0" +"\164\325\145\327\135\170\345\245\327\136\174\365\345\327\137\200\5\46\330\140" +"\204\25\146\330\141\210\45\246\330\142\214\65\346\130\0\1\374\10\144\0" "cp1256\0" "windows1256\0" "\0\0" -"\63\222\146\142\41\51\266\250\342\212\216\270\70\332\213\130\224\206\232\151" -"\252\221\130\342\211\50\262\10\142\210\251\331\170\32\214\131\160\330\341\152" -"\0\314\5\0\0\0\0\0\0\0\0\0\300\32\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\100\27\0" -"\0\0\0\100\135\255\331\165\27\136\171\351\265\27\137\175\371\365\27\140" -"\201\11\66\30\141\205\31\166\30\142\211\51\266\30\0\214\65\346\330\143" -"\220\105\46\331\144\0\120\6\100\145\226\135\206\31\0\0\0\0\0\0\231\151\6\0\0" -"\233\161\326\231\147\0\174\6\32\0\241\1\40\32\0\0\170\370\241\153" +"\124\26\167\244\51\112\72\271\44\223\257\74\111\34\224\171\30\227\334\161" +"\313\25\151\44\222\111\66\31\244\220\312\141\211\134\224\172\364\350\43\163" +"\0\120\6\0\0\0\0\0\0\0\0\0\320\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\120\31\0" +"\0\0\0\200\145\316\135\206\131\146\232\155\306\131\147\236\175\6\132\150" +"\242\215\106\132\151\246\235\206\132\152\252\255\306\32\0\255\271\366\32\154" +"\261\311\66\33\155\0\324\6\200\155\267\341\226\33\0\0\0\0\0\0\272\355\6\0\0" +"\274\365\346\333\157\0\0\27\34\0\302\1\60\34\0\0\374\10\344\163" "cp1257\0" "windows1257\0" "\0\0" -"\63\6\140\142\0\51\266\250\342\212\1\270\30\300\213\1\20\360\210\2" -"\1\220\130\342\211\50\262\10\142\210\1\330\30\0\214\1\30\40\111\0\0\4\0\0\0" -"\0\4\0\0\0\15\0\300\5\0\0\0\0\300\2\0\0\0\0\0\0\0\0\0\0\20\0\320\5\0" -"\0\0\0\200\3\25\354\20\301\5\0\0\160\302\10\35\0\360\107\11\61\4\221\203\21" -"\146\60\341\4\0\124\0\0\0\0\170\50\1\6\34\0\4\62\10\0\26\360\40\1\6" -"\0\0\200\2\11\36\0\0\210\11\62\10\241\303\21\147\64\361\4\0\125\0\0\0\0" -"\171\54\21\106\34\0\10\102\110\44" +"\124\6\160\144\0\112\72\271\44\223\1\74\31\0\224\1\20\0\213\2\1\24\151\44\222" +"\111\66\31\244\220\1\140\31\100\224\1\30\60\113\0\0\4\0\0\0\0\4\0\0\0" +"\15\0\320\7\0\0\0\0\300\2\0\0\0\0\0\0\0\0\0\0\20\0\340\7\0\0\0\0\200\3" +"\66\160\41\3\16\0\0\200\4\21\76\0\0\212\21\122\210\241\305\31\207\264\361\6\0" +"\165\0\0\0\0\231\254\21\110\44\0\210\102\12\0\67\164\61\103\16\0\0\220\104\21" +"\77\0\20\312\21\123\214\261\5\32\210\270\1\7\0\166\0\0\0\0\232\260\41\210\44" +"\0\214\122\212\54" "cp1258\0" "windows1258\0" "\0\0" -"\63\6\140\142\41\51\266\250\342\212\216\270\30\300\213\130\4\20\100\0" -"\1\220\130\342\211\50\262\10\142\210\223\330\30\0\214\131\4\20\200\37" +"\124\6\160\244\51\112\72\271\44\223\257\74\31\0\224\171\4\20\100\0" +"\1\24\151\44\222\111\66\31\244\220\264\140\31\100\224\172\4\20\300\47" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" -"\0\0\0\0\0\0\0\0\300\4\0\0\0\0\0\0\0\0\0\0\225\0\0\0\0\41\0\200\11\0" -"\0\30\2\0\0\0\0\0\0\0\0\40\162\11\0\0\0\0\0\5\0\0\0\0\0\0\0\0\0\0\226\0\0\0\0" -"\42\0\220\11\0\0\34\2\0\0\0\0\0\0\0\0\44\42\43\0" +"\0\0\0\0\0\0\0\0\0\15\0\0\0\0\0\0\0\0\0\0\266\0\0\0\0\102\0\220\13\0" +"\0\234\2\0\0\0\0\0\0\0\0\244\202\13\0\0\0\0\100\15\0\0\0\0\0\0\0\0\0\0" +"\267\0\0\0\0\103\0\240\13\0\0\240\2\0\0\0\0\0\0\0\0\250\62\45\0" "koi8r\0" "\0\0" -"\76\376\10\144\220\102\16\111\144\221\106\36\211\244\231\147\242\231\246\232" -"\153\262\331\46\217\156\336\210\143\216\72\356\50\100\217\7\40\220\300\3" -"\111\52\271\44\114\114\66\351\344\223\120\106\51\345\224\124\126\151\345\225" -"\130\146\251\245\70\133\162\331\245\227\137\202\31\246\230\143\222\131\146\1" -"\56\101\24\221\111\24\125\104\322\104\45\141\224\221\106\33\161\324\221\107" -"\37\275\4\122\110\42\215\144\221\104\54\255\164\21\112\55\245\164\222\112" -"\16\301\23\217\101\364\324\103\320\74\5\341\223\217\76\373\360\323\217\77" -"\377\74\4\120\100\2\15\144\217\74\14\55\164\17\102\15\45\164\220\102" +"\140\206\51\346\230\144\226\151\346\231\150\246\251\46\242\211\52\272\50\243" +"\215\72\372\250\227\220\146\251\345\226\134\166\51\300\227\7\40\220\300\3" +"\153\262\331\146\124\156\276\11\147\234\162\316\111\147\235" +"\166\336\211\147\236\172\356\311\347\100\175\372\371\47\240\201\12\72\50\241" +"\205\32\172\150\1\117\305\44\323\121\65\331\124\24\115\106\345\244\323\116" +"\74\365\344\323\117\100\101\25\224\120\103\21\165\323\114\115\61\205\123\122" +"\116\51\205\324\122\57\105\44\321\111\25\131\124\22\105\46\145\244\321\106" +"\34\165\344\321\107\40\301\24\222\110\43\221\164\321\104\55\261\204\121\112" +"\56\251\204\322\112" "koi8u\0" "\0\0" -"\76\376\10\144\220\102\16\111\144\221\106\36\211\244\231\147\242\231\246\232" -"\153\262\331\46\217\156\336\210\143\216\72\356\50\100\217\7\40\220\300\3" -"\111\52\271\44\114\63\65\131\223\115\120\106\51\345\224\124\376\144\345\225" -"\130\146\251\245\70\345\160\171\16\72\137\202\31\246\230\143\372\124\146\1" -"\56\101\24\221\111\24\125\104\322\104\45\141\224\221\106\33\161\324\221\107" -"\37\275\4\122\110\42\215\144\221\104\54\255\164\21\112\55\245\164\222\112" -"\16\301\23\217\101\364\324\103\320\74\5\341\223\217\76\373\360\323\217\77" -"\377\74\4\120\100\2\15\144\217\74\14\55\164\17\102\15\45\164\220\102" +"\140\206\51\346\230\144\226\151\346\231\150\246\251\46\242\211\52\272\50\243" +"\215\72\372\250\227\220\146\251\345\226\134\166\51\300\227\7\40\220\300\3" +"\153\262\331\146\124\124\275\151\325\125\162\316\111\147\235" +"\166\202\205\147\236\172\356\311\347\100\6\371\211\120\102\201\12\72\50\241" +"\205\176\165\150\1\117\305\44\323\121\65\331\124\24\115\106\345\244\323\116" +"\74\365\344\323\117\100\101\25\224\120\103\21\165\323\114\115\61\205\123\122" +"\116\51\205\324\122\57\105\44\321\111\25\131\124\22\105\46\145\244\321\106" +"\34\165\344\321\107\40\301\24\222\110\43\221\164\321\104\55\261\204\121\112" +"\56\251\204\322\112" + +"cp437\0" +"\0\0" +"\27\300\100\202\7\37\164\0\202\10\45\230\60\102\12\50\234\100\101\5" +"\30\70\260\300\12\54\250\360\202\13\61\144\300\101\4\22\114\140\245\51" +"\221\106\32\151\244\221\106\32\151\244\221\106\32\151\244\221\106\32\151\244" +"\215\72\372\150\230\147\362\331\147\234\160\372\311\246\234" +"\170\336\151\347\230\144\246\211\246\231\140\252\231\247\236" +"\165\276\111\150\240\173\256\171\250\240\203\376\11\50\235\163\266\351\246\241" +"\205\226\51\246\242\211\56\312\50\242\345\104\212\14\75\327\334\23\51\76" +"\332\64\323\15\72\221\352\223\116\244\221\106\332\45\227\136\176\371\300\226" +"\7\144\231\200\226\221\42\0\251\0" + +"cp850\0" +"\0\0" +"\27\300\100\202\7\37\164\0\202\10\45\230\60\102\12\50\234\100\101\5" +"\30\70\260\300\12\54\250\360\202\13\61\144\300\1\4\22\64\300\200\51" +"\221\106\32\151\244\221\106\32\151\244\221\106\32\151\244\221\106\32\151\244" +"\215\72\372\150\230\147\106\32\151\244\5\370\311\246\234\170\106\60\301\230" +"\144\246\211\246\231\140\252\31\151\244\165\276\111\150\240" +"\173\256\171\150\244\221\106\32\151\244\221\176\21\151\244\221\226\51\246\242" +"\211\106\32\51\242\221\106\32\151\244\221\106\32\151\244\221\106\32\151\244" +"\221\106\152\100\244\221\106\112\144\244\221\16\360\200\2\7\20\220\100\244" +"\221\42\0\251\0" diff --git a/system/lib/libc/musl/src/locale/dcngettext.c b/system/lib/libc/musl/src/locale/dcngettext.c new file mode 100644 index 0000000000000..a5ff847504f58 --- /dev/null +++ b/system/lib/libc/musl/src/locale/dcngettext.c @@ -0,0 +1,249 @@ +#include +#include +#include +#include +#include +#include +#include +#include "locale_impl.h" +#include "libc.h" +#include "atomic.h" + +struct binding { + struct binding *next; + int dirlen; + volatile int active; + char *domainname; + char *dirname; + char buf[]; +}; + +static void *volatile bindings; + +static char *gettextdir(const char *domainname, size_t *dirlen) +{ + struct binding *p; + for (p=bindings; p; p=p->next) { + if (!strcmp(p->domainname, domainname) && p->active) { + *dirlen = p->dirlen; + return (char *)p->dirname; + } + } + return 0; +} + +char *bindtextdomain(const char *domainname, const char *dirname) +{ + static volatile int lock[2]; + struct binding *p, *q; + + if (!domainname) return 0; + if (!dirname) return gettextdir(domainname, &(size_t){0}); + + size_t domlen = strlen(domainname); + size_t dirlen = strlen(dirname); + if (domlen > NAME_MAX || dirlen >= PATH_MAX) { + errno = EINVAL; + return 0; + } + + LOCK(lock); + + for (p=bindings; p; p=p->next) { + if (!strcmp(p->domainname, domainname) && + !strcmp(p->dirname, dirname)) { + break; + } + } + + if (!p) { + p = malloc(sizeof *p + domlen + dirlen + 2); + if (!p) { + UNLOCK(lock); + return 0; + } + p->next = bindings; + p->dirlen = dirlen; + p->domainname = p->buf; + p->dirname = p->buf + domlen + 1; + memcpy(p->domainname, domainname, domlen+1); + memcpy(p->dirname, dirname, dirlen+1); + a_cas_p(&bindings, bindings, p); + } + + a_store(&p->active, 1); + + for (q=bindings; q; q=q->next) { + if (!strcmp(p->domainname, domainname) && q != p) + a_store(&q->active, 0); + } + + UNLOCK(lock); + + return (char *)p->dirname; +} + +static const char catnames[][12] = { + "LC_CTYPE", + "LC_NUMERIC", + "LC_TIME", + "LC_COLLATE", + "LC_MONETARY", + "LC_MESSAGES", +}; + +static const char catlens[] = { 8, 10, 7, 10, 11, 11 }; + +struct msgcat { + struct msgcat *next; + const void *map; + size_t map_size; + void *volatile plural_rule; + volatile int nplurals; + char name[]; +}; + +static char *dummy_gettextdomain() +{ + return "messages"; +} + +weak_alias(dummy_gettextdomain, __gettextdomain); + +const unsigned char *__map_file(const char *, size_t *); +int __munmap(void *, size_t); +unsigned long __pleval(const char *, unsigned long); + +char *dcngettext(const char *domainname, const char *msgid1, const char *msgid2, unsigned long int n, int category) +{ + static struct msgcat *volatile cats; + struct msgcat *p; + struct __locale_struct *loc = CURRENT_LOCALE; + const struct __locale_map *lm; + const char *dirname, *locname, *catname; + size_t dirlen, loclen, catlen, domlen; + + if ((unsigned)category >= LC_ALL) goto notrans; + + if (!domainname) domainname = __gettextdomain(); + + domlen = strlen(domainname); + if (domlen > NAME_MAX) goto notrans; + + dirname = gettextdir(domainname, &dirlen); + if (!dirname) goto notrans; + + lm = loc->cat[category]; + if (!lm) { +notrans: + return (char *) ((n == 1) ? msgid1 : msgid2); + } + locname = lm->name; + + catname = catnames[category]; + catlen = catlens[category]; + loclen = strlen(locname); + + size_t namelen = dirlen+1 + loclen+1 + catlen+1 + domlen+3; + char name[namelen+1], *s = name; + + memcpy(s, dirname, dirlen); + s[dirlen] = '/'; + s += dirlen + 1; + memcpy(s, locname, loclen); + s[loclen] = '/'; + s += loclen + 1; + memcpy(s, catname, catlen); + s[catlen] = '/'; + s += catlen + 1; + memcpy(s, domainname, domlen); + s[domlen] = '.'; + s[domlen+1] = 'm'; + s[domlen+2] = 'o'; + s[domlen+3] = 0; + + for (p=cats; p; p=p->next) + if (!strcmp(p->name, name)) + break; + + if (!p) { + void *old_cats; + size_t map_size; + const void *map = __map_file(name, &map_size); + if (!map) goto notrans; + p = malloc(sizeof *p + namelen + 1); + if (!p) { + __munmap((void *)map, map_size); + goto notrans; + } + p->map = map; + p->map_size = map_size; + memcpy(p->name, name, namelen+1); + do { + old_cats = cats; + p->next = old_cats; + } while (a_cas_p(&cats, old_cats, p) != old_cats); + } + + const char *trans = __mo_lookup(p->map, p->map_size, msgid1); + if (!trans) goto notrans; + + /* Non-plural-processing gettext forms pass a null pointer as + * msgid2 to request that dcngettext suppress plural processing. */ + if (!msgid2) return (char *)trans; + + if (!p->plural_rule) { + const char *rule = "n!=1;"; + unsigned long np = 2; + const char *r = __mo_lookup(p->map, p->map_size, ""); + char *z; + while (r && strncmp(r, "Plural-Forms:", 13)) { + z = strchr(r, '\n'); + r = z ? z+1 : 0; + } + if (r) { + r += 13; + while (isspace(*r)) r++; + if (!strncmp(r, "nplurals=", 9)) { + np = strtoul(r+9, &z, 10); + r = z; + } + while (*r && *r != ';') r++; + if (*r) { + r++; + while (isspace(*r)) r++; + if (!strncmp(r, "plural=", 7)) + rule = r+7; + } + } + a_store(&p->nplurals, np); + a_cas_p(&p->plural_rule, 0, (void *)rule); + } + if (p->nplurals) { + unsigned long plural = __pleval(p->plural_rule, n); + if (plural > p->nplurals) goto notrans; + while (plural--) { + size_t rem = p->map_size - (trans - (char *)p->map); + size_t l = strnlen(trans, rem); + if (l+1 >= rem) + goto notrans; + trans += l+1; + } + } + return (char *)trans; +} + +char *dcgettext(const char *domainname, const char *msgid, int category) +{ + return dcngettext(domainname, msgid, 0, 1, category); +} + +char *dngettext(const char *domainname, const char *msgid1, const char *msgid2, unsigned long int n) +{ + return dcngettext(domainname, msgid1, msgid2, n, LC_MESSAGES); +} + +char *dgettext(const char *domainname, const char *msgid) +{ + return dcngettext(domainname, msgid, 0, 1, LC_MESSAGES); +} diff --git a/system/lib/libc/musl/src/locale/duplocale.c b/system/lib/libc/musl/src/locale/duplocale.c index f9fc1ffa75dac..030b64cb0e706 100644 --- a/system/lib/libc/musl/src/locale/duplocale.c +++ b/system/lib/libc/musl/src/locale/duplocale.c @@ -3,12 +3,13 @@ #include "locale_impl.h" #include "libc.h" -locale_t duplocale(locale_t old) +locale_t __duplocale(locale_t old) { - locale_t new; - new = calloc(1, sizeof *new); - if (new && old != LC_GLOBAL_LOCALE) memcpy(new, old, sizeof *new); + locale_t new = malloc(sizeof *new); + if (!new) return 0; + if (old == LC_GLOBAL_LOCALE) old = &libc.global_locale; + *new = *old; return new; } -weak_alias(duplocale, __duplocale); +weak_alias(__duplocale, duplocale); diff --git a/system/lib/libc/musl/src/locale/freelocale.c b/system/lib/libc/musl/src/locale/freelocale.c index ee3f029abf5a1..c2ae1a3180693 100644 --- a/system/lib/libc/musl/src/locale/freelocale.c +++ b/system/lib/libc/musl/src/locale/freelocale.c @@ -2,9 +2,11 @@ #include "locale_impl.h" #include "libc.h" +int __loc_is_allocated(locale_t); + void freelocale(locale_t l) { - free(l); + if (__loc_is_allocated(l)) free(l); } weak_alias(freelocale, __freelocale); diff --git a/system/lib/libc/musl/src/locale/iconv.c b/system/lib/libc/musl/src/locale/iconv.c index a0b0232015a2b..1eeea94e0a387 100644 --- a/system/lib/libc/musl/src/locale/iconv.c +++ b/system/lib/libc/musl/src/locale/iconv.c @@ -5,6 +5,7 @@ #include #include #include +#include "locale_impl.h" #define UTF_32BE 0300 #define UTF_16LE 0301 @@ -23,19 +24,13 @@ #define BIG5 0340 #define EUC_KR 0350 -/* FIXME: these are not implemented yet - * EUC: A1-FE A1-FE - * GBK: 81-FE 40-7E,80-FE - * Big5: A1-FE 40-7E,A1-FE - */ - /* Definitions of charmaps. Each charmap consists of: * 1. Empty-string-terminated list of null-terminated aliases. * 2. Special type code or number of elided entries. * 3. Character table (size determined by field 2). */ static const unsigned char charmaps[] = -"utf8\0\0\310" +"utf8\0char\0\0\310" "wchart\0\0\306" "ucs2\0ucs2be\0\0\304" "ucs2le\0\0\305" @@ -90,6 +85,7 @@ static int fuzzycmp(const unsigned char *a, const unsigned char *b) static size_t find_charmap(const void *name) { const unsigned char *s; + if (!*(char *)name) name=charmaps; /* "utf8" */ for (s=charmaps; *s; ) { if (!fuzzycmp(name, s)) { for (; *s; s+=strlen((void *)s)+1); @@ -170,9 +166,12 @@ size_t iconv(iconv_t cd0, char **restrict in, size_t *restrict inb, char **restr int err; unsigned char type = map[-1]; unsigned char totype = tomap[-1]; + locale_t *ploc = &CURRENT_LOCALE, loc = *ploc; if (!in || !*in || !*inb) return 0; + *ploc = UTF8_LOCALE; + for (; *inb; *in+=l, *inb-=l) { c = *(unsigned char *)*in; l = 1; @@ -436,6 +435,7 @@ size_t iconv(iconv_t cd0, char **restrict in, size_t *restrict inb, char **restr break; } } + *ploc = loc; return x; ilseq: err = EILSEQ; @@ -450,5 +450,6 @@ size_t iconv(iconv_t cd0, char **restrict in, size_t *restrict inb, char **restr x = -1; end: errno = err; + *ploc = loc; return x; } diff --git a/system/lib/libc/musl/src/locale/intl.c b/system/lib/libc/musl/src/locale/intl.c deleted file mode 100644 index ad040524ba79b..0000000000000 --- a/system/lib/libc/musl/src/locale/intl.c +++ /dev/null @@ -1,68 +0,0 @@ -#include -#include -#include -#include -#include - -char *gettext(const char *msgid) -{ - return (char *) msgid; -} - -char *dgettext(const char *domainname, const char *msgid) -{ - return (char *) msgid; -} - -char *dcgettext(const char *domainname, const char *msgid, int category) -{ - return (char *) msgid; -} - -char *ngettext(const char *msgid1, const char *msgid2, unsigned long int n) -{ - return (char *) ((n == 1) ? msgid1 : msgid2); -} - -char *dngettext(const char *domainname, const char *msgid1, const char *msgid2, unsigned long int n) -{ - return (char *) ((n == 1) ? msgid1 : msgid2); -} - -char *dcngettext(const char *domainname, const char *msgid1, const char *msgid2, unsigned long int n, int category) -{ - return (char *) ((n == 1) ? msgid1 : msgid2); -} - -char *textdomain(const char *domainname) -{ - static const char default_str[] = "messages"; - - if (domainname && *domainname && strcmp(domainname, default_str)) { - errno = EINVAL; - return NULL; - } - return (char *) default_str; -} - -char *bindtextdomain(const char *domainname, const char *dirname) -{ - static const char dir[] = "/"; - - if (!domainname || !*domainname - || (dirname && ((dirname[0] != '/') || dirname[1])) - ) { - errno = EINVAL; - return NULL; - } - - return (char *) dir; -} - -char *bind_textdomain_codeset(const char *domainname, const char *codeset) -{ - if (!domainname || !*domainname || (codeset && strcasecmp(codeset, "UTF-8"))) { - errno = EINVAL; - } - return NULL; -} diff --git a/system/lib/libc/musl/src/locale/langinfo.c b/system/lib/libc/musl/src/locale/langinfo.c index 8159033f3cbee..b2c8569e4d195 100644 --- a/system/lib/libc/musl/src/locale/langinfo.c +++ b/system/lib/libc/musl/src/locale/langinfo.c @@ -1,5 +1,6 @@ #include #include +#include "locale_impl.h" #include "libc.h" static const char c_time[] = @@ -32,36 +33,37 @@ char *__nl_langinfo_l(nl_item item, locale_t loc) int idx = item & 65535; const char *str; - if (item == CODESET) return "UTF-8"; + if (item == CODESET) return MB_CUR_MAX==1 ? "ASCII" : "UTF-8"; switch (cat) { case LC_NUMERIC: - if (idx > 1) return NULL; + if (idx > 1) return ""; str = c_numeric; break; case LC_TIME: - if (idx > 0x31) return NULL; + if (idx > 0x31) return ""; str = c_time; break; case LC_MONETARY: - if (idx > 0) return NULL; + if (idx > 0) return ""; str = ""; break; case LC_MESSAGES: - if (idx > 3) return NULL; + if (idx > 3) return ""; str = c_messages; break; default: - return NULL; + return ""; } for (; idx; idx--, str++) for (; *str; str++); + if (cat != LC_NUMERIC && *str) str = LCTRANS(str, cat, loc); return (char *)str; } char *__nl_langinfo(nl_item item) { - return __nl_langinfo_l(item, 0); + return __nl_langinfo_l(item, CURRENT_LOCALE); } weak_alias(__nl_langinfo, nl_langinfo); diff --git a/system/lib/libc/musl/src/locale/legacychars.h b/system/lib/libc/musl/src/locale/legacychars.h index 4ddbaeba8af34..914ad0d5127b4 100644 --- a/system/lib/libc/musl/src/locale/legacychars.h +++ b/system/lib/libc/musl/src/locale/legacychars.h @@ -1,39 +1,41 @@ -0,1,160,167,168,169,175,176,178,183,184,198,215,216,230,247,248,256,257,258, -259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,278,279, -280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298, -299,302,303,304,305,308,309,310,311,312,313,314,315,316,317,318,321,322,323, -324,325,326,327,328,330,331,332,333,336,337,338,339,340,341,342,343,344,345, -346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364, -365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,402, -416,417,431,432,536,537,538,539,710,711,728,729,731,732,733,768,769,771,777, -803,890,900,901,902,904,905,906,908,910,911,912,913,914,915,916,917,918,919, -920,921,922,923,924,925,926,927,928,929,931,932,933,934,935,936,937,938,939, -940,941,942,943,944,945,946,947,948,949,950,951,952,953,954,955,956,957,958, -959,960,961,962,963,964,965,966,967,968,969,970,971,972,973,974,1025,1026, -1027,1028,1029,1030,1031,1032,1033,1034,1035,1036,1038,1039,1040,1041,1042, -1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057, -1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1072, -1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087, -1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102, -1103,1105,1106,1107,1108,1109,1110,1111,1112,1113,1114,1115,1116,1118,1119, -1168,1169,1456,1457,1458,1459,1460,1461,1462,1463,1464,1465,1467,1468,1469, -1470,1471,1472,1473,1474,1475,1488,1489,1490,1491,1492,1493,1494,1495,1496, -1497,1498,1499,1500,1501,1502,1503,1504,1505,1506,1507,1508,1509,1510,1511, -1512,1513,1514,1520,1521,1522,1523,1524,1548,1563,1567,1569,1570,1571,1572, -1573,1574,1575,1576,1577,1578,1579,1580,1581,1582,1583,1584,1585,1586,1587, -1588,1589,1590,1591,1592,1593,1594,1600,1601,1602,1603,1604,1605,1606,1607, -1608,1609,1610,1611,1612,1613,1614,1615,1616,1617,1618,1657,1662,1670,1672, -1681,1688,1705,1711,1722,1726,1729,1746,3585,3586,3587,3588,3589,3590,3591, -3592,3593,3594,3595,3596,3597,3598,3599,3600,3601,3602,3603,3604,3605,3606, -3607,3608,3609,3610,3611,3612,3613,3614,3615,3616,3617,3618,3619,3620,3621, -3622,3623,3624,3625,3626,3627,3628,3629,3630,3631,3632,3633,3634,3635,3636, -3637,3638,3639,3640,3641,3642,3647,3648,3649,3650,3651,3652,3653,3654,3655, -3656,3657,3658,3659,3660,3661,3662,3663,3664,3665,3666,3667,3668,3669,3670, -3671,3672,3673,3674,3675,7682,7683,7690,7691,7710,7711,7744,7745,7766,7767, -7776,7777,7786,7787,7808,7809,7810,7811,7812,7813,7922,7923,8204,8205,8206, -8207,8211,8212,8213,8215,8216,8217,8218,8220,8221,8222,8224,8225,8226,8230, -8240,8249,8250,8362,8363,8364,8367,8470,8482,8729,8730,8776,8804,8805,8992, -8993,9472,9474,9484,9488,9492,9496,9500,9508,9516,9524,9532,9552,9553,9554, -9555,9556,9557,9558,9559,9560,9561,9562,9563,9564,9565,9566,9567,9568,9569, -9570,9571,9572,9573,9574,9575,9576,9577,9578,9579,9580,9600,9604,9608,9612, -9616,9617,9618,9619,9632, +0,1,160,167,168,169,175,176,178,183,184,198,215,216,230,247,248,162,163,165, +196,197,198,199,201,214,215,216,220,224,226,228,229,230,231,232,233,234,235, +236,238,239,242,244,246,248,249,251,252,255,256,257,258,259,260,261,262,263, +264,265,266,267,268,269,270,271,272,273,274,275,278,279,280,281,282,283,284, +285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,302,303,304,305, +308,309,310,311,312,313,314,315,316,317,318,321,322,323,324,325,326,327,328, +330,331,332,333,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350, +351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369, +370,371,372,373,374,375,376,377,378,379,380,381,382,402,416,417,431,432,536, +537,538,539,710,711,728,729,731,732,733,768,769,771,777,803,890,900,901,902, +904,905,906,908,910,911,912,913,914,915,916,917,918,919,920,921,922,923,924, +925,926,927,928,929,931,932,933,934,935,936,937,938,939,940,941,942,943,944, +945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,962,963, +964,965,966,967,968,969,970, +971,972,973,974,1025,1026,1027,1028,1029,1030,1031,1032,1033,1034,1035,1036, +1038,1039,1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052, +1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067, +1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082, +1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097, +1098,1099,1100,1101,1102,1103,1105,1106,1107,1108,1109,1110,1111,1112,1113, +1114,1115,1116,1118,1119,1168,1169,1456,1457,1458,1459,1460,1461,1462,1463, +1464,1465,1467,1468,1469,1470,1471,1472,1473,1474,1475,1488,1489,1490,1491, +1492,1493,1494,1495,1496,1497,1498,1499,1500,1501,1502,1503,1504,1505,1506, +1507,1508,1509,1510,1511,1512,1513,1514,1520,1521,1522,1523,1524,1548,1563, +1567,1569,1570,1571,1572,1573,1574,1575,1576,1577,1578,1579,1580,1581,1582, +1583,1584,1585,1586,1587,1588,1589,1590,1591,1592,1593,1594,1600,1601,1602, +1603,1604,1605,1606,1607,1608,1609,1610,1611,1612,1613,1614,1615,1616,1617, +1618,1657,1662,1670,1672,1681,1688,1705,1711,1722,1726,1729,1746,3585,3586, +3587,3588,3589,3590,3591,3592,3593,3594,3595,3596,3597,3598,3599,3600,3601, +3602,3603,3604,3605,3606,3607,3608,3609,3610,3611,3612,3613,3614,3615,3616, +3617,3618,3619,3620,3621,3622,3623,3624,3625,3626,3627,3628,3629,3630,3631, +3632,3633,3634,3635,3636,3637,3638,3639,3640,3641,3642,3647,3648,3649,3650, +3651,3652,3653,3654,3655,3656,3657,3658,3659,3660,3661,3662,3663,3664,3665, +3666,3667,3668,3669,3670,3671,3672,3673,3674,3675,7682,7683,7690,7691,7710, +7711,7744,7745,7766,7767,7776,7777,7786,7787,7808,7809,7810,7811,7812,7813, +7922,7923,8204,8205,8206,8207,8211,8212,8213,8215,8216,8217,8218,8220,8221, +8222,8224,8225,8226,8230,8240,8249,8250,8362,8363,8364,8367,8359,8470,8482, +8729,8730,8776,8804,8805,8992,8993,9472,9474,9484,9488,9492,9496,9500,9508, +9516,9524,9532,9552,9553,9554,9555,9556,9557,9558,9559,9560,9561,9562,9563, +9564,9565,9566,9567,9568,9569,9570,9571,9572,9573,9574,9575,9576,9577,9578, +9579,9580,9600,9604,9608,9612,9616,9617,9618,9619,9632, diff --git a/system/lib/libc/musl/src/locale/locale_map.c b/system/lib/libc/musl/src/locale/locale_map.c new file mode 100644 index 0000000000000..c3e591746fb00 --- /dev/null +++ b/system/lib/libc/musl/src/locale/locale_map.c @@ -0,0 +1,116 @@ +#include +#include +#include "locale_impl.h" +#include "libc.h" +#include "atomic.h" + +const char *__lctrans_impl(const char *msg, const struct __locale_map *lm) +{ + const char *trans = 0; + if (lm) trans = __mo_lookup(lm->map, lm->map_size, msg); + return trans ? trans : msg; +} + +const unsigned char *__map_file(const char *, size_t *); +int __munmap(void *, size_t); +char *__strchrnul(const char *, int); + +static const char envvars[][12] = { + "LC_CTYPE", + "LC_NUMERIC", + "LC_TIME", + "LC_COLLATE", + "LC_MONETARY", + "LC_MESSAGES", +}; + +const struct __locale_map *__get_locale(int cat, const char *val) +{ + static int lock[2]; + static void *volatile loc_head; + const struct __locale_map *p; + struct __locale_map *new = 0; + const char *path = 0, *z; + char buf[256]; + size_t l, n; + + if (!*val) { + (val = getenv("LC_ALL")) && *val || + (val = getenv(envvars[cat])) && *val || + (val = getenv("LANG")) && *val || + (val = "C.UTF-8"); + } + + /* Limit name length and forbid leading dot or any slashes. */ + for (n=0; nnext) + if (!strcmp(val, p->name)) return p; + + LOCK(lock); + + for (p=loc_head; p; p=p->next) + if (!strcmp(val, p->name)) { + UNLOCK(lock); + return p; + } + + if (!libc.secure) path = getenv("MUSL_LOCPATH"); + /* FIXME: add a default path? */ + + if (path) for (; *path; path=z+!!*z) { + z = __strchrnul(path, ':'); + l = z - path - !!*z; + if (l >= sizeof buf - n - 2) continue; + memcpy(buf, path, l); + buf[l] = '/'; + memcpy(buf+l+1, val, n); + buf[l+1+n] = 0; + size_t map_size; + const void *map = __map_file(buf, &map_size); + if (map) { + new = malloc(sizeof *new); + if (!new) { + __munmap((void *)map, map_size); + break; + } + new->map = map; + new->map_size = map_size; + memcpy(new->name, val, n); + new->name[n] = 0; + new->next = loc_head; + loc_head = new; + break; + } + } + + /* If no locale definition was found, make a locale map + * object anyway to store the name, which is kept for the + * sake of being able to do message translations at the + * application level. */ + if (!new && (new = malloc(sizeof *new))) { + new->map = __c_dot_utf8.map; + new->map_size = __c_dot_utf8.map_size; + memcpy(new->name, val, n); + new->name[n] = 0; + new->next = loc_head; + loc_head = new; + } + + /* For LC_CTYPE, never return a null pointer unless the + * requested name was "C" or "POSIX". */ + if (!new && cat == LC_CTYPE) new = (void *)&__c_dot_utf8; + + UNLOCK(lock); + return new; +} diff --git a/system/lib/libc/musl/src/locale/localeconv.c b/system/lib/libc/musl/src/locale/localeconv.c index cbc75d7a45693..4cbb9dc52d22d 100644 --- a/system/lib/libc/musl/src/locale/localeconv.c +++ b/system/lib/libc/musl/src/locale/localeconv.c @@ -1,4 +1,5 @@ #include +#include static const struct lconv posix_lconv = { .decimal_point = ".", @@ -11,20 +12,20 @@ static const struct lconv posix_lconv = { .mon_grouping = "", .positive_sign = "", .negative_sign = "", - .int_frac_digits = -1, - .frac_digits = -1, - .p_cs_precedes = -1, - .p_sep_by_space = -1, - .n_cs_precedes = -1, - .n_sep_by_space = -1, - .p_sign_posn = -1, - .n_sign_posn = -1, - .int_p_cs_precedes = -1, - .int_p_sep_by_space = -1, - .int_n_cs_precedes = -1, - .int_n_sep_by_space = -1, - .int_p_sign_posn = -1, - .int_n_sign_posn = -1, + .int_frac_digits = CHAR_MAX, + .frac_digits = CHAR_MAX, + .p_cs_precedes = CHAR_MAX, + .p_sep_by_space = CHAR_MAX, + .n_cs_precedes = CHAR_MAX, + .n_sep_by_space = CHAR_MAX, + .p_sign_posn = CHAR_MAX, + .n_sign_posn = CHAR_MAX, + .int_p_cs_precedes = CHAR_MAX, + .int_p_sep_by_space = CHAR_MAX, + .int_n_cs_precedes = CHAR_MAX, + .int_n_sep_by_space = CHAR_MAX, + .int_p_sign_posn = CHAR_MAX, + .int_n_sign_posn = CHAR_MAX, }; struct lconv *localeconv(void) diff --git a/system/lib/libc/musl/src/locale/newlocale.c b/system/lib/libc/musl/src/locale/newlocale.c index e4404cd2379ad..bbc312084efbd 100644 --- a/system/lib/libc/musl/src/locale/newlocale.c +++ b/system/lib/libc/musl/src/locale/newlocale.c @@ -3,22 +3,45 @@ #include "locale_impl.h" #include "libc.h" -locale_t newlocale(int mask, const char *name, locale_t base) +int __loc_is_allocated(locale_t loc) { - if (*name && strcmp(name, "C") && strcmp(name, "POSIX")) - return 0; - if (!base) { - // XXX EMSCRIPTEN: avoid a malloc (which does time(), sysconf(), sbrk(), etc.) during startup - static struct __locale_struct first; - static int used_first = 0; - if (!used_first) { - used_first = 1; - base = &first; - } else { - base = calloc(1, sizeof *base); - } + return loc && loc != C_LOCALE && loc != UTF8_LOCALE; +} + +locale_t __newlocale(int mask, const char *name, locale_t loc) +{ + int i, j; + struct __locale_struct tmp; + const struct __locale_map *lm; + + /* For locales with allocated storage, modify in-place. */ + if (__loc_is_allocated(loc)) { + for (i=0; icat[i] = __get_locale(i, name); + return loc; } - return base; + + /* Otherwise, build a temporary locale object, which will only + * be instantiated in allocated storage if it does not match + * one of the built-in static locales. This makes the common + * usage case for newlocale, getting a C locale with predictable + * behavior, very fast, and more importantly, fail-safe. */ + for (j=i=0; icat[i]; + else + lm = __get_locale(i, mask & (1< +#include + +/* +grammar: + +Start = Expr ';' +Expr = Or | Or '?' Expr ':' Expr +Or = And | Or '||' And +And = Eq | And '&&' Eq +Eq = Rel | Eq '==' Rel | Eq '!=' Rel +Rel = Add | Rel '<=' Add | Rel '>=' Add | Rel '<' Add | Rel '>' Add +Add = Mul | Add '+' Mul | Add '-' Mul +Mul = Prim | Mul '*' Prim | Mul '/' Prim | Mul '%' Prim +Prim = '(' Expr ')' | '!' Prim | decimal | 'n' + +internals: + +recursive descent expression evaluator with stack depth limit. +for binary operators an operator-precedence parser is used. +eval* functions store the result of the parsed subexpression +and return a pointer to the next non-space character. +*/ + +struct st { + unsigned long r; + unsigned long n; + int op; +}; + +static const char *skipspace(const char *s) +{ + while (isspace(*s)) s++; + return s; +} + +static const char *evalexpr(struct st *st, const char *s, int d); + +static const char *evalprim(struct st *st, const char *s, int d) +{ + char *e; + if (--d < 0) return ""; + s = skipspace(s); + if (isdigit(*s)) { + st->r = strtoul(s, &e, 10); + if (e == s || st->r == -1) return ""; + return skipspace(e); + } + if (*s == 'n') { + st->r = st->n; + return skipspace(s+1); + } + if (*s == '(') { + s = evalexpr(st, s+1, d); + if (*s != ')') return ""; + return skipspace(s+1); + } + if (*s == '!') { + s = evalprim(st, s+1, d); + st->r = !st->r; + return s; + } + return ""; +} + +static int binop(struct st *st, int op, unsigned long left) +{ + unsigned long a = left, b = st->r; + switch (op) { + case 0: st->r = a||b; return 0; + case 1: st->r = a&&b; return 0; + case 2: st->r = a==b; return 0; + case 3: st->r = a!=b; return 0; + case 4: st->r = a>=b; return 0; + case 5: st->r = a<=b; return 0; + case 6: st->r = a>b; return 0; + case 7: st->r = ar = a+b; return 0; + case 9: st->r = a-b; return 0; + case 10: st->r = a*b; return 0; + case 11: if (b) {st->r = a%b; return 0;} return 1; + case 12: if (b) {st->r = a/b; return 0;} return 1; + } + return 1; +} + +static const char *parseop(struct st *st, const char *s) +{ + static const char opch[11] = "|&=!><+-*%/"; + static const char opch2[6] = "|&===="; + int i; + for (i=0; i<11; i++) + if (*s == opch[i]) { + /* note: >,< are accepted with or without = */ + if (i<6 && s[1] == opch2[i]) { + st->op = i; + return s+2; + } + if (i>=4) { + st->op = i+2; + return s+1; + } + break; + } + st->op = 13; + return s; +} + +static const char *evalbinop(struct st *st, const char *s, int minprec, int d) +{ + static const char prec[14] = {1,2,3,3,4,4,4,4,5,5,6,6,6,0}; + unsigned long left; + int op; + d--; + s = evalprim(st, s, d); + s = parseop(st, s); + for (;;) { + /* + st->r (left hand side value) and st->op are now set, + get the right hand side or back out if op has low prec, + if op was missing then prec[op]==0 + */ + op = st->op; + if (prec[op] <= minprec) + return s; + left = st->r; + s = evalbinop(st, s, prec[op], d); + if (binop(st, op, left)) + return ""; + } +} + +static const char *evalexpr(struct st *st, const char *s, int d) +{ + unsigned long a, b; + if (--d < 0) + return ""; + s = evalbinop(st, s, 0, d); + if (*s != '?') + return s; + a = st->r; + s = evalexpr(st, s+1, d); + if (*s != ':') + return ""; + b = st->r; + s = evalexpr(st, s+1, d); + st->r = a ? b : st->r; + return s; +} + +unsigned long __pleval(const char *s, unsigned long n) +{ + struct st st; + st.n = n; + s = evalexpr(&st, s, 100); + return *s == ';' ? st.r : -1; +} diff --git a/system/lib/libc/musl/src/locale/setlocale.c b/system/lib/libc/musl/src/locale/setlocale.c index 28f29b8041461..8dae5a4e8e446 100644 --- a/system/lib/libc/musl/src/locale/setlocale.c +++ b/system/lib/libc/musl/src/locale/setlocale.c @@ -1,9 +1,70 @@ #include +#include +#include +#include "locale_impl.h" +#include "libc.h" +#include "atomic.h" -char *setlocale(int category, const char *locale) +static char buf[LC_ALL*(LOCALE_NAME_MAX+1)]; + +static char *setlocale_one_unlocked(int cat, const char *name) +{ + const struct __locale_map *lm; + + if (name) libc.global_locale.cat[cat] = lm = __get_locale(cat, name); + else lm = libc.global_locale.cat[cat]; + + return lm ? (char *)lm->name : "C"; +} + +char *__strchrnul(const char *, int); + +char *setlocale(int cat, const char *name) { - /* Note: plain "C" would be better, but puts some broken - * software into legacy 8-bit-codepage mode, ignoring - * the standard library's multibyte encoding */ - return "C.UTF-8"; + static volatile int lock[2]; + + if ((unsigned)cat > LC_ALL) return 0; + + LOCK(lock); + + /* For LC_ALL, setlocale is required to return a string which + * encodes the current setting for all categories. The format of + * this string is unspecified, and only the following code, which + * performs both the serialization and deserialization, depends + * on the format, so it can easily be changed if needed. */ + if (cat == LC_ALL) { + int i; + if (name) { + char part[LOCALE_NAME_MAX+1] = "C.UTF-8"; + const char *p = name; + for (i=0; iname : "C"; + size_t l = strlen(part); + memcpy(s, part, l); + s[l] = ';'; + s += l+1; + } + *--s = 0; + UNLOCK(lock); + return buf; + } + + char *ret = setlocale_one_unlocked(cat, name); + + UNLOCK(lock); + + return ret; } diff --git a/system/lib/libc/musl/src/locale/strcoll.c b/system/lib/libc/musl/src/locale/strcoll.c index 39ea1123c6204..84f199ff9527d 100644 --- a/system/lib/libc/musl/src/locale/strcoll.c +++ b/system/lib/libc/musl/src/locale/strcoll.c @@ -1,5 +1,6 @@ #include #include +#include "locale_impl.h" #include "libc.h" int __strcoll_l(const char *l, const char *r, locale_t loc) @@ -9,7 +10,7 @@ int __strcoll_l(const char *l, const char *r, locale_t loc) int strcoll(const char *l, const char *r) { - return __strcoll_l(l, r, 0); + return __strcoll_l(l, r, CURRENT_LOCALE); } weak_alias(__strcoll_l, strcoll_l); diff --git a/system/lib/libc/musl/src/locale/strfmon.c b/system/lib/libc/musl/src/locale/strfmon.c index e25db9727583d..7cf2136a06fb2 100644 --- a/system/lib/libc/musl/src/locale/strfmon.c +++ b/system/lib/libc/musl/src/locale/strfmon.c @@ -3,6 +3,7 @@ #include #include #include +#include "locale_impl.h" static ssize_t vstrfmon_l(char *s, size_t n, locale_t loc, const char *fmt, va_list ap) { @@ -93,7 +94,7 @@ ssize_t strfmon(char *restrict s, size_t n, const char *restrict fmt, ...) ssize_t ret; va_start(ap, fmt); - ret = vstrfmon_l(s, n, 0, fmt, ap); + ret = vstrfmon_l(s, n, CURRENT_LOCALE, fmt, ap); va_end(ap); return ret; diff --git a/system/lib/libc/musl/src/locale/strxfrm.c b/system/lib/libc/musl/src/locale/strxfrm.c index 32c461939dd42..14b76a632779b 100644 --- a/system/lib/libc/musl/src/locale/strxfrm.c +++ b/system/lib/libc/musl/src/locale/strxfrm.c @@ -1,5 +1,6 @@ #include #include +#include "locale_impl.h" #include "libc.h" /* collate only by code points */ @@ -12,7 +13,7 @@ size_t __strxfrm_l(char *restrict dest, const char *restrict src, size_t n, loca size_t strxfrm(char *restrict dest, const char *restrict src, size_t n) { - return __strxfrm_l(dest, src, n, 0); + return __strxfrm_l(dest, src, n, CURRENT_LOCALE); } weak_alias(__strxfrm_l, strxfrm_l); diff --git a/system/lib/libc/musl/src/locale/textdomain.c b/system/lib/libc/musl/src/locale/textdomain.c new file mode 100644 index 0000000000000..c501501d2b0e7 --- /dev/null +++ b/system/lib/libc/musl/src/locale/textdomain.c @@ -0,0 +1,44 @@ +#include +#include +#include +#include +#include +#include "libc.h" +#include "atomic.h" + +static char *current_domain; + +char *__gettextdomain() +{ + return current_domain ? current_domain : "messages"; +} + +char *textdomain(const char *domainname) +{ + if (!domainname) return __gettextdomain(); + + size_t domlen = strlen(domainname); + if (domlen > NAME_MAX) { + errno = EINVAL; + return 0; + } + + if (!current_domain) { + current_domain = malloc(NAME_MAX+1); + if (!current_domain) return 0; + } + + memcpy(current_domain, domainname, domlen+1); + + return current_domain; +} + +char *gettext(const char *msgid) +{ + return dgettext(0, msgid); +} + +char *ngettext(const char *msgid1, const char *msgid2, unsigned long int n) +{ + return dngettext(0, msgid1, msgid2, n); +} diff --git a/system/lib/libc/musl/src/locale/uselocale.c b/system/lib/libc/musl/src/locale/uselocale.c index 224ef38727310..0fc5ecbc07f29 100644 --- a/system/lib/libc/musl/src/locale/uselocale.c +++ b/system/lib/libc/musl/src/locale/uselocale.c @@ -2,12 +2,15 @@ #include "pthread_impl.h" #include "libc.h" -locale_t uselocale(locale_t l) +locale_t __uselocale(locale_t new) { - pthread_t self = pthread_self(); + pthread_t self = __pthread_self(); locale_t old = self->locale; - if (l) self->locale = l; - return old; + locale_t global = &libc.global_locale; + + if (new) self->locale = new == LC_GLOBAL_LOCALE ? global : new; + + return old == global ? LC_GLOBAL_LOCALE : old; } -weak_alias(uselocale, __uselocale); +weak_alias(__uselocale, uselocale); diff --git a/system/lib/libc/musl/src/locale/wcscoll.c b/system/lib/libc/musl/src/locale/wcscoll.c index 20a60900e0386..14bb8b9f96079 100644 --- a/system/lib/libc/musl/src/locale/wcscoll.c +++ b/system/lib/libc/musl/src/locale/wcscoll.c @@ -1,5 +1,6 @@ #include #include +#include "locale_impl.h" #include "libc.h" /* FIXME: stub */ @@ -10,7 +11,7 @@ int __wcscoll_l(const wchar_t *l, const wchar_t *r, locale_t locale) int wcscoll(const wchar_t *l, const wchar_t *r) { - return __wcscoll_l(l, r, 0); + return __wcscoll_l(l, r, CURRENT_LOCALE); } weak_alias(__wcscoll_l, wcscoll_l); diff --git a/system/lib/libc/musl/src/locale/wcsxfrm.c b/system/lib/libc/musl/src/locale/wcsxfrm.c index 5d89e7dd52274..0a0b776dadf46 100644 --- a/system/lib/libc/musl/src/locale/wcsxfrm.c +++ b/system/lib/libc/musl/src/locale/wcsxfrm.c @@ -1,5 +1,6 @@ #include #include +#include "locale_impl.h" #include "libc.h" /* collate only by code points */ @@ -17,7 +18,7 @@ size_t __wcsxfrm_l(wchar_t *restrict dest, const wchar_t *restrict src, size_t n size_t wcsxfrm(wchar_t *restrict dest, const wchar_t *restrict src, size_t n) { - return __wcsxfrm_l(dest, src, n, 0); + return __wcsxfrm_l(dest, src, n, CURRENT_LOCALE); } weak_alias(__wcsxfrm_l, wcsxfrm_l); diff --git a/system/lib/libc/musl/src/math/__fpclassifyl.c b/system/lib/libc/musl/src/math/__fpclassifyl.c index 6dc10025d2923..481c0b949974a 100644 --- a/system/lib/libc/musl/src/math/__fpclassifyl.c +++ b/system/lib/libc/musl/src/math/__fpclassifyl.c @@ -1,7 +1,10 @@ #include "libm.h" #if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 - +int __fpclassifyl(long double x) +{ + return __fpclassify(x); +} #elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 int __fpclassifyl(long double x) { @@ -21,12 +24,11 @@ int __fpclassifyl(long double x) { union ldshape u = {x}; int e = u.i.se & 0x7fff; + u.i.se = 0; if (!e) return u.i2.lo | u.i2.hi ? FP_SUBNORMAL : FP_ZERO; - if (e == 0x7fff) { - u.i.se = 0; + if (e == 0x7fff) return u.i2.lo | u.i2.hi ? FP_NAN : FP_INFINITE; - } return FP_NORMAL; } #endif diff --git a/system/lib/libc/musl/src/math/__polevll.c b/system/lib/libc/musl/src/math/__polevll.c index a27286514d739..ce1a84046b836 100644 --- a/system/lib/libc/musl/src/math/__polevll.c +++ b/system/lib/libc/musl/src/math/__polevll.c @@ -56,6 +56,8 @@ #include "libm.h" +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +#else /* * Polynomial evaluator: * P[0] x^n + P[1] x^(n-1) + ... + P[n] @@ -88,3 +90,4 @@ long double __p1evll(long double x, const long double *P, int n) return y; } +#endif diff --git a/system/lib/libc/musl/src/math/__rem_pio2.c b/system/lib/libc/musl/src/math/__rem_pio2.c index 5fafc4a8aca54..d403f81c79221 100644 --- a/system/lib/libc/musl/src/math/__rem_pio2.c +++ b/system/lib/libc/musl/src/math/__rem_pio2.c @@ -19,6 +19,12 @@ #include "libm.h" +#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif + /* * invpio2: 53 bits of 2/pi * pio2_1: first 33 bit of pi/2 @@ -29,6 +35,7 @@ * pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3) */ static const double +toint = 1.5/EPS, invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ pio2_1 = 1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */ pio2_1t = 6.07710050650619224932e-11, /* 0x3DD0B461, 0x1A626331 */ @@ -41,8 +48,8 @@ pio2_3t = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ int __rem_pio2(double x, double *y) { union {double f; uint64_t i;} u = {x}; - double_t z,w,t,r; - double tx[3],ty[2],fn; + double_t z,w,t,r,fn; + double tx[3],ty[2]; uint32_t ix; int sign, n, ex, ey, i; @@ -111,8 +118,7 @@ int __rem_pio2(double x, double *y) if (ix < 0x413921fb) { /* |x| ~< 2^20*(pi/2), medium size */ medium: /* rint(x/(pi/2)), Assume round-to-nearest. */ - fn = x*invpio2 + 0x1.8p52; - fn = fn - 0x1.8p52; + fn = (double_t)x*invpio2 + toint - toint; n = (int32_t)fn; r = x - fn*pio2_1; w = fn*pio2_1t; /* 1st round, good to 85 bits */ diff --git a/system/lib/libc/musl/src/math/__rem_pio2f.c b/system/lib/libc/musl/src/math/__rem_pio2f.c index 838e1fcac1921..4473c1c420e92 100644 --- a/system/lib/libc/musl/src/math/__rem_pio2f.c +++ b/system/lib/libc/musl/src/math/__rem_pio2f.c @@ -22,12 +22,19 @@ #include "libm.h" +#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif + /* * invpio2: 53 bits of 2/pi * pio2_1: first 25 bits of pi/2 * pio2_1t: pi/2 - pio2_1 */ static const double +toint = 1.5/EPS, invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ pio2_1 = 1.57079631090164184570e+00, /* 0x3FF921FB, 0x50000000 */ pio2_1t = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ @@ -35,7 +42,8 @@ pio2_1t = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ int __rem_pio2f(float x, double *y) { union {float f; uint32_t i;} u = {x}; - double tx[1],ty[1],fn; + double tx[1],ty[1]; + double_t fn; uint32_t ix; int n, sign, e0; @@ -43,8 +51,7 @@ int __rem_pio2f(float x, double *y) /* 25+53 bit pi is good enough for medium size */ if (ix < 0x4dc90fdb) { /* |x| ~< 2^28*(pi/2), medium size */ /* Use a specialized rint() to get fn. Assume round-to-nearest. */ - fn = x*invpio2 + 0x1.8p52; - fn = fn - 0x1.8p52; + fn = (double_t)x*invpio2 + toint - toint; n = (int32_t)fn; *y = x - fn*pio2_1 - fn*pio2_1t; return n; diff --git a/system/lib/libc/musl/src/math/__rem_pio2l.c b/system/lib/libc/musl/src/math/__rem_pio2l.c index 8b15b7b2a3d80..77255bd80ae48 100644 --- a/system/lib/libc/musl/src/math/__rem_pio2l.c +++ b/system/lib/libc/musl/src/math/__rem_pio2l.c @@ -20,10 +20,11 @@ * use __rem_pio2_large() for large x */ +static const long double toint = 1.5/LDBL_EPSILON; + #if LDBL_MANT_DIG == 64 /* u ~< 0x1p25*pi/2 */ #define SMALL(u) (((u.i.se & 0x7fffU)<<16 | u.i.m>>48) < ((0x3fff + 25)<<16 | 0x921f>>1 | 0x8000)) -#define TOINT 0x1.8p63 #define QUOBITS(x) ((uint32_t)(int32_t)x & 0x7fffffff) #define ROUND1 22 #define ROUND2 61 @@ -50,7 +51,6 @@ pio2_3t = -2.75299651904407171810e-37L; /* -0xbb5bf6c7ddd660ce.0p-185 */ #elif LDBL_MANT_DIG == 113 /* u ~< 0x1p45*pi/2 */ #define SMALL(u) (((u.i.se & 0x7fffU)<<16 | u.i.top) < ((0x3fff + 45)<<16 | 0x921f)) -#define TOINT 0x1.8p112 #define QUOBITS(x) ((uint32_t)(int64_t)x & 0x7fffffff) #define ROUND1 51 #define ROUND2 119 @@ -77,7 +77,7 @@ int __rem_pio2l(long double x, long double *y) ex = u.i.se & 0x7fff; if (SMALL(u)) { /* rint(x/(pi/2)), Assume round-to-nearest. */ - fn = x*invpio2 + TOINT - TOINT; + fn = x*invpio2 + toint - toint; n = QUOBITS(fn); r = x-fn*pio2_1; w = fn*pio2_1t; /* 1st round good to 102/180 bits (ld80/ld128) */ diff --git a/system/lib/libc/musl/src/math/__signbitl.c b/system/lib/libc/musl/src/math/__signbitl.c index c52c87bba062b..63b3dc5a08f3d 100644 --- a/system/lib/libc/musl/src/math/__signbitl.c +++ b/system/lib/libc/musl/src/math/__signbitl.c @@ -6,4 +6,9 @@ int __signbitl(long double x) union ldshape u = {x}; return u.i.se >> 15; } +#elif LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +int __signbitl(long double x) +{ + return __signbit(x); +} #endif diff --git a/system/lib/libc/musl/src/math/acoshl.c b/system/lib/libc/musl/src/math/acoshl.c index 4aa84acb2ea36..8d4b43f64cdd8 100644 --- a/system/lib/libc/musl/src/math/acoshl.c +++ b/system/lib/libc/musl/src/math/acoshl.c @@ -20,4 +20,10 @@ long double acoshl(long double x) return logl(2*x - 1/(x+sqrtl(x*x-1))); return logl(x) + 0.693147180559945309417232121458176568L; } +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double acoshl(long double x) +{ + return acosh(x); +} #endif diff --git a/system/lib/libc/musl/src/math/asinhl.c b/system/lib/libc/musl/src/math/asinhl.c index e5f3175121cc6..8635f52e82381 100644 --- a/system/lib/libc/musl/src/math/asinhl.c +++ b/system/lib/libc/musl/src/math/asinhl.c @@ -32,4 +32,10 @@ long double asinhl(long double x) } return s ? -x : x; } +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double asinhl(long double x) +{ + return asinh(x); +} #endif diff --git a/system/lib/libc/musl/src/math/atanhl.c b/system/lib/libc/musl/src/math/atanhl.c index f63d60b153fae..87cd1cdb5f325 100644 --- a/system/lib/libc/musl/src/math/atanhl.c +++ b/system/lib/libc/musl/src/math/atanhl.c @@ -5,7 +5,7 @@ long double atanhl(long double x) { return atanh(x); } -#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 /* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ long double atanhl(long double x) { diff --git a/system/lib/libc/musl/src/math/ceil.c b/system/lib/libc/musl/src/math/ceil.c index 22dc224c5f38b..b13e6f2d63689 100644 --- a/system/lib/libc/musl/src/math/ceil.c +++ b/system/lib/libc/musl/src/math/ceil.c @@ -1,5 +1,12 @@ #include "libm.h" +#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif +static const double_t toint = 1/EPS; + double ceil(double x) { union {double f; uint64_t i;} u = {x}; @@ -10,9 +17,9 @@ double ceil(double x) return x; /* y = int(x) - x, where int(x) is an integer neighbor of x */ if (u.i >> 63) - y = (double)(x - 0x1p52) + 0x1p52 - x; + y = x - toint + toint - x; else - y = (double)(x + 0x1p52) - 0x1p52 - x; + y = x + toint - toint - x; /* special case because of non-nearest rounding modes */ if (e <= 0x3ff-1) { FORCE_EVAL(y); diff --git a/system/lib/libc/musl/src/math/ceill.c b/system/lib/libc/musl/src/math/ceill.c index a2cb0a7f99960..60a83020dd1cb 100644 --- a/system/lib/libc/musl/src/math/ceill.c +++ b/system/lib/libc/musl/src/math/ceill.c @@ -6,11 +6,9 @@ long double ceill(long double x) return ceil(x); } #elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 -#if LDBL_MANT_DIG == 64 -#define TOINT 0x1p63 -#elif LDBL_MANT_DIG == 113 -#define TOINT 0x1p112 -#endif + +static const long double toint = 1/LDBL_EPSILON; + long double ceill(long double x) { union ldshape u = {x}; @@ -21,9 +19,9 @@ long double ceill(long double x) return x; /* y = int(x) - x, where int(x) is an integer neighbor of x */ if (u.i.se >> 15) - y = x - TOINT + TOINT - x; + y = x - toint + toint - x; else - y = x + TOINT - TOINT - x; + y = x + toint - toint - x; /* special case because of non-nearest rounding modes */ if (e <= 0x3fff-1) { FORCE_EVAL(y); diff --git a/system/lib/libc/musl/src/math/coshl.c b/system/lib/libc/musl/src/math/coshl.c index 080e5eb0425c0..06a56fe3be85d 100644 --- a/system/lib/libc/musl/src/math/coshl.c +++ b/system/lib/libc/musl/src/math/coshl.c @@ -38,4 +38,10 @@ long double coshl(long double x) t = expl(0.5*x); return 0.5*t*t; } +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double coshl(long double x) +{ + return cosh(x); +} #endif diff --git a/system/lib/libc/musl/src/math/erfl.c b/system/lib/libc/musl/src/math/erfl.c index 96b74dee6652e..e267c231059cb 100644 --- a/system/lib/libc/musl/src/math/erfl.c +++ b/system/lib/libc/musl/src/math/erfl.c @@ -340,4 +340,14 @@ long double erfcl(long double x) y = 0x1p-16382L; return sign ? 2 - y : y*y; } +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double erfl(long double x) +{ + return erf(x); +} +long double erfcl(long double x) +{ + return erfc(x); +} #endif diff --git a/system/lib/libc/musl/src/math/exp10.c b/system/lib/libc/musl/src/math/exp10.c index 16d704a71095e..9f5e3c2c51ea4 100644 --- a/system/lib/libc/musl/src/math/exp10.c +++ b/system/lib/libc/musl/src/math/exp10.c @@ -1,5 +1,6 @@ #define _GNU_SOURCE #include +#include #include "libc.h" double exp10(double x) @@ -11,7 +12,9 @@ double exp10(double x) 1e10, 1e11, 1e12, 1e13, 1e14, 1e15 }; double n, y = modf(x, &n); - if (fabs(n) < 16) { + union {double f; uint64_t i;} u = {n}; + /* fabs(n) < 16 without raising invalid on nan */ + if ((u.i>>52 & 0x7ff) < 0x3ff+4) { if (!y) return p10[(int)n+15]; y = exp2(3.32192809488736234787031942948939 * y); return y * p10[(int)n+15]; diff --git a/system/lib/libc/musl/src/math/exp10f.c b/system/lib/libc/musl/src/math/exp10f.c index 5fd1af9c7d818..7a8d447033eb7 100644 --- a/system/lib/libc/musl/src/math/exp10f.c +++ b/system/lib/libc/musl/src/math/exp10f.c @@ -1,5 +1,6 @@ #define _GNU_SOURCE #include +#include #include "libc.h" float exp10f(float x) @@ -9,7 +10,9 @@ float exp10f(float x) 1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7 }; float n, y = modff(x, &n); - if (fabsf(n) < 8) { + union {float f; uint32_t i;} u = {n}; + /* fabsf(n) < 8 without raising invalid on nan */ + if ((u.i>>23 & 0xff) < 0x7f+3) { if (!y) return p10[(int)n+7]; y = exp2f(3.32192809488736234787031942948939f * y); return y * p10[(int)n+7]; diff --git a/system/lib/libc/musl/src/math/exp10l.c b/system/lib/libc/musl/src/math/exp10l.c index 22a4636af4630..b758ebffe1dac 100644 --- a/system/lib/libc/musl/src/math/exp10l.c +++ b/system/lib/libc/musl/src/math/exp10l.c @@ -1,7 +1,15 @@ #define _GNU_SOURCE +#include #include #include "libc.h" +#include "libm.h" +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double exp10l(long double x) +{ + return exp10(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 long double exp10l(long double x) { static const long double p10[] = { @@ -11,12 +19,15 @@ long double exp10l(long double x) 1e10, 1e11, 1e12, 1e13, 1e14, 1e15 }; long double n, y = modfl(x, &n); - if (fabsl(n) < 16) { + union ldshape u = {n}; + /* fabsl(n) < 16 without raising invalid on nan */ + if ((u.i.se & 0x7fff) < 0x3fff+4) { if (!y) return p10[(int)n+15]; y = exp2l(3.32192809488736234787031942948939L * y); return y * p10[(int)n+15]; } return powl(10.0, x); } +#endif weak_alias(exp10l, pow10l); diff --git a/system/lib/libc/musl/src/math/exp2f.c b/system/lib/libc/musl/src/math/exp2f.c index cf6126eea776a..296b63436f644 100644 --- a/system/lib/libc/musl/src/math/exp2f.c +++ b/system/lib/libc/musl/src/math/exp2f.c @@ -91,6 +91,8 @@ float exp2f(float x) /* Filter out exceptional cases. */ ix = u.i & 0x7fffffff; if (ix > 0x42fc0000) { /* |x| > 126 */ + if (ix > 0x7f800000) /* NaN */ + return x; if (u.i >= 0x43000000 && u.i < 0x80000000) { /* x >= 128 */ x *= 0x1p127f; return x; diff --git a/system/lib/libc/musl/src/math/exp2l.c b/system/lib/libc/musl/src/math/exp2l.c index 8fc4037c56015..3565c1e67da8e 100644 --- a/system/lib/libc/musl/src/math/exp2l.c +++ b/system/lib/libc/musl/src/math/exp2l.c @@ -1,4 +1,4 @@ -/* origin: FreeBSD /usr/src/lib/msun/ld80/s_exp2l.c */ +/* origin: FreeBSD /usr/src/lib/msun/ld80/s_exp2l.c and /usr/src/lib/msun/ld128/s_exp2l.c */ /*- * Copyright (c) 2005-2008 David Schultz * All rights reserved. @@ -251,4 +251,369 @@ long double exp2l(long double x) return scalbnl(r, k.i); } +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +#define TBLBITS 7 +#define TBLSIZE (1 << TBLBITS) + +static const long double + P1 = 0x1.62e42fefa39ef35793c7673007e6p-1L, + P2 = 0x1.ebfbdff82c58ea86f16b06ec9736p-3L, + P3 = 0x1.c6b08d704a0bf8b33a762bad3459p-5L, + P4 = 0x1.3b2ab6fba4e7729ccbbe0b4f3fc2p-7L, + P5 = 0x1.5d87fe78a67311071dee13fd11d9p-10L, + P6 = 0x1.430912f86c7876f4b663b23c5fe5p-13L; + +static const double + P7 = 0x1.ffcbfc588b041p-17, + P8 = 0x1.62c0223a5c7c7p-20, + P9 = 0x1.b52541ff59713p-24, + P10 = 0x1.e4cf56a391e22p-28, + redux = 0x1.8p112 / TBLSIZE; + +static const long double tbl[TBLSIZE] = { + 0x1.6a09e667f3bcc908b2fb1366dfeap-1L, + 0x1.6c012750bdabeed76a99800f4edep-1L, + 0x1.6dfb23c651a2ef220e2cbe1bc0d4p-1L, + 0x1.6ff7df9519483cf87e1b4f3e1e98p-1L, + 0x1.71f75e8ec5f73dd2370f2ef0b148p-1L, + 0x1.73f9a48a58173bd5c9a4e68ab074p-1L, + 0x1.75feb564267c8bf6e9aa33a489a8p-1L, + 0x1.780694fde5d3f619ae02808592a4p-1L, + 0x1.7a11473eb0186d7d51023f6ccb1ap-1L, + 0x1.7c1ed0130c1327c49334459378dep-1L, + 0x1.7e2f336cf4e62105d02ba1579756p-1L, + 0x1.80427543e1a11b60de67649a3842p-1L, + 0x1.82589994cce128acf88afab34928p-1L, + 0x1.8471a4623c7acce52f6b97c6444cp-1L, + 0x1.868d99b4492ec80e41d90ac2556ap-1L, + 0x1.88ac7d98a669966530bcdf2d4cc0p-1L, + 0x1.8ace5422aa0db5ba7c55a192c648p-1L, + 0x1.8cf3216b5448bef2aa1cd161c57ap-1L, + 0x1.8f1ae991577362b982745c72eddap-1L, + 0x1.9145b0b91ffc588a61b469f6b6a0p-1L, + 0x1.93737b0cdc5e4f4501c3f2540ae8p-1L, + 0x1.95a44cbc8520ee9b483695a0e7fep-1L, + 0x1.97d829fde4e4f8b9e920f91e8eb6p-1L, + 0x1.9a0f170ca07b9ba3109b8c467844p-1L, + 0x1.9c49182a3f0901c7c46b071f28dep-1L, + 0x1.9e86319e323231824ca78e64c462p-1L, + 0x1.a0c667b5de564b29ada8b8cabbacp-1L, + 0x1.a309bec4a2d3358c171f770db1f4p-1L, + 0x1.a5503b23e255c8b424491caf88ccp-1L, + 0x1.a799e1330b3586f2dfb2b158f31ep-1L, + 0x1.a9e6b5579fdbf43eb243bdff53a2p-1L, + 0x1.ac36bbfd3f379c0db966a3126988p-1L, + 0x1.ae89f995ad3ad5e8734d17731c80p-1L, + 0x1.b0e07298db66590842acdfc6fb4ep-1L, + 0x1.b33a2b84f15faf6bfd0e7bd941b0p-1L, + 0x1.b59728de559398e3881111648738p-1L, + 0x1.b7f76f2fb5e46eaa7b081ab53ff6p-1L, + 0x1.ba5b030a10649840cb3c6af5b74cp-1L, + 0x1.bcc1e904bc1d2247ba0f45b3d06cp-1L, + 0x1.bf2c25bd71e088408d7025190cd0p-1L, + 0x1.c199bdd85529c2220cb12a0916bap-1L, + 0x1.c40ab5fffd07a6d14df820f17deap-1L, + 0x1.c67f12e57d14b4a2137fd20f2a26p-1L, + 0x1.c8f6d9406e7b511acbc48805c3f6p-1L, + 0x1.cb720dcef90691503cbd1e949d0ap-1L, + 0x1.cdf0b555dc3f9c44f8958fac4f12p-1L, + 0x1.d072d4a07897b8d0f22f21a13792p-1L, + 0x1.d2f87080d89f18ade123989ea50ep-1L, + 0x1.d5818dcfba48725da05aeb66dff8p-1L, + 0x1.d80e316c98397bb84f9d048807a0p-1L, + 0x1.da9e603db3285708c01a5b6d480cp-1L, + 0x1.dd321f301b4604b695de3c0630c0p-1L, + 0x1.dfc97337b9b5eb968cac39ed284cp-1L, + 0x1.e264614f5a128a12761fa17adc74p-1L, + 0x1.e502ee78b3ff6273d130153992d0p-1L, + 0x1.e7a51fbc74c834b548b2832378a4p-1L, + 0x1.ea4afa2a490d9858f73a18f5dab4p-1L, + 0x1.ecf482d8e67f08db0312fb949d50p-1L, + 0x1.efa1bee615a27771fd21a92dabb6p-1L, + 0x1.f252b376bba974e8696fc3638f24p-1L, + 0x1.f50765b6e4540674f84b762861a6p-1L, + 0x1.f7bfdad9cbe138913b4bfe72bd78p-1L, + 0x1.fa7c1819e90d82e90a7e74b26360p-1L, + 0x1.fd3c22b8f71f10975ba4b32bd006p-1L, + 0x1.0000000000000000000000000000p+0L, + 0x1.0163da9fb33356d84a66ae336e98p+0L, + 0x1.02c9a3e778060ee6f7caca4f7a18p+0L, + 0x1.04315e86e7f84bd738f9a20da442p+0L, + 0x1.059b0d31585743ae7c548eb68c6ap+0L, + 0x1.0706b29ddf6ddc6dc403a9d87b1ep+0L, + 0x1.0874518759bc808c35f25d942856p+0L, + 0x1.09e3ecac6f3834521e060c584d5cp+0L, + 0x1.0b5586cf9890f6298b92b7184200p+0L, + 0x1.0cc922b7247f7407b705b893dbdep+0L, + 0x1.0e3ec32d3d1a2020742e4f8af794p+0L, + 0x1.0fb66affed31af232091dd8a169ep+0L, + 0x1.11301d0125b50a4ebbf1aed9321cp+0L, + 0x1.12abdc06c31cbfb92bad324d6f84p+0L, + 0x1.1429aaea92ddfb34101943b2588ep+0L, + 0x1.15a98c8a58e512480d573dd562aep+0L, + 0x1.172b83c7d517adcdf7c8c50eb162p+0L, + 0x1.18af9388c8de9bbbf70b9a3c269cp+0L, + 0x1.1a35beb6fcb753cb698f692d2038p+0L, + 0x1.1bbe084045cd39ab1e72b442810ep+0L, + 0x1.1d4873168b9aa7805b8028990be8p+0L, + 0x1.1ed5022fcd91cb8819ff61121fbep+0L, + 0x1.2063b88628cd63b8eeb0295093f6p+0L, + 0x1.21f49917ddc962552fd29294bc20p+0L, + 0x1.2387a6e75623866c1fadb1c159c0p+0L, + 0x1.251ce4fb2a63f3582ab7de9e9562p+0L, + 0x1.26b4565e27cdd257a673281d3068p+0L, + 0x1.284dfe1f5638096cf15cf03c9fa0p+0L, + 0x1.29e9df51fdee12c25d15f5a25022p+0L, + 0x1.2b87fd0dad98ffddea46538fca24p+0L, + 0x1.2d285a6e4030b40091d536d0733ep+0L, + 0x1.2ecafa93e2f5611ca0f45d5239a4p+0L, + 0x1.306fe0a31b7152de8d5a463063bep+0L, + 0x1.32170fc4cd8313539cf1c3009330p+0L, + 0x1.33c08b26416ff4c9c8610d96680ep+0L, + 0x1.356c55f929ff0c94623476373be4p+0L, + 0x1.371a7373aa9caa7145502f45452ap+0L, + 0x1.38cae6d05d86585a9cb0d9bed530p+0L, + 0x1.3a7db34e59ff6ea1bc9299e0a1fep+0L, + 0x1.3c32dc313a8e484001f228b58cf0p+0L, + 0x1.3dea64c12342235b41223e13d7eep+0L, + 0x1.3fa4504ac801ba0bf701aa417b9cp+0L, + 0x1.4160a21f72e29f84325b8f3dbacap+0L, + 0x1.431f5d950a896dc704439410b628p+0L, + 0x1.44e086061892d03136f409df0724p+0L, + 0x1.46a41ed1d005772512f459229f0ap+0L, + 0x1.486a2b5c13cd013c1a3b69062f26p+0L, + 0x1.4a32af0d7d3de672d8bcf46f99b4p+0L, + 0x1.4bfdad5362a271d4397afec42e36p+0L, + 0x1.4dcb299fddd0d63b36ef1a9e19dep+0L, + 0x1.4f9b2769d2ca6ad33d8b69aa0b8cp+0L, + 0x1.516daa2cf6641c112f52c84d6066p+0L, + 0x1.5342b569d4f81df0a83c49d86bf4p+0L, + 0x1.551a4ca5d920ec52ec620243540cp+0L, + 0x1.56f4736b527da66ecb004764e61ep+0L, + 0x1.58d12d497c7fd252bc2b7343d554p+0L, + 0x1.5ab07dd48542958c93015191e9a8p+0L, + 0x1.5c9268a5946b701c4b1b81697ed4p+0L, + 0x1.5e76f15ad21486e9be4c20399d12p+0L, + 0x1.605e1b976dc08b076f592a487066p+0L, + 0x1.6247eb03a5584b1f0fa06fd2d9eap+0L, + 0x1.6434634ccc31fc76f8714c4ee122p+0L, + 0x1.66238825522249127d9e29b92ea2p+0L, + 0x1.68155d44ca973081c57227b9f69ep+0L, +}; + +static const float eps[TBLSIZE] = { + -0x1.5c50p-101, + -0x1.5d00p-106, + 0x1.8e90p-102, + -0x1.5340p-103, + 0x1.1bd0p-102, + -0x1.4600p-105, + -0x1.7a40p-104, + 0x1.d590p-102, + -0x1.d590p-101, + 0x1.b100p-103, + -0x1.0d80p-105, + 0x1.6b00p-103, + -0x1.9f00p-105, + 0x1.c400p-103, + 0x1.e120p-103, + -0x1.c100p-104, + -0x1.9d20p-103, + 0x1.a800p-108, + 0x1.4c00p-106, + -0x1.9500p-106, + 0x1.6900p-105, + -0x1.29d0p-100, + 0x1.4c60p-103, + 0x1.13a0p-102, + -0x1.5b60p-103, + -0x1.1c40p-103, + 0x1.db80p-102, + 0x1.91a0p-102, + 0x1.dc00p-105, + 0x1.44c0p-104, + 0x1.9710p-102, + 0x1.8760p-103, + -0x1.a720p-103, + 0x1.ed20p-103, + -0x1.49c0p-102, + -0x1.e000p-111, + 0x1.86a0p-103, + 0x1.2b40p-103, + -0x1.b400p-108, + 0x1.1280p-99, + -0x1.02d8p-102, + -0x1.e3d0p-103, + -0x1.b080p-105, + -0x1.f100p-107, + -0x1.16c0p-105, + -0x1.1190p-103, + -0x1.a7d2p-100, + 0x1.3450p-103, + -0x1.67c0p-105, + 0x1.4b80p-104, + -0x1.c4e0p-103, + 0x1.6000p-108, + -0x1.3f60p-105, + 0x1.93f0p-104, + 0x1.5fe0p-105, + 0x1.6f80p-107, + -0x1.7600p-106, + 0x1.21e0p-106, + -0x1.3a40p-106, + -0x1.40c0p-104, + -0x1.9860p-105, + -0x1.5d40p-108, + -0x1.1d70p-106, + 0x1.2760p-105, + 0x0.0000p+0, + 0x1.21e2p-104, + -0x1.9520p-108, + -0x1.5720p-106, + -0x1.4810p-106, + -0x1.be00p-109, + 0x1.0080p-105, + -0x1.5780p-108, + -0x1.d460p-105, + -0x1.6140p-105, + 0x1.4630p-104, + 0x1.ad50p-103, + 0x1.82e0p-105, + 0x1.1d3cp-101, + 0x1.6100p-107, + 0x1.ec30p-104, + 0x1.f200p-108, + 0x1.0b40p-103, + 0x1.3660p-102, + 0x1.d9d0p-103, + -0x1.02d0p-102, + 0x1.b070p-103, + 0x1.b9c0p-104, + -0x1.01c0p-103, + -0x1.dfe0p-103, + 0x1.1b60p-104, + -0x1.ae94p-101, + -0x1.3340p-104, + 0x1.b3d8p-102, + -0x1.6e40p-105, + -0x1.3670p-103, + 0x1.c140p-104, + 0x1.1840p-101, + 0x1.1ab0p-102, + -0x1.a400p-104, + 0x1.1f00p-104, + -0x1.7180p-103, + 0x1.4ce0p-102, + 0x1.9200p-107, + -0x1.54c0p-103, + 0x1.1b80p-105, + -0x1.1828p-101, + 0x1.5720p-102, + -0x1.a060p-100, + 0x1.9160p-102, + 0x1.a280p-104, + 0x1.3400p-107, + 0x1.2b20p-102, + 0x1.7800p-108, + 0x1.cfd0p-101, + 0x1.2ef0p-102, + -0x1.2760p-99, + 0x1.b380p-104, + 0x1.0048p-101, + -0x1.60b0p-102, + 0x1.a1ccp-100, + -0x1.a640p-104, + -0x1.08a0p-101, + 0x1.7e60p-102, + 0x1.22c0p-103, + -0x1.7200p-106, + 0x1.f0f0p-102, + 0x1.eb4ep-99, + 0x1.c6e0p-103, +}; + +/* + * exp2l(x): compute the base 2 exponential of x + * + * Accuracy: Peak error < 0.502 ulp. + * + * Method: (accurate tables) + * + * Reduce x: + * x = 2**k + y, for integer k and |y| <= 1/2. + * Thus we have exp2(x) = 2**k * exp2(y). + * + * Reduce y: + * y = i/TBLSIZE + z - eps[i] for integer i near y * TBLSIZE. + * Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z - eps[i]), + * with |z - eps[i]| <= 2**-8 + 2**-98 for the table used. + * + * We compute exp2(i/TBLSIZE) via table lookup and exp2(z - eps[i]) via + * a degree-10 minimax polynomial with maximum error under 2**-120. + * The values in exp2t[] and eps[] are chosen such that + * exp2t[i] = exp2(i/TBLSIZE + eps[i]), and eps[i] is a small offset such + * that exp2t[i] is accurate to 2**-122. + * + * Note that the range of i is +-TBLSIZE/2, so we actually index the tables + * by i0 = i + TBLSIZE/2. + * + * This method is due to Gal, with many details due to Gal and Bachelis: + * + * Gal, S. and Bachelis, B. An Accurate Elementary Mathematical Library + * for the IEEE Floating Point Standard. TOMS 17(1), 26-46 (1991). + */ +long double +exp2l(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + long double r, z, t; + uint32_t i0; + union {uint32_t u; int32_t i;} k; + + /* Filter out exceptional cases. */ + if (e >= 0x3fff + 14) { /* |x| >= 16384 or x is NaN */ + if (u.i.se >= 0x3fff + 15 && u.i.se >> 15 == 0) + /* overflow */ + return x * 0x1p16383L; + if (e == 0x7fff) /* -inf or -nan */ + return -1/x; + if (x < -16382) { + if (x <= -16495 || x - 0x1p112 + 0x1p112 != x) + /* underflow */ + FORCE_EVAL((float)(-0x1p-149/x)); + if (x <= -16446) + return 0; + } + } else if (e < 0x3fff - 114) { + return 1 + x; + } + + /* + * Reduce x, computing z, i0, and k. The low bits of x + redux + * contain the 16-bit integer part of the exponent (k) followed by + * TBLBITS fractional bits (i0). We use bit tricks to extract these + * as integers, then set z to the remainder. + * + * Example: Suppose x is 0xabc.123456p0 and TBLBITS is 8. + * Then the low-order word of x + redux is 0x000abc12, + * We split this into k = 0xabc and i0 = 0x12 (adjusted to + * index into the table), then we compute z = 0x0.003456p0. + */ + u.f = x + redux; + i0 = u.i2.lo + TBLSIZE / 2; + k.u = i0 / TBLSIZE * TBLSIZE; + k.i /= TBLSIZE; + i0 %= TBLSIZE; + u.f -= redux; + z = x - u.f; + + /* Compute r = exp2(y) = exp2t[i0] * p(z - eps[i]). */ + t = tbl[i0]; + z -= eps[i0]; + r = t + t * z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * (P5 + z * (P6 + + z * (P7 + z * (P8 + z * (P9 + z * P10))))))))); + + return scalbnl(r, k.i); +} #endif diff --git a/system/lib/libc/musl/src/math/expf.c b/system/lib/libc/musl/src/math/expf.c index 16e9afe62a21c..feee2b0ed2174 100644 --- a/system/lib/libc/musl/src/math/expf.c +++ b/system/lib/libc/musl/src/math/expf.c @@ -39,6 +39,8 @@ float expf(float x) /* special cases */ if (hx >= 0x42aeac50) { /* if |x| >= -87.33655f or NaN */ + if (hx > 0x7f800000) /* NaN */ + return x; if (hx >= 0x42b17218 && !sign) { /* x >= 88.722839f */ /* overflow */ x *= 0x1p127f; diff --git a/system/lib/libc/musl/src/math/expl.c b/system/lib/libc/musl/src/math/expl.c index b62980fa4065f..0a7f44f685ee3 100644 --- a/system/lib/libc/musl/src/math/expl.c +++ b/system/lib/libc/musl/src/math/expl.c @@ -119,4 +119,10 @@ long double expl(long double x) x = 1.0 + 2.0 * x; return scalbnl(x, k); } +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double expl(long double x) +{ + return exp(x); +} #endif diff --git a/system/lib/libc/musl/src/math/expm1l.c b/system/lib/libc/musl/src/math/expm1l.c index 21a86c0051878..d17150785282f 100644 --- a/system/lib/libc/musl/src/math/expm1l.c +++ b/system/lib/libc/musl/src/math/expm1l.c @@ -114,4 +114,10 @@ long double expm1l(long double x) x = px * qx + (px - 1.0); return x; } +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double expm1l(long double x) +{ + return expm1(x); +} #endif diff --git a/system/lib/libc/musl/src/math/floor.c b/system/lib/libc/musl/src/math/floor.c index ebc9fabe90822..14a31cd8c4c54 100644 --- a/system/lib/libc/musl/src/math/floor.c +++ b/system/lib/libc/musl/src/math/floor.c @@ -1,5 +1,12 @@ #include "libm.h" +#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif +static const double_t toint = 1/EPS; + double floor(double x) { union {double f; uint64_t i;} u = {x}; @@ -10,9 +17,9 @@ double floor(double x) return x; /* y = int(x) - x, where int(x) is an integer neighbor of x */ if (u.i >> 63) - y = (double)(x - 0x1p52) + 0x1p52 - x; + y = x - toint + toint - x; else - y = (double)(x + 0x1p52) - 0x1p52 - x; + y = x + toint - toint - x; /* special case because of non-nearest rounding modes */ if (e <= 0x3ff-1) { FORCE_EVAL(y); diff --git a/system/lib/libc/musl/src/math/floorl.c b/system/lib/libc/musl/src/math/floorl.c index 961f9e890b736..16aaec48eea8e 100644 --- a/system/lib/libc/musl/src/math/floorl.c +++ b/system/lib/libc/musl/src/math/floorl.c @@ -6,11 +6,9 @@ long double floorl(long double x) return floor(x); } #elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 -#if LDBL_MANT_DIG == 64 -#define TOINT 0x1p63 -#elif LDBL_MANT_DIG == 113 -#define TOINT 0x1p112 -#endif + +static const long double toint = 1/LDBL_EPSILON; + long double floorl(long double x) { union ldshape u = {x}; @@ -21,9 +19,9 @@ long double floorl(long double x) return x; /* y = int(x) - x, where int(x) is an integer neighbor of x */ if (u.i.se >> 15) - y = x - TOINT + TOINT - x; + y = x - toint + toint - x; else - y = x + TOINT - TOINT - x; + y = x + toint - toint - x; /* special case because of non-nearest rounding modes */ if (e <= 0x3fff-1) { FORCE_EVAL(y); diff --git a/system/lib/libc/musl/src/math/fmodl.c b/system/lib/libc/musl/src/math/fmodl.c index 54af6a3fd1592..9f5b87393dcad 100644 --- a/system/lib/libc/musl/src/math/fmodl.c +++ b/system/lib/libc/musl/src/math/fmodl.c @@ -63,7 +63,7 @@ long double fmodl(long double x, long double y) xhi = (ux.i2.hi & -1ULL>>16) | 1ULL<<48; yhi = (uy.i2.hi & -1ULL>>16) | 1ULL<<48; xlo = ux.i2.lo; - ylo = ux.i2.lo; + ylo = uy.i2.lo; for (; ex > ey; ex--) { hi = xhi - yhi; lo = xlo - ylo; diff --git a/system/lib/libc/musl/src/math/hypot.c b/system/lib/libc/musl/src/math/hypot.c index 29ec6a476d1bf..6071bf1e284f3 100644 --- a/system/lib/libc/musl/src/math/hypot.c +++ b/system/lib/libc/musl/src/math/hypot.c @@ -12,10 +12,10 @@ static void sq(double_t *hi, double_t *lo, double x) { double_t xh, xl, xc; - xc = x*SPLIT; + xc = (double_t)x*SPLIT; xh = x - xc + xc; xl = x - xh; - *hi = x*x; + *hi = (double_t)x*x; *lo = xh*xh - *hi + 2*xh*xl + xl*xl; } diff --git a/system/lib/libc/musl/src/math/lgammal.c b/system/lib/libc/musl/src/math/lgammal.c index 55ec5325ed138..2b354a7c13245 100644 --- a/system/lib/libc/musl/src/math/lgammal.c +++ b/system/lib/libc/musl/src/math/lgammal.c @@ -340,9 +340,16 @@ long double __lgammal_r(long double x, int *sg) { r = nadj - r; return r; } +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +double __lgamma_r(double x, int *sg); + +long double __lgammal_r(long double x, int *sg) +{ + return __lgamma_r(x, sg); +} #endif -#if (LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024) || (LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384) extern int __signgam; long double lgammal(long double x) @@ -351,4 +358,3 @@ long double lgammal(long double x) } weak_alias(__lgammal_r, lgammal_r); -#endif diff --git a/system/lib/libc/musl/src/math/log10l.c b/system/lib/libc/musl/src/math/log10l.c index c7aacf909a451..63dcc286d6211 100644 --- a/system/lib/libc/musl/src/math/log10l.c +++ b/system/lib/libc/musl/src/math/log10l.c @@ -182,4 +182,10 @@ long double log10l(long double x) z += e * (L102A); return z; } +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double log10l(long double x) +{ + return log10(x); +} #endif diff --git a/system/lib/libc/musl/src/math/log1pl.c b/system/lib/libc/musl/src/math/log1pl.c index 37da46d23914b..141b5f0b0c295 100644 --- a/system/lib/libc/musl/src/math/log1pl.c +++ b/system/lib/libc/musl/src/math/log1pl.c @@ -168,4 +168,10 @@ long double log1pl(long double xm1) z = z + e * C1; return z; } +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double log1pl(long double x) +{ + return log1p(x); +} #endif diff --git a/system/lib/libc/musl/src/math/log2l.c b/system/lib/libc/musl/src/math/log2l.c index d00531d5976e2..722b451a026ae 100644 --- a/system/lib/libc/musl/src/math/log2l.c +++ b/system/lib/libc/musl/src/math/log2l.c @@ -173,4 +173,10 @@ long double log2l(long double x) z += e; return z; } +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double log2l(long double x) +{ + return log2(x); +} #endif diff --git a/system/lib/libc/musl/src/math/logl.c b/system/lib/libc/musl/src/math/logl.c index 03c5188fd9d79..5d5365929e62a 100644 --- a/system/lib/libc/musl/src/math/logl.c +++ b/system/lib/libc/musl/src/math/logl.c @@ -166,4 +166,10 @@ long double logl(long double x) z = z + e * C1; /* This sum has an error of 1/2 lsb. */ return z; } +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double logl(long double x) +{ + return log(x); +} #endif diff --git a/system/lib/libc/musl/src/math/modfl.c b/system/lib/libc/musl/src/math/modfl.c index 4b03a4be0aa46..a47b1924f75d1 100644 --- a/system/lib/libc/musl/src/math/modfl.c +++ b/system/lib/libc/musl/src/math/modfl.c @@ -11,11 +11,9 @@ long double modfl(long double x, long double *iptr) return r; } #elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 -#if LDBL_MANT_DIG == 64 -#define TOINT 0x1p63 -#elif LDBL_MANT_DIG == 113 -#define TOINT 0x1p112 -#endif + +static const long double toint = 1/LDBL_EPSILON; + long double modfl(long double x, long double *iptr) { union ldshape u = {x}; @@ -40,7 +38,7 @@ long double modfl(long double x, long double *iptr) /* raises spurious inexact */ absx = s ? -x : x; - y = absx + TOINT - TOINT - absx; + y = absx + toint - toint - absx; if (y == 0) { *iptr = x; return s ? -0.0 : 0.0; diff --git a/system/lib/libc/musl/src/math/pow.c b/system/lib/libc/musl/src/math/pow.c index 82f684bdb0e36..b66f632d8eea9 100644 --- a/system/lib/libc/musl/src/math/pow.c +++ b/system/lib/libc/musl/src/math/pow.c @@ -143,7 +143,7 @@ double pow(double x, double y) return 1.0; else if (ix >= 0x3ff00000) /* (|x|>1)**+-inf = inf,0 */ return hy >= 0 ? y : 0.0; - else if ((ix|lx) != 0) /* (|x|<1)**+-inf = 0,inf if x!=0 */ + else /* (|x|<1)**+-inf = 0,inf */ return hy >= 0 ? 0.0 : -y; } if (iy == 0x3ff00000) { /* y is +-1 */ diff --git a/system/lib/libc/musl/src/math/powf.c b/system/lib/libc/musl/src/math/powf.c index 59baf6f3809cf..427c8965b9e8e 100644 --- a/system/lib/libc/musl/src/math/powf.c +++ b/system/lib/libc/musl/src/math/powf.c @@ -90,7 +90,7 @@ float powf(float x, float y) return 1.0f; else if (ix > 0x3f800000) /* (|x|>1)**+-inf = inf,0 */ return hy >= 0 ? y : 0.0f; - else if (ix != 0) /* (|x|<1)**+-inf = 0,inf if x!=0 */ + else /* (|x|<1)**+-inf = 0,inf */ return hy >= 0 ? 0.0f: -y; } if (iy == 0x3f800000) /* y is +-1 */ diff --git a/system/lib/libc/musl/src/math/powl.c b/system/lib/libc/musl/src/math/powl.c index ce6274cf73e00..5b6da07b2efcc 100644 --- a/system/lib/libc/musl/src/math/powl.c +++ b/system/lib/libc/musl/src/math/powl.c @@ -227,7 +227,7 @@ long double powl(long double x, long double y) if (y <= -LDBL_MAX) { if (x > 1.0 || x < -1.0) return 0.0; - if (x != 0.0) + if (x != 0.0 || y == -INFINITY) return INFINITY; } if (x >= LDBL_MAX) { @@ -513,5 +513,10 @@ static long double powil(long double x, int nn) y = 1.0/y; return y; } - +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double powl(long double x, long double y) +{ + return pow(x, y); +} #endif diff --git a/system/lib/libc/musl/src/math/rint.c b/system/lib/libc/musl/src/math/rint.c index 81f4e6223b748..fbba390e7d723 100644 --- a/system/lib/libc/musl/src/math/rint.c +++ b/system/lib/libc/musl/src/math/rint.c @@ -1,6 +1,14 @@ +#include #include #include +#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif +static const double_t toint = 1/EPS; + double rint(double x) { union {double f; uint64_t i;} u = {x}; @@ -11,9 +19,9 @@ double rint(double x) if (e >= 0x3ff+52) return x; if (s) - y = (double)(x - 0x1p52) + 0x1p52; + y = x - toint + toint; else - y = (double)(x + 0x1p52) - 0x1p52; + y = x + toint - toint; if (y == 0) return s ? -0.0 : 0; return y; diff --git a/system/lib/libc/musl/src/math/rintf.c b/system/lib/libc/musl/src/math/rintf.c index 9cfc2a261f3c7..9047688d246a6 100644 --- a/system/lib/libc/musl/src/math/rintf.c +++ b/system/lib/libc/musl/src/math/rintf.c @@ -1,6 +1,16 @@ +#include #include #include +#if FLT_EVAL_METHOD==0 +#define EPS FLT_EPSILON +#elif FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif +static const float_t toint = 1/EPS; + float rintf(float x) { union {float f; uint32_t i;} u = {x}; @@ -11,9 +21,9 @@ float rintf(float x) if (e >= 0x7f+23) return x; if (s) - y = (float)(x - 0x1p23f) + 0x1p23f; + y = x - toint + toint; else - y = (float)(x + 0x1p23f) - 0x1p23f; + y = x + toint - toint; if (y == 0) return s ? -0.0f : 0.0f; return y; diff --git a/system/lib/libc/musl/src/math/rintl.c b/system/lib/libc/musl/src/math/rintl.c index 267250737f0a8..374327db2282d 100644 --- a/system/lib/libc/musl/src/math/rintl.c +++ b/system/lib/libc/musl/src/math/rintl.c @@ -6,11 +6,9 @@ long double rintl(long double x) return rint(x); } #elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 -#if LDBL_MANT_DIG == 64 -#define TOINT 0x1p63 -#elif LDBL_MANT_DIG == 113 -#define TOINT 0x1p112 -#endif + +static const long double toint = 1/LDBL_EPSILON; + long double rintl(long double x) { union ldshape u = {x}; @@ -21,9 +19,9 @@ long double rintl(long double x) if (e >= 0x3fff+LDBL_MANT_DIG-1) return x; if (s) - y = x - TOINT + TOINT; + y = x - toint + toint; else - y = x + TOINT - TOINT; + y = x + toint - toint; if (y == 0) return 0*x; return y; diff --git a/system/lib/libc/musl/src/math/round.c b/system/lib/libc/musl/src/math/round.c index 4b38d1fdbb2ad..130d58d2571e7 100644 --- a/system/lib/libc/musl/src/math/round.c +++ b/system/lib/libc/musl/src/math/round.c @@ -1,5 +1,12 @@ #include "libm.h" +#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif +static const double_t toint = 1/EPS; + double round(double x) { union {double f; uint64_t i;} u = {x}; @@ -12,10 +19,10 @@ double round(double x) x = -x; if (e < 0x3ff-1) { /* raise inexact if x!=0 */ - FORCE_EVAL(x + 0x1p52); + FORCE_EVAL(x + toint); return 0*u.f; } - y = (double)(x + 0x1p52) - 0x1p52 - x; + y = x + toint - toint - x; if (y > 0.5) y = y + x - 1; else if (y <= -0.5) diff --git a/system/lib/libc/musl/src/math/roundf.c b/system/lib/libc/musl/src/math/roundf.c index c6b277979038e..e8210af5621aa 100644 --- a/system/lib/libc/musl/src/math/roundf.c +++ b/system/lib/libc/musl/src/math/roundf.c @@ -1,5 +1,14 @@ #include "libm.h" +#if FLT_EVAL_METHOD==0 +#define EPS FLT_EPSILON +#elif FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif +static const float_t toint = 1/EPS; + float roundf(float x) { union {float f; uint32_t i;} u = {x}; @@ -11,10 +20,10 @@ float roundf(float x) if (u.i >> 31) x = -x; if (e < 0x7f-1) { - FORCE_EVAL(x + 0x1p23f); + FORCE_EVAL(x + toint); return 0*u.f; } - y = (float)(x + 0x1p23f) - 0x1p23f - x; + y = x + toint - toint - x; if (y > 0.5f) y = y + x - 1; else if (y <= -0.5f) diff --git a/system/lib/libc/musl/src/math/roundl.c b/system/lib/libc/musl/src/math/roundl.c index 8f3f28b348e13..f4ff6820a9822 100644 --- a/system/lib/libc/musl/src/math/roundl.c +++ b/system/lib/libc/musl/src/math/roundl.c @@ -6,11 +6,9 @@ long double roundl(long double x) return round(x); } #elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 -#if LDBL_MANT_DIG == 64 -#define TOINT 0x1p63 -#elif LDBL_MANT_DIG == 113 -#define TOINT 0x1p112 -#endif + +static const long double toint = 1/LDBL_EPSILON; + long double roundl(long double x) { union ldshape u = {x}; @@ -22,10 +20,10 @@ long double roundl(long double x) if (u.i.se >> 15) x = -x; if (e < 0x3fff-1) { - FORCE_EVAL(x + TOINT); + FORCE_EVAL(x + toint); return 0*u.f; } - y = x + TOINT - TOINT - x; + y = x + toint - toint - x; if (y > 0.5) y = y + x - 1; else if (y <= -0.5) diff --git a/system/lib/libc/musl/src/math/sinhl.c b/system/lib/libc/musl/src/math/sinhl.c index 4864ddfa6a77c..b305d4d2f3e9c 100644 --- a/system/lib/libc/musl/src/math/sinhl.c +++ b/system/lib/libc/musl/src/math/sinhl.c @@ -34,4 +34,10 @@ long double sinhl(long double x) t = expl(0.5*absx); return h*t*t; } +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double sinhl(long double x) +{ + return sinh(x); +} #endif diff --git a/system/lib/libc/musl/src/math/tanhl.c b/system/lib/libc/musl/src/math/tanhl.c index f594b85f3d6ce..4e1aa9f87dde3 100644 --- a/system/lib/libc/musl/src/math/tanhl.c +++ b/system/lib/libc/musl/src/math/tanhl.c @@ -39,4 +39,10 @@ long double tanhl(long double x) } return sign ? -t : t; } +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double tanhl(long double x) +{ + return tanh(x); +} #endif diff --git a/system/lib/libc/musl/src/math/tgammal.c b/system/lib/libc/musl/src/math/tgammal.c index 5c1a02a639969..5336c5b194e86 100644 --- a/system/lib/libc/musl/src/math/tgammal.c +++ b/system/lib/libc/musl/src/math/tgammal.c @@ -272,4 +272,10 @@ long double tgammal(long double x) q = z / (x * __polevll(x, S, 8)); return q; } +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double tgammal(long double x) +{ + return tgamma(x); +} #endif diff --git a/system/lib/libc/musl/src/math/truncl.c b/system/lib/libc/musl/src/math/truncl.c index 3eedb08397131..f07b1934097bc 100644 --- a/system/lib/libc/musl/src/math/truncl.c +++ b/system/lib/libc/musl/src/math/truncl.c @@ -6,11 +6,9 @@ long double truncl(long double x) return trunc(x); } #elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 -#if LDBL_MANT_DIG == 64 -#define TOINT 0x1p63 -#elif LDBL_MANT_DIG == 113 -#define TOINT 0x1p112 -#endif + +static const long double toint = 1/LDBL_EPSILON; + long double truncl(long double x) { union ldshape u = {x}; @@ -27,7 +25,7 @@ long double truncl(long double x) /* y = int(|x|) - |x|, where int(|x|) is an integer neighbor of |x| */ if (s) x = -x; - y = x + TOINT - TOINT - x; + y = x + toint - toint - x; if (y > 0) y -= 1; x += y; diff --git a/system/lib/libc/musl/src/misc/a64l.c b/system/lib/libc/musl/src/misc/a64l.c index 86aeefe0d5f70..6055771040349 100644 --- a/system/lib/libc/musl/src/misc/a64l.c +++ b/system/lib/libc/musl/src/misc/a64l.c @@ -9,9 +9,12 @@ long a64l(const char *s) { int e; uint32_t x = 0; - for (e=0; e<36 && *s; e+=6, s++) - x |= (strchr(digits, *s)-digits)< +#include "libc.h" +#include "pthread_impl.h" + +#if !__EMSCRIPTEN_PTHREADS__ +static struct pthread __main_pthread; +pthread_t pthread_self(void) { + return &__main_pthread; +} +#endif + +__attribute__((constructor)) +void __emscripten_pthread_data_constructor(void) { + pthread_self()->locale = &libc.global_locale; +} diff --git a/system/lib/libc/musl/src/misc/ffsl.c b/system/lib/libc/musl/src/misc/ffsl.c new file mode 100644 index 0000000000000..0105c66af9d18 --- /dev/null +++ b/system/lib/libc/musl/src/misc/ffsl.c @@ -0,0 +1,7 @@ +#include +#include "atomic.h" + +int ffsl(long i) +{ + return i ? a_ctz_l(i)+1 : 0; +} diff --git a/system/lib/libc/musl/src/misc/ffsll.c b/system/lib/libc/musl/src/misc/ffsll.c new file mode 100644 index 0000000000000..0c5ced8266579 --- /dev/null +++ b/system/lib/libc/musl/src/misc/ffsll.c @@ -0,0 +1,7 @@ +#include +#include "atomic.h" + +int ffsll(long long i) +{ + return i ? a_ctz_64(i)+1 : 0; +} diff --git a/system/lib/libc/musl/src/misc/fmtmsg.c b/system/lib/libc/musl/src/misc/fmtmsg.c new file mode 100644 index 0000000000000..69170b25429c4 --- /dev/null +++ b/system/lib/libc/musl/src/misc/fmtmsg.c @@ -0,0 +1,90 @@ +/* Public domain fmtmsg() + * Written by Isaac Dunham, 2014 + */ +#include +#include +#include +#include +#include +#include +#include + +/* + * If lstr is the first part of bstr, check that the next char in bstr + * is either \0 or : + */ +static int _strcolcmp(const char *lstr, const char *bstr) +{ + size_t i = 0; + while (lstr[i] && bstr[i] && (bstr[i] == lstr[i])) i++; + if ( lstr[i] || (bstr[i] && bstr[i] != ':')) return 1; + return 0; +} + +int fmtmsg(long classification, const char *label, int severity, + const char *text, const char *action, const char *tag) +{ + int ret = 0, i, consolefd, verb = 0; + char *errstring = MM_NULLSEV, *cmsg = getenv("MSGVERB"); + char *const msgs[] = { + "label", "severity", "text", "action", "tag", NULL + }; + int cs; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + + if (severity == MM_HALT) errstring = "HALT: "; + else if (severity == MM_ERROR) errstring = "ERROR: "; + else if (severity == MM_WARNING) errstring = "WARNING: "; + else if (severity == MM_INFO) errstring = "INFO: "; + + if (classification & MM_CONSOLE) { + consolefd = open("/dev/console", O_WRONLY); + if (consolefd < 0) { + ret = MM_NOCON; + } else { + if (dprintf(consolefd, "%s%s%s%s%s%s%s%s\n", + label?label:"", label?": ":"", + severity?errstring:"", text?text:"", + action?"\nTO FIX: ":"", + action?action:"", action?" ":"", + tag?tag:"" )<1) + ret = MM_NOCON; + close(consolefd); + } + } + + if (classification & MM_PRINT) { + while (cmsg && cmsg[0]) { + for(i=0; msgs[i]; i++) { + if (!_strcolcmp(msgs[i], cmsg)) break; + } + if (msgs[i] == NULL) { + //ignore MSGVERB-unrecognized component + verb = 0xFF; + break; + } else { + verb |= (1 << i); + cmsg = strchr(cmsg, ':'); + if (cmsg) cmsg++; + } + } + if (!verb) verb = 0xFF; + if (dprintf(2, "%s%s%s%s%s%s%s%s\n", + (verb&1 && label) ? label : "", + (verb&1 && label) ? ": " : "", + (verb&2 && severity) ? errstring : "", + (verb&4 && text) ? text : "", + (verb&8 && action) ? "\nTO FIX: " : "", + (verb&8 && action) ? action : "", + (verb&8 && action) ? " " : "", + (verb&16 && tag) ? tag : "" ) < 1) + ret |= MM_NOMSG; + } + if ((ret & (MM_NOCON|MM_NOMSG)) == (MM_NOCON|MM_NOMSG)) + ret = MM_NOTOK; + + pthread_setcancelstate(cs, 0); + + return ret; +} diff --git a/system/lib/libc/musl/src/misc/forkpty.c b/system/lib/libc/musl/src/misc/forkpty.c index 07f8d01eed667..caf13adbf3f9a 100644 --- a/system/lib/libc/musl/src/misc/forkpty.c +++ b/system/lib/libc/musl/src/misc/forkpty.c @@ -1,38 +1,57 @@ #include +#include #include -#include +#include #include +#include +#include -int forkpty(int *m, char *name, const struct termios *tio, const struct winsize *ws) +int forkpty(int *pm, char *name, const struct termios *tio, const struct winsize *ws) { - int s, t, i, istmp[3]={0}; - pid_t pid; - - if (openpty(m, &s, name, tio, ws) < 0) return -1; - - /* Ensure before forking that we don't exceed fd limit */ - for (i=0; i<3; i++) { - if (fcntl(i, F_GETFL) < 0) { - t = fcntl(s, F_DUPFD, i); - if (t<0) break; - else if (t!=i) close(t); - else istmp[i] = 1; - } + int m, s, ec=0, p[2], cs; + pid_t pid=-1; + sigset_t set, oldset; + + if (openpty(&m, &s, name, tio, ws) < 0) return -1; + + sigfillset(&set); + pthread_sigmask(SIG_BLOCK, &set, &oldset); + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + + if (pipe2(p, O_CLOEXEC)) { + close(s); + goto out; } - pid = i==3 ? fork() : -1; + + pid = fork(); if (!pid) { - close(*m); - setsid(); - ioctl(s, TIOCSCTTY, (char *)0); - dup2(s, 0); - dup2(s, 1); - dup2(s, 2); - if (s>2) close(s); + close(m); + close(p[0]); + if (login_tty(s)) { + write(p[1], &errno, sizeof errno); + _exit(127); + } + close(p[1]); + pthread_setcancelstate(cs, 0); + pthread_sigmask(SIG_SETMASK, &oldset, 0); return 0; } - for (i=0; i<3; i++) - if (istmp[i]) close(i); close(s); - if (pid < 0) close(*m); + close(p[1]); + if (read(p[0], &ec, sizeof ec) > 0) { + int status; + waitpid(pid, &status, 0); + pid = -1; + errno = ec; + } + close(p[0]); + +out: + if (pid > 0) *pm = m; + else close(m); + + pthread_setcancelstate(cs, 0); + pthread_sigmask(SIG_SETMASK, &oldset, 0); + return pid; } diff --git a/system/lib/libc/musl/src/misc/getauxval.c b/system/lib/libc/musl/src/misc/getauxval.c new file mode 100644 index 0000000000000..b846c80fdd4c0 --- /dev/null +++ b/system/lib/libc/musl/src/misc/getauxval.c @@ -0,0 +1,13 @@ +#include +#include +#include "libc.h" + +unsigned long getauxval(unsigned long item) +{ + size_t *auxv = libc.auxv; + if (item == AT_SECURE) return libc.secure; + for (; *auxv; auxv+=2) + if (*auxv==item) return auxv[1]; + errno = ENOENT; + return 0; +} diff --git a/system/lib/libc/musl/src/misc/getopt.c b/system/lib/libc/musl/src/misc/getopt.c index f1a1639c56da1..8290aef75aa43 100644 --- a/system/lib/libc/musl/src/misc/getopt.c +++ b/system/lib/libc/musl/src/misc/getopt.c @@ -4,6 +4,7 @@ #include #include #include "libc.h" +#include "locale_impl.h" char *optarg; int optind=1, opterr=1, optopt, __optpos, __optreset=0; @@ -11,6 +12,18 @@ int optind=1, opterr=1, optopt, __optpos, __optreset=0; #define optpos __optpos weak_alias(__optreset, optreset); +void __getopt_msg(const char *a, const char *b, const char *c, size_t l) +{ + FILE *f = stderr; + b = __lctrans_cur(b); + flockfile(f); + fputs(a, f)>=0 + && fwrite(b, strlen(b), 1, f) + && fwrite(c, 1, l, f)==l + && putc('\n', f); + funlockfile(f); +} + int getopt(int argc, char * const argv[], const char *optstring) { int i; @@ -24,8 +37,20 @@ int getopt(int argc, char * const argv[], const char *optstring) optind = 1; } - if (optind >= argc || !argv[optind] || argv[optind][0] != '-' || !argv[optind][1]) + if (optind >= argc || !argv[optind]) + return -1; + + if (argv[optind][0] != '-') { + if (optstring[0] == '-') { + optarg = argv[optind++]; + return 1; + } + return -1; + } + + if (!argv[optind][1]) return -1; + if (argv[optind][1] == '-' && !argv[optind][2]) return optind++, -1; @@ -43,30 +68,34 @@ int getopt(int argc, char * const argv[], const char *optstring) optpos = 0; } - for (i=0; (l = mbtowc(&d, optstring+i, MB_LEN_MAX)) && d!=c; i+=l>0?l:1); + if (optstring[0] == '-' || optstring[0] == '+') + optstring++; + + i = 0; + d = 0; + do { + l = mbtowc(&d, optstring+i, MB_LEN_MAX); + if (l>0) i+=l; else i++; + } while (l && d != c); if (d != c) { - if (optstring[0] != ':' && opterr) { - write(2, argv[0], strlen(argv[0])); - write(2, ": illegal option: ", 18); - write(2, optchar, k); - write(2, "\n", 1); - } + if (optstring[0] != ':' && opterr) + __getopt_msg(argv[0], ": unrecognized option: ", optchar, k); return '?'; } - if (optstring[i+1] == ':') { - if (optind >= argc) { + if (optstring[i] == ':') { + if (optstring[i+1] == ':') optarg = 0; + else if (optind >= argc) { if (optstring[0] == ':') return ':'; - if (opterr) { - write(2, argv[0], strlen(argv[0])); - write(2, ": option requires an argument: ", 31); - write(2, optchar, k); - write(2, "\n", 1); - } + if (opterr) __getopt_msg(argv[0], + ": option requires an argument: ", + optchar, k); return '?'; } - optarg = argv[optind++] + optpos; - optpos = 0; + if (optstring[i+1] != ':' || optpos) { + optarg = argv[optind++] + optpos; + optpos = 0; + } } return c; } diff --git a/system/lib/libc/musl/src/misc/getopt_long.c b/system/lib/libc/musl/src/misc/getopt_long.c index 4ef5a5c7a861d..480c00139e086 100644 --- a/system/lib/libc/musl/src/misc/getopt_long.c +++ b/system/lib/libc/musl/src/misc/getopt_long.c @@ -2,37 +2,103 @@ #include #include #include +#include extern int __optpos, __optreset; +static void permute(char *const *argv, int dest, int src) +{ + char **av = (char **)argv; + char *tmp = av[src]; + int i; + for (i=src; i>dest; i--) + av[i] = av[i-1]; + av[dest] = tmp; +} + +void __getopt_msg(const char *, const char *, const char *, size_t); + +static int __getopt_long_core(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly); + static int __getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly) { + int ret, skipped, resumed; if (!optind || __optreset) { __optreset = 0; __optpos = 0; optind = 1; } - if (optind >= argc || !argv[optind] || argv[optind][0] != '-') return -1; - if ((longonly && argv[optind][1]) || - (argv[optind][1] == '-' && argv[optind][2])) - { + if (optind >= argc || !argv[optind]) return -1; + skipped = optind; + if (optstring[0] != '+' && optstring[0] != '-') { int i; - for (i=0; longopts[i].name; i++) { + for (i=optind; ; i++) { + if (i >= argc || !argv[i]) return -1; + if (argv[i][0] == '-' && argv[i][1]) break; + } + optind = i; + } + resumed = optind; + ret = __getopt_long_core(argc, argv, optstring, longopts, idx, longonly); + if (resumed > skipped) { + int i, cnt = optind-resumed; + for (i=0; i= 0) { + dprintf(fd, "%.*s", l-hlen, buf+hlen); + close(fd); + } + } + if (log_opt & LOG_PERROR) dprintf(2, "%.*s", l-hlen, buf+hlen); } } diff --git a/system/lib/libc/musl/src/mman/mmap.c b/system/lib/libc/musl/src/mman/mmap.c index b56cff86b6da4..b85f25ca083e8 100644 --- a/system/lib/libc/musl/src/mman/mmap.c +++ b/system/lib/libc/musl/src/mman/mmap.c @@ -6,17 +6,14 @@ #include "syscall.h" #include "libc.h" -static void dummy1(int x) { } -static void dummy0(void) { } -weak_alias(dummy1, __vm_lock); -weak_alias(dummy0, __vm_unlock); +static void dummy(void) { } +weak_alias(dummy, __vm_wait); -#define OFF_MASK ((-0x2000ULL << (8*sizeof(long)-1)) | 0xfff) +#define UNIT SYSCALL_MMAP2_UNIT +#define OFF_MASK ((-0x2000ULL << (8*sizeof(long)-1)) | (UNIT-1)) void *__mmap(void *start, size_t len, int prot, int flags, int fd, off_t off) { - void *ret; - if (off & OFF_MASK) { errno = EINVAL; return MAP_FAILED; @@ -25,14 +22,14 @@ void *__mmap(void *start, size_t len, int prot, int flags, int fd, off_t off) errno = ENOMEM; return MAP_FAILED; } - if (flags & MAP_FIXED) __vm_lock(-1); + if (flags & MAP_FIXED) { + __vm_wait(); + } #ifdef SYS_mmap2 - ret = (void *)syscall(SYS_mmap2, start, len, prot, flags, fd, off>>12); + return (void *)syscall(SYS_mmap2, start, len, prot, flags, fd, off/UNIT); #else - ret = (void *)syscall(SYS_mmap, start, len, prot, flags, fd, off); + return (void *)syscall(SYS_mmap, start, len, prot, flags, fd, off); #endif - if (flags & MAP_FIXED) __vm_unlock(); - return ret; } weak_alias(__mmap, mmap); diff --git a/system/lib/libc/musl/src/mman/mprotect.c b/system/lib/libc/musl/src/mman/mprotect.c index f488486db6e2d..535787b9ec527 100644 --- a/system/lib/libc/musl/src/mman/mprotect.c +++ b/system/lib/libc/musl/src/mman/mprotect.c @@ -2,10 +2,12 @@ #include "libc.h" #include "syscall.h" -int mprotect(void *addr, size_t len, int prot) +int __mprotect(void *addr, size_t len, int prot) { size_t start, end; start = (size_t)addr & -PAGE_SIZE; end = (size_t)((char *)addr + len + PAGE_SIZE-1) & -PAGE_SIZE; return syscall(SYS_mprotect, start, end-start, prot); } + +weak_alias(__mprotect, mprotect); diff --git a/system/lib/libc/musl/src/mman/mremap.c b/system/lib/libc/musl/src/mman/mremap.c index 596c45fbded84..ce4e8ea13677a 100644 --- a/system/lib/libc/musl/src/mman/mremap.c +++ b/system/lib/libc/musl/src/mman/mremap.c @@ -1,17 +1,31 @@ +#define _GNU_SOURCE #include #include +#include +#include #include #include "syscall.h" #include "libc.h" +static void dummy(void) { } +weak_alias(dummy, __vm_wait); + void *__mremap(void *old_addr, size_t old_len, size_t new_len, int flags, ...) { va_list ap; - void *new_addr; - - va_start(ap, flags); - new_addr = va_arg(ap, void *); - va_end(ap); + void *new_addr = 0; + + if (new_len >= PTRDIFF_MAX) { + errno = ENOMEM; + return MAP_FAILED; + } + + if (flags & MREMAP_FIXED) { + __vm_wait(); + va_start(ap, flags); + new_addr = va_arg(ap, void *); + va_end(ap); + } return (void *)syscall(SYS_mremap, old_addr, old_len, new_len, flags, new_addr); } diff --git a/system/lib/libc/musl/src/mman/msync.c b/system/lib/libc/musl/src/mman/msync.c index bb20475b4de3c..fcd8cdf9fc17d 100644 --- a/system/lib/libc/musl/src/mman/msync.c +++ b/system/lib/libc/musl/src/mman/msync.c @@ -3,5 +3,5 @@ int msync(void *start, size_t len, int flags) { - return syscall(SYS_msync, start, len, flags); + return syscall_cp(SYS_msync, start, len, flags); } diff --git a/system/lib/libc/musl/src/mman/munmap.c b/system/lib/libc/musl/src/mman/munmap.c index 8488d75ce5294..3f711ee50145b 100644 --- a/system/lib/libc/musl/src/mman/munmap.c +++ b/system/lib/libc/musl/src/mman/munmap.c @@ -2,18 +2,13 @@ #include "syscall.h" #include "libc.h" -static void dummy1(int x) { } -static void dummy0(void) { } -weak_alias(dummy1, __vm_lock); -weak_alias(dummy0, __vm_unlock); +static void dummy(void) { } +weak_alias(dummy, __vm_wait); int __munmap(void *start, size_t len) { - int ret; - __vm_lock(-1); - ret = syscall(SYS_munmap, start, len); - __vm_unlock(); - return ret; + __vm_wait(); + return syscall(SYS_munmap, start, len); } weak_alias(__munmap, munmap); diff --git a/system/lib/libc/musl/src/multibyte/btowc.c b/system/lib/libc/musl/src/multibyte/btowc.c index 9d2c3b16eb77a..8acd0a2cf1002 100644 --- a/system/lib/libc/musl/src/multibyte/btowc.c +++ b/system/lib/libc/musl/src/multibyte/btowc.c @@ -1,7 +1,10 @@ #include #include +#include +#include "internal.h" wint_t btowc(int c) { - return c<128U ? c : EOF; + int b = (unsigned char)c; + return b<128U ? b : (MB_CUR_MAX==1 && c!=EOF) ? CODEUNIT(c) : WEOF; } diff --git a/system/lib/libc/musl/src/multibyte/c16rtomb.c b/system/lib/libc/musl/src/multibyte/c16rtomb.c new file mode 100644 index 0000000000000..39ca3758fa16e --- /dev/null +++ b/system/lib/libc/musl/src/multibyte/c16rtomb.c @@ -0,0 +1,35 @@ +#include +#include +#include + +size_t c16rtomb(char *restrict s, char16_t c16, mbstate_t *restrict ps) +{ + static unsigned internal_state; + if (!ps) ps = (void *)&internal_state; + unsigned *x = (unsigned *)ps; + wchar_t wc; + + if (!s) { + if (*x) goto ilseq; + return 1; + } + + if (!*x && c16 - 0xd800u < 0x400) { + *x = c16 - 0xd7c0 << 10; + return 0; + } + + if (*x) { + if (c16 - 0xdc00u >= 0x400) goto ilseq; + else wc = *x + c16 - 0xdc00; + *x = 0; + } else { + wc = c16; + } + return wcrtomb(s, wc, 0); + +ilseq: + *x = 0; + errno = EILSEQ; + return -1; +} diff --git a/system/lib/libc/musl/src/multibyte/c32rtomb.c b/system/lib/libc/musl/src/multibyte/c32rtomb.c new file mode 100644 index 0000000000000..67851328e889a --- /dev/null +++ b/system/lib/libc/musl/src/multibyte/c32rtomb.c @@ -0,0 +1,7 @@ +#include +#include + +size_t c32rtomb(char *restrict s, char32_t c32, mbstate_t *restrict ps) +{ + return wcrtomb(s, c32, ps); +} diff --git a/system/lib/libc/musl/src/multibyte/internal.c b/system/lib/libc/musl/src/multibyte/internal.c index 1813b266c75d2..7e1b1c03409f0 100644 --- a/system/lib/libc/musl/src/multibyte/internal.c +++ b/system/lib/libc/musl/src/multibyte/internal.c @@ -1,9 +1,3 @@ -/* - * This code was written by Rich Felker in 2010; no copyright is claimed. - * This code is in the public domain. Attribution is appreciated but - * unnecessary. - */ - #include "internal.h" #define C(x) ( x<2 ? -1 : ( R(0x80,0xc0) | x ) ) @@ -30,7 +24,3 @@ const uint32_t bittab[] = { E(0x8),E(0x9),E(0xa),E(0xb),E(0xc),E(0xd),E(0xe),E(0xf), F(0x0),F(0x1),F(0x2),F(0x3),F(0x4) }; - -#ifdef BROKEN_VISIBILITY -__asm__(".hidden __fsmu8"); -#endif diff --git a/system/lib/libc/musl/src/multibyte/internal.h b/system/lib/libc/musl/src/multibyte/internal.h index 82f5a07e58011..421a3d4af9b10 100644 --- a/system/lib/libc/musl/src/multibyte/internal.h +++ b/system/lib/libc/musl/src/multibyte/internal.h @@ -1,23 +1,26 @@ -/* - * This code was written by Rich Felker in 2010; no copyright is claimed. - * This code is in the public domain. Attribution is appreciated but - * unnecessary. - */ - #define bittab __fsmu8 #include -#include "libc.h" -extern const uint32_t bittab[] ATTR_LIBC_VISIBILITY; +#ifdef __PIC__ +__attribute__((__visibility__("hidden"))) +#endif +extern const uint32_t bittab[]; /* Upper 6 state bits are a negative integer offset to bound-check next byte */ /* equivalent to: ( (b-0x80) | (b+offset) ) & ~0x3f */ #define OOB(c,b) (((((b)>>3)-0x10)|(((b)>>3)+((int32_t)(c)>>26))) & ~7) /* Interval [a,b). Either a must be 80 or b must be c0, lower 3 bits clear. */ -#define R(a,b) ((uint32_t)((a==0x80 ? 0x40-b : -a) << 23)) +#define R(a,b) ((uint32_t)((a==0x80 ? 0x40u-b : 0u-a) << 23)) #define FAILSTATE R(0x80,0x80) #define SA 0xc2u #define SB 0xf4u + +/* Arbitrary encoding for representing code units instead of characters. */ +#define CODEUNIT(c) (0xdfff & (signed char)(c)) +#define IS_CODEUNIT(c) ((unsigned)(c)-0xdf80 < 0x80) + +/* Get inline definition of MB_CUR_MAX. */ +#include "locale_impl.h" diff --git a/system/lib/libc/musl/src/multibyte/mblen.c b/system/lib/libc/musl/src/multibyte/mblen.c index 96b47b123842b..a4304bf5ada91 100644 --- a/system/lib/libc/musl/src/multibyte/mblen.c +++ b/system/lib/libc/musl/src/multibyte/mblen.c @@ -1,9 +1,3 @@ -/* - * This code was written by Rich Felker in 2010; no copyright is claimed. - * This code is in the public domain. Attribution is appreciated but - * unnecessary. - */ - #include int mblen(const char *s, size_t n) diff --git a/system/lib/libc/musl/src/multibyte/mbrlen.c b/system/lib/libc/musl/src/multibyte/mbrlen.c index 3a5a74336287f..accf4b33150ee 100644 --- a/system/lib/libc/musl/src/multibyte/mbrlen.c +++ b/system/lib/libc/musl/src/multibyte/mbrlen.c @@ -1,9 +1,3 @@ -/* - * This code was written by Rich Felker in 2010; no copyright is claimed. - * This code is in the public domain. Attribution is appreciated but - * unnecessary. - */ - #include size_t mbrlen(const char *restrict s, size_t n, mbstate_t *restrict st) diff --git a/system/lib/libc/musl/src/multibyte/mbrtoc16.c b/system/lib/libc/musl/src/multibyte/mbrtoc16.c new file mode 100644 index 0000000000000..765ff9037cd35 --- /dev/null +++ b/system/lib/libc/musl/src/multibyte/mbrtoc16.c @@ -0,0 +1,30 @@ +#include +#include + +size_t mbrtoc16(char16_t *restrict pc16, const char *restrict s, size_t n, mbstate_t *restrict ps) +{ + static unsigned internal_state; + if (!ps) ps = (void *)&internal_state; + unsigned *pending = (unsigned *)ps; + + if (!s) return mbrtoc16(0, "", 1, ps); + + /* mbrtowc states for partial UTF-8 characters have the high bit set; + * we use nonzero states without high bit for pending surrogates. */ + if ((int)*pending > 0) { + if (pc16) *pc16 = *pending; + *pending = 0; + return -3; + } + + wchar_t wc; + size_t ret = mbrtowc(&wc, s, n, ps); + if (ret <= 4) { + if (wc >= 0x10000) { + *pending = (wc & 0x3ff) + 0xdc00; + wc = 0xd7c0 + (wc >> 10); + } + if (pc16) *pc16 = wc; + } + return ret; +} diff --git a/system/lib/libc/musl/src/multibyte/mbrtoc32.c b/system/lib/libc/musl/src/multibyte/mbrtoc32.c new file mode 100644 index 0000000000000..9b6b2367398e4 --- /dev/null +++ b/system/lib/libc/musl/src/multibyte/mbrtoc32.c @@ -0,0 +1,13 @@ +#include +#include + +size_t mbrtoc32(char32_t *restrict pc32, const char *restrict s, size_t n, mbstate_t *restrict ps) +{ + static unsigned internal_state; + if (!ps) ps = (void *)&internal_state; + if (!s) return mbrtoc32(0, "", 1, ps); + wchar_t wc; + size_t ret = mbrtowc(&wc, s, n, ps); + if (ret <= 4 && pc32) *pc32 = wc; + return ret; +} diff --git a/system/lib/libc/musl/src/multibyte/mbrtowc.c b/system/lib/libc/musl/src/multibyte/mbrtowc.c index e7b365403bbb0..c94819e720aac 100644 --- a/system/lib/libc/musl/src/multibyte/mbrtowc.c +++ b/system/lib/libc/musl/src/multibyte/mbrtowc.c @@ -1,9 +1,4 @@ -/* - * This code was written by Rich Felker in 2010; no copyright is claimed. - * This code is in the public domain. Attribution is appreciated but - * unnecessary. - */ - +#include #include #include #include "internal.h" @@ -27,6 +22,7 @@ size_t mbrtowc(wchar_t *restrict wc, const char *restrict src, size_t n, mbstate if (!n) return -2; if (!c) { if (*s < 0x80) return !!(*wc = *s); + if (MB_CUR_MAX==1) return (*wc = CODEUNIT(*s)), 1; if (*s-SA > SB-SA) goto ilseq; c = bittab[*s++-SA]; n--; } diff --git a/system/lib/libc/musl/src/multibyte/mbsinit.c b/system/lib/libc/musl/src/multibyte/mbsinit.c index e001d84443664..c608194a0791e 100644 --- a/system/lib/libc/musl/src/multibyte/mbsinit.c +++ b/system/lib/libc/musl/src/multibyte/mbsinit.c @@ -1,9 +1,3 @@ -/* - * This code was written by Rich Felker in 2010; no copyright is claimed. - * This code is in the public domain. Attribution is appreciated but - * unnecessary. - */ - #include int mbsinit(const mbstate_t *st) diff --git a/system/lib/libc/musl/src/multibyte/mbsnrtowcs.c b/system/lib/libc/musl/src/multibyte/mbsnrtowcs.c index 68b9960f375e3..cae4caa2a6c74 100644 --- a/system/lib/libc/musl/src/multibyte/mbsnrtowcs.c +++ b/system/lib/libc/musl/src/multibyte/mbsnrtowcs.c @@ -1,9 +1,3 @@ -/* - * This code was written by Rich Felker in 2010; no copyright is claimed. - * This code is in the public domain. Attribution is appreciated but - * unnecessary. - */ - #include size_t mbsnrtowcs(wchar_t *restrict wcs, const char **restrict src, size_t n, size_t wn, mbstate_t *restrict st) diff --git a/system/lib/libc/musl/src/multibyte/mbsrtowcs.c b/system/lib/libc/musl/src/multibyte/mbsrtowcs.c index 3c1343aea81f8..0ee8b69cbfda8 100644 --- a/system/lib/libc/musl/src/multibyte/mbsrtowcs.c +++ b/system/lib/libc/musl/src/multibyte/mbsrtowcs.c @@ -1,12 +1,8 @@ -/* - * This code was written by Rich Felker in 2010; no copyright is claimed. - * This code is in the public domain. Attribution is appreciated but - * unnecessary. - */ - #include #include #include +#include +#include #include "internal.h" size_t mbsrtowcs(wchar_t *restrict ws, const char **restrict src, size_t wn, mbstate_t *restrict st) @@ -24,6 +20,23 @@ size_t mbsrtowcs(wchar_t *restrict ws, const char **restrict src, size_t wn, mbs } } + if (MB_CUR_MAX==1) { + if (!ws) return strlen((const char *)s); + for (;;) { + if (!wn) { + *src = (const void *)s; + return wn0; + } + if (!*s) break; + c = *s++; + *ws++ = CODEUNIT(c); + wn--; + } + *ws = 0; + *src = 0; + return wn0-wn; + } + if (!ws) for (;;) { if (*s-1u < 0x7f && (uintptr_t)s%4 == 0) { while (!(( *(uint32_t*)s | *(uint32_t*)s-0x01010101) & 0x80808080)) { diff --git a/system/lib/libc/musl/src/multibyte/mbtowc.c b/system/lib/libc/musl/src/multibyte/mbtowc.c index 803d2213d7bd3..c191bb038bbfd 100644 --- a/system/lib/libc/musl/src/multibyte/mbtowc.c +++ b/system/lib/libc/musl/src/multibyte/mbtowc.c @@ -1,9 +1,4 @@ -/* - * This code was written by Rich Felker in 2010; no copyright is claimed. - * This code is in the public domain. Attribution is appreciated but - * unnecessary. - */ - +#include #include #include #include "internal.h" @@ -19,6 +14,7 @@ int mbtowc(wchar_t *restrict wc, const char *restrict src, size_t n) if (!wc) wc = &dummy; if (*s < 0x80) return !!(*wc = *s); + if (MB_CUR_MAX==1) return (*wc = CODEUNIT(*s)), 1; if (*s-SA > SB-SA) goto ilseq; c = bittab[*s++-SA]; diff --git a/system/lib/libc/musl/src/multibyte/wcrtomb.c b/system/lib/libc/musl/src/multibyte/wcrtomb.c index 59f733db6e33d..8e34926ed8c5f 100644 --- a/system/lib/libc/musl/src/multibyte/wcrtomb.c +++ b/system/lib/libc/musl/src/multibyte/wcrtomb.c @@ -1,11 +1,7 @@ -/* - * This code was written by Rich Felker in 2010; no copyright is claimed. - * This code is in the public domain. Attribution is appreciated but - * unnecessary. - */ - +#include #include #include +#include "internal.h" size_t wcrtomb(char *restrict s, wchar_t wc, mbstate_t *restrict st) { @@ -13,6 +9,13 @@ size_t wcrtomb(char *restrict s, wchar_t wc, mbstate_t *restrict st) if ((unsigned)wc < 0x80) { *s = wc; return 1; + } else if (MB_CUR_MAX == 1) { + if (!IS_CODEUNIT(wc)) { + errno = EILSEQ; + return -1; + } + *s = wc; + return 1; } else if ((unsigned)wc < 0x800) { *s++ = 0xc0 | (wc>>6); *s = 0x80 | (wc&0x3f); diff --git a/system/lib/libc/musl/src/multibyte/wcsnrtombs.c b/system/lib/libc/musl/src/multibyte/wcsnrtombs.c index 7eb05d459ab82..640cbbeb5416d 100644 --- a/system/lib/libc/musl/src/multibyte/wcsnrtombs.c +++ b/system/lib/libc/musl/src/multibyte/wcsnrtombs.c @@ -1,9 +1,3 @@ -/* - * This code was written by Rich Felker in 2010; no copyright is claimed. - * This code is in the public domain. Attribution is appreciated but - * unnecessary. - */ - #include size_t wcsnrtombs(char *restrict dst, const wchar_t **restrict wcs, size_t wn, size_t n, mbstate_t *restrict st) @@ -40,7 +34,7 @@ size_t wcsnrtombs(char *restrict dst, const wchar_t **restrict wcs, size_t wn, s ws++; wn--; /* safe - this loop runs fewer than sizeof(buf) times */ s+=l; n-=l; - cnt++; + cnt += l; } if (dst) *wcs = ws; return cnt; diff --git a/system/lib/libc/musl/src/multibyte/wcsrtombs.c b/system/lib/libc/musl/src/multibyte/wcsrtombs.c index 30be415d0683f..b5713aeacd84e 100644 --- a/system/lib/libc/musl/src/multibyte/wcsrtombs.c +++ b/system/lib/libc/musl/src/multibyte/wcsrtombs.c @@ -1,9 +1,3 @@ -/* - * This code was written by Rich Felker in 2010; no copyright is claimed. - * This code is in the public domain. Attribution is appreciated but - * unnecessary. - */ - #include size_t wcsrtombs(char *restrict s, const wchar_t **restrict ws, size_t n, mbstate_t *restrict st) diff --git a/system/lib/libc/musl/src/multibyte/wctob.c b/system/lib/libc/musl/src/multibyte/wctob.c index d6353ee179357..b484a3fd01ad7 100644 --- a/system/lib/libc/musl/src/multibyte/wctob.c +++ b/system/lib/libc/musl/src/multibyte/wctob.c @@ -1,8 +1,11 @@ -#include #include +#include +#include +#include "internal.h" int wctob(wint_t c) { if (c < 128U) return c; + if (MB_CUR_MAX==1 && IS_CODEUNIT(c)) return (unsigned char)c; return EOF; } diff --git a/system/lib/libc/musl/src/multibyte/wctomb.c b/system/lib/libc/musl/src/multibyte/wctomb.c index de7ed84d9bbcf..bad41c5edf963 100644 --- a/system/lib/libc/musl/src/multibyte/wctomb.c +++ b/system/lib/libc/musl/src/multibyte/wctomb.c @@ -1,9 +1,3 @@ -/* - * This code was written by Rich Felker in 2010; no copyright is claimed. - * This code is in the public domain. Attribution is appreciated but - * unnecessary. - */ - #include #include diff --git a/system/lib/libc/musl/src/network/dn_comp.c b/system/lib/libc/musl/src/network/dn_comp.c index 4f4452aa4217a..a17d434dc260a 100644 --- a/system/lib/libc/musl/src/network/dn_comp.c +++ b/system/lib/libc/musl/src/network/dn_comp.c @@ -1,9 +1,110 @@ +#include #include #include "libc.h" +/* RFC 1035 message compression */ + +/* label start offsets of a compressed domain name s */ +static int getoffs(short *offs, const unsigned char *base, const unsigned char *s) +{ + int i=0; + for (;;) { + while (*s & 0xc0) { + if ((*s & 0xc0) != 0xc0) return 0; + s = base + ((s[0]&0x3f)<<8 | s[1]); + } + if (!*s) return i; + if (s-base >= 0x4000) return 0; + offs[i++] = s-base; + s += *s + 1; + } +} + +/* label lengths of an ascii domain name s */ +static int getlens(unsigned char *lens, const char *s, int l) +{ + int i=0,j=0,k=0; + for (;;) { + for (; j 62) return 0; + lens[i++] = j-k; + if (j==l) return i; + k = ++j; + } +} + +/* longest suffix match of an ascii domain with a compressed domain name dn */ +static int match(int *offset, const unsigned char *base, const unsigned char *dn, + const char *end, const unsigned char *lens, int nlen) +{ + int l, o, m=0; + short offs[128]; + int noff = getoffs(offs, base, dn); + if (!noff) return 0; + for (;;) { + l = lens[--nlen]; + o = offs[--noff]; + end -= l; + if (l != base[o] || memcmp(base+o+1, end, l)) + return m; + *offset = o; + m += l; + if (nlen) m++; + if (!nlen || !noff) return m; + end--; + } +} + int __dn_comp(const char *src, unsigned char *dst, int space, unsigned char **dnptrs, unsigned char **lastdnptr) { - return -1; + int i, j, n, m=0, offset, bestlen=0, bestoff; + unsigned char lens[127]; + unsigned char **p; + const char *end; + size_t l = strnlen(src, 255); + if (l && src[l-1] == '.') l--; + if (l>253 || space<=0) return -1; + if (!l) { + *dst = 0; + return 1; + } + end = src+l; + n = getlens(lens, src, l); + if (!n) return -1; + + p = dnptrs; + if (p && *p) for (p++; *p; p++) { + m = match(&offset, *dnptrs, *p, end, lens, n); + if (m > bestlen) { + bestlen = m; + bestoff = offset; + if (m == l) + break; + } + } + + /* encode unmatched part */ + if (space < l-bestlen+2+(bestlen-1 < l-1)) return -1; + memcpy(dst+1, src, l-bestlen); + for (i=j=0; i>8; + dst[i++] = bestoff; + } else + dst[i++] = 0; + + /* save dst pointer */ + if (i>2 && lastdnptr && dnptrs && *dnptrs) { + while (*p) p++; + if (p+1 < lastdnptr) { + *p++ = dst; + *p=0; + } + } + return i; } weak_alias(__dn_comp, dn_comp); diff --git a/system/lib/libc/musl/src/network/dns_parse.c b/system/lib/libc/musl/src/network/dns_parse.c new file mode 100644 index 0000000000000..0c7a601124739 --- /dev/null +++ b/system/lib/libc/musl/src/network/dns_parse.c @@ -0,0 +1,32 @@ +#include + +int __dns_parse(const unsigned char *r, int rlen, int (*callback)(void *, int, const void *, int, const void *), void *ctx) +{ + int qdcount, ancount; + const unsigned char *p; + int len; + + if (rlen<12) return -1; + if ((r[3]&15)) return 0; + p = r+12; + qdcount = r[4]*256 + r[5]; + ancount = r[6]*256 + r[7]; + if (qdcount+ancount > 64) return -1; + while (qdcount--) { + while (p-r < rlen && *p-1U < 127) p++; + if (*p>193 || (*p==193 && p[1]>254) || p>r+rlen-6) + return -1; + p += 5 + !!*p; + } + while (ancount--) { + while (p-r < rlen && *p-1U < 127) p++; + if (*p>193 || (*p==193 && p[1]>254) || p>r+rlen-6) + return -1; + p += 1 + !!*p; + len = p[8]*256 + p[9]; + if (p+len > r+rlen) return -1; + if (callback(ctx, p[1], p+10, len, r) < 0) return -1; + p += 10 + len; + } + return 0; +} diff --git a/system/lib/libc/musl/src/network/gai_strerror.c b/system/lib/libc/musl/src/network/gai_strerror.c index 0bf3e37978412..9596580e9ffbd 100644 --- a/system/lib/libc/musl/src/network/gai_strerror.c +++ b/system/lib/libc/musl/src/network/gai_strerror.c @@ -1,4 +1,5 @@ #include +#include "locale_impl.h" static const char msgs[] = "Invalid flags\0" @@ -19,5 +20,6 @@ const char *gai_strerror(int ecode) { const char *s; for (s=msgs, ecode++; ecode && *s; ecode++, s++) for (; *s; s++); - return *s ? s : s+1; + if (!*s) s++; + return LCTRANS_CUR(s); } diff --git a/system/lib/libc/musl/src/network/getaddrinfo.c b/system/lib/libc/musl/src/network/getaddrinfo.c index 5d45be747a455..b9439f776fceb 100644 --- a/system/lib/libc/musl/src/network/getaddrinfo.c +++ b/system/lib/libc/musl/src/network/getaddrinfo.c @@ -1,249 +1,92 @@ #include -#include -#include -#include #include -#include +#include +#include #include -#include -#include "__dns.h" -#include "stdio_impl.h" - -static int is_valid(const char *host) -{ - const unsigned char *s; - if (strlen(host)-1 > 254 || mbstowcs(0, host, 0) > 255) return 0; - for (s=(void *)host; *s>=0x80 || *s=='.' || *s=='-' || isalnum(*s); s++); - return !*s; -} - -#if 0 -static int have_af(int family) -{ - struct sockaddr_in6 sin6 = { .sin6_family = family }; - socklen_t sl = family == AF_INET - ? sizeof(struct sockaddr_in) - : sizeof(struct sockaddr_in6); - int sock = socket(family, SOCK_STREAM, 0); - int have = !bind(sock, (void *)&sin6, sl); - close(sock); - return have; -} -#endif - -union sa { - struct sockaddr_in sin; - struct sockaddr_in6 sin6; -}; - -struct aibuf { - struct addrinfo ai; - union sa sa; -}; - -/* Extra slots needed for storing canonical name */ -#define EXTRA ((256+sizeof(struct aibuf)-1)/sizeof(struct aibuf)) +#include "lookup.h" int getaddrinfo(const char *restrict host, const char *restrict serv, const struct addrinfo *restrict hint, struct addrinfo **restrict res) { - int flags = hint ? hint->ai_flags : 0; - int family = hint ? hint->ai_family : AF_UNSPEC; - int type = hint ? hint->ai_socktype : 0; - int proto = hint ? hint->ai_protocol : 0; - unsigned long port = 0; - struct aibuf *buf; - union sa sa = {{0}}; - unsigned char reply[1024]; - int i, j; - char line[512]; - FILE *f, _f; - unsigned char _buf[1024]; - char *z; - int result; - int cnt; - - if (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC) - return EAI_FAMILY; - - if (host && strlen(host)>255) return EAI_NONAME; - if (serv && strlen(serv)>32) return EAI_SERVICE; - - if (type && !proto) - proto = type==SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP; - if (!type && proto) - type = proto==IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM; - - if (serv) { - if (!*serv) return EAI_SERVICE; - port = strtoul(serv, &z, 10); - if (*z) { - size_t servlen = strlen(serv); - char *end = line; - - if (flags & AI_NUMERICSERV) return EAI_SERVICE; - - f = __fopen_rb_ca("/etc/services", &_f, _buf, sizeof _buf); - if (!f) return EAI_SERVICE; - while (fgets(line, sizeof line, f)) { - if (strncmp(line, serv, servlen) || !isspace(line[servlen])) - continue; - port = strtoul(line+servlen, &end, 10); - if (strncmp(end, proto==IPPROTO_UDP ? "/udp" : "/tcp", 4)) - continue; - break; - } - __fclose_ca(f); - if (feof(f)) return EAI_SERVICE; + struct service ports[MAXSERVS]; + struct address addrs[MAXADDRS]; + char canon[256], *outcanon; + int nservs, naddrs, nais, canon_len, i, j, k; + int family = AF_UNSPEC, flags = 0, proto = 0, socktype = 0; + struct aibuf { + struct addrinfo ai; + union sa { + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + } sa; + } *out; + + if (!host && !serv) return EAI_NONAME; + + if (hint) { + family = hint->ai_family; + flags = hint->ai_flags; + proto = hint->ai_protocol; + socktype = hint->ai_socktype; + + const int mask = AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | + AI_V4MAPPED | AI_ALL | AI_ADDRCONFIG | AI_NUMERICSERV; + if ((flags & mask) != flags) + return EAI_BADFLAGS; + + switch (family) { + case AF_INET: + case AF_INET6: + case AF_UNSPEC: + break; + default: + return EAI_FAMILY; } - if (port > 65535) return EAI_SERVICE; - port = htons(port); } - if (!host) { - if (family == AF_UNSPEC) { - cnt = 2; family = AF_INET; - } else { - cnt = 1; - } - buf = calloc(sizeof *buf, cnt); - if (!buf) return EAI_MEMORY; - for (i=0; iai; - return 0; - } - - if (!*host) return EAI_NONAME; - - /* Try as a numeric address */ - if (__ipparse(&sa, family, host) >= 0) { - buf = calloc(sizeof *buf, 1+EXTRA); - if (!buf) return EAI_MEMORY; - family = sa.sin.sin_family; - buf->ai.ai_protocol = proto; - buf->ai.ai_socktype = type; - buf->ai.ai_addr = (void *)&buf->sa; - buf->ai.ai_addrlen = family==AF_INET6 ? sizeof sa.sin6 : sizeof sa.sin; - buf->ai.ai_family = family; - buf->ai.ai_canonname = (char *)host; - buf->sa = sa; - buf->sa.sin.sin_port = port; - *res = &buf->ai; - return 0; - } - - if (flags & AI_NUMERICHOST) return EAI_NONAME; - - f = __fopen_rb_ca("/etc/hosts", &_f, _buf, sizeof _buf); - if (f) while (fgets(line, sizeof line, f)) { - char *p; - size_t l = strlen(host); - - if ((p=strchr(line, '#'))) *p++='\n', *p=0; - for(p=line+1; (p=strstr(p, host)) && - (!isspace(p[-1]) || !isspace(p[l])); p++); - if (!p) continue; - __fclose_ca(f); - - /* Isolate IP address to parse */ - for (p=line; *p && !isspace(*p); p++); - *p++ = 0; - if (__ipparse(&sa, family, line) < 0) return EAI_NONAME; - - /* Allocate and fill result buffer */ - buf = calloc(sizeof *buf, 1+EXTRA); - if (!buf) return EAI_MEMORY; - family = sa.sin.sin_family; - buf->ai.ai_protocol = proto; - buf->ai.ai_socktype = type; - buf->ai.ai_addr = (void *)&buf->sa; - buf->ai.ai_addrlen = family==AF_INET6 ? sizeof sa.sin6 : sizeof sa.sin; - buf->ai.ai_family = family; - buf->sa = sa; - buf->sa.sin.sin_port = port; - - /* Extract first name as canonical name */ - for (; *p && isspace(*p); p++); - buf->ai.ai_canonname = (void *)(buf+1); - snprintf(buf->ai.ai_canonname, 256, "%s", p); - for (p=buf->ai.ai_canonname; *p && !isspace(*p); p++); - *p = 0; - if (!is_valid(buf->ai.ai_canonname)) - buf->ai.ai_canonname = 0; + nservs = __lookup_serv(ports, serv, proto, socktype, flags); + if (nservs < 0) return nservs; - *res = &buf->ai; - return 0; - } - if (f) __fclose_ca(f); - -#if 0 - f = __fopen_rb_ca("/etc/resolv.conf", &_f, _buf, sizeof _buf); - if (f) while (fgets(line, sizeof line, f)) { - if (!isspace(line[10]) || (strncmp(line, "search", 6) - && strncmp(line, "domain", 6))) continue; - } - if (f) __fclose_ca(f); -#endif - - /* Perform one or more DNS queries for host */ - memset(reply, 0, sizeof reply); - result = __dns_query(reply, host, family, 0); - if (result < 0) return result; - - cnt = __dns_count_addrs(reply, result); - if (cnt <= 0) return EAI_NONAME; + naddrs = __lookup_name(addrs, canon, host, family, flags); + if (naddrs < 0) return naddrs; - buf = calloc(sizeof *buf, cnt+EXTRA); - if (!buf) return EAI_MEMORY; + nais = nservs * naddrs; + canon_len = strlen(canon); + out = calloc(1, nais * sizeof(*out) + canon_len + 1); + if (!out) return EAI_MEMORY; - i = 0; - if (family != AF_INET6) { - j = __dns_get_rr(&buf[i].sa.sin.sin_addr, sizeof *buf, 4, cnt-i, reply, RR_A, 0); - while (j--) buf[i++].sa.sin.sin_family = AF_INET; + if (canon_len) { + outcanon = (void *)&out[nais]; + memcpy(outcanon, canon, canon_len+1); + } else { + outcanon = 0; } - if (family != AF_INET) { - j = __dns_get_rr(&buf[i].sa.sin6.sin6_addr, sizeof *buf, 16, cnt-i, reply, RR_AAAA, 0); - while (j--) buf[i++].sa.sin.sin_family = AF_INET6; - } - if (result>1) { - j = __dns_get_rr(&buf[i].sa.sin.sin_addr, sizeof *buf, 4, cnt-i, reply+512, RR_A, 0); - while (j--) buf[i++].sa.sin.sin_family = AF_INET; - j = __dns_get_rr(&buf[i].sa.sin6.sin6_addr, sizeof *buf, 16, cnt-i, reply+512, RR_AAAA, 0); - while (j--) buf[i++].sa.sin.sin_family = AF_INET6; - } - - if (__dns_get_rr((void *)&buf[cnt], 0, 256, 1, reply, RR_CNAME, 1) <= 0) - strcpy((void *)&buf[cnt], host); - for (i=0; iai; - + out[nais-1].ai.ai_next = 0; + *res = &out->ai; return 0; } diff --git a/system/lib/libc/musl/src/network/gethostbyaddr_r.c b/system/lib/libc/musl/src/network/gethostbyaddr_r.c index 66e03309408c9..0f1e61aa0c358 100644 --- a/system/lib/libc/musl/src/network/gethostbyaddr_r.c +++ b/system/lib/libc/musl/src/network/gethostbyaddr_r.c @@ -64,6 +64,7 @@ int gethostbyaddr_r(const void *a, socklen_t l, int af, } h->h_addrtype = af; + h->h_length = l; h->h_name = h->h_aliases[0]; *res = h; return 0; diff --git a/system/lib/libc/musl/src/network/gethostbyname2_r.c b/system/lib/libc/musl/src/network/gethostbyname2_r.c index d6920b26242e9..5c1cae98f3f74 100644 --- a/system/lib/libc/musl/src/network/gethostbyname2_r.c +++ b/system/lib/libc/musl/src/network/gethostbyname2_r.c @@ -6,43 +6,32 @@ #include #include #include +#include "lookup.h" int gethostbyname2_r(const char *name, int af, struct hostent *h, char *buf, size_t buflen, struct hostent **res, int *err) { - struct addrinfo hint = { - .ai_family = af==AF_INET6 ? af : AF_INET, - .ai_flags = AI_CANONNAME - }; - struct addrinfo *ai, *p; - int i; - size_t need; - const char *canon; + struct address addrs[MAXADDRS]; + char canon[256]; + int i, cnt; + size_t align, need; *res = 0; - - af = hint.ai_family; - - /* Align buffer */ - i = (uintptr_t)buf & sizeof(char *)-1; - if (i) { - if (buflen < sizeof(char *)-i) return ERANGE; - buf += sizeof(char *)-i; - buflen -= sizeof(char *)-i; - } - - switch (getaddrinfo(name, 0, &hint, &ai)) { + cnt = __lookup_name(addrs, canon, name, af, AI_CANONNAME); + if (cnt<0) switch (cnt) { case EAI_NONAME: *err = HOST_NOT_FOUND; - return errno; + return ENOENT; case EAI_AGAIN: *err = TRY_AGAIN; - return errno; + return EAGAIN; default: + case EAI_FAIL: + *err = NO_RECOVERY; + return EBADMSG; case EAI_MEMORY: case EAI_SYSTEM: - case EAI_FAIL: *err = NO_RECOVERY; return errno; case 0: @@ -52,22 +41,29 @@ int gethostbyname2_r(const char *name, int af, h->h_addrtype = af; h->h_length = af==AF_INET6 ? 16 : 4; - canon = ai->ai_canonname ? ai->ai_canonname : name; + /* Align buffer */ + align = -(uintptr_t)buf & sizeof(char *)-1; + need = 4*sizeof(char *); - for (i=0, p=ai; p; i++, p=p->ai_next) - need += sizeof(char *) + h->h_length; + need += (cnt + 1) * (sizeof(char *) + h->h_length); need += strlen(name)+1; need += strlen(canon)+1; + need += align; - if (need > buflen) { - freeaddrinfo(ai); - return ERANGE; - } + if (need > buflen) return ERANGE; + buf += align; h->h_aliases = (void *)buf; buf += 3*sizeof(char *); h->h_addr_list = (void *)buf; - buf += (i+1)*sizeof(char *); + buf += (cnt+1)*sizeof(char *); + + for (i=0; ih_addr_list[i] = (void *)buf; + buf += h->h_length; + memcpy(h->h_addr_list[i], addrs[i].addr, h->h_length); + } + h->h_addr_list[i] = 0; h->h_name = h->h_aliases[0] = buf; strcpy(h->h_name, canon); @@ -81,16 +77,6 @@ int gethostbyname2_r(const char *name, int af, h->h_aliases[2] = 0; - for (i=0, p=ai; p; i++, p=p->ai_next) { - h->h_addr_list[i] = (void *)buf; - buf += h->h_length; - memcpy(h->h_addr_list[i], - &((struct sockaddr_in *)p->ai_addr)->sin_addr, - h->h_length); - } - h->h_addr_list[i] = 0; - *res = h; - freeaddrinfo(ai); return 0; } diff --git a/system/lib/libc/musl/src/network/getifaddrs.c b/system/lib/libc/musl/src/network/getifaddrs.c index 5a94cc7c4496f..fed75bd8d9293 100644 --- a/system/lib/libc/musl/src/network/getifaddrs.c +++ b/system/lib/libc/musl/src/network/getifaddrs.c @@ -1,181 +1,216 @@ -/* (C) 2013 John Spencer. released under musl's standard MIT license. */ -#undef _GNU_SOURCE #define _GNU_SOURCE -#include -#include -#include /* IFNAMSIZ, ifreq, ifconf */ -#include -#include -#include #include -#include /* inet_pton */ +#include +#include #include -#include -#include +#include +#include +#include +#include +#include "netlink.h" -typedef union { - struct sockaddr_in6 v6; +#define IFADDRS_HASH_SIZE 64 + +/* getifaddrs() reports hardware addresses with PF_PACKET that implies + * struct sockaddr_ll. But e.g. Infiniband socket address length is + * longer than sockaddr_ll.ssl_addr[8] can hold. Use this hack struct + * to extend ssl_addr - callers should be able to still use it. */ +struct sockaddr_ll_hack { + unsigned short sll_family, sll_protocol; + int sll_ifindex; + unsigned short sll_hatype; + unsigned char sll_pkttype, sll_halen; + unsigned char sll_addr[24]; +}; + +union sockany { + struct sockaddr sa; + struct sockaddr_ll_hack ll; struct sockaddr_in v4; -} soa; + struct sockaddr_in6 v6; +}; -typedef struct ifaddrs_storage { +struct ifaddrs_storage { struct ifaddrs ifa; - soa addr; - soa netmask; - soa dst; + struct ifaddrs_storage *hash_next; + union sockany addr, netmask, ifu; + unsigned int index; char name[IFNAMSIZ+1]; -} stor; -#define next ifa.ifa_next +}; -static stor* list_add(stor** list, stor** head, char* ifname) +struct ifaddrs_ctx { + struct ifaddrs_storage *first; + struct ifaddrs_storage *last; + struct ifaddrs_storage *hash[IFADDRS_HASH_SIZE]; +}; + +void freeifaddrs(struct ifaddrs *ifp) { - stor* curr = calloc(1, sizeof(stor)); - if(curr) { - strcpy(curr->name, ifname); - curr->ifa.ifa_name = curr->name; - if(*head) (*head)->next = (struct ifaddrs*) curr; - *head = curr; - if(!*list) *list = curr; + struct ifaddrs *n; + while (ifp) { + n = ifp->ifa_next; + free(ifp); + ifp = n; } - return curr; } -void freeifaddrs(struct ifaddrs *ifp) +static void copy_addr(struct sockaddr **r, int af, union sockany *sa, void *addr, size_t addrlen, int ifindex) { - stor *head = (stor *) ifp; - while(head) { - void *p = head; - head = (stor *) head->next; - free(p); + uint8_t *dst; + int len; + + switch (af) { + case AF_INET: + dst = (uint8_t*) &sa->v4.sin_addr; + len = 4; + break; + case AF_INET6: + dst = (uint8_t*) &sa->v6.sin6_addr; + len = 16; + if (IN6_IS_ADDR_LINKLOCAL(addr) || IN6_IS_ADDR_MC_LINKLOCAL(addr)) + sa->v6.sin6_scope_id = ifindex; + break; + default: + return; } + if (addrlen < len) return; + sa->sa.sa_family = af; + memcpy(dst, addr, len); + *r = &sa->sa; } -static void ipv6netmask(unsigned prefix_length, struct sockaddr_in6 *sa) +static void gen_netmask(struct sockaddr **r, int af, union sockany *sa, int prefixlen) { - unsigned char* hb = sa->sin6_addr.s6_addr; - unsigned onebytes = prefix_length / 8; - unsigned bits = prefix_length % 8; - unsigned nullbytes = 16 - onebytes; - memset(hb, -1, onebytes); - memset(hb+onebytes, 0, nullbytes); - if(bits) { - unsigned char x = -1; - x <<= 8 - bits; - hb[onebytes] = x; - } + uint8_t addr[16] = {0}; + int i; + + if (prefixlen > 8*sizeof(addr)) prefixlen = 8*sizeof(addr); + i = prefixlen / 8; + memset(addr, 0xff, i); + if (i < sizeof(addr)) addr[i++] = 0xff << (8 - (prefixlen % 8)); + copy_addr(r, af, sa, addr, sizeof(addr), 0); } -static void dealwithipv6(stor **list, stor** head) +static void copy_lladdr(struct sockaddr **r, union sockany *sa, void *addr, size_t addrlen, int ifindex, unsigned short hatype) { - FILE* f = fopen("/proc/net/if_inet6", "rbe"); - /* 00000000000000000000000000000001 01 80 10 80 lo - A B C D E F - all numbers in hex - A = addr B=netlink device#, C=prefix length, - D = scope value (ipv6.h) E = interface flags (rnetlink.h, addrconf.c) - F = if name */ - char v6conv[32 + 7 + 1], *v6; - char *line, linebuf[512]; - if(!f) return; - while((line = fgets(linebuf, sizeof linebuf, f))) { - v6 = v6conv; - size_t i = 0; - for(; i < 8; i++) { - memcpy(v6, line, 4); - v6+=4; - *v6++=':'; - line+=4; - } - --v6; *v6 = 0; - line++; - unsigned b, c, d, e; - char name[IFNAMSIZ+1]; - if(5 == sscanf(line, "%x %x %x %x %s", &b, &c, &d, &e, name)) { - struct sockaddr_in6 sa = {0}; - if(1 == inet_pton(AF_INET6, v6conv, &sa.sin6_addr)) { - sa.sin6_family = AF_INET6; - stor* curr = list_add(list, head, name); - if(!curr) goto out; - curr->addr.v6 = sa; - curr->ifa.ifa_addr = (struct sockaddr*) &curr->addr; - ipv6netmask(c, &sa); - curr->netmask.v6 = sa; - curr->ifa.ifa_netmask = (struct sockaddr*) &curr->netmask; - /* find ipv4 struct with the same interface name to copy flags */ - stor* scan = *list; - for(;scan && strcmp(name, scan->name);scan=(stor*)scan->next); - if(scan) curr->ifa.ifa_flags = scan->ifa.ifa_flags; - else curr->ifa.ifa_flags = 0; - } else errno = 0; - } - } - out: - fclose(f); + if (addrlen > sizeof(sa->ll.sll_addr)) return; + sa->ll.sll_family = AF_PACKET; + sa->ll.sll_ifindex = ifindex; + sa->ll.sll_hatype = hatype; + sa->ll.sll_halen = addrlen; + memcpy(sa->ll.sll_addr, addr, addrlen); + *r = &sa->sa; } -int getifaddrs(struct ifaddrs **ifap) +static int netlink_msg_to_ifaddr(void *pctx, struct nlmsghdr *h) { - stor *list = 0, *head = 0; - struct if_nameindex* ii = if_nameindex(); - if(!ii) return -1; - size_t i; - for(i = 0; ii[i].if_index || ii[i].if_name; i++) { - stor* curr = list_add(&list, &head, ii[i].if_name); - if(!curr) { - if_freenameindex(ii); - goto err2; + struct ifaddrs_ctx *ctx = pctx; + struct ifaddrs_storage *ifs, *ifs0; + struct ifinfomsg *ifi = NLMSG_DATA(h); + struct ifaddrmsg *ifa = NLMSG_DATA(h); + struct rtattr *rta; + int stats_len = 0; + + if (h->nlmsg_type == RTM_NEWLINK) { + for (rta = NLMSG_RTA(h, sizeof(*ifi)); NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) { + if (rta->rta_type != IFLA_STATS) continue; + stats_len = RTA_DATALEN(rta); + break; } + } else { + for (ifs0 = ctx->hash[ifa->ifa_index % IFADDRS_HASH_SIZE]; ifs0; ifs0 = ifs0->hash_next) + if (ifs0->index == ifa->ifa_index) + break; + if (!ifs0) return 0; } - if_freenameindex(ii); - - int sock = socket(PF_INET, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_IP); - if(sock == -1) goto err2; - struct ifreq reqs[32]; /* arbitrary chosen boundary */ - struct ifconf conf = {.ifc_len = sizeof reqs, .ifc_req = reqs}; - if(-1 == ioctl(sock, SIOCGIFCONF, &conf)) goto err; - size_t reqitems = conf.ifc_len / sizeof(struct ifreq); - for(head = list; head; head = (stor*)head->next) { - for(i = 0; i < reqitems; i++) { - // get SIOCGIFADDR of active interfaces. - if(!strcmp(reqs[i].ifr_name, head->name)) { - head->addr.v4 = *(struct sockaddr_in*)&reqs[i].ifr_addr; - head->ifa.ifa_addr = (struct sockaddr*) &head->addr; + + ifs = calloc(1, sizeof(struct ifaddrs_storage) + stats_len); + if (ifs == 0) return -1; + + if (h->nlmsg_type == RTM_NEWLINK) { + ifs->index = ifi->ifi_index; + ifs->ifa.ifa_flags = ifi->ifi_flags; + + for (rta = NLMSG_RTA(h, sizeof(*ifi)); NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) { + switch (rta->rta_type) { + case IFLA_IFNAME: + if (RTA_DATALEN(rta) < sizeof(ifs->name)) { + memcpy(ifs->name, RTA_DATA(rta), RTA_DATALEN(rta)); + ifs->ifa.ifa_name = ifs->name; + } + break; + case IFLA_ADDRESS: + copy_lladdr(&ifs->ifa.ifa_addr, &ifs->addr, RTA_DATA(rta), RTA_DATALEN(rta), ifi->ifi_index, ifi->ifi_type); + break; + case IFLA_BROADCAST: + copy_lladdr(&ifs->ifa.ifa_broadaddr, &ifs->ifu, RTA_DATA(rta), RTA_DATALEN(rta), ifi->ifi_index, ifi->ifi_type); + break; + case IFLA_STATS: + ifs->ifa.ifa_data = (void*)(ifs+1); + memcpy(ifs->ifa.ifa_data, RTA_DATA(rta), RTA_DATALEN(rta)); break; } } - struct ifreq req; - snprintf(req.ifr_name, sizeof req.ifr_name, "%s", head->name); - if(-1 == ioctl(sock, SIOCGIFFLAGS, &req)) goto err; - - head->ifa.ifa_flags = req.ifr_flags; - if(head->ifa.ifa_addr) { - /* or'ing flags with IFF_LOWER_UP on active interfaces to mimic glibc */ - head->ifa.ifa_flags |= IFF_LOWER_UP; - if(-1 == ioctl(sock, SIOCGIFNETMASK, &req)) goto err; - head->netmask.v4 = *(struct sockaddr_in*)&req.ifr_netmask; - head->ifa.ifa_netmask = (struct sockaddr*) &head->netmask; - - if(head->ifa.ifa_flags & IFF_POINTOPOINT) { - if(-1 == ioctl(sock, SIOCGIFDSTADDR, &req)) goto err; - head->dst.v4 = *(struct sockaddr_in*)&req.ifr_dstaddr; - } else { - if(-1 == ioctl(sock, SIOCGIFBRDADDR, &req)) goto err; - head->dst.v4 = *(struct sockaddr_in*)&req.ifr_broadaddr; + if (ifs->ifa.ifa_name) { + unsigned int bucket = ifs->index % IFADDRS_HASH_SIZE; + ifs->hash_next = ctx->hash[bucket]; + ctx->hash[bucket] = ifs; + } + } else { + ifs->ifa.ifa_name = ifs0->ifa.ifa_name; + ifs->ifa.ifa_flags = ifs0->ifa.ifa_flags; + for (rta = NLMSG_RTA(h, sizeof(*ifa)); NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) { + switch (rta->rta_type) { + case IFA_ADDRESS: + /* If ifa_addr is already set we, received an IFA_LOCAL before + * so treat this as destination address */ + if (ifs->ifa.ifa_addr) + copy_addr(&ifs->ifa.ifa_dstaddr, ifa->ifa_family, &ifs->ifu, RTA_DATA(rta), RTA_DATALEN(rta), ifa->ifa_index); + else + copy_addr(&ifs->ifa.ifa_addr, ifa->ifa_family, &ifs->addr, RTA_DATA(rta), RTA_DATALEN(rta), ifa->ifa_index); + break; + case IFA_BROADCAST: + copy_addr(&ifs->ifa.ifa_broadaddr, ifa->ifa_family, &ifs->ifu, RTA_DATA(rta), RTA_DATALEN(rta), ifa->ifa_index); + break; + case IFA_LOCAL: + /* If ifa_addr is set and we get IFA_LOCAL, assume we have + * a point-to-point network. Move address to correct field. */ + if (ifs->ifa.ifa_addr) { + ifs->ifu = ifs->addr; + ifs->ifa.ifa_dstaddr = &ifs->ifu.sa; + memset(&ifs->addr, 0, sizeof(ifs->addr)); + } + copy_addr(&ifs->ifa.ifa_addr, ifa->ifa_family, &ifs->addr, RTA_DATA(rta), RTA_DATALEN(rta), ifa->ifa_index); + break; + case IFA_LABEL: + if (RTA_DATALEN(rta) < sizeof(ifs->name)) { + memcpy(ifs->name, RTA_DATA(rta), RTA_DATALEN(rta)); + ifs->ifa.ifa_name = ifs->name; + } + break; } - head->ifa.ifa_ifu.ifu_dstaddr = (struct sockaddr*) &head->dst; } + if (ifs->ifa.ifa_addr) + gen_netmask(&ifs->ifa.ifa_netmask, ifa->ifa_family, &ifs->netmask, ifa->ifa_prefixlen); + } + + if (ifs->ifa.ifa_name) { + if (!ctx->first) ctx->first = ifs; + if (ctx->last) ctx->last->ifa.ifa_next = &ifs->ifa; + ctx->last = ifs; + } else { + free(ifs); } - close(sock); - void* last = 0; - for(head = list; head; head=(stor*)head->next) last=head; - head = last; - dealwithipv6(&list, &head); - *ifap = (struct ifaddrs*) list; return 0; - err: - close(sock); - err2: - freeifaddrs((struct ifaddrs*) list); - return -1; } +int getifaddrs(struct ifaddrs **ifap) +{ + struct ifaddrs_ctx _ctx, *ctx = &_ctx; + int r; + memset(ctx, 0, sizeof *ctx); + r = __rtnetlink_enumerate(AF_UNSPEC, AF_UNSPEC, netlink_msg_to_ifaddr, ctx); + if (r == 0) *ifap = &ctx->first->ifa; + else freeifaddrs(&ctx->first->ifa); + return r; +} diff --git a/system/lib/libc/musl/src/network/getnameinfo.c b/system/lib/libc/musl/src/network/getnameinfo.c index 33f89a38efe84..5e6fae3ed0e51 100644 --- a/system/lib/libc/musl/src/network/getnameinfo.c +++ b/system/lib/libc/musl/src/network/getnameinfo.c @@ -5,48 +5,197 @@ #include #include #include -#include "__dns.h" +#include +#include +#include "lookup.h" +#include "stdio_impl.h" + +int __dns_parse(const unsigned char *, int, int (*)(void *, int, const void *, int, const void *), void *); +int __dn_expand(const unsigned char *, const unsigned char *, const unsigned char *, char *, int); +int __res_mkquery(int, const char *, int, int, const unsigned char *, int, const unsigned char*, unsigned char *, int); +int __res_send(const unsigned char *, int, unsigned char *, int); + +#define PTR_MAX (64 + sizeof ".in-addr.arpa") +#define RR_PTR 12 + +static char *itoa(char *p, unsigned x) { + p += 3*sizeof(int); + *--p = 0; + do { + *--p = '0' + x % 10; + x /= 10; + } while (x); + return p; +} + +static void mkptr4(char *s, const unsigned char *ip) +{ + sprintf(s, "%d.%d.%d.%d.in-addr.arpa", + ip[3], ip[2], ip[1], ip[0]); +} + +static void mkptr6(char *s, const unsigned char *ip) +{ + static const char xdigits[] = "0123456789abcdef"; + int i; + for (i=15; i>=0; i--) { + *s++ = xdigits[ip[i]&15]; *s++ = '.'; + *s++ = xdigits[ip[i]>>4]; *s++ = '.'; + } + strcpy(s, "ip6.arpa"); +} + +static void reverse_hosts(char *buf, const unsigned char *a, unsigned scopeid, int family) +{ + char line[512], *p, *z; + unsigned char _buf[1032], atmp[16]; + struct address iplit; + FILE _f, *f = __fopen_rb_ca("/etc/hosts", &_f, _buf, sizeof _buf); + if (!f) return; + if (family == AF_INET) { + memcpy(atmp+12, a, 4); + memcpy(atmp, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); + a = atmp; + } + while (fgets(line, sizeof line, f)) { + if ((p=strchr(line, '#'))) *p++='\n', *p=0; + + for (p=line; *p && !isspace(*p); p++); + *p++ = 0; + if (__lookup_ipliteral(&iplit, line, AF_UNSPEC)<=0) + continue; + + if (iplit.family == AF_INET) { + memcpy(iplit.addr+12, iplit.addr, 4); + memcpy(iplit.addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); + iplit.scopeid = 0; + } + + if (memcmp(a, iplit.addr, 16) || iplit.scopeid != scopeid) + continue; + + for (; *p && isspace(*p); p++); + for (z=p; *z && !isspace(*z); z++); + *z = 0; + if (z-p < 256) { + memcpy(buf, p, z-p+1); + break; + } + } + __fclose_ca(f); +} + +static void reverse_services(char *buf, int port, int dgram) +{ + unsigned long svport; + char line[128], *p, *z; + unsigned char _buf[1032]; + FILE _f, *f = __fopen_rb_ca("/etc/services", &_f, _buf, sizeof _buf); + if (!f) return; + while (fgets(line, sizeof line, f)) { + if ((p=strchr(line, '#'))) *p++='\n', *p=0; + + for (p=line; *p && !isspace(*p); p++); + if (!*p) continue; + *p++ = 0; + svport = strtoul(p, &z, 10); + + if (svport != port || z==p) continue; + if (dgram && strncmp(z, "/udp", 4)) continue; + if (!dgram && strncmp(z, "/tcp", 4)) continue; + if (p-line > 32) continue; + + memcpy(buf, line, p-line); + break; + } + __fclose_ca(f); +} + +static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet) +{ + if (rr != RR_PTR) return 0; + if (__dn_expand(packet, (const unsigned char *)packet + 512, + data, c, 256) <= 0) + *(char *)c = 0; + return 0; + +} int getnameinfo(const struct sockaddr *restrict sa, socklen_t sl, char *restrict node, socklen_t nodelen, char *restrict serv, socklen_t servlen, int flags) { - char buf[256]; - unsigned char reply[512]; + char ptr[PTR_MAX]; + char buf[256], num[3*sizeof(int)+1]; int af = sa->sa_family; unsigned char *a; + unsigned scopeid; switch (af) { case AF_INET: a = (void *)&((struct sockaddr_in *)sa)->sin_addr; - if (sl != sizeof(struct sockaddr_in)) return EAI_FAMILY; + if (sl < sizeof(struct sockaddr_in)) return EAI_FAMILY; + mkptr4(ptr, a); + scopeid = 0; break; case AF_INET6: a = (void *)&((struct sockaddr_in6 *)sa)->sin6_addr; - if (sl != sizeof(struct sockaddr_in6)) return EAI_FAMILY; + if (sl < sizeof(struct sockaddr_in6)) return EAI_FAMILY; + if (memcmp(a, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12)) + mkptr6(ptr, a); + else + mkptr4(ptr, a+12); + scopeid = ((struct sockaddr_in6 *)sa)->sin6_scope_id; break; default: return EAI_FAMILY; } if (node && nodelen) { - if ((flags & NI_NUMERICHOST) - || __dns_query(reply, a, af, 1) <= 0 - || __dns_get_rr(buf, 0, 256, 1, reply, RR_PTR, 1) <= 0) - { + buf[0] = 0; + if (!(flags & NI_NUMERICHOST)) { + reverse_hosts(buf, a, scopeid, af); + } + if (!*buf && !(flags & NI_NUMERICHOST)) { + unsigned char query[18+PTR_MAX], reply[512]; + int qlen = __res_mkquery(0, ptr, 1, RR_PTR, + 0, 0, 0, query, sizeof query); + int rlen = __res_send(query, qlen, reply, sizeof reply); + buf[0] = 0; + if (rlen > 0) + __dns_parse(reply, rlen, dns_parse_callback, buf); + } + if (!*buf) { if (flags & NI_NAMEREQD) return EAI_NONAME; inet_ntop(af, a, buf, sizeof buf); + if (scopeid) { + char *p = 0, tmp[IF_NAMESIZE+1]; + if (!(flags & NI_NUMERICSCOPE) && + (IN6_IS_ADDR_LINKLOCAL(a) || + IN6_IS_ADDR_MC_LINKLOCAL(a))) + p = if_indextoname(scopeid, tmp+1); + if (!p) + p = itoa(num, scopeid); + *--p = '%'; + strcat(buf, p); + } } if (strlen(buf) >= nodelen) return EAI_OVERFLOW; strcpy(node, buf); } if (serv && servlen) { - if (snprintf(buf, sizeof buf, "%d", - ntohs(((struct sockaddr_in *)sa)->sin_port))>=servlen) + char *p = buf; + int port = ntohs(((struct sockaddr_in *)sa)->sin_port); + buf[0] = 0; + if (!(flags & NI_NUMERICSERV)) + reverse_services(buf, port, flags & NI_DGRAM); + if (!*p) + p = itoa(num, port); + if (strlen(p) >= servlen) return EAI_OVERFLOW; - strcpy(serv, buf); + strcpy(serv, p); } return 0; diff --git a/system/lib/libc/musl/src/network/getservbyname.c b/system/lib/libc/musl/src/network/getservbyname.c index 0b00ce11da82b..dd3037678c278 100644 --- a/system/lib/libc/musl/src/network/getservbyname.c +++ b/system/lib/libc/musl/src/network/getservbyname.c @@ -4,7 +4,7 @@ struct servent *getservbyname(const char *name, const char *prots) { static struct servent se; - static long buf[32/sizeof(long)]; + static char *buf[2]; struct servent *res; if (getservbyname_r(name, prots, &se, (void *)buf, sizeof buf, &res)) return 0; diff --git a/system/lib/libc/musl/src/network/getservbyname_r.c b/system/lib/libc/musl/src/network/getservbyname_r.c index 811c174c8bc20..056c2f33bbd32 100644 --- a/system/lib/libc/musl/src/network/getservbyname_r.c +++ b/system/lib/libc/musl/src/network/getservbyname_r.c @@ -5,49 +5,43 @@ #include #include #include +#include "lookup.h" + +#define ALIGN (sizeof(struct { char a; char *b; }) - sizeof(char *)) int getservbyname_r(const char *name, const char *prots, struct servent *se, char *buf, size_t buflen, struct servent **res) { - struct addrinfo *ai, hint = { .ai_family = AF_INET }; - int i; - - if (!prots) { - int r = getservbyname_r(name, "tcp", se, buf, buflen, res); - if (r) r = getservbyname_r(name, "udp", se, buf, buflen, res); - return r; - } + struct service servs[MAXSERVS]; + int cnt, proto, align; /* Align buffer */ - i = (uintptr_t)buf & sizeof(char *)-1; - if (!i) i = sizeof(char *); - if (buflen < 3*sizeof(char *)-i) + align = -(uintptr_t)buf & ALIGN-1; + if (buflen < 2*sizeof(char *)+align) return ERANGE; - buf += sizeof(char *)-i; - buflen -= sizeof(char *)-i; + buf += align; - if (!strcmp(prots, "tcp")) hint.ai_protocol = IPPROTO_TCP; - else if (!strcmp(prots, "udp")) hint.ai_protocol = IPPROTO_UDP; + if (!prots) proto = 0; + else if (!strcmp(prots, "tcp")) proto = IPPROTO_TCP; + else if (!strcmp(prots, "udp")) proto = IPPROTO_UDP; else return EINVAL; - switch (getaddrinfo(0, name, &hint, &ai)) { + cnt = __lookup_serv(servs, name, proto, 0, 0); + if (cnt<0) switch (cnt) { case EAI_MEMORY: case EAI_SYSTEM: return ENOMEM; default: return ENOENT; - case 0: - break; } se->s_name = (char *)name; se->s_aliases = (void *)buf; se->s_aliases[0] = se->s_name; se->s_aliases[1] = 0; - se->s_port = ((struct sockaddr_in *)ai->ai_addr)->sin_port; - se->s_proto = (char *)prots; + se->s_port = htons(servs[0].port); + se->s_proto = servs[0].proto == IPPROTO_TCP ? "tcp" : "udp"; - freeaddrinfo(ai); *res = se; return 0; } diff --git a/system/lib/libc/musl/src/network/hstrerror.c b/system/lib/libc/musl/src/network/hstrerror.c index b7a6ab6ce74d4..a4d001c53410a 100644 --- a/system/lib/libc/musl/src/network/hstrerror.c +++ b/system/lib/libc/musl/src/network/hstrerror.c @@ -1,5 +1,6 @@ #define _GNU_SOURCE #include +#include "locale_impl.h" static const char msgs[] = "Host not found\0" @@ -12,5 +13,6 @@ const char *hstrerror(int ecode) { const char *s; for (s=msgs, ecode--; ecode && *s; ecode--, s++) for (; *s; s++); - return *s ? s : s+1; + if (!*s) s++; + return LCTRANS_CUR(s); } diff --git a/system/lib/libc/musl/src/network/if_nameindex.c b/system/lib/libc/musl/src/network/if_nameindex.c index 53b80b21dc557..2deaef769600e 100644 --- a/system/lib/libc/musl/src/network/if_nameindex.c +++ b/system/lib/libc/musl/src/network/if_nameindex.c @@ -1,55 +1,114 @@ #define _GNU_SOURCE #include -#include -#include -#include #include -#include "syscall.h" +#include +#include +#include +#include +#include "netlink.h" -static void *do_nameindex(int s, size_t n) -{ - size_t i, len, k; - struct ifconf conf; - struct if_nameindex *idx; +#define IFADDRS_HASH_SIZE 64 - idx = malloc(n * (sizeof(struct if_nameindex)+sizeof(struct ifreq))); - if (!idx) return 0; +struct ifnamemap { + unsigned int hash_next; + unsigned int index; + unsigned char namelen; + char name[IFNAMSIZ]; +}; - conf.ifc_buf = (void *)&idx[n]; - conf.ifc_len = len = n * sizeof(struct ifreq); - if (ioctl(s, SIOCGIFCONF, &conf) < 0) { - free(idx); - return 0; - } - if (conf.ifc_len == len) { - free(idx); - return (void *)-1; +struct ifnameindexctx { + unsigned int num, allocated, str_bytes; + struct ifnamemap *list; + unsigned int hash[IFADDRS_HASH_SIZE]; +}; + +static int netlink_msg_to_nameindex(void *pctx, struct nlmsghdr *h) +{ + struct ifnameindexctx *ctx = pctx; + struct ifnamemap *map; + struct rtattr *rta; + unsigned int i; + int index, type, namelen, bucket; + + if (h->nlmsg_type == RTM_NEWLINK) { + struct ifinfomsg *ifi = NLMSG_DATA(h); + index = ifi->ifi_index; + type = IFLA_IFNAME; + rta = NLMSG_RTA(h, sizeof(*ifi)); + } else { + struct ifaddrmsg *ifa = NLMSG_DATA(h); + index = ifa->ifa_index; + type = IFA_LABEL; + rta = NLMSG_RTA(h, sizeof(*ifa)); } + for (; NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) { + if (rta->rta_type != type) continue; - n = conf.ifc_len / sizeof(struct ifreq); - for (i=k=0; i IFNAMSIZ) return 0; + + /* suppress duplicates */ + bucket = index % IFADDRS_HASH_SIZE; + i = ctx->hash[bucket]; + while (i) { + map = &ctx->list[i-1]; + if (map->index == index && + map->namelen == namelen && + memcmp(map->name, RTA_DATA(rta), namelen) == 0) + return 0; + i = map->hash_next; } - idx[i-k].if_index = conf.ifc_req[i].ifr_ifindex; - idx[i-k].if_name = conf.ifc_req[i].ifr_name; - } - idx[i-k].if_name = 0; - idx[i-k].if_index = 0; - return idx; + if (ctx->num >= ctx->allocated) { + size_t a = ctx->allocated ? ctx->allocated * 2 + 1 : 8; + if (a > SIZE_MAX/sizeof *map) return -1; + map = realloc(ctx->list, a * sizeof *map); + if (!map) return -1; + ctx->list = map; + ctx->allocated = a; + } + map = &ctx->list[ctx->num]; + map->index = index; + map->namelen = namelen; + memcpy(map->name, RTA_DATA(rta), namelen); + ctx->str_bytes += namelen + 1; + ctx->num++; + map->hash_next = ctx->hash[bucket]; + ctx->hash[bucket] = ctx->num; + return 0; + } + return 0; } struct if_nameindex *if_nameindex() { - size_t n; - void *p = 0; - int s = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0); - if (s>=0) { - for (n=0; (p=do_nameindex(s, n)) == (void *)-1; n++); - __syscall(SYS_close, s); + struct ifnameindexctx _ctx, *ctx = &_ctx; + struct if_nameindex *ifs = 0, *d; + struct ifnamemap *s; + char *p; + int i; + int cs; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + memset(ctx, 0, sizeof(*ctx)); + if (__rtnetlink_enumerate(AF_UNSPEC, AF_INET, netlink_msg_to_nameindex, ctx) < 0) goto err; + + ifs = malloc(sizeof(struct if_nameindex[ctx->num+1]) + ctx->str_bytes); + if (!ifs) goto err; + + p = (char*)(ifs + ctx->num + 1); + for (i = ctx->num, d = ifs, s = ctx->list; i; i--, s++, d++) { + d->if_index = s->index; + d->if_name = p; + memcpy(p, s->name, s->namelen); + p += s->namelen; + *p++ = 0; } + d->if_index = 0; + d->if_name = 0; +err: + pthread_setcancelstate(cs, 0); + free(ctx->list); errno = ENOBUFS; - return p; + return ifs; } diff --git a/system/lib/libc/musl/src/network/if_nametoindex.c b/system/lib/libc/musl/src/network/if_nametoindex.c index cb6ec054efbd9..331413c68912d 100644 --- a/system/lib/libc/musl/src/network/if_nametoindex.c +++ b/system/lib/libc/musl/src/network/if_nametoindex.c @@ -10,7 +10,7 @@ unsigned if_nametoindex(const char *name) struct ifreq ifr; int fd, r; - if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) return -1; + if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) return 0; strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); r = ioctl(fd, SIOCGIFINDEX, &ifr); __syscall(SYS_close, fd); diff --git a/system/lib/libc/musl/src/network/inet_addr.c b/system/lib/libc/musl/src/network/inet_addr.c index ea0a8f7a455ec..10b21f211cfd7 100644 --- a/system/lib/libc/musl/src/network/inet_addr.c +++ b/system/lib/libc/musl/src/network/inet_addr.c @@ -1,11 +1,12 @@ #include #include #include -#include "__dns.h" + +int __inet_aton(const char *, struct in_addr *); in_addr_t inet_addr(const char *p) { - struct sockaddr_in sin; - if (__ipparse(&sin, AF_INET, p) < 0) return -1; - return sin.sin_addr.s_addr; + struct in_addr a; + if (!__inet_aton(p, &a)) return -1; + return a.s_addr; } diff --git a/system/lib/libc/musl/src/network/inet_aton.c b/system/lib/libc/musl/src/network/inet_aton.c new file mode 100644 index 0000000000000..0f9a45f66ddee --- /dev/null +++ b/system/lib/libc/musl/src/network/inet_aton.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#include "libc.h" + +int __inet_aton(const char *s0, struct in_addr *dest) +{ + const char *s = s0; + unsigned char *d = (void *)dest; + unsigned long a[4] = { 0 }; + char *z; + int i; + + for (i=0; i<4; i++) { + a[i] = strtoul(s, &z, 0); + if (z==s || (*z && *z != '.') || !isdigit(*s)) + return 0; + if (!*z) break; + s=z+1; + } + if (i==4) return 0; + switch (i) { + case 0: + a[1] = a[0] & 0xffffff; + a[0] >>= 24; + case 1: + a[2] = a[1] & 0xffff; + a[1] >>= 16; + case 2: + a[3] = a[2] & 0xff; + a[2] >>= 8; + } + for (i=0; i<4; i++) { + if (a[i] > 255) return 0; + d[i] = a[i]; + } + return 1; +} + +weak_alias(__inet_aton, inet_aton); diff --git a/system/lib/libc/musl/src/network/inet_legacy.c b/system/lib/libc/musl/src/network/inet_legacy.c index de5b75c1ae4de..621b47b05086d 100644 --- a/system/lib/libc/musl/src/network/inet_legacy.c +++ b/system/lib/libc/musl/src/network/inet_legacy.c @@ -1,21 +1,12 @@ #include #include #include -#include "__dns.h" in_addr_t inet_network(const char *p) { return ntohl(inet_addr(p)); } -int inet_aton(const char *cp, struct in_addr *inp) -{ - struct sockaddr_in sin; - if (__ipparse(&sin, AF_INET, cp) < 0) return 0; - *inp = sin.sin_addr; - return 1; -} - struct in_addr inet_makeaddr(in_addr_t n, in_addr_t h) { if (n < 256) h |= n<<24; diff --git a/system/lib/libc/musl/src/network/lookup.h b/system/lib/libc/musl/src/network/lookup.h new file mode 100644 index 0000000000000..0468edbc61c56 --- /dev/null +++ b/system/lib/libc/musl/src/network/lookup.h @@ -0,0 +1,39 @@ +#ifndef LOOKUP_H +#define LOOKUP_H + +#include +#include + +struct address { + int family; + unsigned scopeid; + uint8_t addr[16]; + int sortkey; +}; + +struct service { + uint16_t port; + unsigned char proto, socktype; +}; + +#define MAXNS 3 + +struct resolvconf { + struct address ns[MAXNS]; + unsigned nns, attempts, ndots; + unsigned timeout; +}; + +/* The limit of 48 results is a non-sharp bound on the number of addresses + * that can fit in one 512-byte DNS packet full of v4 results and a second + * packet full of v6 results. Due to headers, the actual limit is lower. */ +#define MAXADDRS 48 +#define MAXSERVS 2 + +int __lookup_serv(struct service buf[static MAXSERVS], const char *name, int proto, int socktype, int flags); +int __lookup_name(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family, int flags); +int __lookup_ipliteral(struct address buf[static 1], const char *name, int family); + +int __get_resolv_conf(struct resolvconf *, char *, size_t); + +#endif diff --git a/system/lib/libc/musl/src/network/lookup_ipliteral.c b/system/lib/libc/musl/src/network/lookup_ipliteral.c new file mode 100644 index 0000000000000..8ed14605238ef --- /dev/null +++ b/system/lib/libc/musl/src/network/lookup_ipliteral.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "lookup.h" + +int __inet_aton(const char *, struct in_addr *); + +int __lookup_ipliteral(struct address buf[static 1], const char *name, int family) +{ + struct in_addr a4; + struct in6_addr a6; + if (__inet_aton(name, &a4) > 0) { + if (family == AF_INET6) /* wrong family */ + return EAI_NONAME; + memcpy(&buf[0].addr, &a4, sizeof a4); + buf[0].family = AF_INET; + buf[0].scopeid = 0; + return 1; + } + + char tmp[64]; + char *p = strchr(name, '%'), *z; + unsigned long long scopeid = 0; + if (p && p-name < 64) { + memcpy(tmp, name, p-name); + tmp[p-name] = 0; + name = tmp; + } + + if (inet_pton(AF_INET6, name, &a6) <= 0) + return 0; + if (family == AF_INET) /* wrong family */ + return EAI_NONAME; + + memcpy(&buf[0].addr, &a6, sizeof a6); + buf[0].family = AF_INET6; + if (p) { + if (isdigit(*++p)) scopeid = strtoull(p, &z, 10); + else z = p-1; + if (*z) { + if (!IN6_IS_ADDR_LINKLOCAL(&a6) && + !IN6_IS_ADDR_MC_LINKLOCAL(&a6)) + return EAI_NONAME; + scopeid = if_nametoindex(p); + if (!scopeid) return EAI_NONAME; + } + if (scopeid > UINT_MAX) return EAI_NONAME; + } + buf[0].scopeid = scopeid; + return 1; +} diff --git a/system/lib/libc/musl/src/network/lookup_name.c b/system/lib/libc/musl/src/network/lookup_name.c new file mode 100644 index 0000000000000..fb7303a309618 --- /dev/null +++ b/system/lib/libc/musl/src/network/lookup_name.c @@ -0,0 +1,398 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "lookup.h" +#include "stdio_impl.h" +#include "syscall.h" + +static int is_valid_hostname(const char *host) +{ + const unsigned char *s; + if (strnlen(host, 255)-1 >= 254 || mbstowcs(0, host, 0) == -1) return 0; + for (s=(void *)host; *s>=0x80 || *s=='.' || *s=='-' || isalnum(*s); s++); + return !*s; +} + +static int name_from_null(struct address buf[static 2], const char *name, int family, int flags) +{ + int cnt = 0; + if (name) return 0; + if (flags & AI_PASSIVE) { + if (family != AF_INET6) + buf[cnt++] = (struct address){ .family = AF_INET }; + if (family != AF_INET) + buf[cnt++] = (struct address){ .family = AF_INET6 }; + } else { + if (family != AF_INET6) + buf[cnt++] = (struct address){ .family = AF_INET, .addr = { 127,0,0,1 } }; + if (family != AF_INET) + buf[cnt++] = (struct address){ .family = AF_INET6, .addr = { [15] = 1 } }; + } + return cnt; +} + +static int name_from_numeric(struct address buf[static 1], const char *name, int family) +{ + return __lookup_ipliteral(buf, name, family); +} + +static int name_from_hosts(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family) +{ + char line[512]; + size_t l = strlen(name); + int cnt = 0, badfam = 0; + unsigned char _buf[1032]; + FILE _f, *f = __fopen_rb_ca("/etc/hosts", &_f, _buf, sizeof _buf); + if (!f) switch (errno) { + case ENOENT: + case ENOTDIR: + case EACCES: + return 0; + default: + return EAI_SYSTEM; + } + while (fgets(line, sizeof line, f) && cnt < MAXADDRS) { + char *p, *z; + + if ((p=strchr(line, '#'))) *p++='\n', *p=0; + for(p=line+1; (p=strstr(p, name)) && + (!isspace(p[-1]) || !isspace(p[l])); p++); + if (!p) continue; + + /* Isolate IP address to parse */ + for (p=line; *p && !isspace(*p); p++); + *p++ = 0; + switch (name_from_numeric(buf+cnt, line, family)) { + case 1: + cnt++; + break; + case 0: + continue; + default: + badfam = EAI_NONAME; + continue; + } + + /* Extract first name as canonical name */ + for (; *p && isspace(*p); p++); + for (z=p; *z && !isspace(*z); z++); + *z = 0; + if (is_valid_hostname(p)) memcpy(canon, p, z-p+1); + } + __fclose_ca(f); + return cnt ? cnt : badfam; +} + +struct dpc_ctx { + struct address *addrs; + char *canon; + int cnt; +}; + +int __dns_parse(const unsigned char *, int, int (*)(void *, int, const void *, int, const void *), void *); +int __dn_expand(const unsigned char *, const unsigned char *, const unsigned char *, char *, int); +int __res_mkquery(int, const char *, int, int, const unsigned char *, int, const unsigned char*, unsigned char *, int); +int __res_msend_rc(int, const unsigned char *const *, const int *, unsigned char *const *, int *, int, const struct resolvconf *); + +#define RR_A 1 +#define RR_CNAME 5 +#define RR_AAAA 28 + +static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet) +{ + char tmp[256]; + struct dpc_ctx *ctx = c; + switch (rr) { + case RR_A: + if (len != 4) return -1; + ctx->addrs[ctx->cnt].family = AF_INET; + ctx->addrs[ctx->cnt].scopeid = 0; + memcpy(ctx->addrs[ctx->cnt++].addr, data, 4); + break; + case RR_AAAA: + if (len != 16) return -1; + ctx->addrs[ctx->cnt].family = AF_INET6; + ctx->addrs[ctx->cnt].scopeid = 0; + memcpy(ctx->addrs[ctx->cnt++].addr, data, 16); + break; + case RR_CNAME: + if (__dn_expand(packet, (const unsigned char *)packet + 512, + data, tmp, sizeof tmp) > 0 && is_valid_hostname(tmp)) + strcpy(ctx->canon, tmp); + break; + } + return 0; +} + +static int name_from_dns(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family, const struct resolvconf *conf) +{ + unsigned char qbuf[2][280], abuf[2][512]; + const unsigned char *qp[2] = { qbuf[0], qbuf[1] }; + unsigned char *ap[2] = { abuf[0], abuf[1] }; + int qlens[2], alens[2]; + int i, nq = 0; + struct dpc_ctx ctx = { .addrs = buf, .canon = canon }; + static const struct { int af; int rr; } afrr[2] = { + { .af = AF_INET6, .rr = RR_A }, + { .af = AF_INET, .rr = RR_AAAA }, + }; + + for (i=0; i<2; i++) { + if (family != afrr[i].af) { + qlens[nq] = __res_mkquery(0, name, 1, afrr[i].rr, + 0, 0, 0, qbuf[nq], sizeof *qbuf); + if (qlens[nq] == -1) + return EAI_NONAME; + nq++; + } + } + + if (__res_msend_rc(nq, qp, qlens, ap, alens, sizeof *abuf, conf) < 0) + return EAI_SYSTEM; + + for (i=0; i=ndots or name ends in + * a dot, which is an explicit request for global scope. */ + for (dots=l=0; name[l]; l++) if (name[l]=='.') dots++; + if (dots >= conf.ndots || name[l-1]=='.') *search = 0; + + /* This can never happen; the caller already checked length. */ + if (l >= 256) return EAI_NONAME; + + /* Name with search domain appended is setup in canon[]. This both + * provides the desired default canonical name (if the requested + * name is not a CNAME record) and serves as a buffer for passing + * the full requested name to name_from_dns. */ + memcpy(canon, name, l); + canon[l] = '.'; + + for (p=search; *p; p=z) { + for (; isspace(*p); p++); + for (z=p; *z && !isspace(*z); z++); + if (z==p) break; + if (z-p < 256 - l - 1) { + memcpy(canon+l+1, p, z-p); + canon[z-p+1+l] = 0; + int cnt = name_from_dns(buf, canon, canon, family, &conf); + if (cnt) return cnt; + } + } + + canon[l] = 0; + return name_from_dns(buf, canon, name, family, &conf); +} + +static const struct policy { + unsigned char addr[16]; + unsigned char len, mask; + unsigned char prec, label; +} defpolicy[] = { + { "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1", 15, 0xff, 50, 0 }, + { "\0\0\0\0\0\0\0\0\0\0\xff\xff", 11, 0xff, 35, 4 }, + { "\x20\2", 1, 0xff, 30, 2 }, + { "\x20\1", 3, 0xff, 5, 5 }, + { "\xfc", 0, 0xfe, 3, 13 }, +#if 0 + /* These are deprecated and/or returned to the address + * pool, so despite the RFC, treating them as special + * is probably wrong. */ + { "", 11, 0xff, 1, 3 }, + { "\xfe\xc0", 1, 0xc0, 1, 11 }, + { "\x3f\xfe", 1, 0xff, 1, 12 }, +#endif + /* Last rule must match all addresses to stop loop. */ + { "", 0, 0, 40, 1 }, +}; + +static const struct policy *policyof(const struct in6_addr *a) +{ + int i; + for (i=0; ; i++) { + if (memcmp(a->s6_addr, defpolicy[i].addr, defpolicy[i].len)) + continue; + if ((a->s6_addr[defpolicy[i].len] & defpolicy[i].mask) + != defpolicy[i].addr[defpolicy[i].len]) + continue; + return defpolicy+i; + } +} + +static int labelof(const struct in6_addr *a) +{ + return policyof(a)->label; +} + +static int scopeof(const struct in6_addr *a) +{ + if (IN6_IS_ADDR_MULTICAST(a)) return a->s6_addr[1] & 15; + if (IN6_IS_ADDR_LINKLOCAL(a)) return 2; + if (IN6_IS_ADDR_LOOPBACK(a)) return 2; + if (IN6_IS_ADDR_SITELOCAL(a)) return 5; + return 14; +} + +static int prefixmatch(const struct in6_addr *s, const struct in6_addr *d) +{ + /* FIXME: The common prefix length should be limited to no greater + * than the nominal length of the prefix portion of the source + * address. However the definition of the source prefix length is + * not clear and thus this limiting is not yet implemented. */ + unsigned i; + for (i=0; i<128 && !((s->s6_addr[i/8]^d->s6_addr[i/8])&(128>>(i%8))); i++); + return i; +} + +#define DAS_USABLE 0x40000000 +#define DAS_MATCHINGSCOPE 0x20000000 +#define DAS_MATCHINGLABEL 0x10000000 +#define DAS_PREC_SHIFT 20 +#define DAS_SCOPE_SHIFT 16 +#define DAS_PREFIX_SHIFT 8 +#define DAS_ORDER_SHIFT 0 + +static int addrcmp(const void *_a, const void *_b) +{ + const struct address *a = _a, *b = _b; + return b->sortkey - a->sortkey; +} + +int __lookup_name(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family, int flags) +{ + int cnt = 0, i, j; + + *canon = 0; + if (name) { + /* reject empty name and check len so it fits into temp bufs */ + size_t l = strnlen(name, 255); + if (l-1 >= 254) + return EAI_NONAME; + memcpy(canon, name, l+1); + } + + /* Procedurally, a request for v6 addresses with the v4-mapped + * flag set is like a request for unspecified family, followed + * by filtering of the results. */ + if (flags & AI_V4MAPPED) { + if (family == AF_INET6) family = AF_UNSPEC; + else flags -= AI_V4MAPPED; + } + + /* Try each backend until there's at least one result. */ + cnt = name_from_null(buf, name, family, flags); + if (!cnt) cnt = name_from_numeric(buf, name, family); + if (!cnt && !(flags & AI_NUMERICHOST)) { + cnt = name_from_hosts(buf, canon, name, family); + if (!cnt) cnt = name_from_dns_search(buf, canon, name, family); + } + if (cnt<=0) return cnt ? cnt : EAI_NONAME; + + /* Filter/transform results for v4-mapped lookup, if requested. */ + if (flags & AI_V4MAPPED) { + if (!(flags & AI_ALL)) { + /* If any v6 results exist, remove v4 results. */ + for (i=0; ilabel; + int dprec = dpolicy->prec; + int prefixlen = 0; + int fd = socket(AF_INET6, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_UDP); + if (fd >= 0) { + if (!connect(fd, (void *)&da, sizeof da)) { + key |= DAS_USABLE; + if (!getsockname(fd, (void *)&sa, + &(socklen_t){sizeof sa})) { + if (dscope == scopeof(&sa.sin6_addr)) + key |= DAS_MATCHINGSCOPE; + if (dlabel == labelof(&sa.sin6_addr)) + key |= DAS_MATCHINGLABEL; + prefixlen = prefixmatch(&sa.sin6_addr, + &da.sin6_addr); + } + } + close(fd); + } + key |= dprec << DAS_PREC_SHIFT; + key |= (15-dscope) << DAS_SCOPE_SHIFT; + key |= prefixlen << DAS_PREFIX_SHIFT; + key |= (MAXADDRS-i) << DAS_ORDER_SHIFT; + buf[i].sortkey = key; + } + qsort(buf, cnt, sizeof *buf, addrcmp); + + pthread_setcancelstate(cs, 0); + + return cnt; +} diff --git a/system/lib/libc/musl/src/network/lookup_serv.c b/system/lib/libc/musl/src/network/lookup_serv.c new file mode 100644 index 0000000000000..66ebaea25a3fb --- /dev/null +++ b/system/lib/libc/musl/src/network/lookup_serv.c @@ -0,0 +1,113 @@ +#include +#include +#include +#include +#include +#include +#include +#include "lookup.h" +#include "stdio_impl.h" + +int __lookup_serv(struct service buf[static MAXSERVS], const char *name, int proto, int socktype, int flags) +{ + char line[128]; + int cnt = 0; + char *p, *z = ""; + unsigned long port = 0; + + switch (socktype) { + case SOCK_STREAM: + switch (proto) { + case 0: + proto = IPPROTO_TCP; + case IPPROTO_TCP: + break; + default: + return EAI_SERVICE; + } + break; + case SOCK_DGRAM: + switch (proto) { + case 0: + proto = IPPROTO_UDP; + case IPPROTO_UDP: + break; + default: + return EAI_SERVICE; + } + case 0: + break; + default: + if (name) return EAI_SERVICE; + buf[0].port = 0; + buf[0].proto = proto; + buf[0].socktype = socktype; + return 1; + } + + if (name) { + if (!*name) return EAI_SERVICE; + port = strtoul(name, &z, 10); + } + if (!*z) { + if (port > 65535) return EAI_SERVICE; + if (proto != IPPROTO_UDP) { + buf[cnt].port = port; + buf[cnt].socktype = SOCK_STREAM; + buf[cnt++].proto = IPPROTO_TCP; + } + if (proto != IPPROTO_TCP) { + buf[cnt].port = port; + buf[cnt].socktype = SOCK_DGRAM; + buf[cnt++].proto = IPPROTO_UDP; + } + return cnt; + } + + if (flags & AI_NUMERICSERV) return EAI_SERVICE; + + size_t l = strlen(name); + + unsigned char _buf[1032]; + FILE _f, *f = __fopen_rb_ca("/etc/services", &_f, _buf, sizeof _buf); + if (!f) switch (errno) { + case ENOENT: + case ENOTDIR: + case EACCES: + return EAI_SERVICE; + default: + return EAI_SYSTEM; + } + + while (fgets(line, sizeof line, f) && cnt < MAXSERVS) { + if ((p=strchr(line, '#'))) *p++='\n', *p=0; + + /* Find service name */ + for(p=line; (p=strstr(p, name)); p++) { + if (p>line && !isspace(p[-1])) continue; + if (p[l] && !isspace(p[l])) continue; + break; + } + if (!p) continue; + + /* Skip past canonical name at beginning of line */ + for (p=line; *p && !isspace(*p); p++); + + port = strtoul(p, &z, 10); + if (port > 65535 || z==p) continue; + if (!strncmp(z, "/udp", 4)) { + if (proto == IPPROTO_TCP) continue; + buf[cnt].port = port; + buf[cnt].socktype = SOCK_DGRAM; + buf[cnt++].proto = IPPROTO_UDP; + } + if (!strncmp(z, "/tcp", 4)) { + if (proto == IPPROTO_UDP) continue; + buf[cnt].port = port; + buf[cnt].socktype = SOCK_STREAM; + buf[cnt++].proto = IPPROTO_TCP; + } + } + __fclose_ca(f); + return cnt > 0 ? cnt : EAI_SERVICE; +} diff --git a/system/lib/libc/musl/src/network/netlink.c b/system/lib/libc/musl/src/network/netlink.c new file mode 100644 index 0000000000000..94dba7f5c9e40 --- /dev/null +++ b/system/lib/libc/musl/src/network/netlink.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include "netlink.h" + +static int __netlink_enumerate(int fd, unsigned int seq, int type, int af, + int (*cb)(void *ctx, struct nlmsghdr *h), void *ctx) +{ + struct nlmsghdr *h; + union { + uint8_t buf[8192]; + struct { + struct nlmsghdr nlh; + struct rtgenmsg g; + } req; + struct nlmsghdr reply; + } u; + int r, ret; + + memset(&u.req, 0, sizeof(u.req)); + u.req.nlh.nlmsg_len = sizeof(u.req); + u.req.nlh.nlmsg_type = type; + u.req.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; + u.req.nlh.nlmsg_seq = seq; + u.req.g.rtgen_family = af; + r = send(fd, &u.req, sizeof(u.req), 0); + if (r < 0) return r; + + while (1) { + r = recv(fd, u.buf, sizeof(u.buf), MSG_DONTWAIT); + if (r <= 0) return -1; + for (h = &u.reply; NLMSG_OK(h, (void*)&u.buf[r]); h = NLMSG_NEXT(h)) { + if (h->nlmsg_type == NLMSG_DONE) return 0; + if (h->nlmsg_type == NLMSG_ERROR) return -1; + ret = cb(ctx, h); + if (ret) return ret; + } + } +} + +int __rtnetlink_enumerate(int link_af, int addr_af, int (*cb)(void *ctx, struct nlmsghdr *h), void *ctx) +{ + int fd, r; + + fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, NETLINK_ROUTE); + if (fd < 0) return -1; + r = __netlink_enumerate(fd, 1, RTM_GETLINK, link_af, cb, ctx); + if (!r) r = __netlink_enumerate(fd, 2, RTM_GETADDR, addr_af, cb, ctx); + __syscall(SYS_close,fd); + return r; +} diff --git a/system/lib/libc/musl/src/network/netlink.h b/system/lib/libc/musl/src/network/netlink.h new file mode 100644 index 0000000000000..20700ac5b4f03 --- /dev/null +++ b/system/lib/libc/musl/src/network/netlink.h @@ -0,0 +1,94 @@ +#include + +/* linux/netlink.h */ + +#define NETLINK_ROUTE 0 + +struct nlmsghdr { + uint32_t nlmsg_len; + uint16_t nlmsg_type; + uint16_t nlmsg_flags; + uint32_t nlmsg_seq; + uint32_t nlmsg_pid; +}; + +#define NLM_F_REQUEST 1 +#define NLM_F_MULTI 2 +#define NLM_F_ACK 4 + +#define NLM_F_ROOT 0x100 +#define NLM_F_MATCH 0x200 +#define NLM_F_ATOMIC 0x400 +#define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH) + +#define NLMSG_NOOP 0x1 +#define NLMSG_ERROR 0x2 +#define NLMSG_DONE 0x3 +#define NLMSG_OVERRUN 0x4 + +/* linux/rtnetlink.h */ + +#define RTM_NEWLINK 16 +#define RTM_GETLINK 18 +#define RTM_NEWADDR 20 +#define RTM_GETADDR 22 + +struct rtattr { + unsigned short rta_len; + unsigned short rta_type; +}; + +struct rtgenmsg { + unsigned char rtgen_family; +}; + +struct ifinfomsg { + unsigned char ifi_family; + unsigned char __ifi_pad; + unsigned short ifi_type; + int ifi_index; + unsigned ifi_flags; + unsigned ifi_change; +}; + +/* linux/if_link.h */ + +#define IFLA_ADDRESS 1 +#define IFLA_BROADCAST 2 +#define IFLA_IFNAME 3 +#define IFLA_STATS 7 + +/* linux/if_addr.h */ + +struct ifaddrmsg { + uint8_t ifa_family; + uint8_t ifa_prefixlen; + uint8_t ifa_flags; + uint8_t ifa_scope; + uint32_t ifa_index; +}; + +#define IFA_ADDRESS 1 +#define IFA_LOCAL 2 +#define IFA_LABEL 3 +#define IFA_BROADCAST 4 + +/* musl */ + +#define NETLINK_ALIGN(len) (((len)+3) & ~3) +#define NLMSG_DATA(nlh) ((void*)((char*)(nlh)+sizeof(struct nlmsghdr))) +#define NLMSG_DATALEN(nlh) ((nlh)->nlmsg_len-sizeof(struct nlmsghdr)) +#define NLMSG_DATAEND(nlh) ((char*)(nlh)+(nlh)->nlmsg_len) +#define NLMSG_NEXT(nlh) (struct nlmsghdr*)((char*)(nlh)+NETLINK_ALIGN((nlh)->nlmsg_len)) +#define NLMSG_OK(nlh,end) ((char*)(end)-(char*)(nlh) >= sizeof(struct nlmsghdr)) + +#define RTA_DATA(rta) ((void*)((char*)(rta)+sizeof(struct rtattr))) +#define RTA_DATALEN(rta) ((rta)->rta_len-sizeof(struct rtattr)) +#define RTA_DATAEND(rta) ((char*)(rta)+(rta)->rta_len) +#define RTA_NEXT(rta) (struct rtattr*)((char*)(rta)+NETLINK_ALIGN((rta)->rta_len)) +#define RTA_OK(nlh,end) ((char*)(end)-(char*)(rta) >= sizeof(struct rtattr)) + +#define NLMSG_RTA(nlh,len) ((void*)((char*)(nlh)+sizeof(struct nlmsghdr)+NETLINK_ALIGN(len))) +#define NLMSG_RTAOK(rta,nlh) RTA_OK(rta,NLMSG_DATAEND(nlh)) + +int __rtnetlink_enumerate(int link_af, int addr_af, int (*cb)(void *ctx, struct nlmsghdr *h), void *ctx); diff --git a/system/lib/libc/musl/src/network/ns_parse.c b/system/lib/libc/musl/src/network/ns_parse.c new file mode 100644 index 0000000000000..71bd309cfdc7f --- /dev/null +++ b/system/lib/libc/musl/src/network/ns_parse.c @@ -0,0 +1,171 @@ +#define _BSD_SOURCE +#include +#include +#include +#include + +const struct _ns_flagdata _ns_flagdata[16] = { + { 0x8000, 15 }, + { 0x7800, 11 }, + { 0x0400, 10 }, + { 0x0200, 9 }, + { 0x0100, 8 }, + { 0x0080, 7 }, + { 0x0040, 6 }, + { 0x0020, 5 }, + { 0x0010, 4 }, + { 0x000f, 0 }, + { 0x0000, 0 }, + { 0x0000, 0 }, + { 0x0000, 0 }, + { 0x0000, 0 }, + { 0x0000, 0 }, + { 0x0000, 0 }, +}; + +unsigned ns_get16(const unsigned char *cp) +{ + return cp[0]<<8 | cp[1]; +} + +unsigned long ns_get32(const unsigned char *cp) +{ + return (unsigned)cp[0]<<24 | cp[1]<<16 | cp[2]<<8 | cp[3]; +} + +void ns_put16(unsigned s, unsigned char *cp) +{ + *cp++ = s>>8; + *cp++ = s; +} + +void ns_put32(unsigned long l, unsigned char *cp) +{ + *cp++ = l>>24; + *cp++ = l>>16; + *cp++ = l>>8; + *cp++ = l; +} + +int ns_skiprr(const unsigned char *ptr, const unsigned char *eom, ns_sect section, int count) +{ + const unsigned char *p = ptr; + int r; + + while (count--) { + r = dn_skipname(p, eom); + if (r < 0) goto bad; + if (r + 2 * NS_INT16SZ > eom - p) goto bad; + p += r + 2 * NS_INT16SZ; + if (section != ns_s_qd) { + if (NS_INT32SZ + NS_INT16SZ > eom - p) goto bad; + p += NS_INT32SZ; + NS_GET16(r, p); + if (r > eom - p) goto bad; + p += r; + } + } + return p - ptr; +bad: + errno = EMSGSIZE; + return -1; +} + +int ns_initparse(const unsigned char *msg, int msglen, ns_msg *handle) +{ + int i, r; + + handle->_msg = msg; + handle->_eom = msg + msglen; + if (msglen < (2 + ns_s_max) * NS_INT16SZ) goto bad; + NS_GET16(handle->_id, msg); + NS_GET16(handle->_flags, msg); + for (i = 0; i < ns_s_max; i++) NS_GET16(handle->_counts[i], msg); + for (i = 0; i < ns_s_max; i++) { + if (handle->_counts[i]) { + handle->_sections[i] = msg; + r = ns_skiprr(msg, handle->_eom, i, handle->_counts[i]); + if (r < 0) return -1; + msg += r; + } else { + handle->_sections[i] = NULL; + } + } + if (msg != handle->_eom) goto bad; + handle->_sect = ns_s_max; + handle->_rrnum = -1; + handle->_msg_ptr = NULL; + return 0; +bad: + errno = EMSGSIZE; + return -1; +} + +int ns_name_uncompress(const unsigned char *msg, const unsigned char *eom, + const unsigned char *src, char *dst, size_t dstsiz) +{ + int r; + r = dn_expand(msg, eom, src, dst, dstsiz); + if (r < 0) errno = EMSGSIZE; + return r; +} + +int ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr) +{ + int r; + + if (section >= ns_s_max) goto bad; + if (section != handle->_sect) { + handle->_sect = section; + handle->_rrnum = 0; + handle->_msg_ptr = handle->_sections[section]; + } + if (rrnum == -1) rrnum = handle->_rrnum; + if (rrnum < 0 || rrnum >= handle->_counts[section]) goto bad; + if (rrnum < handle->_rrnum) { + handle->_rrnum = 0; + handle->_msg_ptr = handle->_sections[section]; + } + if (rrnum > handle->_rrnum) { + r = ns_skiprr(handle->_msg_ptr, handle->_eom, section, rrnum - handle->_rrnum); + if (r < 0) return -1; + handle->_msg_ptr += r; + handle->_rrnum = rrnum; + } + r = ns_name_uncompress(handle->_msg, handle->_eom, handle->_msg_ptr, rr->name, NS_MAXDNAME); + if (r < 0) return -1; + handle->_msg_ptr += r; + if (2 * NS_INT16SZ > handle->_eom - handle->_msg_ptr) goto size; + NS_GET16(rr->type, handle->_msg_ptr); + NS_GET16(rr->rr_class, handle->_msg_ptr); + if (section != ns_s_qd) { + if (NS_INT32SZ + NS_INT16SZ > handle->_eom - handle->_msg_ptr) goto size; + NS_GET32(rr->ttl, handle->_msg_ptr); + NS_GET16(rr->rdlength, handle->_msg_ptr); + if (rr->rdlength > handle->_eom - handle->_msg_ptr) goto size; + rr->rdata = handle->_msg_ptr; + handle->_msg_ptr += rr->rdlength; + } else { + rr->ttl = 0; + rr->rdlength = 0; + rr->rdata = NULL; + } + handle->_rrnum++; + if (handle->_rrnum > handle->_counts[section]) { + handle->_sect = section + 1; + if (handle->_sect == ns_s_max) { + handle->_rrnum = -1; + handle->_msg_ptr = NULL; + } else { + handle->_rrnum = 0; + } + } + return 0; +bad: + errno = ENODEV; + return -1; +size: + errno = EMSGSIZE; + return -1; +} + diff --git a/system/lib/libc/musl/src/network/proto.c b/system/lib/libc/musl/src/network/proto.c index 3d0f584fbf695..c4fd34efb0ad4 100644 --- a/system/lib/libc/musl/src/network/proto.c +++ b/system/lib/libc/musl/src/network/proto.c @@ -4,19 +4,43 @@ /* do we really need all these?? */ static int idx; -static const unsigned char protos[][8] = { - "\000ip", - "\001icmp", - "\002igmp", - "\003ggp", - "\006tcp", - "\014pup", - "\021udp", - "\026idp", - "\051ipv6", - "\072icmpv6", - "\377raw", - "\0\0" +static const unsigned char protos[] = { + "\000ip\0" + "\001icmp\0" + "\002igmp\0" + "\003ggp\0" + "\004ipencap\0" + "\005st\0" + "\006tcp\0" + "\010egp\0" + "\014pup\0" + "\021udp\0" + "\024hmp\0" + "\026xns-idp\0" + "\033rdp\0" + "\035iso-tp4\0" + "\044xtp\0" + "\045ddp\0" + "\046idpr-cmtp\0" + "\051ipv6\0" + "\053ipv6-route\0" + "\054ipv6-frag\0" + "\055idrp\0" + "\056rsvp\0" + "\057gre\0" + "\062esp\0" + "\063ah\0" + "\071skip\0" + "\072ipv6-icmp\0" + "\073ipv6-nonxt\0" + "\074ipv6-opts\0" + "\111rspf\0" + "\121vmtp\0" + "\131ospf\0" + "\136ipip\0" + "\142encap\0" + "\147pim\0" + "\377raw" }; void endprotoent(void) @@ -33,10 +57,11 @@ struct protoent *getprotoent(void) { static struct protoent p; static const char *aliases; - if (!protos[idx][1]) return NULL; - p.p_proto = protos[idx][0]; - p.p_name = (char *)protos[idx++]+1; + if (idx >= sizeof protos) return NULL; + p.p_proto = protos[idx]; + p.p_name = (char *)&protos[idx+1]; p.p_aliases = (char **)&aliases; + idx += strlen(p.p_name) + 2; return &p; } diff --git a/system/lib/libc/musl/src/network/recvmmsg.c b/system/lib/libc/musl/src/network/recvmmsg.c new file mode 100644 index 0000000000000..58b1b2f635bde --- /dev/null +++ b/system/lib/libc/musl/src/network/recvmmsg.c @@ -0,0 +1,15 @@ +#define _GNU_SOURCE +#include +#include +#include "syscall.h" + +int recvmmsg(int fd, struct mmsghdr *msgvec, unsigned int vlen, unsigned int flags, struct timespec *timeout) +{ +#if LONG_MAX > INT_MAX + struct mmsghdr *mh = msgvec; + unsigned int i; + for (i = vlen; i; i--, mh++) + mh->msg_hdr.__pad1 = mh->msg_hdr.__pad2 = 0; +#endif + return syscall_cp(SYS_recvmmsg, fd, msgvec, vlen, flags, timeout); +} diff --git a/system/lib/libc/musl/src/network/res_init.c b/system/lib/libc/musl/src/network/res_init.c index cbd5b1556473c..5dba9dfc3fd8e 100644 --- a/system/lib/libc/musl/src/network/res_init.c +++ b/system/lib/libc/musl/src/network/res_init.c @@ -1,3 +1,5 @@ +#include + int res_init() { return 0; diff --git a/system/lib/libc/musl/src/network/res_mkquery.c b/system/lib/libc/musl/src/network/res_mkquery.c new file mode 100644 index 0000000000000..ec4568acb8166 --- /dev/null +++ b/system/lib/libc/musl/src/network/res_mkquery.c @@ -0,0 +1,44 @@ +#include +#include +#include +#include "libc.h" + +int __res_mkquery(int op, const char *dname, int class, int type, + const unsigned char *data, int datalen, + const unsigned char *newrr, unsigned char *buf, int buflen) +{ + int id, i, j; + unsigned char q[280]; + struct timespec ts; + size_t l = strnlen(dname, 255); + int n; + + if (l && dname[l-1]=='.') l--; + n = 17+l+!!l; + if (l>253 || buflen15u || class>255u || type>255u) + return -1; + + /* Construct query template - ID will be filled later */ + memset(q, 0, n); + q[2] = op*8 + 1; + q[5] = 1; + memcpy((char *)q+13, dname, l); + for (i=13; q[i]; i=j+1) { + for (j=i; q[j] && q[j] != '.'; j++); + if (j-i-1u > 62u) return -1; + q[i-1] = j-i; + } + q[i+1] = type; + q[i+3] = class; + + /* Make a reasonably unpredictable id */ + clock_gettime(CLOCK_REALTIME, &ts); + id = ts.tv_nsec + ts.tv_nsec/65536UL & 0xffff; + q[0] = id/256; + q[1] = id; + + memcpy(buf, q, n); + return n; +} + +weak_alias(__res_mkquery, res_mkquery); diff --git a/system/lib/libc/musl/src/network/res_msend.c b/system/lib/libc/musl/src/network/res_msend.c new file mode 100644 index 0000000000000..de7f615762e72 --- /dev/null +++ b/system/lib/libc/musl/src/network/res_msend.c @@ -0,0 +1,184 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "stdio_impl.h" +#include "syscall.h" +#include "lookup.h" + +static void cleanup(void *p) +{ + __syscall(SYS_close, (intptr_t)p); +} + +static unsigned long mtime() +{ + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + return (unsigned long)ts.tv_sec * 1000 + + ts.tv_nsec / 1000000; +} + +int __res_msend_rc(int nqueries, const unsigned char *const *queries, + const int *qlens, unsigned char *const *answers, int *alens, int asize, + const struct resolvconf *conf) +{ + int fd; + int timeout, attempts, retry_interval, servfail_retry; + union { + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + } sa = {0}, ns[MAXNS] = {{0}}; + socklen_t sl = sizeof sa.sin; + int nns = 0; + int family = AF_INET; + int rlen; + int next; + int i, j; + int cs; + struct pollfd pfd; + unsigned long t0, t1, t2; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + + timeout = 1000*conf->timeout; + attempts = conf->attempts; + + for (nns=0; nnsnns; nns++) { + const struct address *iplit = &conf->ns[nns]; + if (iplit->family == AF_INET) { + memcpy(&ns[nns].sin.sin_addr, iplit->addr, 4); + ns[nns].sin.sin_port = htons(53); + ns[nns].sin.sin_family = AF_INET; + } else { + sl = sizeof sa.sin6; + memcpy(&ns[nns].sin6.sin6_addr, iplit->addr, 16); + ns[nns].sin6.sin6_port = htons(53); + ns[nns].sin6.sin6_scope_id = iplit->scopeid; + ns[nns].sin6.sin6_family = family = AF_INET6; + } + } + + /* Get local address and open/bind a socket */ + sa.sin.sin_family = family; + fd = socket(family, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + + /* Handle case where system lacks IPv6 support */ + if (fd < 0 && family == AF_INET6 && errno == EAFNOSUPPORT) { + fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + family = AF_INET; + } + if (fd < 0 || bind(fd, (void *)&sa, sl) < 0) return -1; + + /* Past this point, there are no errors. Each individual query will + * yield either no reply (indicated by zero length) or an answer + * packet which is up to the caller to interpret. */ + + pthread_cleanup_push(cleanup, (void *)(intptr_t)fd); + pthread_setcancelstate(cs, 0); + + /* Convert any IPv4 addresses in a mixed environment to v4-mapped */ + if (family == AF_INET6) { + setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &(int){0}, sizeof 0); + for (i=0; i= retry_interval) { + /* Query all configured namservers in parallel */ + for (i=0; i= 0) { + + /* Ignore non-identifiable packets */ + if (rlen < 4) continue; + + /* Ignore replies from addresses we didn't send to */ + for (j=0; j #include -#include "__dns.h" #include "libc.h" -int res_query(const char *name, int class, int type, unsigned char *dest, int len) +int __res_mkquery(int, const char *, int, int, const unsigned char *, int, const unsigned char*, unsigned char *, int); +int __res_send(const unsigned char *, int, unsigned char *, int); + +int __res_query(const char *name, int class, int type, unsigned char *dest, int len) { - if (class != 1 || len < 512) - return -1; - switch(__dns_doqueries(dest, name, &type, 1)) { - case EAI_NONAME: - h_errno = HOST_NOT_FOUND; - return -1; - case EAI_AGAIN: - h_errno = TRY_AGAIN; - return -1; - case EAI_FAIL: - h_errno = NO_RECOVERY; - return -1; - } - return 512; + unsigned char q[280]; + int ql = __res_mkquery(0, name, class, type, 0, 0, 0, q, sizeof q); + if (ql < 0) return ql; + return __res_send(q, ql, dest, len); } -weak_alias(res_query, res_search); +weak_alias(__res_query, res_query); +weak_alias(__res_query, res_search); diff --git a/system/lib/libc/musl/src/network/res_querydomain.c b/system/lib/libc/musl/src/network/res_querydomain.c new file mode 100644 index 0000000000000..727e6f6ba525a --- /dev/null +++ b/system/lib/libc/musl/src/network/res_querydomain.c @@ -0,0 +1,14 @@ +#include +#include + +int res_querydomain(const char *name, const char *domain, int class, int type, unsigned char *dest, int len) +{ + char tmp[255]; + size_t nl = strnlen(name, 255); + size_t dl = strnlen(domain, 255); + if (nl+dl+1 > 254) return -1; + memcpy(tmp, name, nl); + tmp[nl] = '.'; + memcpy(tmp+nl+1, domain, dl+1); + return res_query(tmp, class, type, dest, len); +} diff --git a/system/lib/libc/musl/src/network/res_send.c b/system/lib/libc/musl/src/network/res_send.c new file mode 100644 index 0000000000000..19cfe0f6b4050 --- /dev/null +++ b/system/lib/libc/musl/src/network/res_send.c @@ -0,0 +1,12 @@ +#include +#include "libc.h" + +int __res_msend(int, const unsigned char *const *, const int *, unsigned char *const *, int *, int); + +int __res_send(const unsigned char *msg, int msglen, unsigned char *answer, int anslen) +{ + int r = __res_msend(1, &msg, &msglen, &answer, &anslen, anslen); + return r<0 ? r : anslen; +} + +weak_alias(__res_send, res_send); diff --git a/system/lib/libc/musl/src/network/resolvconf.c b/system/lib/libc/musl/src/network/resolvconf.c new file mode 100644 index 0000000000000..2cf1f47542ab5 --- /dev/null +++ b/system/lib/libc/musl/src/network/resolvconf.c @@ -0,0 +1,93 @@ +#include "lookup.h" +#include "stdio_impl.h" +#include +#include +#include +#include + +int __get_resolv_conf(struct resolvconf *conf, char *search, size_t search_sz) +{ + char line[256]; + unsigned char _buf[256]; + FILE *f, _f; + int nns = 0; + + conf->ndots = 1; + conf->timeout = 5; + conf->attempts = 2; + if (search) *search = 0; + + f = __fopen_rb_ca("/etc/resolv.conf", &_f, _buf, sizeof _buf); + if (!f) switch (errno) { + case ENOENT: + case ENOTDIR: + case EACCES: + goto no_resolv_conf; + default: + return -1; + } + + while (fgets(line, sizeof line, f)) { + char *p, *z; + if (!strchr(line, '\n') && !feof(f)) { + /* Ignore lines that get truncated rather than + * potentially misinterpreting them. */ + int c; + do c = getc(f); + while (c != '\n' && c != EOF); + continue; + } + if (!strncmp(line, "options", 7) && isspace(line[7])) { + p = strstr(line, "ndots:"); + if (p && isdigit(p[6])) { + p += 6; + unsigned long x = strtoul(p, &z, 10); + if (z != p) conf->ndots = x > 15 ? 15 : x; + } + p = strstr(line, "attempts:"); + if (p && isdigit(p[6])) { + p += 6; + unsigned long x = strtoul(p, &z, 10); + if (z != p) conf->attempts = x > 10 ? 10 : x; + } + p = strstr(line, "timeout:"); + if (p && (isdigit(p[8]) || p[8]=='.')) { + p += 8; + unsigned long x = strtoul(p, &z, 10); + if (z != p) conf->timeout = x > 60 ? 60 : x; + } + continue; + } + if (!strncmp(line, "nameserver", 10) && isspace(line[10])) { + if (nns >= MAXNS) continue; + for (p=line+11; isspace(*p); p++); + for (z=p; *z && !isspace(*z); z++); + *z=0; + if (__lookup_ipliteral(conf->ns+nns, p, AF_UNSPEC) > 0) + nns++; + continue; + } + + if (!search) continue; + if ((strncmp(line, "domain", 6) && strncmp(line, "search", 6)) + || !isspace(line[6])) + continue; + for (p=line+7; isspace(*p); p++); + size_t l = strlen(p); + /* This can never happen anyway with chosen buffer sizes. */ + if (l >= search_sz) continue; + memcpy(search, p, l+1); + } + + __fclose_ca(f); + +no_resolv_conf: + if (!nns) { + __lookup_ipliteral(conf->ns, "127.0.0.1", AF_UNSPEC); + nns = 1; + } + + conf->nns = nns; + + return 0; +} diff --git a/system/lib/libc/musl/src/network/sendmmsg.c b/system/lib/libc/musl/src/network/sendmmsg.c new file mode 100644 index 0000000000000..eeae1d0a58225 --- /dev/null +++ b/system/lib/libc/musl/src/network/sendmmsg.c @@ -0,0 +1,30 @@ +#define _GNU_SOURCE +#include +#include +#include +#include "syscall.h" + +int sendmmsg(int fd, struct mmsghdr *msgvec, unsigned int vlen, unsigned int flags) +{ +#if LONG_MAX > INT_MAX + /* Can't use the syscall directly because the kernel has the wrong + * idea for the types of msg_iovlen, msg_controllen, and cmsg_len, + * and the cmsg blocks cannot be modified in-place. */ + int i; + if (vlen > IOV_MAX) vlen = IOV_MAX; /* This matches the kernel. */ + if (!vlen) return 0; + for (i=0; i +#include +#include #include "syscall.h" int socketpair(int domain, int type, int protocol, int fd[2]) { - return socketcall(socketpair, domain, type, protocol, fd, 0, 0); + int r = socketcall(socketpair, domain, type, protocol, fd, 0, 0); + if (r<0 && (errno==EINVAL || errno==EPROTONOSUPPORT) + && (type&(SOCK_CLOEXEC|SOCK_NONBLOCK))) { + r = socketcall(socketpair, domain, + type & ~(SOCK_CLOEXEC|SOCK_NONBLOCK), + protocol, fd, 0, 0); + if (r < 0) return r; + if (type & SOCK_CLOEXEC) { + __syscall(SYS_fcntl, fd[0], F_SETFD, FD_CLOEXEC); + __syscall(SYS_fcntl, fd[1], F_SETFD, FD_CLOEXEC); + } + if (type & SOCK_NONBLOCK) { + __syscall(SYS_fcntl, fd[0], F_SETFL, O_NONBLOCK); + __syscall(SYS_fcntl, fd[1], F_SETFL, O_NONBLOCK); + } + } + return r; } diff --git a/system/lib/libc/musl/src/passwd/fgetgrent.c b/system/lib/libc/musl/src/passwd/fgetgrent.c index d8d1c77362549..7d045fd22be97 100644 --- a/system/lib/libc/musl/src/passwd/fgetgrent.c +++ b/system/lib/libc/musl/src/passwd/fgetgrent.c @@ -5,6 +5,8 @@ struct group *fgetgrent(FILE *f) { static char *line, **mem; static struct group gr; + struct group *res; size_t size=0, nmem=0; - return __getgrent_a(f, &gr, &line, &size, &mem, &nmem); + __getgrent_a(f, &gr, &line, &size, &mem, &nmem, &res); + return res; } diff --git a/system/lib/libc/musl/src/passwd/fgetpwent.c b/system/lib/libc/musl/src/passwd/fgetpwent.c index eb47b2a119379..fd472a07add9f 100644 --- a/system/lib/libc/musl/src/passwd/fgetpwent.c +++ b/system/lib/libc/musl/src/passwd/fgetpwent.c @@ -6,5 +6,7 @@ struct passwd *fgetpwent(FILE *f) static char *line; static struct passwd pw; size_t size=0; - return __getpwent_a(f, &pw, &line, &size); + struct passwd *res; + __getpwent_a(f, &pw, &line, &size, &res); + return res; } diff --git a/system/lib/libc/musl/src/passwd/getgr_a.c b/system/lib/libc/musl/src/passwd/getgr_a.c new file mode 100644 index 0000000000000..afeb1eceb5f86 --- /dev/null +++ b/system/lib/libc/musl/src/passwd/getgr_a.c @@ -0,0 +1,169 @@ +#include +#include +#include +#include +#include "pwf.h" +#include "nscd.h" + +static char *itoa(char *p, uint32_t x) +{ + // number of digits in a uint32_t + NUL + p += 11; + *--p = 0; + do { + *--p = '0' + x % 10; + x /= 10; + } while (x); + return p; +} + +int __getgr_a(const char *name, gid_t gid, struct group *gr, char **buf, size_t *size, char ***mem, size_t *nmem, struct group **res) +{ + FILE *f; + int rv = 0; + int cs; + + *res = 0; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + f = fopen("/etc/group", "rbe"); + if (!f) { + rv = errno; + goto done; + } + + while (!(rv = __getgrent_a(f, gr, buf, size, mem, nmem, res)) && *res) { + if (name && !strcmp(name, (*res)->gr_name) + || !name && (*res)->gr_gid == gid) { + break; + } + } + fclose(f); + + if (!*res && (rv == 0 || rv == ENOENT || rv == ENOTDIR)) { + int32_t req = name ? GETGRBYNAME : GETGRBYGID; + int32_t i; + const char *key; + int32_t groupbuf[GR_LEN] = {0}; + size_t len = 0; + size_t grlist_len = 0; + char gidbuf[11] = {0}; + int swap = 0; + char *ptr; + + if (name) { + key = name; + } else { + if (gid < 0 || gid > UINT32_MAX) { + rv = 0; + goto done; + } + key = itoa(gidbuf, gid); + } + + f = __nscd_query(req, key, groupbuf, sizeof groupbuf, &swap); + if (!f) { rv = errno; goto done; } + + if (!groupbuf[GRFOUND]) { rv = 0; goto cleanup_f; } + + if (!groupbuf[GRNAMELEN] || !groupbuf[GRPASSWDLEN]) { + rv = EIO; + goto cleanup_f; + } + + if (groupbuf[GRNAMELEN] > SIZE_MAX - groupbuf[GRPASSWDLEN]) { + rv = ENOMEM; + goto cleanup_f; + } + len = groupbuf[GRNAMELEN] + groupbuf[GRPASSWDLEN]; + + for (i = 0; i < groupbuf[GRMEMCNT]; i++) { + uint32_t name_len; + if (fread(&name_len, sizeof name_len, 1, f) < 1) { + rv = ferror(f) ? errno : EIO; + goto cleanup_f; + } + if (swap) { + name_len = bswap_32(name_len); + } + if (name_len > SIZE_MAX - grlist_len + || name_len > SIZE_MAX - len) { + rv = ENOMEM; + goto cleanup_f; + } + len += name_len; + grlist_len += name_len; + } + + if (len > *size || !*buf) { + char *tmp = realloc(*buf, len); + if (!tmp) { + rv = errno; + goto cleanup_f; + } + *buf = tmp; + *size = len; + } + + if (!fread(*buf, len, 1, f)) { + rv = ferror(f) ? errno : EIO; + goto cleanup_f; + } + + if (groupbuf[GRMEMCNT] + 1 > *nmem) { + if (groupbuf[GRMEMCNT] + 1 > SIZE_MAX/sizeof(char*)) { + rv = ENOMEM; + goto cleanup_f; + } + char **tmp = realloc(*mem, (groupbuf[GRMEMCNT]+1)*sizeof(char*)); + if (!tmp) { + rv = errno; + goto cleanup_f; + } + *mem = tmp; + *nmem = groupbuf[GRMEMCNT] + 1; + } + + if (groupbuf[GRMEMCNT]) { + mem[0][0] = *buf + groupbuf[GRNAMELEN] + groupbuf[GRPASSWDLEN]; + for (ptr = mem[0][0], i = 0; ptr != mem[0][0]+grlist_len; ptr++) + if (!*ptr) mem[0][++i] = ptr+1; + mem[0][i] = 0; + + if (i != groupbuf[GRMEMCNT]) { + rv = EIO; + goto cleanup_f; + } + } else { + mem[0][0] = 0; + } + + gr->gr_name = *buf; + gr->gr_passwd = gr->gr_name + groupbuf[GRNAMELEN]; + gr->gr_gid = groupbuf[GRGID]; + gr->gr_mem = *mem; + + if (gr->gr_passwd[-1] + || gr->gr_passwd[groupbuf[GRPASSWDLEN]-1]) { + rv = EIO; + goto cleanup_f; + } + + if (name && strcmp(name, gr->gr_name) + || !name && gid != gr->gr_gid) { + rv = EIO; + goto cleanup_f; + } + + *res = gr; + +cleanup_f: + fclose(f); + goto done; + } + +done: + pthread_setcancelstate(cs, 0); + if (rv) errno = rv; + return rv; +} diff --git a/system/lib/libc/musl/src/passwd/getgr_r.c b/system/lib/libc/musl/src/passwd/getgr_r.c index 3fe2e2b20b17c..7246e8a42d387 100644 --- a/system/lib/libc/musl/src/passwd/getgr_r.c +++ b/system/lib/libc/musl/src/passwd/getgr_r.c @@ -5,7 +5,6 @@ static int getgr_r(const char *name, gid_t gid, struct group *gr, char *buf, size_t size, struct group **res) { - FILE *f; char *line = 0; size_t len = 0; char **mem = 0; @@ -16,37 +15,24 @@ static int getgr_r(const char *name, gid_t gid, struct group *gr, char *buf, siz pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); - f = fopen("/etc/group", "rbe"); - if (!f) { - rv = errno; - goto done; + rv = __getgr_a(name, gid, gr, &line, &len, &mem, &nmem, res); + if (*res && size < len + (nmem+1)*sizeof(char *) + 32) { + *res = 0; + rv = ERANGE; } - - *res = 0; - while (__getgrent_a(f, gr, &line, &len, &mem, &nmem)) { - if (name && !strcmp(name, gr->gr_name) - || !name && gr->gr_gid == gid) { - if (size < len + (nmem+1)*sizeof(char *) + 32) { - rv = ERANGE; - break; - } - *res = gr; - buf += (16-(uintptr_t)buf)%16; - gr->gr_mem = (void *)buf; - buf += (nmem+1)*sizeof(char *); - memcpy(buf, line, len); - FIX(name); - FIX(passwd); - for (i=0; mem[i]; i++) - gr->gr_mem[i] = mem[i]-line+buf; - gr->gr_mem[i] = 0; - break; - } + if (*res) { + buf += (16-(uintptr_t)buf)%16; + gr->gr_mem = (void *)buf; + buf += (nmem+1)*sizeof(char *); + memcpy(buf, line, len); + FIX(name); + FIX(passwd); + for (i=0; mem[i]; i++) + gr->gr_mem[i] = mem[i]-line+buf; + gr->gr_mem[i] = 0; } free(mem); free(line); - fclose(f); -done: pthread_setcancelstate(cs, 0); return rv; } diff --git a/system/lib/libc/musl/src/passwd/getgrent.c b/system/lib/libc/musl/src/passwd/getgrent.c index 429a3e58a7aa9..835b9ab5a22a7 100644 --- a/system/lib/libc/musl/src/passwd/getgrent.c +++ b/system/lib/libc/musl/src/passwd/getgrent.c @@ -1,6 +1,8 @@ #include "pwf.h" static FILE *f; +static char *line, **mem; +static struct group gr; void setgrent() { @@ -12,34 +14,26 @@ weak_alias(setgrent, endgrent); struct group *getgrent() { - static char *line, **mem; - static struct group gr; + struct group *res; size_t size=0, nmem=0; if (!f) f = fopen("/etc/group", "rbe"); if (!f) return 0; - return __getgrent_a(f, &gr, &line, &size, &mem, &nmem); + __getgrent_a(f, &gr, &line, &size, &mem, &nmem, &res); + return res; } struct group *getgrgid(gid_t gid) { - struct group *gr; - int errno_saved; - setgrent(); - while ((gr=getgrent()) && gr->gr_gid != gid); - errno_saved = errno; - endgrent(); - errno = errno_saved; - return gr; + struct group *res; + size_t size=0, nmem=0; + __getgr_a(0, gid, &gr, &line, &size, &mem, &nmem, &res); + return res; } struct group *getgrnam(const char *name) { - struct group *gr; - int errno_saved; - setgrent(); - while ((gr=getgrent()) && strcmp(gr->gr_name, name)); - errno_saved = errno; - endgrent(); - errno = errno_saved; - return gr; + struct group *res; + size_t size=0, nmem=0; + __getgr_a(name, 0, &gr, &line, &size, &mem, &nmem, &res); + return res; } diff --git a/system/lib/libc/musl/src/passwd/getgrent_a.c b/system/lib/libc/musl/src/passwd/getgrent_a.c index 2cb8521532f81..7fc389d46332a 100644 --- a/system/lib/libc/musl/src/passwd/getgrent_a.c +++ b/system/lib/libc/musl/src/passwd/getgrent_a.c @@ -8,15 +8,17 @@ static unsigned atou(char **s) return x; } -struct group *__getgrent_a(FILE *f, struct group *gr, char **line, size_t *size, char ***mem, size_t *nmem) +int __getgrent_a(FILE *f, struct group *gr, char **line, size_t *size, char ***mem, size_t *nmem, struct group **res) { ssize_t l; char *s, *mems; size_t i; + int rv = 0; int cs; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); for (;;) { if ((l=getline(line, size, f)) < 0) { + rv = ferror(f) ? errno : 0; free(*line); *line = 0; gr = 0; @@ -43,9 +45,11 @@ struct group *__getgrent_a(FILE *f, struct group *gr, char **line, size_t *size, free(*mem); *mem = calloc(sizeof(char *), *nmem+1); if (!*mem) { + rv = errno; free(*line); *line = 0; - return 0; + gr = 0; + goto end; } if (*mems) { mem[0][0] = mems; @@ -58,5 +62,7 @@ struct group *__getgrent_a(FILE *f, struct group *gr, char **line, size_t *size, gr->gr_mem = *mem; end: pthread_setcancelstate(cs, 0); - return gr; + *res = gr; + if(rv) errno = rv; + return rv; } diff --git a/system/lib/libc/musl/src/passwd/getgrouplist.c b/system/lib/libc/musl/src/passwd/getgrouplist.c new file mode 100644 index 0000000000000..43e518245f8e6 --- /dev/null +++ b/system/lib/libc/musl/src/passwd/getgrouplist.c @@ -0,0 +1,80 @@ +#define _GNU_SOURCE +#include "pwf.h" +#include +#include +#include +#include +#include +#include +#include +#include "nscd.h" + +int getgrouplist(const char *user, gid_t gid, gid_t *groups, int *ngroups) +{ + int rv, nlim, ret = -1; + ssize_t i, n = 1; + struct group gr; + struct group *res; + FILE *f; + int swap = 0; + int32_t resp[INITGR_LEN]; + uint32_t *nscdbuf = 0; + char *buf = 0; + char **mem = 0; + size_t nmem = 0; + size_t size; + nlim = *ngroups; + if (nlim >= 1) *groups++ = gid; + + f = __nscd_query(GETINITGR, user, resp, sizeof resp, &swap); + if (!f) goto cleanup; + if (resp[INITGRFOUND]) { + nscdbuf = calloc(resp[INITGRNGRPS], sizeof(uint32_t)); + if (!nscdbuf) goto cleanup; + if (!fread(nscdbuf, sizeof(*nscdbuf)*resp[INITGRNGRPS], 1, f)) { + if (!ferror(f)) errno = EIO; + goto cleanup; + } + if (swap) { + for (i = 0; i < resp[INITGRNGRPS]; i++) + nscdbuf[i] = bswap_32(nscdbuf[i]); + } + } + fclose(f); + + f = fopen("/etc/group", "rbe"); + if (!f && errno != ENOENT && errno != ENOTDIR) + goto cleanup; + + if (f) { + while (!(rv = __getgrent_a(f, &gr, &buf, &size, &mem, &nmem, &res)) && res) { + if (nscdbuf) + for (i=0; i < resp[INITGRNGRPS]; i++) { + if (nscdbuf[i] == gr.gr_gid) nscdbuf[i] = gid; + } + for (i=0; gr.gr_mem[i] && strcmp(user, gr.gr_mem[i]); i++); + if (!gr.gr_mem[i]) continue; + if (++n <= nlim) *groups++ = gr.gr_gid; + } + if (rv) { + errno = rv; + goto cleanup; + } + } + if (nscdbuf) { + for(i=0; i < resp[INITGRNGRPS]; i++) { + if (nscdbuf[i] != gid) + if(++n <= nlim) *groups++ = nscdbuf[i]; + } + } + + ret = n > nlim ? -1 : n; + *ngroups = n; + +cleanup: + if (f) fclose(f); + free(nscdbuf); + free(buf); + free(mem); + return ret; +} diff --git a/system/lib/libc/musl/src/passwd/getpw_a.c b/system/lib/libc/musl/src/passwd/getpw_a.c new file mode 100644 index 0000000000000..15a70c0330c13 --- /dev/null +++ b/system/lib/libc/musl/src/passwd/getpw_a.c @@ -0,0 +1,142 @@ +#include +#include +#include +#include +#include "pwf.h" +#include "nscd.h" + +static char *itoa(char *p, uint32_t x) +{ + // number of digits in a uint32_t + NUL + p += 11; + *--p = 0; + do { + *--p = '0' + x % 10; + x /= 10; + } while (x); + return p; +} + +int __getpw_a(const char *name, uid_t uid, struct passwd *pw, char **buf, size_t *size, struct passwd **res) +{ + FILE *f; + int cs; + int rv = 0; + + *res = 0; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + + f = fopen("/etc/passwd", "rbe"); + if (!f) { + rv = errno; + goto done; + } + + while (!(rv = __getpwent_a(f, pw, buf, size, res)) && *res) { + if (name && !strcmp(name, (*res)->pw_name) + || !name && (*res)->pw_uid == uid) + break; + } + fclose(f); + + if (!*res && (rv == 0 || rv == ENOENT || rv == ENOTDIR)) { + int32_t req = name ? GETPWBYNAME : GETPWBYUID; + const char *key; + int32_t passwdbuf[PW_LEN] = {0}; + size_t len = 0; + char uidbuf[11] = {0}; + + if (name) { + key = name; + } else { + /* uid outside of this range can't be queried with the + * nscd interface, but might happen if uid_t ever + * happens to be a larger type (this is not true as of + * now) + */ + if(uid < 0 || uid > UINT32_MAX) { + rv = 0; + goto done; + } + key = itoa(uidbuf, uid); + } + + f = __nscd_query(req, key, passwdbuf, sizeof passwdbuf, (int[]){0}); + if (!f) { rv = errno; goto done; } + + if(!passwdbuf[PWFOUND]) { rv = 0; goto cleanup_f; } + + /* A zero length response from nscd is invalid. We ignore + * invalid responses and just report an error, rather than + * trying to do something with them. + */ + if (!passwdbuf[PWNAMELEN] || !passwdbuf[PWPASSWDLEN] + || !passwdbuf[PWGECOSLEN] || !passwdbuf[PWDIRLEN] + || !passwdbuf[PWSHELLLEN]) { + rv = EIO; + goto cleanup_f; + } + + if ((passwdbuf[PWNAMELEN]|passwdbuf[PWPASSWDLEN] + |passwdbuf[PWGECOSLEN]|passwdbuf[PWDIRLEN] + |passwdbuf[PWSHELLLEN]) >= SIZE_MAX/8) { + rv = ENOMEM; + goto cleanup_f; + } + + len = passwdbuf[PWNAMELEN] + passwdbuf[PWPASSWDLEN] + + passwdbuf[PWGECOSLEN] + passwdbuf[PWDIRLEN] + + passwdbuf[PWSHELLLEN]; + + if (len > *size || !*buf) { + char *tmp = realloc(*buf, len); + if (!tmp) { + rv = errno; + goto cleanup_f; + } + *buf = tmp; + *size = len; + } + + if (!fread(*buf, len, 1, f)) { + rv = ferror(f) ? errno : EIO; + goto cleanup_f; + } + + pw->pw_name = *buf; + pw->pw_passwd = pw->pw_name + passwdbuf[PWNAMELEN]; + pw->pw_gecos = pw->pw_passwd + passwdbuf[PWPASSWDLEN]; + pw->pw_dir = pw->pw_gecos + passwdbuf[PWGECOSLEN]; + pw->pw_shell = pw->pw_dir + passwdbuf[PWDIRLEN]; + pw->pw_uid = passwdbuf[PWUID]; + pw->pw_gid = passwdbuf[PWGID]; + + /* Don't assume that nscd made sure to null terminate strings. + * It's supposed to, but malicious nscd should be ignored + * rather than causing a crash. + */ + if (pw->pw_passwd[-1] || pw->pw_gecos[-1] || pw->pw_dir[-1] + || pw->pw_shell[passwdbuf[PWSHELLLEN]-1]) { + rv = EIO; + goto cleanup_f; + } + + if (name && strcmp(name, pw->pw_name) + || !name && uid != pw->pw_uid) { + rv = EIO; + goto cleanup_f; + } + + + *res = pw; +cleanup_f: + fclose(f); + goto done; + } + +done: + pthread_setcancelstate(cs, 0); + if (rv) errno = rv; + return rv; +} diff --git a/system/lib/libc/musl/src/passwd/getpw_r.c b/system/lib/libc/musl/src/passwd/getpw_r.c index 285525727dc74..e8cc811e4d898 100644 --- a/system/lib/libc/musl/src/passwd/getpw_r.c +++ b/system/lib/libc/musl/src/passwd/getpw_r.c @@ -5,7 +5,6 @@ static int getpw_r(const char *name, uid_t uid, struct passwd *pw, char *buf, size_t size, struct passwd **res) { - FILE *f; char *line = 0; size_t len = 0; int rv = 0; @@ -13,33 +12,20 @@ static int getpw_r(const char *name, uid_t uid, struct passwd *pw, char *buf, si pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); - f = fopen("/etc/passwd", "rbe"); - if (!f) { - rv = errno; - goto done; + rv = __getpw_a(name, uid, pw, &line, &len, res); + if (*res && size < len) { + *res = 0; + rv = ERANGE; } - - *res = 0; - while (__getpwent_a(f, pw, &line, &len)) { - if (name && !strcmp(name, pw->pw_name) - || !name && pw->pw_uid == uid) { - if (size < len) { - rv = ERANGE; - break; - } - *res = pw; - memcpy(buf, line, len); - FIX(name); - FIX(passwd); - FIX(gecos); - FIX(dir); - FIX(shell); - break; - } + if (*res) { + memcpy(buf, line, len); + FIX(name); + FIX(passwd); + FIX(gecos); + FIX(dir); + FIX(shell); } free(line); - fclose(f); -done: pthread_setcancelstate(cs, 0); return rv; } diff --git a/system/lib/libc/musl/src/passwd/getpwent.c b/system/lib/libc/musl/src/passwd/getpwent.c index c655135e254fd..f2bd516e57ba3 100644 --- a/system/lib/libc/musl/src/passwd/getpwent.c +++ b/system/lib/libc/musl/src/passwd/getpwent.c @@ -1,6 +1,9 @@ #include "pwf.h" static FILE *f; +static char *line; +static struct passwd pw; +static size_t size; void setpwent() { @@ -12,34 +15,23 @@ weak_alias(setpwent, endpwent); struct passwd *getpwent() { - static char *line; - static struct passwd pw; - size_t size=0; + struct passwd *res; if (!f) f = fopen("/etc/passwd", "rbe"); if (!f) return 0; - return __getpwent_a(f, &pw, &line, &size); + __getpwent_a(f, &pw, &line, &size, &res); + return res; } struct passwd *getpwuid(uid_t uid) { - struct passwd *pw; - int errno_saved; - setpwent(); - while ((pw=getpwent()) && pw->pw_uid != uid); - errno_saved = errno; - endpwent(); - errno = errno_saved; - return pw; + struct passwd *res; + __getpw_a(0, uid, &pw, &line, &size, &res); + return res; } struct passwd *getpwnam(const char *name) { - struct passwd *pw; - int errno_saved; - setpwent(); - while ((pw=getpwent()) && strcmp(pw->pw_name, name)); - errno_saved = errno; - endpwent(); - errno = errno_saved; - return pw; + struct passwd *res; + __getpw_a(name, 0, &pw, &line, &size, &res); + return res; } diff --git a/system/lib/libc/musl/src/passwd/getpwent_a.c b/system/lib/libc/musl/src/passwd/getpwent_a.c index 34842a07aaab2..d1b4b53ce2008 100644 --- a/system/lib/libc/musl/src/passwd/getpwent_a.c +++ b/system/lib/libc/musl/src/passwd/getpwent_a.c @@ -8,14 +8,16 @@ static unsigned atou(char **s) return x; } -struct passwd *__getpwent_a(FILE *f, struct passwd *pw, char **line, size_t *size) +int __getpwent_a(FILE *f, struct passwd *pw, char **line, size_t *size, struct passwd **res) { ssize_t l; char *s; + int rv = 0; int cs; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); for (;;) { if ((l=getline(line, size, f)) < 0) { + rv = ferror(f) ? errno : 0; free(*line); *line = 0; pw = 0; @@ -46,5 +48,7 @@ struct passwd *__getpwent_a(FILE *f, struct passwd *pw, char **line, size_t *siz break; } pthread_setcancelstate(cs, 0); - return pw; + *res = pw; + if (rv) errno = rv; + return rv; } diff --git a/system/lib/libc/musl/src/passwd/nscd.h b/system/lib/libc/musl/src/passwd/nscd.h new file mode 100644 index 0000000000000..9a53c3283338d --- /dev/null +++ b/system/lib/libc/musl/src/passwd/nscd.h @@ -0,0 +1,44 @@ +#ifndef NSCD_H +#define NSCD_H + +#include + +#define NSCDVERSION 2 +#define GETPWBYNAME 0 +#define GETPWBYUID 1 +#define GETGRBYNAME 2 +#define GETGRBYGID 3 +#define GETINITGR 15 + +#define REQVERSION 0 +#define REQTYPE 1 +#define REQKEYLEN 2 +#define REQ_LEN 3 + +#define PWVERSION 0 +#define PWFOUND 1 +#define PWNAMELEN 2 +#define PWPASSWDLEN 3 +#define PWUID 4 +#define PWGID 5 +#define PWGECOSLEN 6 +#define PWDIRLEN 7 +#define PWSHELLLEN 8 +#define PW_LEN 9 + +#define GRVERSION 0 +#define GRFOUND 1 +#define GRNAMELEN 2 +#define GRPASSWDLEN 3 +#define GRGID 4 +#define GRMEMCNT 5 +#define GR_LEN 6 + +#define INITGRVERSION 0 +#define INITGRFOUND 1 +#define INITGRNGRPS 2 +#define INITGR_LEN 3 + +FILE *__nscd_query(int32_t req, const char *key, int32_t *buf, size_t len, int *swap); + +#endif diff --git a/system/lib/libc/musl/src/passwd/nscd_query.c b/system/lib/libc/musl/src/passwd/nscd_query.c new file mode 100644 index 0000000000000..d38e371bcda39 --- /dev/null +++ b/system/lib/libc/musl/src/passwd/nscd_query.c @@ -0,0 +1,107 @@ +#include +#include +#include +#include +#include +#include +#include +#include "nscd.h" + +static const struct { + short sun_family; + char sun_path[21]; +} addr = { + AF_UNIX, + "/var/run/nscd/socket" +}; + +FILE *__nscd_query(int32_t req, const char *key, int32_t *buf, size_t len, int *swap) +{ + size_t i; + int fd; + FILE *f = 0; + int32_t req_buf[REQ_LEN] = { + NSCDVERSION, + req, + strnlen(key,LOGIN_NAME_MAX)+1 + }; + struct msghdr msg = { + .msg_iov = (struct iovec[]){ + {&req_buf, sizeof(req_buf)}, + {(char*)key, strlen(key)+1} + }, + .msg_iovlen = 2 + }; + int errno_save = errno; + + *swap = 0; +retry: + memset(buf, 0, len); + buf[0] = NSCDVERSION; + + fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (fd < 0) return NULL; + + if(!(f = fdopen(fd, "r"))) { + close(fd); + return 0; + } + + if (req_buf[2] > LOGIN_NAME_MAX) + return f; + + if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + /* If there isn't a running nscd we simulate a "not found" + * result and the caller is responsible for calling + * fclose on the (unconnected) socket. The value of + * errno must be left unchanged in this case. */ + if (errno == EACCES || errno == ECONNREFUSED || errno == ENOENT) { + errno = errno_save; + return f; + } + goto error; + } + + if (sendmsg(fd, &msg, MSG_NOSIGNAL) < 0) + goto error; + + if (!fread(buf, len, 1, f)) { + /* If the VERSION entry mismatches nscd will disconnect. The + * most likely cause is that the endianness mismatched. So, we + * byteswap and try once more. (if we already swapped, just + * fail out) + */ + if (ferror(f)) goto error; + if (!*swap) { + fclose(f); + for (i = 0; i < sizeof(req_buf)/sizeof(req_buf[0]); i++) { + req_buf[i] = bswap_32(req_buf[i]); + } + *swap = 1; + goto retry; + } else { + errno = EIO; + goto error; + } + } + + if (*swap) { + for (i = 0; i < len/sizeof(buf[0]); i++) { + buf[i] = bswap_32(buf[i]); + } + } + + /* The first entry in every nscd response is the version number. This + * really shouldn't happen, and is evidence of some form of malformed + * response. + */ + if(buf[0] != NSCDVERSION) { + errno = EIO; + goto error; + } + + return f; +error: + fclose(f); + return 0; +} diff --git a/system/lib/libc/musl/src/passwd/pwf.h b/system/lib/libc/musl/src/passwd/pwf.h index 2d813ada24a3d..fc63db21a2cd8 100644 --- a/system/lib/libc/musl/src/passwd/pwf.h +++ b/system/lib/libc/musl/src/passwd/pwf.h @@ -8,6 +8,8 @@ #include #include "libc.h" -struct passwd *__getpwent_a(FILE *f, struct passwd *pw, char **line, size_t *size); -struct group *__getgrent_a(FILE *f, struct group *gr, char **line, size_t *size, char ***mem, size_t *nmem); +int __getpwent_a(FILE *f, struct passwd *pw, char **line, size_t *size, struct passwd **res); +int __getpw_a(const char *name, uid_t uid, struct passwd *pw, char **buf, size_t *size, struct passwd **res); +int __getgrent_a(FILE *f, struct group *gr, char **line, size_t *size, char ***mem, size_t *nmem, struct group **res); +int __getgr_a(const char *name, gid_t gid, struct group *gr, char **buf, size_t *size, char ***mem, size_t *nmem, struct group **res); int __parsespent(char *s, struct spwd *sp); diff --git a/system/lib/libc/musl/src/prng/random.c b/system/lib/libc/musl/src/prng/random.c index e250e28e98919..7d557d700de02 100644 --- a/system/lib/libc/musl/src/prng/random.c +++ b/system/lib/libc/musl/src/prng/random.c @@ -22,7 +22,7 @@ static int n = 31; static int i = 3; static int j = 0; static uint32_t *x = init+1; -static int lock[2]; +static volatile int lock[2]; static uint32_t lcg31(uint32_t x) { return (1103515245*x + 12345) & 0x7fffffff; diff --git a/system/lib/libc/musl/src/process/execvp.c b/system/lib/libc/musl/src/process/execvp.c index 0a33e42db9a66..3a8bbe83295ab 100644 --- a/system/lib/libc/musl/src/process/execvp.c +++ b/system/lib/libc/musl/src/process/execvp.c @@ -3,6 +3,7 @@ #include #include #include +#include "libc.h" extern char **__environ; @@ -10,6 +11,7 @@ int __execvpe(const char *file, char *const argv[], char *const envp[]) { const char *p, *z, *path = getenv("PATH"); size_t l, k; + int seen_eacces = 0; errno = ENOENT; if (!*file) return -1; @@ -37,9 +39,11 @@ int __execvpe(const char *file, char *const argv[], char *const envp[]) b[z-p] = '/'; memcpy(b+(z-p)+(z>p), file, k+1); execve(b, argv, envp); - if (errno != ENOENT) return -1; + if (errno == EACCES) seen_eacces = 1; + else if (errno != ENOENT) return -1; if (!*z++) break; } + if (seen_eacces) errno = EACCES; return -1; } @@ -47,3 +51,5 @@ int execvp(const char *file, char *const argv[]) { return __execvpe(file, argv, __environ); } + +weak_alias(__execvpe, execvpe); diff --git a/system/lib/libc/musl/src/process/fork.c b/system/lib/libc/musl/src/process/fork.c index 1a82f4286bacd..b96f0024f4c03 100644 --- a/system/lib/libc/musl/src/process/fork.c +++ b/system/lib/libc/musl/src/process/fork.c @@ -1,5 +1,6 @@ #include #include +#include #include "syscall.h" #include "libc.h" #include "pthread_impl.h" @@ -16,13 +17,17 @@ pid_t fork(void) sigset_t set; __fork_handler(-1); __block_all_sigs(&set); +#ifdef SYS_fork ret = syscall(SYS_fork); - if (libc.main_thread && !ret) { +#else + ret = syscall(SYS_clone, SIGCHLD, 0); +#endif + if (!ret) { pthread_t self = __pthread_self(); - self->tid = self->pid = syscall(SYS_getpid); - memset(&self->robust_list, 0, sizeof self->robust_list); + self->tid = __syscall(SYS_gettid); + self->robust_list.off = 0; + self->robust_list.pending = 0; libc.threads_minus_1 = 0; - libc.main_thread = self; } __restore_sigs(&set); __fork_handler(!ret); diff --git a/system/lib/libc/musl/src/process/posix_spawn.c b/system/lib/libc/musl/src/process/posix_spawn.c index f675a13c37dbb..0bdf71cd8d043 100644 --- a/system/lib/libc/musl/src/process/posix_spawn.c +++ b/system/lib/libc/musl/src/process/posix_spawn.c @@ -22,6 +22,20 @@ struct args { void __get_handler_set(sigset_t *); +static int __sys_dup2(int old, int new) +{ +#ifdef SYS_dup2 + return __syscall(SYS_dup2, old, new); +#else + if (old==new) { + int r = __syscall(SYS_fcntl, old, F_GETFD); + return r<0 ? r : old; + } else { + return __syscall(SYS_dup3, old, new, 0); + } +#endif +} + static int child(void *args_vp) { int i, ret; @@ -63,9 +77,9 @@ static int child(void *args_vp) if ((ret=__syscall(SYS_setpgid, 0, attr->__pgrp))) goto fail; - /* Use syscalls directly because pthread state because the - * library functions attempt to do a multi-threaded synchronized - * id-change, which would trash the parent's state. */ + /* Use syscalls directly because the library functions attempt + * to do a multi-threaded synchronized id-change, which would + * trash the parent's state. */ if (attr->__flags & POSIX_SPAWN_RESETIDS) if ((ret=__syscall(SYS_setgid, __syscall(SYS_getgid))) || (ret=__syscall(SYS_setuid, __syscall(SYS_getuid))) ) @@ -88,19 +102,17 @@ static int child(void *args_vp) } switch(op->cmd) { case FDOP_CLOSE: - if ((ret=__syscall(SYS_close, op->fd))) - goto fail; + __syscall(SYS_close, op->fd); break; case FDOP_DUP2: - if ((ret=__syscall(SYS_dup2, op->srcfd, op->fd))<0) + if ((ret=__sys_dup2(op->srcfd, op->fd))<0) goto fail; break; case FDOP_OPEN: - fd = __syscall(SYS_open, op->path, - op->oflag | O_LARGEFILE, op->mode); + fd = __sys_open(op->path, op->oflag, op->mode); if ((ret=fd) < 0) goto fail; if (fd != op->fd) { - if ((ret=__syscall(SYS_dup2, fd, op->fd))<0) + if ((ret=__sys_dup2(fd, op->fd))<0) goto fail; __syscall(SYS_close, fd); } @@ -124,7 +136,7 @@ static int child(void *args_vp) fail: /* Since sizeof errno < PIPE_BUF, the write is atomic. */ ret = -ret; - if (ret) while (write(p, &ret, sizeof ret) < 0); + if (ret) while (__syscall(SYS_write, p, &ret, sizeof ret) < 0); _exit(127); } diff --git a/system/lib/libc/musl/src/process/vfork.c b/system/lib/libc/musl/src/process/vfork.c index fc4adb464f13c..ac954651b7016 100644 --- a/system/lib/libc/musl/src/process/vfork.c +++ b/system/lib/libc/musl/src/process/vfork.c @@ -1,12 +1,17 @@ #define _GNU_SOURCE #include +#include #include "syscall.h" #include "libc.h" pid_t __vfork(void) { /* vfork syscall cannot be made from C code */ +#ifdef SYS_fork return syscall(SYS_fork); +#else + return syscall(SYS_clone, SIGCHLD, 0); +#endif } weak_alias(__vfork, vfork); diff --git a/system/lib/libc/musl/src/regex/fnmatch.c b/system/lib/libc/musl/src/regex/fnmatch.c index 4df10a3c0675c..978fff884239b 100644 --- a/system/lib/libc/musl/src/regex/fnmatch.c +++ b/system/lib/libc/musl/src/regex/fnmatch.c @@ -18,6 +18,7 @@ #include #include #include +#include "locale_impl.h" #define END 0 #define UNMATCHABLE -2 @@ -97,7 +98,13 @@ static int pat_next(const char *pat, size_t m, size_t *step, int flags) return pat[0]; } -static int match_bracket(const char *p, int k) +static int casefold(int k) +{ + int c = towupper(k); + return c == k ? towlower(k) : c; +} + +static int match_bracket(const char *p, int k, int kfold) { wchar_t wc; int inv = 0; @@ -119,7 +126,10 @@ static int match_bracket(const char *p, int k) wchar_t wc2; int l = mbtowc(&wc2, p+1, 4); if (l < 0) return 0; - if (wc<=wc2 && (unsigned)k-wc <= wc2-wc) return !inv; + if (wc <= wc2) + if ((unsigned)k-wc <= wc2-wc || + (unsigned)kfold-wc <= wc2-wc) + return !inv; p += l-1; continue; } @@ -132,7 +142,9 @@ static int match_bracket(const char *p, int k) char buf[16]; memcpy(buf, p0, p-1-p0); buf[p-1-p0] = 0; - if (iswctype(k, wctype(buf))) return !inv; + if (iswctype(k, wctype(buf)) || + iswctype(kfold, wctype(buf))) + return !inv; } continue; } @@ -143,7 +155,7 @@ static int match_bracket(const char *p, int k) if (l < 0) return 0; p += l-1; } - if (wc==k) return !inv; + if (wc==k || wc==kfold) return !inv; } return inv; } @@ -153,7 +165,7 @@ static int fnmatch_internal(const char *pat, size_t m, const char *str, size_t n const char *p, *ptail, *endpat; const char *s, *stail, *endstr; size_t pinc, sinc, tailcnt=0; - int c, k; + int c, k, kfold; if (flags & FNM_PERIOD) { if (*str == '.' && *pat != '.') @@ -173,10 +185,11 @@ static int fnmatch_internal(const char *pat, size_t m, const char *str, size_t n return (c==END) ? 0 : FNM_NOMATCH; str += sinc; n -= sinc; + kfold = flags & FNM_CASEFOLD ? casefold(k) : k; if (c == BRACKET) { - if (!match_bracket(pat, k)) + if (!match_bracket(pat, k, kfold)) return FNM_NOMATCH; - } else if (c != QUESTION && k != c) { + } else if (c != QUESTION && k != c && kfold != c) { return FNM_NOMATCH; } pat+=pinc; @@ -217,7 +230,7 @@ static int fnmatch_internal(const char *pat, size_t m, const char *str, size_t n * On illegal sequences we may get it wrong, but in that case * we necessarily have a matching failure anyway. */ for (s=endstr; s>str && tailcnt; tailcnt--) { - if (s[-1] < 128U) s--; + if (s[-1] < 128U || MB_CUR_MAX==1) s--; else while ((unsigned char)*--s-0x80U<0x40 && s>str); } if (tailcnt) return FNM_NOMATCH; @@ -233,10 +246,11 @@ static int fnmatch_internal(const char *pat, size_t m, const char *str, size_t n break; } s += sinc; + kfold = flags & FNM_CASEFOLD ? casefold(k) : k; if (c == BRACKET) { - if (!match_bracket(p-pinc, k)) + if (!match_bracket(p-pinc, k, kfold)) return FNM_NOMATCH; - } else if (c != QUESTION && k != c) { + } else if (c != QUESTION && k != c && kfold != c) { return FNM_NOMATCH; } } @@ -261,10 +275,11 @@ static int fnmatch_internal(const char *pat, size_t m, const char *str, size_t n k = str_next(s, endstr-s, &sinc); if (!k) return FNM_NOMATCH; + kfold = flags & FNM_CASEFOLD ? casefold(k) : k; if (c == BRACKET) { - if (!match_bracket(p-pinc, k)) + if (!match_bracket(p-pinc, k, kfold)) break; - } else if (c != QUESTION && k != c) { + } else if (c != QUESTION && k != c && kfold != c) { break; } s += sinc; diff --git a/system/lib/libc/musl/src/regex/regcomp.c b/system/lib/libc/musl/src/regex/regcomp.c index 33213257b8098..65f2fd0bbba86 100644 --- a/system/lib/libc/musl/src/regex/regcomp.c +++ b/system/lib/libc/musl/src/regex/regcomp.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "tre.h" @@ -135,108 +136,88 @@ typedef struct { tre_ast_node_t *right; } tre_union_t; -static tre_ast_node_t * -tre_ast_new_node(tre_mem_t mem, tre_ast_type_t type, size_t size); - -static tre_ast_node_t * -tre_ast_new_literal(tre_mem_t mem, int code_min, int code_max, int position); - -static tre_ast_node_t * -tre_ast_new_iter(tre_mem_t mem, tre_ast_node_t *arg, int min, int max, - int minimal); - -static tre_ast_node_t * -tre_ast_new_union(tre_mem_t mem, tre_ast_node_t *left, tre_ast_node_t *right); - -static tre_ast_node_t * -tre_ast_new_catenation(tre_mem_t mem, tre_ast_node_t *left, - tre_ast_node_t *right); - static tre_ast_node_t * -tre_ast_new_node(tre_mem_t mem, tre_ast_type_t type, size_t size) +tre_ast_new_node(tre_mem_t mem, int type, void *obj) { - tre_ast_node_t *node; - - node = tre_mem_calloc(mem, sizeof(*node)); - if (!node) - return NULL; - node->obj = tre_mem_calloc(mem, size); - if (!node->obj) - return NULL; - node->type = type; - node->nullable = -1; - node->submatch_id = -1; - - return node; + tre_ast_node_t *node = tre_mem_calloc(mem, sizeof *node); + if (!node || !obj) + return 0; + node->obj = obj; + node->type = type; + node->nullable = -1; + node->submatch_id = -1; + return node; } static tre_ast_node_t * tre_ast_new_literal(tre_mem_t mem, int code_min, int code_max, int position) { - tre_ast_node_t *node; - tre_literal_t *lit; - - node = tre_ast_new_node(mem, LITERAL, sizeof(tre_literal_t)); - if (!node) - return NULL; - lit = node->obj; - lit->code_min = code_min; - lit->code_max = code_max; - lit->position = position; - - return node; + tre_ast_node_t *node; + tre_literal_t *lit; + + lit = tre_mem_calloc(mem, sizeof *lit); + node = tre_ast_new_node(mem, LITERAL, lit); + if (!node) + return 0; + lit->code_min = code_min; + lit->code_max = code_max; + lit->position = position; + return node; } static tre_ast_node_t * -tre_ast_new_iter(tre_mem_t mem, tre_ast_node_t *arg, int min, int max, - int minimal) +tre_ast_new_iter(tre_mem_t mem, tre_ast_node_t *arg, int min, int max, int minimal) { - tre_ast_node_t *node; - tre_iteration_t *iter; - - node = tre_ast_new_node(mem, ITERATION, sizeof(tre_iteration_t)); - if (!node) - return NULL; - iter = node->obj; - iter->arg = arg; - iter->min = min; - iter->max = max; - iter->minimal = minimal; - node->num_submatches = arg->num_submatches; - - return node; + tre_ast_node_t *node; + tre_iteration_t *iter; + + iter = tre_mem_calloc(mem, sizeof *iter); + node = tre_ast_new_node(mem, ITERATION, iter); + if (!node) + return 0; + iter->arg = arg; + iter->min = min; + iter->max = max; + iter->minimal = minimal; + node->num_submatches = arg->num_submatches; + return node; } static tre_ast_node_t * tre_ast_new_union(tre_mem_t mem, tre_ast_node_t *left, tre_ast_node_t *right) { - tre_ast_node_t *node; - - node = tre_ast_new_node(mem, UNION, sizeof(tre_union_t)); - if (node == NULL) - return NULL; - ((tre_union_t *)node->obj)->left = left; - ((tre_union_t *)node->obj)->right = right; - node->num_submatches = left->num_submatches + right->num_submatches; - - return node; + tre_ast_node_t *node; + tre_union_t *un; + + if (!left) + return right; + un = tre_mem_calloc(mem, sizeof *un); + node = tre_ast_new_node(mem, UNION, un); + if (!node || !right) + return 0; + un->left = left; + un->right = right; + node->num_submatches = left->num_submatches + right->num_submatches; + return node; } static tre_ast_node_t * -tre_ast_new_catenation(tre_mem_t mem, tre_ast_node_t *left, - tre_ast_node_t *right) +tre_ast_new_catenation(tre_mem_t mem, tre_ast_node_t *left, tre_ast_node_t *right) { - tre_ast_node_t *node; - - node = tre_ast_new_node(mem, CATENATION, sizeof(tre_catenation_t)); - if (node == NULL) - return NULL; - ((tre_catenation_t *)node->obj)->left = left; - ((tre_catenation_t *)node->obj)->right = right; - node->num_submatches = left->num_submatches + right->num_submatches; - - return node; + tre_ast_node_t *node; + tre_catenation_t *cat; + + if (!left) + return right; + cat = tre_mem_calloc(mem, sizeof *cat); + node = tre_ast_new_node(mem, CATENATION, cat); + if (!node) + return 0; + cat->left = left; + cat->right = right; + node->num_submatches = left->num_submatches + right->num_submatches; + return node; } @@ -412,1074 +393,678 @@ define_popf(voidptr, void *) /* Parse context. */ typedef struct { - /* Memory allocator. The AST is allocated using this. */ - tre_mem_t mem; - /* Stack used for keeping track of regexp syntax. */ - tre_stack_t *stack; - /* The parse result. */ - tre_ast_node_t *result; - /* The regexp to parse and its length. */ - const char *re; - /* The first character of the entire regexp. */ - const char *re_start; - /* Current submatch ID. */ - int submatch_id; - /* Current position (number of literal). */ - int position; - /* The highest back reference or -1 if none seen so far. */ - int max_backref; - /* This flag is set if the regexp uses approximate matching. */ - int have_approx; - /* Compilation flags. */ - int cflags; - /* If this flag is set the top-level submatch is not captured. */ - int nofirstsub; + /* Memory allocator. The AST is allocated using this. */ + tre_mem_t mem; + /* Stack used for keeping track of regexp syntax. */ + tre_stack_t *stack; + /* The parsed node after a parse function returns. */ + tre_ast_node_t *n; + /* Position in the regexp pattern after a parse function returns. */ + const char *s; + /* The first character of the regexp. */ + const char *re; + /* Current submatch ID. */ + int submatch_id; + /* Current position (number of literal). */ + int position; + /* The highest back reference or -1 if none seen so far. */ + int max_backref; + /* Compilation flags. */ + int cflags; } tre_parse_ctx_t; -/* Parses a wide character regexp pattern into a syntax tree. This parser - handles both syntaxes (BRE and ERE), including the TRE extensions. */ -static reg_errcode_t -tre_parse(tre_parse_ctx_t *ctx); - - -/* - This parser is just a simple recursive descent parser for POSIX.2 - regexps. The parser supports both the obsolete default syntax and - the "extended" syntax, and some nonstandard extensions. -*/ - -/* Characters with special meanings in regexp syntax. */ -#define CHAR_PIPE '|' -#define CHAR_LPAREN '(' -#define CHAR_RPAREN ')' -#define CHAR_LBRACE '{' -#define CHAR_RBRACE '}' -#define CHAR_LBRACKET '[' -#define CHAR_RBRACKET ']' -#define CHAR_MINUS '-' -#define CHAR_STAR '*' -#define CHAR_QUESTIONMARK '?' -#define CHAR_PLUS '+' -#define CHAR_PERIOD '.' -#define CHAR_COLON ':' -#define CHAR_EQUAL '=' -#define CHAR_COMMA ',' -#define CHAR_CARET '^' -#define CHAR_DOLLAR '$' -#define CHAR_BACKSLASH '\\' -#define CHAR_HASH '#' -#define CHAR_TILDE '~' - - /* Some macros for expanding \w, \s, etc. */ -static const struct tre_macro_struct { - const char c; - const char *expansion; -} tre_macros[] = - { {'t', "\t"}, {'n', "\n"}, {'r', "\r"}, - {'f', "\f"}, {'a', "\a"}, {'e', "\033"}, - {'w', "[[:alnum:]_]"}, {'W', "[^[:alnum:]_]"}, {'s', "[[:space:]]"}, - {'S', "[^[:space:]]"}, {'d', "[[:digit:]]"}, {'D', "[^[:digit:]]"}, - { 0, NULL } - }; - +static const struct { + char c; + const char *expansion; +} tre_macros[] = { + {'t', "\t"}, {'n', "\n"}, {'r', "\r"}, + {'f', "\f"}, {'a', "\a"}, {'e', "\033"}, + {'w', "[[:alnum:]_]"}, {'W', "[^[:alnum:]_]"}, {'s', "[[:space:]]"}, + {'S', "[^[:space:]]"}, {'d', "[[:digit:]]"}, {'D', "[^[:digit:]]"}, + { 0, 0 } +}; /* Expands a macro delimited by `regex' and `regex_end' to `buf', which must have at least `len' items. Sets buf[0] to zero if the there is no match in `tre_macros'. */ -static const char * -tre_expand_macro(const char *regex) +static const char *tre_expand_macro(const char *s) { - int i; - - if (!*regex) - return 0; - - for (i = 0; tre_macros[i].expansion && tre_macros[i].c != *regex; i++); - return tre_macros[i].expansion; + int i; + for (i = 0; tre_macros[i].c && tre_macros[i].c != *s; i++); + return tre_macros[i].expansion; } -static reg_errcode_t -tre_new_item(tre_mem_t mem, int min, int max, int *i, int *max_i, - tre_ast_node_t ***items) +static int +tre_compare_lit(const void *a, const void *b) { - reg_errcode_t status; - tre_ast_node_t **array = *items; - /* Allocate more space if necessary. */ - if (*i >= *max_i) - { - tre_ast_node_t **new_items; - /* If the array is already 1024 items large, give up -- there's - probably an error in the regexp (e.g. not a '\0' terminated - string and missing ']') */ - if (*max_i > 1024) - return REG_ESPACE; - *max_i *= 2; - new_items = xrealloc(array, sizeof(*array) * *max_i); - if (new_items == NULL) - return REG_ESPACE; - *items = array = new_items; - } - array[*i] = tre_ast_new_literal(mem, min, max, -1); - status = array[*i] == NULL ? REG_ESPACE : REG_OK; - (*i)++; - return status; + const tre_literal_t *const *la = a; + const tre_literal_t *const *lb = b; + /* assumes the range of valid code_min is < INT_MAX */ + return la[0]->code_min - lb[0]->code_min; } +struct literals { + tre_mem_t mem; + tre_literal_t **a; + int len; + int cap; +}; -static int -tre_compare_items(const void *a, const void *b) +static tre_literal_t *tre_new_lit(struct literals *p) { - const tre_ast_node_t *node_a = *(tre_ast_node_t * const *)a; - const tre_ast_node_t *node_b = *(tre_ast_node_t * const *)b; - tre_literal_t *l_a = node_a->obj, *l_b = node_b->obj; - int a_min = l_a->code_min, b_min = l_b->code_min; - - if (a_min < b_min) - return -1; - else if (a_min > b_min) - return 1; - else - return 0; + tre_literal_t **a; + if (p->len >= p->cap) { + if (p->cap >= 1<<15) + return 0; + p->cap *= 2; + a = xrealloc(p->a, p->cap * sizeof *p->a); + if (!a) + return 0; + p->a = a; + } + a = p->a + p->len++; + *a = tre_mem_calloc(p->mem, sizeof **a); + return *a; } -/* Maximum number of character classes that can occur in a negated bracket - expression. */ -#define MAX_NEG_CLASSES 64 - -/* Maximum length of character class names. */ -#define MAX_CLASS_NAME - -static reg_errcode_t -tre_parse_bracket_items(tre_parse_ctx_t *ctx, int negate, - tre_ctype_t neg_classes[], int *num_neg_classes, - tre_ast_node_t ***items, int *num_items, - int *items_size) +static int add_icase_literals(struct literals *ls, int min, int max) { - const char *re = ctx->re; - reg_errcode_t status = REG_OK; - tre_ctype_t class = (tre_ctype_t)0; - int i = *num_items; - int max_i = *items_size; - int skip; - - /* Build an array of the items in the bracket expression. */ - while (status == REG_OK) - { - skip = 0; - if (!*re) - { - status = REG_EBRACK; - } - else if (*re == CHAR_RBRACKET && re > ctx->re) - { - re++; - break; + tre_literal_t *lit; + int b, e, c; + for (c=min; c<=max; ) { + /* assumes islower(c) and isupper(c) are exclusive + and toupper(c)!=c if islower(c). + multiple opposite case characters are not supported */ + if (tre_islower(c)) { + b = e = tre_toupper(c); + for (c++, e++; c<=max; c++, e++) + if (tre_toupper(c) != e) break; + } else if (tre_isupper(c)) { + b = e = tre_tolower(c); + for (c++, e++; c<=max; c++, e++) + if (tre_tolower(c) != e) break; + } else { + c++; + continue; + } + lit = tre_new_lit(ls); + if (!lit) + return -1; + lit->code_min = b; + lit->code_max = e-1; + lit->position = -1; } - else - { - tre_cint_t min = 0, max = 0; - wchar_t wc; - int clen = mbtowc(&wc, re, -1); + return 0; +} - if (clen<0) clen=1, wc=WEOF; - class = (tre_ctype_t)0; - if (*(re + clen) == CHAR_MINUS && *(re + clen + 1) != CHAR_RBRACKET) - { - min = wc; - re += clen+1; - clen = mbtowc(&wc, re, -1); - if (clen<0) clen=1, wc=WEOF; - max = wc; - re += clen; - /* XXX - Should use collation order instead of encoding values - in character ranges. */ - if (min > max) - status = REG_ERANGE; - } - else if (*re == CHAR_LBRACKET && *(re + 1) == CHAR_PERIOD) - status = REG_ECOLLATE; - else if (*re == CHAR_LBRACKET && *(re + 1) == CHAR_EQUAL) - status = REG_ECOLLATE; - else if (*re == CHAR_LBRACKET && *(re + 1) == CHAR_COLON) - { - char tmp_str[64]; - const char *endptr = re + 2; - int len; - while (*endptr && *endptr != CHAR_COLON) - endptr++; - if (*endptr) - { - len = MIN(endptr - re - 2, 63); - strncpy(tmp_str, re + 2, len); - tmp_str[len] = '\0'; - class = tre_ctype(tmp_str); - if (!class) - status = REG_ECTYPE; - re = endptr + 2; - } - else - status = REG_ECTYPE; - min = 0; - max = TRE_CHAR_MAX; - } - else - { - if (*re == CHAR_MINUS && *(re + 1) != CHAR_RBRACKET - && ctx->re != re) - /* Two ranges are not allowed to share and endpoint. */ - status = REG_ERANGE; - min = max = wc; - re += clen; - } +/* Maximum number of character classes in a negated bracket expression. */ +#define MAX_NEG_CLASSES 64 - if (status != REG_OK) - break; +struct neg { + int negate; + int len; + tre_ctype_t a[MAX_NEG_CLASSES]; +}; - if (class && negate) - if (*num_neg_classes >= MAX_NEG_CLASSES) - status = REG_ESPACE; - else - neg_classes[(*num_neg_classes)++] = class; - else if (!skip) - { - status = tre_new_item(ctx->mem, min, max, &i, &max_i, items); - if (status != REG_OK) - break; - ((tre_literal_t*)((*items)[i-1])->obj)->class = class; - } +// TODO: parse bracket into a set of non-overlapping [lo,hi] ranges - /* Add opposite-case counterpoints if REG_ICASE is present. - This is broken if there are more than two "same" characters. */ - if (ctx->cflags & REG_ICASE && !class && status == REG_OK && !skip) - { - tre_cint_t cmin, ccurr; +/* +bracket grammar: +Bracket = '[' List ']' | '[^' List ']' +List = Term | List Term +Term = Char | Range | Chclass | Eqclass +Range = Char '-' Char | Char '-' '-' +Char = Coll | coll_single +Meta = ']' | '-' +Coll = '[.' coll_single '.]' | '[.' coll_multi '.]' | '[.' Meta '.]' +Eqclass = '[=' coll_single '=]' | '[=' coll_multi '=]' +Chclass = '[:' class ':]' + +coll_single is a single char collating element but it can be + '-' only at the beginning or end of a List and + ']' only at the beginning of a List and + '^' anywhere except after the openning '[' +*/ - while (min <= max) - { - if (tre_islower(min)) - { - cmin = ccurr = tre_toupper(min++); - while (tre_islower(min) && tre_toupper(min) == ccurr + 1 - && min <= max) - ccurr = tre_toupper(min++); - status = tre_new_item(ctx->mem, cmin, ccurr, - &i, &max_i, items); - } - else if (tre_isupper(min)) - { - cmin = ccurr = tre_tolower(min++); - while (tre_isupper(min) && tre_tolower(min) == ccurr + 1 - && min <= max) - ccurr = tre_tolower(min++); - status = tre_new_item(ctx->mem, cmin, ccurr, - &i, &max_i, items); - } - else min++; - if (status != REG_OK) - break; +static reg_errcode_t parse_bracket_terms(tre_parse_ctx_t *ctx, const char *s, struct literals *ls, struct neg *neg) +{ + const char *start = s; + tre_ctype_t class; + int min, max; + wchar_t wc; + int len; + + for (;;) { + class = 0; + len = mbtowc(&wc, s, -1); + if (len <= 0) + return *s ? REG_BADPAT : REG_EBRACK; + if (*s == ']' && s != start) { + ctx->s = s+1; + return REG_OK; + } + if (*s == '-' && s != start && s[1] != ']' && + /* extension: [a-z--@] is accepted as [a-z]|[--@] */ + (s[1] != '-' || s[2] == ']')) + return REG_ERANGE; + if (*s == '[' && (s[1] == '.' || s[1] == '=')) + /* collating symbols and equivalence classes are not supported */ + return REG_ECOLLATE; + if (*s == '[' && s[1] == ':') { + char tmp[CHARCLASS_NAME_MAX+1]; + s += 2; + for (len=0; len < CHARCLASS_NAME_MAX && s[len]; len++) { + if (s[len] == ':') { + memcpy(tmp, s, len); + tmp[len] = 0; + class = tre_ctype(tmp); + break; + } + } + if (!class || s[len+1] != ']') + return REG_ECTYPE; + min = 0; + max = TRE_CHAR_MAX; + s += len+2; + } else { + min = max = wc; + s += len; + if (*s == '-' && s[1] != ']') { + s++; + len = mbtowc(&wc, s, -1); + max = wc; + /* XXX - Should use collation order instead of + encoding values in character ranges. */ + if (len <= 0 || min > max) + return REG_ERANGE; + s += len; + } + } + + if (class && neg->negate) { + if (neg->len >= MAX_NEG_CLASSES) + return REG_ESPACE; + neg->a[neg->len++] = class; + } else { + tre_literal_t *lit = tre_new_lit(ls); + if (!lit) + return REG_ESPACE; + lit->code_min = min; + lit->code_max = max; + lit->class = class; + lit->position = -1; + + /* Add opposite-case codepoints if REG_ICASE is present. + It seems that POSIX requires that bracket negation + should happen before case-folding, but most practical + implementations do it the other way around. Changing + the order would need efficient representation of + case-fold ranges and bracket range sets even with + simple patterns so this is ok for now. */ + if (ctx->cflags & REG_ICASE && !class) + if (add_icase_literals(ls, min, max)) + return REG_ESPACE; } - if (status != REG_OK) - break; - } } - } - *num_items = i; - *items_size = max_i; - ctx->re = re; - return status; } -static reg_errcode_t -tre_parse_bracket(tre_parse_ctx_t *ctx, tre_ast_node_t **result) +static reg_errcode_t parse_bracket(tre_parse_ctx_t *ctx, const char *s) { - tre_ast_node_t *node = NULL; - int negate = 0; - reg_errcode_t status = REG_OK; - tre_ast_node_t **items, *u, *n; - int i = 0, j, max_i = 32, curr_max, curr_min; - tre_ctype_t neg_classes[MAX_NEG_CLASSES]; - int num_neg_classes = 0; - - /* Start off with an array of `max_i' elements. */ - items = xmalloc(sizeof(*items) * max_i); - if (items == NULL) - return REG_ESPACE; - - if (*ctx->re == CHAR_CARET) - { - negate = 1; - ctx->re++; - } - - status = tre_parse_bracket_items(ctx, negate, neg_classes, &num_neg_classes, - &items, &i, &max_i); - - if (status != REG_OK) - goto parse_bracket_done; - - /* Sort the array if we need to negate it. */ - if (negate) - qsort(items, (unsigned)i, sizeof(*items), tre_compare_items); - - curr_max = curr_min = 0; - /* Build a union of the items in the array, negated if necessary. */ - for (j = 0; j < i && status == REG_OK; j++) - { - int min, max; - tre_literal_t *l = items[j]->obj; - min = l->code_min; - max = l->code_max; - - if (negate) - { - if (min < curr_max) - { - /* Overlap. */ - curr_max = MAX(max + 1, curr_max); - l = NULL; - } - else - { - /* No overlap. */ - curr_max = min - 1; - if (curr_max >= curr_min) - { - l->code_min = curr_min; - l->code_max = curr_max; + int i, max, min, negmax, negmin; + tre_ast_node_t *node = 0, *n; + tre_ctype_t *nc = 0; + tre_literal_t *lit; + struct literals ls; + struct neg neg; + reg_errcode_t err; + + ls.mem = ctx->mem; + ls.len = 0; + ls.cap = 32; + ls.a = xmalloc(ls.cap * sizeof *ls.a); + if (!ls.a) + return REG_ESPACE; + neg.len = 0; + neg.negate = *s == '^'; + if (neg.negate) + s++; + + err = parse_bracket_terms(ctx, s, &ls, &neg); + if (err != REG_OK) + goto parse_bracket_done; + + if (neg.negate) { + /* Sort the array if we need to negate it. */ + qsort(ls.a, ls.len, sizeof *ls.a, tre_compare_lit); + /* extra lit for the last negated range */ + lit = tre_new_lit(&ls); + if (!lit) { + err = REG_ESPACE; + goto parse_bracket_done; } - else - { - l = NULL; + lit->code_min = TRE_CHAR_MAX+1; + lit->code_max = TRE_CHAR_MAX+1; + lit->position = -1; + /* negated classes */ + if (neg.len) { + nc = tre_mem_alloc(ctx->mem, (neg.len+1)*sizeof *neg.a); + if (!nc) { + err = REG_ESPACE; + goto parse_bracket_done; + } + memcpy(nc, neg.a, neg.len*sizeof *neg.a); + nc[neg.len] = 0; } - curr_min = curr_max = max + 1; - } } - if (l != NULL) - { - int k; - l->position = ctx->position; - if (num_neg_classes > 0) - { - l->neg_classes = tre_mem_alloc(ctx->mem, - (sizeof(*l->neg_classes) - * (num_neg_classes + 1))); - if (l->neg_classes == NULL) - { - status = REG_ESPACE; - break; + /* Build a union of the items in the array, negated if necessary. */ + negmax = negmin = 0; + for (i = 0; i < ls.len; i++) { + lit = ls.a[i]; + min = lit->code_min; + max = lit->code_max; + if (neg.negate) { + if (min <= negmin) { + /* Overlap. */ + negmin = MAX(max + 1, negmin); + continue; + } + negmax = min - 1; + lit->code_min = negmin; + lit->code_max = negmax; + negmin = max + 1; } - for (k = 0; k < num_neg_classes; k++) - l->neg_classes[k] = neg_classes[k]; - l->neg_classes[k] = (tre_ctype_t)0; - } - else - l->neg_classes = NULL; - if (node == NULL) - node = items[j]; - else - { - u = tre_ast_new_union(ctx->mem, node, items[j]); - if (u == NULL) - status = REG_ESPACE; - node = u; - } - } - } - - if (status != REG_OK) - goto parse_bracket_done; - - if (negate) - { - int k; - n = tre_ast_new_literal(ctx->mem, curr_min, TRE_CHAR_MAX, ctx->position); - if (n == NULL) - status = REG_ESPACE; - else - { - tre_literal_t *l = n->obj; - if (num_neg_classes > 0) - { - l->neg_classes = tre_mem_alloc(ctx->mem, - (sizeof(*l->neg_classes) - * (num_neg_classes + 1))); - if (l->neg_classes == NULL) - { - status = REG_ESPACE; - goto parse_bracket_done; + lit->position = ctx->position; + lit->neg_classes = nc; + n = tre_ast_new_node(ctx->mem, LITERAL, lit); + node = tre_ast_new_union(ctx->mem, node, n); + if (!node) { + err = REG_ESPACE; + break; } - for (k = 0; k < num_neg_classes; k++) - l->neg_classes[k] = neg_classes[k]; - l->neg_classes[k] = (tre_ctype_t)0; - } - else - l->neg_classes = NULL; - if (node == NULL) - node = n; - else - { - u = tre_ast_new_union(ctx->mem, node, n); - if (u == NULL) - status = REG_ESPACE; - node = u; - } } - } - - if (status != REG_OK) - goto parse_bracket_done; -#ifdef TRE_DEBUG - tre_ast_print(node); -#endif /* TRE_DEBUG */ - - parse_bracket_done: - xfree(items); - ctx->position++; - *result = node; - return status; +parse_bracket_done: + xfree(ls.a); + ctx->position++; + ctx->n = node; + return err; } - -/* Parses a positive decimal integer. Returns -1 if the string does not - contain a valid number. */ -static int -tre_parse_int(const char **regex) +static const char *parse_dup_count(const char *s, int *n) { - int num = -1; - const char *r = *regex; - while (*r-'0'<10U) - { - if (num < 0) - num = 0; - num = num * 10 + *r - '0'; - r++; - } - *regex = r; - return num; + *n = -1; + if (!isdigit(*s)) + return s; + *n = 0; + for (;;) { + *n = 10 * *n + (*s - '0'); + s++; + if (!isdigit(*s) || *n > RE_DUP_MAX) + break; + } + return s; } - -static reg_errcode_t -tre_parse_bound(tre_parse_ctx_t *ctx, tre_ast_node_t **result) +static const char *parse_dup(const char *s, int ere, int *pmin, int *pmax) { - int min, max; - const char *r = ctx->re; - int minimal = 0; - - /* Parse number (minimum repetition count). */ - min = -1; - if (*r >= '0' && *r <= '9') { - min = tre_parse_int(&r); - } - - /* Parse comma and second number (maximum repetition count). */ - max = min; - if (*r == CHAR_COMMA) - { - r++; - max = tre_parse_int(&r); - } - - /* Check that the repeat counts are sane. */ - if ((max >= 0 && min > max) || max > RE_DUP_MAX) - return REG_BADBR; - - /* Missing }. */ - if (!*r) - return REG_EBRACE; - - /* Empty contents of {}. */ - if (r == ctx->re) - return REG_BADBR; - - /* Parse the ending '}' or '\}'.*/ - if (ctx->cflags & REG_EXTENDED) - { - if (*r != CHAR_RBRACE) - return REG_BADBR; - r++; - } - else - { - if (*r != CHAR_BACKSLASH || *(r + 1) != CHAR_RBRACE) - return REG_BADBR; - r += 2; - } - - /* Create the AST node(s). */ - if (min == 0 && max == 0) - { - *result = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1); - if (*result == NULL) - return REG_ESPACE; - } - else - { - if (min < 0 && max < 0) - /* Only approximate parameters set, no repetitions. */ - min = max = 1; - - *result = tre_ast_new_iter(ctx->mem, *result, min, max, minimal); - if (!*result) - return REG_ESPACE; - } - - ctx->re = r; - return REG_OK; + int min, max; + + s = parse_dup_count(s, &min); + if (*s == ',') + s = parse_dup_count(s+1, &max); + else + max = min; + + if ( + (max < min && max >= 0) || + max > RE_DUP_MAX || + min > RE_DUP_MAX || + min < 0 || + (!ere && *s++ != '\\') || + *s++ != '}' + ) + return 0; + *pmin = min; + *pmax = max; + return s; } -typedef enum { - PARSE_RE = 0, - PARSE_ATOM, - PARSE_MARK_FOR_SUBMATCH, - PARSE_BRANCH, - PARSE_PIECE, - PARSE_CATENATION, - PARSE_POST_CATENATION, - PARSE_UNION, - PARSE_POST_UNION, - PARSE_POSTFIX, - PARSE_RESTORE_CFLAGS -} tre_parse_re_stack_symbol_t; - - -static reg_errcode_t -tre_parse(tre_parse_ctx_t *ctx) +static int hexval(unsigned c) { - tre_ast_node_t *result = NULL; - tre_parse_re_stack_symbol_t symbol; - reg_errcode_t status = REG_OK; - tre_stack_t *stack = ctx->stack; - int bottom = tre_stack_num_objects(stack); - int depth = 0; - wchar_t wc; - int clen; - - if (!ctx->nofirstsub) - { - STACK_PUSH(stack, int, ctx->submatch_id); - STACK_PUSH(stack, int, PARSE_MARK_FOR_SUBMATCH); - ctx->submatch_id++; - } - STACK_PUSH(stack, int, PARSE_RE); - ctx->re_start = ctx->re; - - - /* The following is basically just a recursive descent parser. I use - an explicit stack instead of recursive functions mostly because of - two reasons: compatibility with systems which have an overflowable - call stack, and efficiency (both in lines of code and speed). */ - while (tre_stack_num_objects(stack) > bottom && status == REG_OK) - { - if (status != REG_OK) - break; - symbol = tre_stack_pop_int(stack); - switch (symbol) - { - case PARSE_RE: - /* Parse a full regexp. A regexp is one or more branches, - separated by the union operator `|'. */ - if (ctx->cflags & REG_EXTENDED) - STACK_PUSHX(stack, int, PARSE_UNION); - STACK_PUSHX(stack, int, PARSE_BRANCH); - break; - - case PARSE_BRANCH: - /* Parse a branch. A branch is one or more pieces, concatenated. - A piece is an atom possibly followed by a postfix operator. */ - STACK_PUSHX(stack, int, PARSE_CATENATION); - STACK_PUSHX(stack, int, PARSE_PIECE); - break; - - case PARSE_PIECE: - /* Parse a piece. A piece is an atom possibly followed by one - or more postfix operators. */ - STACK_PUSHX(stack, int, PARSE_POSTFIX); - STACK_PUSHX(stack, int, PARSE_ATOM); - break; - - case PARSE_CATENATION: - /* If the expression has not ended, parse another piece. */ - { - tre_char_t c; - if (!*ctx->re) - break; - c = *ctx->re; - if (ctx->cflags & REG_EXTENDED && c == CHAR_PIPE) - break; - if ((ctx->cflags & REG_EXTENDED - && c == CHAR_RPAREN && depth > 0) - || (!(ctx->cflags & REG_EXTENDED) - && (c == CHAR_BACKSLASH - && *(ctx->re + 1) == CHAR_RPAREN))) - { - if (!(ctx->cflags & REG_EXTENDED) && depth == 0) - status = REG_EPAREN; - depth--; - if (!(ctx->cflags & REG_EXTENDED)) - ctx->re += 2; - break; - } - - { - /* Default case, left associative concatenation. */ - STACK_PUSHX(stack, int, PARSE_CATENATION); - STACK_PUSHX(stack, voidptr, result); - STACK_PUSHX(stack, int, PARSE_POST_CATENATION); - STACK_PUSHX(stack, int, PARSE_PIECE); - } - break; - } - - case PARSE_POST_CATENATION: - { - tre_ast_node_t *tree = tre_stack_pop_voidptr(stack); - tre_ast_node_t *tmp_node; - tmp_node = tre_ast_new_catenation(ctx->mem, tree, result); - if (!tmp_node) - return REG_ESPACE; - result = tmp_node; - break; - } - - case PARSE_UNION: - switch (*ctx->re) - { - case CHAR_PIPE: - STACK_PUSHX(stack, int, PARSE_UNION); - STACK_PUSHX(stack, voidptr, result); - STACK_PUSHX(stack, int, PARSE_POST_UNION); - STACK_PUSHX(stack, int, PARSE_BRANCH); - ctx->re++; - break; - - case CHAR_RPAREN: - ctx->re++; - break; - - default: - break; - } - break; - - case PARSE_POST_UNION: - { - tre_ast_node_t *tmp_node; - tre_ast_node_t *tree = tre_stack_pop_voidptr(stack); - tmp_node = tre_ast_new_union(ctx->mem, tree, result); - if (!tmp_node) - return REG_ESPACE; - result = tmp_node; - break; - } - - case PARSE_POSTFIX: - /* Parse postfix operators. */ - switch (*ctx->re) - { - case CHAR_PLUS: - case CHAR_QUESTIONMARK: - if (!(ctx->cflags & REG_EXTENDED)) - break; - /*FALLTHROUGH*/ - case CHAR_STAR: - { - tre_ast_node_t *tmp_node; - int minimal = 0; - int rep_min = 0; - int rep_max = -1; - - if (*ctx->re == CHAR_PLUS) - rep_min = 1; - if (*ctx->re == CHAR_QUESTIONMARK) - rep_max = 1; - - ctx->re++; - tmp_node = tre_ast_new_iter(ctx->mem, result, rep_min, rep_max, - minimal); - if (tmp_node == NULL) - return REG_ESPACE; - result = tmp_node; - STACK_PUSHX(stack, int, PARSE_POSTFIX); - } - break; - - case CHAR_BACKSLASH: - /* "\{" is special without REG_EXTENDED */ - if (!(ctx->cflags & REG_EXTENDED) - && *(ctx->re + 1) == CHAR_LBRACE) - { - ctx->re++; - goto parse_brace; - } - else - break; - - case CHAR_LBRACE: - /* "{" is literal without REG_EXTENDED */ - if (!(ctx->cflags & REG_EXTENDED)) - break; - - parse_brace: - ctx->re++; + if (c-'0'<10) return c-'0'; + c |= 32; + if (c-'a'<6) return c-'a'+10; + return -1; +} - status = tre_parse_bound(ctx, &result); - if (status != REG_OK) - return status; - STACK_PUSHX(stack, int, PARSE_POSTFIX); - break; - } - break; +static reg_errcode_t marksub(tre_parse_ctx_t *ctx, tre_ast_node_t *node, int subid) +{ + if (node->submatch_id >= 0) { + tre_ast_node_t *n = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1); + if (!n) + return REG_ESPACE; + n = tre_ast_new_catenation(ctx->mem, n, node); + if (!n) + return REG_ESPACE; + n->num_submatches = node->num_submatches; + node = n; + } + node->submatch_id = subid; + node->num_submatches++; + ctx->n = node; + return REG_OK; +} - case PARSE_ATOM: - /* Parse an atom. An atom is a regular expression enclosed in `()', - an empty set of `()', a bracket expression, `.', `^', `$', - a `\' followed by a character, or a single character. */ +/* +BRE grammar: +Regex = Branch | '^' | '$' | '^$' | '^' Branch | Branch '$' | '^' Branch '$' +Branch = Atom | Branch Atom +Atom = char | quoted_char | '.' | Bracket | Atom Dup | '\(' Branch '\)' | back_ref +Dup = '*' | '\{' Count '\}' | '\{' Count ',\}' | '\{' Count ',' Count '\}' - switch (*ctx->re) - { - case CHAR_LPAREN: /* parenthesized subexpression */ +(leading ^ and trailing $ in a sub expr may be an anchor or literal as well) - if (ctx->cflags & REG_EXTENDED) - { - lparen: - depth++; - { - ctx->re++; - /* First parse a whole RE, then mark the resulting tree - for submatching. */ - STACK_PUSHX(stack, int, ctx->submatch_id); - STACK_PUSHX(stack, int, PARSE_MARK_FOR_SUBMATCH); - STACK_PUSHX(stack, int, PARSE_RE); - ctx->submatch_id++; - } - } - else - goto parse_literal; - break; +ERE grammar: +Regex = Branch | Regex '|' Branch +Branch = Atom | Branch Atom +Atom = char | quoted_char | '.' | Bracket | Atom Dup | '(' Regex ')' | '^' | '$' +Dup = '*' | '+' | '?' | '{' Count '}' | '{' Count ',}' | '{' Count ',' Count '}' - case CHAR_LBRACKET: /* bracket expression */ - ctx->re++; - status = tre_parse_bracket(ctx, &result); - if (status != REG_OK) - return status; - break; +(a*+?, ^*, $+, \X, {, (|a) are unspecified) +*/ - case CHAR_BACKSLASH: - /* If this is "\(" or "\)" chew off the backslash and - try again. */ - if (!(ctx->cflags & REG_EXTENDED) && *(ctx->re + 1) == CHAR_LPAREN) - { - ctx->re++; - goto lparen; - } - if (!(ctx->cflags & REG_EXTENDED) && *(ctx->re + 1) == CHAR_RPAREN) - { - goto empty_atom; +static reg_errcode_t parse_atom(tre_parse_ctx_t *ctx, const char *s) +{ + int len, ere = ctx->cflags & REG_EXTENDED; + const char *p; + tre_ast_node_t *node; + wchar_t wc; + switch (*s) { + case '[': + return parse_bracket(ctx, s+1); + case '\\': + p = tre_expand_macro(s+1); + if (p) { + /* assume \X expansion is a single atom */ + reg_errcode_t err = parse_atom(ctx, p); + ctx->s = s+2; + return err; } - - /* If a macro is used, parse the expanded macro recursively. */ - { - const char *buf = tre_expand_macro(ctx->re + 1); - if (buf) - { - tre_parse_ctx_t subctx; - memcpy(&subctx, ctx, sizeof(subctx)); - subctx.re = buf; - subctx.nofirstsub = 1; - status = tre_parse(&subctx); - if (status != REG_OK) - return status; - ctx->re += 2; - ctx->position = subctx.position; - result = subctx.result; - break; - } - } - - if (!ctx->re[1]) - /* Trailing backslash. */ - return REG_EESCAPE; - - ctx->re++; - switch (*ctx->re) - { + /* extensions: \b, \B, \<, \>, \xHH \x{HHHH} */ + switch (*++s) { + case 0: + return REG_EESCAPE; case 'b': - result = tre_ast_new_literal(ctx->mem, ASSERTION, - ASSERT_AT_WB, -1); - ctx->re++; - break; + node = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_WB, -1); + break; case 'B': - result = tre_ast_new_literal(ctx->mem, ASSERTION, - ASSERT_AT_WB_NEG, -1); - ctx->re++; - break; + node = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_WB_NEG, -1); + break; case '<': - result = tre_ast_new_literal(ctx->mem, ASSERTION, - ASSERT_AT_BOW, -1); - ctx->re++; - break; + node = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_BOW, -1); + break; case '>': - result = tre_ast_new_literal(ctx->mem, ASSERTION, - ASSERT_AT_EOW, -1); - ctx->re++; - break; + node = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_EOW, -1); + break; case 'x': - ctx->re++; - if (ctx->re[0] != CHAR_LBRACE) - { - /* 8 bit hex char. */ - char tmp[3] = {0, 0, 0}; - long val; - - if (tre_isxdigit(ctx->re[0])) - { - tmp[0] = (char)ctx->re[0]; - ctx->re++; + s++; + int i, v = 0, c; + len = 2; + if (*s == '{') { + len = 8; + s++; } - if (tre_isxdigit(ctx->re[0])) - { - tmp[1] = (char)ctx->re[0]; - ctx->re++; + for (i=0; imem, (int)val, - (int)val, ctx->position); - ctx->position++; - break; - } - else if (*ctx->re) - { - /* Wide char. */ - char tmp[32]; - long val; - int i = 0; - ctx->re++; - while (*ctx->re && i < sizeof tmp) - { - if (ctx->re[0] == CHAR_RBRACE) - break; - if (tre_isxdigit(ctx->re[0])) - { - tmp[i] = (char)ctx->re[0]; - i++; - ctx->re++; - continue; - } - return REG_EBRACE; + s += i; + if (len == 8) { + if (*s != '}') + return REG_EBRACE; + s++; } - ctx->re++; - tmp[i] = 0; - val = strtol(tmp, NULL, 16); - result = tre_ast_new_literal(ctx->mem, (int)val, (int)val, - ctx->position); - ctx->position++; - break; - } - /*FALLTHROUGH*/ - + node = tre_ast_new_literal(ctx->mem, v, v, ctx->position++); + s--; + break; + case '{': + case '+': + case '?': + /* extension: treat \+, \? as repetitions in BRE */ + /* reject repetitions after empty expression in BRE */ + if (!ere) + return REG_BADRPT; + case '|': + /* extension: treat \| as alternation in BRE */ + if (!ere) { + node = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1); + s--; + goto end; + } + /* fallthrough */ default: - if (tre_isdigit(*ctx->re)) - { - /* Back reference. */ - int val = *ctx->re - '0'; - result = tre_ast_new_literal(ctx->mem, BACKREF, val, - ctx->position); - if (result == NULL) - return REG_ESPACE; - ctx->position++; - ctx->max_backref = MAX(val, ctx->max_backref); - ctx->re++; - } - else - { - /* Escaped character. */ - goto parse_literal; - } - break; - } - if (result == NULL) - return REG_ESPACE; - break; - - case CHAR_PERIOD: /* the any-symbol */ - if (ctx->cflags & REG_NEWLINE) - { - tre_ast_node_t *tmp1; - tre_ast_node_t *tmp2; - tmp1 = tre_ast_new_literal(ctx->mem, 0, '\n' - 1, - ctx->position); - if (!tmp1) - return REG_ESPACE; - tmp2 = tre_ast_new_literal(ctx->mem, '\n' + 1, TRE_CHAR_MAX, - ctx->position + 1); - if (!tmp2) - return REG_ESPACE; - result = tre_ast_new_union(ctx->mem, tmp1, tmp2); - if (!result) - return REG_ESPACE; - ctx->position += 2; - } - else - { - result = tre_ast_new_literal(ctx->mem, 0, TRE_CHAR_MAX, - ctx->position); - if (!result) - return REG_ESPACE; - ctx->position++; + if (!ere && (unsigned)*s-'1' < 9) { + /* back reference */ + int val = *s - '0'; + node = tre_ast_new_literal(ctx->mem, BACKREF, val, ctx->position++); + ctx->max_backref = MAX(val, ctx->max_backref); + } else { + /* extension: accept unknown escaped char + as a literal */ + goto parse_literal; + } } - ctx->re++; - break; - - case CHAR_CARET: /* beginning of line assertion */ - /* '^' has a special meaning everywhere in EREs, and at - beginning of BRE. */ - if (ctx->cflags & REG_EXTENDED - || ctx->re == ctx->re_start) - { - if (!(ctx->cflags & REG_EXTENDED)) - STACK_PUSHX(stack, int, PARSE_CATENATION); - result = tre_ast_new_literal(ctx->mem, ASSERTION, - ASSERT_AT_BOL, -1); - if (result == NULL) - return REG_ESPACE; - ctx->re++; + s++; + break; + case '.': + if (ctx->cflags & REG_NEWLINE) { + tre_ast_node_t *tmp1, *tmp2; + tmp1 = tre_ast_new_literal(ctx->mem, 0, '\n'-1, ctx->position++); + tmp2 = tre_ast_new_literal(ctx->mem, '\n'+1, TRE_CHAR_MAX, ctx->position++); + if (tmp1 && tmp2) + node = tre_ast_new_union(ctx->mem, tmp1, tmp2); + else + node = 0; + } else { + node = tre_ast_new_literal(ctx->mem, 0, TRE_CHAR_MAX, ctx->position++); } - else - goto parse_literal; - break; - - case CHAR_DOLLAR: /* end of line assertion. */ - /* '$' is special everywhere in EREs, and in the end of the - string in BREs. */ - if (ctx->cflags & REG_EXTENDED - || !*(ctx->re + 1)) - { - result = tre_ast_new_literal(ctx->mem, ASSERTION, - ASSERT_AT_EOL, -1); - if (result == NULL) - return REG_ESPACE; - ctx->re++; + s++; + break; + case '^': + /* '^' has a special meaning everywhere in EREs, and at beginning of BRE. */ + if (!ere && s != ctx->re) + goto parse_literal; + node = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_BOL, -1); + s++; + break; + case '$': + /* '$' is special everywhere in EREs, and in the end of the string in BREs. */ + if (!ere && s[1]) + goto parse_literal; + node = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_EOL, -1); + s++; + break; + case '*': + case '{': + case '+': + case '?': + /* reject repetitions after empty expression in ERE */ + if (ere) + return REG_BADRPT; + case '|': + if (!ere) + goto parse_literal; + case 0: + node = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1); + break; + default: +parse_literal: + len = mbtowc(&wc, s, -1); + if (len < 0) + return REG_BADPAT; + if (ctx->cflags & REG_ICASE && (tre_isupper(wc) || tre_islower(wc))) { + tre_ast_node_t *tmp1, *tmp2; + /* multiple opposite case characters are not supported */ + tmp1 = tre_ast_new_literal(ctx->mem, tre_toupper(wc), tre_toupper(wc), ctx->position); + tmp2 = tre_ast_new_literal(ctx->mem, tre_tolower(wc), tre_tolower(wc), ctx->position); + if (tmp1 && tmp2) + node = tre_ast_new_union(ctx->mem, tmp1, tmp2); + else + node = 0; + } else { + node = tre_ast_new_literal(ctx->mem, wc, wc, ctx->position); } - else - goto parse_literal; - break; - - case CHAR_RPAREN: - if (!depth) - goto parse_literal; - case CHAR_STAR: - case CHAR_PIPE: - case CHAR_LBRACE: - case CHAR_PLUS: - case CHAR_QUESTIONMARK: - if (!(ctx->cflags & REG_EXTENDED)) - goto parse_literal; - - case 0: - empty_atom: - result = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1); - if (!result) + ctx->position++; + s += len; + break; + } +end: + if (!node) return REG_ESPACE; - break; + ctx->n = node; + ctx->s = s; + return REG_OK; +} - default: - parse_literal: +#define PUSHPTR(err, s, v) do { \ + if ((err = tre_stack_push_voidptr(s, v)) != REG_OK) \ + return err; \ +} while(0) - clen = mbtowc(&wc, ctx->re, -1); - if (clen<0) clen=1, wc=WEOF; +#define PUSHINT(err, s, v) do { \ + if ((err = tre_stack_push_int(s, v)) != REG_OK) \ + return err; \ +} while(0) - /* Note that we can't use an tre_isalpha() test here, since there - may be characters which are alphabetic but neither upper or - lower case. */ - if (ctx->cflags & REG_ICASE - && (tre_isupper(wc) || tre_islower(wc))) - { - tre_ast_node_t *tmp1; - tre_ast_node_t *tmp2; - - /* XXX - Can there be more than one opposite-case - counterpoints for some character in some locale? Or - more than two characters which all should be regarded - the same character if case is ignored? If yes, there - does not seem to be a portable way to detect it. I guess - that at least for multi-character collating elements there - could be several opposite-case counterpoints, but they - cannot be supported portably anyway. */ - tmp1 = tre_ast_new_literal(ctx->mem, tre_toupper(wc), - tre_toupper(wc), - ctx->position); - if (!tmp1) - return REG_ESPACE; - tmp2 = tre_ast_new_literal(ctx->mem, tre_tolower(wc), - tre_tolower(wc), - ctx->position); - if (!tmp2) - return REG_ESPACE; - result = tre_ast_new_union(ctx->mem, tmp1, tmp2); - if (!result) - return REG_ESPACE; +static reg_errcode_t tre_parse(tre_parse_ctx_t *ctx) +{ + tre_ast_node_t *nbranch=0, *nunion=0; + int ere = ctx->cflags & REG_EXTENDED; + const char *s = ctx->re; + int subid = 0; + int depth = 0; + reg_errcode_t err; + tre_stack_t *stack = ctx->stack; + + PUSHINT(err, stack, subid++); + for (;;) { + if ((!ere && *s == '\\' && s[1] == '(') || + (ere && *s == '(')) { + PUSHPTR(err, stack, nunion); + PUSHPTR(err, stack, nbranch); + PUSHINT(err, stack, subid++); + s++; + if (!ere) + s++; + depth++; + nbranch = nunion = 0; + continue; } - else - { - result = tre_ast_new_literal(ctx->mem, wc, wc, - ctx->position); - if (!result) - return REG_ESPACE; + if ((!ere && *s == '\\' && s[1] == ')') || + (ere && *s == ')' && depth)) { + ctx->n = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1); + if (!ctx->n) + return REG_ESPACE; + } else { + err = parse_atom(ctx, s); + if (err != REG_OK) + return err; + s = ctx->s; } - ctx->position++; - ctx->re += clen; - break; - } - break; - case PARSE_MARK_FOR_SUBMATCH: - { - int submatch_id = tre_stack_pop_int(stack); + parse_iter: + for (;;) { + int min, max; - if (result->submatch_id >= 0) - { - tre_ast_node_t *n, *tmp_node; - n = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1); - if (n == NULL) - return REG_ESPACE; - tmp_node = tre_ast_new_catenation(ctx->mem, n, result); - if (tmp_node == NULL) - return REG_ESPACE; - tmp_node->num_submatches = result->num_submatches; - result = tmp_node; - } - result->submatch_id = submatch_id; - result->num_submatches++; - break; - } - - case PARSE_RESTORE_CFLAGS: - ctx->cflags = tre_stack_pop_int(stack); - break; + if (*s!='\\' && *s!='*') { + if (!ere) + break; + if (*s!='+' && *s!='?' && *s!='{') + break; + } + if (*s=='\\' && ere) + break; + /* extension: treat \+, \? as repetitions in BRE */ + if (*s=='\\' && s[1]!='+' && s[1]!='?' && s[1]!='{') + break; + if (*s=='\\') + s++; + + /* handle ^* at the start of a complete BRE. */ + if (!ere && s==ctx->re+1 && s[-1]=='^') + break; + + /* extension: multiple consecutive *+?{,} is unspecified, + but (a+)+ has to be supported so accepting a++ makes + sense, note however that the RE_DUP_MAX limit can be + circumvented: (a{255}){255} uses a lot of memory.. */ + if (*s=='{') { + s = parse_dup(s+1, ere, &min, &max); + if (!s) + return REG_BADBR; + } else { + min=0; + max=-1; + if (*s == '+') + min = 1; + if (*s == '?') + max = 1; + s++; + } + if (max == 0) + ctx->n = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1); + else + ctx->n = tre_ast_new_iter(ctx->mem, ctx->n, min, max, 0); + if (!ctx->n) + return REG_ESPACE; + } - default: - assert(0); - break; + nbranch = tre_ast_new_catenation(ctx->mem, nbranch, ctx->n); + if ((ere && *s == '|') || + (ere && *s == ')' && depth) || + (!ere && *s == '\\' && s[1] == ')') || + /* extension: treat \| as alternation in BRE */ + (!ere && *s == '\\' && s[1] == '|') || + !*s) { + /* extension: empty branch is unspecified (), (|a), (a|) + here they are not rejected but match on empty string */ + int c = *s; + nunion = tre_ast_new_union(ctx->mem, nunion, nbranch); + nbranch = 0; + + if (c == '\\' && s[1] == '|') { + s+=2; + } else if (c == '|') { + s++; + } else { + if (c == '\\') { + if (!depth) return REG_EPAREN; + s+=2; + } else if (c == ')') + s++; + depth--; + err = marksub(ctx, nunion, tre_stack_pop_int(stack)); + if (err != REG_OK) + return err; + if (!c && depth<0) { + ctx->submatch_id = subid; + return REG_OK; + } + if (!c || depth<0) + return REG_EPAREN; + nbranch = tre_stack_pop_voidptr(stack); + nunion = tre_stack_pop_voidptr(stack); + goto parse_iter; + } + } } - } - - /* Check for missing closing parentheses. */ - if (depth > 0) - return REG_EPAREN; - - if (status == REG_OK) - ctx->result = result; - - return status; } - /*********************************************************************** from tre-compile.c ***********************************************************************/ @@ -1521,6 +1106,7 @@ tre_add_tag_left(tre_mem_t mem, tre_ast_node_t *node, int tag_id) c->right->firstpos = NULL; c->right->lastpos = NULL; c->right->num_tags = 0; + c->right->num_submatches = 0; node->obj = c; node->type = CATENATION; return REG_OK; @@ -1551,6 +1137,7 @@ tre_add_tag_right(tre_mem_t mem, tre_ast_node_t *node, int tag_id) c->left->firstpos = NULL; c->left->lastpos = NULL; c->left->num_tags = 0; + c->left->num_submatches = 0; node->obj = c; node->type = CATENATION; return REG_OK; @@ -2023,7 +1610,8 @@ tre_add_tags(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *tree, { status = tre_add_tag_right(mem, left, tag_left); tnfa->tag_directions[tag_left] = TRE_TAG_MAXIMIZE; - status = tre_add_tag_right(mem, right, tag_right); + if (status == REG_OK) + status = tre_add_tag_right(mem, right, tag_right); tnfa->tag_directions[tag_right] = TRE_TAG_MAXIMIZE; } num_tags += 2; @@ -3102,7 +2690,7 @@ regcomp(regex_t *restrict preg, const char *restrict regex, int cflags) /* Allocate a stack used throughout the compilation process for various purposes. */ - stack = tre_stack_new(512, 10240, 128); + stack = tre_stack_new(512, 1024000, 128); if (!stack) return REG_ESPACE; /* Allocate a fast memory allocator. */ @@ -3124,12 +2712,7 @@ regcomp(regex_t *restrict preg, const char *restrict regex, int cflags) if (errcode != REG_OK) ERROR_EXIT(errcode); preg->re_nsub = parse_ctx.submatch_id - 1; - tree = parse_ctx.result; - - /* Back references and approximate matching cannot currently be used - in the same regexp. */ - if (parse_ctx.max_backref >= 0 && parse_ctx.have_approx) - ERROR_EXIT(REG_BADPAT); + tree = parse_ctx.n; #ifdef TRE_DEBUG tre_ast_print(tree); @@ -3144,7 +2727,7 @@ regcomp(regex_t *restrict preg, const char *restrict regex, int cflags) if (tnfa == NULL) ERROR_EXIT(REG_ESPACE); tnfa->have_backrefs = parse_ctx.max_backref >= 0; - tnfa->have_approx = parse_ctx.have_approx; + tnfa->have_approx = 0; tnfa->num_submatches = parse_ctx.submatch_id; /* Set up tags for submatch addressing. If REG_NOSUB is set and the diff --git a/system/lib/libc/musl/src/regex/regerror.c b/system/lib/libc/musl/src/regex/regerror.c index df4afa4f22a67..5b347cc73c735 100644 --- a/system/lib/libc/musl/src/regex/regerror.c +++ b/system/lib/libc/musl/src/regex/regerror.c @@ -1,6 +1,7 @@ #include #include #include +#include "locale_impl.h" /* Error message strings for error codes listed in `regex.h'. This list needs to be in sync with the codes listed there, naturally. */ @@ -31,5 +32,6 @@ size_t regerror(int e, const regex_t *restrict preg, char *restrict buf, size_t const char *s; for (s=messages; e && *s; e--, s+=strlen(s)+1); if (!*s) s++; + s = LCTRANS_CUR(s); return 1+snprintf(buf, size, "%s", s); } diff --git a/system/lib/libc/musl/src/sched/sched_getcpu.c b/system/lib/libc/musl/src/sched/sched_getcpu.c new file mode 100644 index 0000000000000..e08cfdf13921b --- /dev/null +++ b/system/lib/libc/musl/src/sched/sched_getcpu.c @@ -0,0 +1,44 @@ +#define _GNU_SOURCE +#include +#include +#include "syscall.h" +#include "atomic.h" + +#ifdef VDSO_GETCPU_SYM + +void *__vdsosym(const char *, const char *); + +static void *volatile vdso_func; + +typedef long (*getcpu_f)(unsigned *, unsigned *, void *); + +static long getcpu_init(unsigned *cpu, unsigned *node, void *unused) +{ + void *p = __vdsosym(VDSO_GETCPU_VER, VDSO_GETCPU_SYM); + getcpu_f f = (getcpu_f)p; + a_cas_p(&vdso_func, (void *)getcpu_init, p); + return f ? f(cpu, node, unused) : -ENOSYS; +} + +static void *volatile vdso_func = (void *)getcpu_init; + +#endif + +int sched_getcpu(void) +{ + int r; + unsigned cpu; + +#ifdef VDSO_GETCPU_SYM + getcpu_f f = (getcpu_f)vdso_func; + if (f) { + r = f(&cpu, 0, 0); + if (!r) return cpu; + if (r != -ENOSYS) return __syscall_ret(r); + } +#endif + + r = __syscall(SYS_getcpu, &cpu, 0, 0); + if (!r) return cpu; + return __syscall_ret(r); +} diff --git a/system/lib/libc/musl/src/search/hsearch.c b/system/lib/libc/musl/src/search/hsearch.c index 6fe5ced004e1e..5c8965114bdcb 100644 --- a/system/lib/libc/musl/src/search/hsearch.c +++ b/system/lib/libc/musl/src/search/hsearch.c @@ -1,6 +1,8 @@ +#define _GNU_SOURCE #include #include #include +#include "libc.h" /* open addressing hash table with 2^n table size @@ -14,14 +16,17 @@ with the posix api items cannot be iterated and length cannot be queried #define MINSIZE 8 #define MAXSIZE ((size_t)-1/2 + 1) -struct elem { - ENTRY item; - size_t hash; +struct __tab { + ENTRY *entries; + size_t mask; + size_t used; }; -static size_t mask; -static size_t used; -static struct elem *tab; +static struct hsearch_data htab; + +int __hcreate_r(size_t, struct hsearch_data *); +void __hdestroy_r(struct hsearch_data *); +int __hsearch_r(ENTRY, ACTION, ENTRY **, struct hsearch_data *); static size_t keyhash(char *k) { @@ -33,30 +38,30 @@ static size_t keyhash(char *k) return h; } -static int resize(size_t nel) +static int resize(size_t nel, struct hsearch_data *htab) { size_t newsize; size_t i, j; - struct elem *e, *newe; - struct elem *oldtab = tab; - struct elem *oldend = tab + mask + 1; + ENTRY *e, *newe; + ENTRY *oldtab = htab->__tab->entries; + ENTRY *oldend = htab->__tab->entries + htab->__tab->mask + 1; if (nel > MAXSIZE) nel = MAXSIZE; for (newsize = MINSIZE; newsize < nel; newsize *= 2); - tab = calloc(newsize, sizeof *tab); - if (!tab) { - tab = oldtab; + htab->__tab->entries = calloc(newsize, sizeof *htab->__tab->entries); + if (!htab->__tab->entries) { + htab->__tab->entries = oldtab; return 0; } - mask = newsize - 1; + htab->__tab->mask = newsize - 1; if (!oldtab) return 1; for (e = oldtab; e < oldend; e++) - if (e->item.key) { - for (i=e->hash,j=1; ; i+=j++) { - newe = tab + (i & mask); - if (!newe->item.key) + if (e->key) { + for (i=keyhash(e->key),j=1; ; i+=j++) { + newe = htab->__tab->entries + (i & htab->__tab->mask); + if (!newe->key) break; } *newe = *e; @@ -67,52 +72,83 @@ static int resize(size_t nel) int hcreate(size_t nel) { - mask = 0; - used = 0; - tab = 0; - return resize(nel); + return __hcreate_r(nel, &htab); } void hdestroy(void) { - free(tab); - tab = 0; - mask = 0; - used = 0; + __hdestroy_r(&htab); } -static struct elem *lookup(char *key, size_t hash) +static ENTRY *lookup(char *key, size_t hash, struct hsearch_data *htab) { size_t i, j; - struct elem *e; + ENTRY *e; for (i=hash,j=1; ; i+=j++) { - e = tab + (i & mask); - if (!e->item.key || - (e->hash==hash && strcmp(e->item.key, key)==0)) + e = htab->__tab->entries + (i & htab->__tab->mask); + if (!e->key || strcmp(e->key, key) == 0) break; } return e; } ENTRY *hsearch(ENTRY item, ACTION action) +{ + ENTRY *e; + + __hsearch_r(item, action, &e, &htab); + return e; +} + +int __hcreate_r(size_t nel, struct hsearch_data *htab) +{ + int r; + + htab->__tab = calloc(1, sizeof *htab->__tab); + if (!htab->__tab) + return 0; + r = resize(nel, htab); + if (r == 0) { + free(htab->__tab); + htab->__tab = 0; + } + return r; +} +weak_alias(__hcreate_r, hcreate_r); + +void __hdestroy_r(struct hsearch_data *htab) +{ + if (htab->__tab) free(htab->__tab->entries); + free(htab->__tab); + htab->__tab = 0; +} +weak_alias(__hdestroy_r, hdestroy_r); + +int __hsearch_r(ENTRY item, ACTION action, ENTRY **retval, struct hsearch_data *htab) { size_t hash = keyhash(item.key); - struct elem *e = lookup(item.key, hash); + ENTRY *e = lookup(item.key, hash, htab); - if (e->item.key) - return &e->item; - if (action == FIND) + if (e->key) { + *retval = e; + return 1; + } + if (action == FIND) { + *retval = 0; return 0; - e->item = item; - e->hash = hash; - if (++used > mask - mask/4) { - if (!resize(2*used)) { - used--; - e->item.key = 0; + } + *e = item; + if (++htab->__tab->used > htab->__tab->mask - htab->__tab->mask/4) { + if (!resize(2*htab->__tab->used, htab)) { + htab->__tab->used--; + e->key = 0; + *retval = 0; return 0; } - e = lookup(item.key, hash); + e = lookup(item.key, hash, htab); } - return &e->item; + *retval = e; + return 1; } +weak_alias(__hsearch_r, hsearch_r); diff --git a/system/lib/libc/musl/src/search/tsearch_avl.c b/system/lib/libc/musl/src/search/tsearch_avl.c index 86200928ef6c6..57194c843dcaa 100644 --- a/system/lib/libc/musl/src/search/tsearch_avl.c +++ b/system/lib/libc/musl/src/search/tsearch_avl.c @@ -77,38 +77,45 @@ static struct node *find(struct node *n, const void *k, return find(n->right, k, cmp); } -static struct node *insert(struct node **n, const void *k, - int (*cmp)(const void *, const void *), int *new) +static struct node *insert(struct node *n, const void *k, + int (*cmp)(const void *, const void *), struct node **found) { - struct node *r = *n; + struct node *r; int c; - if (!r) { - *n = r = malloc(sizeof **n); - if (r) { - r->key = k; - r->left = r->right = 0; - r->height = 1; + if (!n) { + n = malloc(sizeof *n); + if (n) { + n->key = k; + n->left = n->right = 0; + n->height = 1; } - *new = 1; - return r; + *found = n; + return n; + } + c = cmp(k, n->key); + if (c == 0) { + *found = n; + return 0; + } + r = insert(c < 0 ? n->left : n->right, k, cmp, found); + if (r) { + if (c < 0) + n->left = r; + else + n->right = r; + r = balance(n); } - c = cmp(k, r->key); - if (c == 0) - return r; - if (c < 0) - r = insert(&r->left, k, cmp, new); - else - r = insert(&r->right, k, cmp, new); - if (*new) - *n = balance(*n); return r; } -static struct node *movr(struct node *n, struct node *r) { - if (!n) - return r; - n->right = movr(n->right, r); +static struct node *remove_rightmost(struct node *n, struct node **rightmost) +{ + if (!n->right) { + *rightmost = n; + return n->left; + } + n->right = remove_rightmost(n->right, rightmost); return balance(n); } @@ -122,7 +129,13 @@ static struct node *remove(struct node **n, const void *k, c = cmp(k, (*n)->key); if (c == 0) { struct node *r = *n; - *n = movr(r->left, r->right); + if (r->left) { + r->left = remove_rightmost(r->left, n); + (*n)->left = r->left; + (*n)->right = r->right; + *n = balance(*n); + } else + *n = r->right; free(r); return parent; } @@ -138,6 +151,8 @@ static struct node *remove(struct node **n, const void *k, void *tdelete(const void *restrict key, void **restrict rootp, int(*compar)(const void *, const void *)) { + if (!rootp) + return 0; struct node *n = *rootp; struct node *ret; /* last argument is arbitrary non-null pointer @@ -150,17 +165,21 @@ void *tdelete(const void *restrict key, void **restrict rootp, void *tfind(const void *key, void *const *rootp, int(*compar)(const void *, const void *)) { + if (!rootp) + return 0; return find(*rootp, key, compar); } void *tsearch(const void *key, void **rootp, int (*compar)(const void *, const void *)) { - int new = 0; - struct node *n = *rootp; + struct node *update; struct node *ret; - ret = insert(&n, key, compar, &new); - *rootp = n; + if (!rootp) + return 0; + update = insert(*rootp, key, compar, &ret); + if (update) + *rootp = update; return ret; } diff --git a/system/lib/libc/musl/src/select/poll.c b/system/lib/libc/musl/src/select/poll.c index f1e73e82f75d0..9e0bcbd804f32 100644 --- a/system/lib/libc/musl/src/select/poll.c +++ b/system/lib/libc/musl/src/select/poll.c @@ -1,8 +1,16 @@ #include +#include +#include #include "syscall.h" #include "libc.h" int poll(struct pollfd *fds, nfds_t n, int timeout) { +#ifdef SYS_poll return syscall_cp(SYS_poll, fds, n, timeout); +#else + return syscall_cp(SYS_ppoll, fds, n, timeout>=0 ? + &((struct timespec){ .tv_sec = timeout/1000, + .tv_nsec = timeout%1000*1000000 }) : 0, 0, _NSIG/8); +#endif } diff --git a/system/lib/libc/musl/src/select/pselect.c b/system/lib/libc/musl/src/select/pselect.c index a19e153e4583c..4e2d7b073dbad 100644 --- a/system/lib/libc/musl/src/select/pselect.c +++ b/system/lib/libc/musl/src/select/pselect.c @@ -1,11 +1,12 @@ #include #include +#include #include "syscall.h" #include "libc.h" int pselect(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restrict efds, const struct timespec *restrict ts, const sigset_t *restrict mask) { - long data[2] = { (long)mask, _NSIG/8 }; + syscall_arg_t data[2] = { (uintptr_t)mask, _NSIG/8 }; struct timespec ts_tmp; if (ts) ts_tmp = *ts; return syscall_cp(SYS_pselect6, n, rfds, wfds, efds, ts ? &ts_tmp : 0, data); diff --git a/system/lib/libc/musl/src/select/select.c b/system/lib/libc/musl/src/select/select.c index f93597b55cf78..7b5f6dcf7a53a 100644 --- a/system/lib/libc/musl/src/select/select.c +++ b/system/lib/libc/musl/src/select/select.c @@ -1,8 +1,26 @@ #include +#include +#include +#include #include "syscall.h" #include "libc.h" int select(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restrict efds, struct timeval *restrict tv) { +#ifdef SYS_select return syscall_cp(SYS_select, n, rfds, wfds, efds, tv); +#else + syscall_arg_t data[2] = { 0, _NSIG/8 }; + struct timespec ts; + if (tv) { + if (tv->tv_sec < 0 || tv->tv_usec < 0) + return __syscall_ret(-EINVAL); + time_t extra_secs = tv->tv_usec / 1000000; + ts.tv_nsec = tv->tv_usec % 1000000 * 1000; + const time_t max_time = (1ULL<<8*sizeof(time_t)-1)-1; + ts.tv_sec = extra_secs > max_time - tv->tv_sec ? + max_time : tv->tv_sec + extra_secs; + } + return syscall_cp(SYS_pselect6, n, rfds, wfds, efds, tv ? &ts : 0, data); +#endif } diff --git a/system/lib/libc/musl/src/signal/raise.c b/system/lib/libc/musl/src/signal/raise.c index 35063c5b89c78..717b1c917a343 100644 --- a/system/lib/libc/musl/src/signal/raise.c +++ b/system/lib/libc/musl/src/signal/raise.c @@ -5,12 +5,11 @@ int raise(int sig) { - int pid, tid, ret; + int tid, ret; sigset_t set; __block_app_sigs(&set); tid = __syscall(SYS_gettid); - pid = __syscall(SYS_getpid); - ret = syscall(SYS_tgkill, pid, tid, sig); + ret = syscall(SYS_tkill, tid, sig); __restore_sigs(&set); return ret; } diff --git a/system/lib/libc/musl/src/signal/sigaction.c b/system/lib/libc/musl/src/signal/sigaction.c index f7ff4a6198b30..6eca06f11fb63 100644 --- a/system/lib/libc/musl/src/signal/sigaction.c +++ b/system/lib/libc/musl/src/signal/sigaction.c @@ -6,11 +6,7 @@ #include "libc.h" #include "ksigaction.h" -void __restore(), __restore_rt(); - -static pthread_t dummy(void) { return 0; } -weak_alias(dummy, __pthread_self_def); - +static int unmask_done; static unsigned long handler_set[_NSIG/(8*sizeof(long))]; void __get_handler_set(sigset_t *set) @@ -21,15 +17,24 @@ void __get_handler_set(sigset_t *set) int __libc_sigaction(int sig, const struct sigaction *restrict sa, struct sigaction *restrict old) { struct k_sigaction ksa, ksa_old; - if (sig >= (unsigned)_NSIG) { - errno = EINVAL; - return -1; - } if (sa) { if ((uintptr_t)sa->sa_handler > 1UL) { a_or_l(handler_set+(sig-1)/(8*sizeof(long)), 1UL<<(sig-1)%(8*sizeof(long))); - __pthread_self_def(); + + /* If pthread_create has not yet been called, + * implementation-internal signals might not + * yet have been unblocked. They must be + * unblocked before any signal handler is + * installed, so that an application cannot + * receive an illegal sigset_t (with them + * blocked) as part of the ucontext_t passed + * to the signal handler. */ + if (!libc.threaded && !unmask_done) { + __syscall(SYS_rt_sigprocmask, SIG_UNBLOCK, + SIGPT_SET, 0, _NSIG/8); + unmask_done = 1; + } } ksa.handler = sa->sa_handler; ksa.flags = sa->sa_flags | SA_RESTORER; @@ -48,7 +53,7 @@ int __libc_sigaction(int sig, const struct sigaction *restrict sa, struct sigact int __sigaction(int sig, const struct sigaction *restrict sa, struct sigaction *restrict old) { - if (sig-32U < 3) { + if (sig-32U < 3 || sig-1U >= _NSIG-1) { errno = EINVAL; return -1; } diff --git a/system/lib/libc/musl/src/signal/siglongjmp.c b/system/lib/libc/musl/src/signal/siglongjmp.c index b644cebb98f60..bc317acce9317 100644 --- a/system/lib/libc/musl/src/signal/siglongjmp.c +++ b/system/lib/libc/musl/src/signal/siglongjmp.c @@ -5,6 +5,5 @@ _Noreturn void siglongjmp(sigjmp_buf buf, int ret) { - if (buf->__fl) __restore_sigs(buf->__ss); longjmp(buf, ret); } diff --git a/system/lib/libc/musl/src/signal/signal.c b/system/lib/libc/musl/src/signal/signal.c index c0f063edb2fa8..29e03c88423fe 100644 --- a/system/lib/libc/musl/src/signal/signal.c +++ b/system/lib/libc/musl/src/signal/signal.c @@ -13,3 +13,4 @@ void (*signal(int sig, void (*func)(int)))(int) } weak_alias(signal, bsd_signal); +weak_alias(signal, __sysv_signal); diff --git a/system/lib/libc/musl/src/signal/sigsetjmp.c b/system/lib/libc/musl/src/signal/sigsetjmp.c index cb2257f0c45f8..e69de29bb2d1d 100644 --- a/system/lib/libc/musl/src/signal/sigsetjmp.c +++ b/system/lib/libc/musl/src/signal/sigsetjmp.c @@ -1,14 +0,0 @@ -#include -#include - -/* !!! This function will not work unless the compiler performs - * tail call optimization. Machine-specific asm versions should - * be created instead even though the workaround (tail call) - * is entirely non-machine-specific... */ - -int sigsetjmp(sigjmp_buf buf, int save) -{ - if ((buf->__fl = save)) - pthread_sigmask(SIG_SETMASK, 0, (sigset_t *)buf->__ss); - return setjmp(buf); -} diff --git a/system/lib/libc/musl/src/signal/sigsetjmp_tail.c b/system/lib/libc/musl/src/signal/sigsetjmp_tail.c new file mode 100644 index 0000000000000..78762aa2bf8d1 --- /dev/null +++ b/system/lib/libc/musl/src/signal/sigsetjmp_tail.c @@ -0,0 +1,11 @@ +#include +#include +#include "syscall.h" + +__attribute__((__visibility__("hidden"))) +int __sigsetjmp_tail(sigjmp_buf jb, int ret) +{ + void *p = jb->__ss; + __syscall(SYS_rt_sigprocmask, SIG_SETMASK, ret?p:0, ret?0:p, _NSIG/8); + return ret; +} diff --git a/system/lib/libc/musl/src/stat/__fxstat.c b/system/lib/libc/musl/src/stat/__fxstat.c deleted file mode 100644 index fd39ee3d6cfaf..0000000000000 --- a/system/lib/libc/musl/src/stat/__fxstat.c +++ /dev/null @@ -1,9 +0,0 @@ -#include -#include "libc.h" - -int __fxstat(int ver, int fd, struct stat *buf) -{ - return fstat(fd, buf); -} - -LFS64(__fxstat); diff --git a/system/lib/libc/musl/src/stat/__fxstatat.c b/system/lib/libc/musl/src/stat/__fxstatat.c deleted file mode 100644 index e389dec798e08..0000000000000 --- a/system/lib/libc/musl/src/stat/__fxstatat.c +++ /dev/null @@ -1,9 +0,0 @@ -#include -#include "libc.h" - -int __fxstatat(int ver, int fd, const char *path, struct stat *buf, int flag) -{ - return fstatat(fd, path, buf, flag); -} - -LFS64(__fxstatat); diff --git a/system/lib/libc/musl/src/stat/__lxstat.c b/system/lib/libc/musl/src/stat/__lxstat.c deleted file mode 100644 index e9992ed2b85aa..0000000000000 --- a/system/lib/libc/musl/src/stat/__lxstat.c +++ /dev/null @@ -1,9 +0,0 @@ -#include -#include "libc.h" - -int __lxstat(int ver, const char *path, struct stat *buf) -{ - return lstat(path, buf); -} - -LFS64(__lxstat); diff --git a/system/lib/libc/musl/src/stat/__xstat.c b/system/lib/libc/musl/src/stat/__xstat.c index 42011d5f4af45..73c873aea226a 100644 --- a/system/lib/libc/musl/src/stat/__xstat.c +++ b/system/lib/libc/musl/src/stat/__xstat.c @@ -1,9 +1,37 @@ #include #include "libc.h" +int __fxstat(int ver, int fd, struct stat *buf) +{ + return fstat(fd, buf); +} + +int __fxstatat(int ver, int fd, const char *path, struct stat *buf, int flag) +{ + return fstatat(fd, path, buf, flag); +} + +int __lxstat(int ver, const char *path, struct stat *buf) +{ + return lstat(path, buf); +} + int __xstat(int ver, const char *path, struct stat *buf) { return stat(path, buf); } +LFS64(__fxstat); +LFS64(__fxstatat); +LFS64(__lxstat); LFS64(__xstat); + +int __xmknod(int ver, const char *path, mode_t mode, dev_t *dev) +{ + return mknod(path, mode, *dev); +} + +int __xmknodat(int ver, int fd, const char *path, mode_t mode, dev_t *dev) +{ + return mknodat(fd, path, mode, *dev); +} diff --git a/system/lib/libc/musl/src/stat/chmod.c b/system/lib/libc/musl/src/stat/chmod.c index beb66e59d0611..d4f53c564e147 100644 --- a/system/lib/libc/musl/src/stat/chmod.c +++ b/system/lib/libc/musl/src/stat/chmod.c @@ -1,7 +1,12 @@ #include +#include #include "syscall.h" int chmod(const char *path, mode_t mode) { +#ifdef SYS_chmod return syscall(SYS_chmod, path, mode); +#else + return syscall(SYS_fchmodat, AT_FDCWD, path, mode); +#endif } diff --git a/system/lib/libc/musl/src/stat/fchmod.c b/system/lib/libc/musl/src/stat/fchmod.c index 6d2814162ebc2..93e1b64c57f90 100644 --- a/system/lib/libc/musl/src/stat/fchmod.c +++ b/system/lib/libc/musl/src/stat/fchmod.c @@ -13,5 +13,9 @@ int fchmod(int fd, mode_t mode) char buf[15+3*sizeof(int)]; __procfdname(buf, fd); +#ifdef SYS_chmod return syscall(SYS_chmod, buf, mode); +#else + return syscall(SYS_fchmodat, AT_FDCWD, buf, mode); +#endif } diff --git a/system/lib/libc/musl/src/stat/fstat.c b/system/lib/libc/musl/src/stat/fstat.c index b5611767b6b84..ab4afc0f9220c 100644 --- a/system/lib/libc/musl/src/stat/fstat.c +++ b/system/lib/libc/musl/src/stat/fstat.c @@ -14,7 +14,11 @@ int fstat(int fd, struct stat *st) char buf[15+3*sizeof(int)]; __procfdname(buf, fd); +#ifdef SYS_stat return syscall(SYS_stat, buf, st); +#else + return syscall(SYS_fstatat, AT_FDCWD, buf, st, 0); +#endif } LFS64(fstat); diff --git a/system/lib/libc/musl/src/stat/futimesat.c b/system/lib/libc/musl/src/stat/futimesat.c index dbefc844c46e0..b4eea1d3c440b 100644 --- a/system/lib/libc/musl/src/stat/futimesat.c +++ b/system/lib/libc/musl/src/stat/futimesat.c @@ -1,10 +1,23 @@ #define _GNU_SOURCE #include +#include +#include #include "syscall.h" +#include "libc.h" -#ifdef SYS_futimesat -int futimesat(int dirfd, const char *pathname, const struct timeval times[2]) +int __futimesat(int dirfd, const char *pathname, const struct timeval times[2]) { - return syscall(SYS_futimesat, dirfd, pathname, times); + struct timespec ts[2]; + if (times) { + int i; + for (i=0; i<2; i++) { + if (times[i].tv_usec >= 1000000ULL) + return __syscall_ret(-EINVAL); + ts[i].tv_sec = times[i].tv_sec; + ts[i].tv_nsec = times[i].tv_usec * 1000; + } + } + return utimensat(dirfd, pathname, times ? ts : 0, 0); } -#endif + +weak_alias(__futimesat, futimesat); diff --git a/system/lib/libc/musl/src/stat/lstat.c b/system/lib/libc/musl/src/stat/lstat.c index 8f60358c19c19..5e8b84fcffad6 100644 --- a/system/lib/libc/musl/src/stat/lstat.c +++ b/system/lib/libc/musl/src/stat/lstat.c @@ -1,10 +1,15 @@ #include +#include #include "syscall.h" #include "libc.h" int lstat(const char *restrict path, struct stat *restrict buf) { +#ifdef SYS_lstat return syscall(SYS_lstat, path, buf); +#else + return syscall(SYS_fstatat, AT_FDCWD, path, buf, AT_SYMLINK_NOFOLLOW); +#endif } LFS64(lstat); diff --git a/system/lib/libc/musl/src/stat/mkdir.c b/system/lib/libc/musl/src/stat/mkdir.c index 770e1cccea889..32625b7de3276 100644 --- a/system/lib/libc/musl/src/stat/mkdir.c +++ b/system/lib/libc/musl/src/stat/mkdir.c @@ -1,7 +1,12 @@ #include +#include #include "syscall.h" int mkdir(const char *path, mode_t mode) { +#ifdef SYS_mkdir return syscall(SYS_mkdir, path, mode); +#else + return syscall(SYS_mkdirat, AT_FDCWD, path, mode); +#endif } diff --git a/system/lib/libc/musl/src/stat/mknod.c b/system/lib/libc/musl/src/stat/mknod.c index c3196571f0806..beebd84e08995 100644 --- a/system/lib/libc/musl/src/stat/mknod.c +++ b/system/lib/libc/musl/src/stat/mknod.c @@ -1,7 +1,12 @@ #include +#include #include "syscall.h" int mknod(const char *path, mode_t mode, dev_t dev) { +#ifdef SYS_mknod return syscall(SYS_mknod, path, mode, dev); +#else + return syscall(SYS_mknodat, AT_FDCWD, path, mode, dev); +#endif } diff --git a/system/lib/libc/musl/src/stat/stat.c b/system/lib/libc/musl/src/stat/stat.c index c6de7168dfda8..b4433a0a7cd13 100644 --- a/system/lib/libc/musl/src/stat/stat.c +++ b/system/lib/libc/musl/src/stat/stat.c @@ -1,10 +1,15 @@ #include +#include #include "syscall.h" #include "libc.h" int stat(const char *restrict path, struct stat *restrict buf) { +#ifdef SYS_stat return syscall(SYS_stat, path, buf); +#else + return syscall(SYS_fstatat, AT_FDCWD, path, buf, 0); +#endif } LFS64(stat); diff --git a/system/lib/libc/musl/src/stat/utimensat.c b/system/lib/libc/musl/src/stat/utimensat.c index 929698bcc47de..159c8be3b3c71 100644 --- a/system/lib/libc/musl/src/stat/utimensat.c +++ b/system/lib/libc/musl/src/stat/utimensat.c @@ -1,7 +1,37 @@ #include +#include +#include +#include #include "syscall.h" int utimensat(int fd, const char *path, const struct timespec times[2], int flags) { - return syscall(SYS_utimensat, fd, path, times, flags); + int r = __syscall(SYS_utimensat, fd, path, times, flags); +#ifdef SYS_futimesat + if (r != -ENOSYS || flags) return __syscall_ret(r); + struct timeval *tv = 0, tmp[2]; + if (times) { + int i; + tv = tmp; + for (i=0; i<2; i++) { + if (times[i].tv_nsec >= 1000000000ULL) { + if (times[i].tv_nsec == UTIME_NOW && + times[1-i].tv_nsec == UTIME_NOW) { + tv = 0; + break; + } + if (times[i].tv_nsec == UTIME_OMIT) + return __syscall_ret(-ENOSYS); + return __syscall_ret(-EINVAL); + } + tmp[i].tv_sec = times[i].tv_sec; + tmp[i].tv_usec = times[i].tv_nsec / 1000; + } + } + + r = __syscall(SYS_futimesat, fd, path, tv); + if (r != -ENOSYS || fd != AT_FDCWD) return __syscall_ret(r); + r = __syscall(SYS_utimes, path, tv); +#endif + return __syscall_ret(r); } diff --git a/system/lib/libc/musl/src/stdio/__fdopen.c b/system/lib/libc/musl/src/stdio/__fdopen.c index a6ae73a202130..8d6ce813e45ec 100644 --- a/system/lib/libc/musl/src/stdio/__fdopen.c +++ b/system/lib/libc/musl/src/stdio/__fdopen.c @@ -1,6 +1,5 @@ #include "stdio_impl.h" #include -#include #include #include #include @@ -9,7 +8,7 @@ FILE *__fdopen(int fd, const char *mode) { FILE *f; - struct termios tio; + struct winsize wsz; /* Check for valid initial mode character */ if (!strchr("rwa", *mode)) { @@ -43,7 +42,7 @@ FILE *__fdopen(int fd, const char *mode) /* Activate line buffered mode for terminals */ f->lbf = EOF; - if (!(f->flags & F_NOWR) && !__syscall(SYS_ioctl, fd, TCGETS, &tio)) + if (!(f->flags & F_NOWR) && !__syscall(SYS_ioctl, fd, TIOCGWINSZ, &wsz)) f->lbf = '\n'; /* Initialize op ptrs. No problem if some are unneeded. */ @@ -55,13 +54,7 @@ FILE *__fdopen(int fd, const char *mode) if (!libc.threaded) f->lock = -1; /* Add new FILE to open file list */ - OFLLOCK(); - f->next = libc.ofl_head; - if (libc.ofl_head) libc.ofl_head->prev = f; - libc.ofl_head = f; - OFLUNLOCK(); - - return f; + return __ofl_add(f); } weak_alias(__fdopen, fdopen); diff --git a/system/lib/libc/musl/src/stdio/__fopen_rb_ca.c b/system/lib/libc/musl/src/stdio/__fopen_rb_ca.c index 9202c8ce5c142..183a5d5538955 100644 --- a/system/lib/libc/musl/src/stdio/__fopen_rb_ca.c +++ b/system/lib/libc/musl/src/stdio/__fopen_rb_ca.c @@ -6,8 +6,9 @@ FILE *__fopen_rb_ca(const char *filename, FILE *f, unsigned char *buf, size_t le { memset(f, 0, sizeof *f); - f->fd = syscall(SYS_open, filename, O_RDONLY|O_LARGEFILE|O_CLOEXEC, 0); + f->fd = sys_open(filename, O_RDONLY|O_CLOEXEC); if (f->fd < 0) return 0; + __syscall(SYS_fcntl, f->fd, F_SETFD, FD_CLOEXEC); f->flags = F_NOWR | F_PERM; f->buf = buf + UNGET; diff --git a/system/lib/libc/musl/src/stdio/__stdio_close.c b/system/lib/libc/musl/src/stdio/__stdio_close.c index 9f7ee18c23fa9..79452bdb6498a 100644 --- a/system/lib/libc/musl/src/stdio/__stdio_close.c +++ b/system/lib/libc/musl/src/stdio/__stdio_close.c @@ -1,6 +1,13 @@ #include "stdio_impl.h" +static int dummy(int fd) +{ + return fd; +} + +weak_alias(dummy, __aio_close); + int __stdio_close(FILE *f) { - return syscall(SYS_close, f->fd); + return syscall(SYS_close, __aio_close(f->fd)); } diff --git a/system/lib/libc/musl/src/stdio/__stdio_exit.c b/system/lib/libc/musl/src/stdio/__stdio_exit.c index 716e5f7366095..191b4454a48d3 100644 --- a/system/lib/libc/musl/src/stdio/__stdio_exit.c +++ b/system/lib/libc/musl/src/stdio/__stdio_exit.c @@ -16,8 +16,7 @@ static void close_file(FILE *f) void __stdio_exit(void) { FILE *f; - OFLLOCK(); - for (f=libc.ofl_head; f; f=f->next) close_file(f); + for (f=*__ofl_lock(); f; f=f->next) close_file(f); close_file(__stdin_used); close_file(__stdout_used); } diff --git a/system/lib/libc/musl/src/stdio/__stdio_read.c b/system/lib/libc/musl/src/stdio/__stdio_read.c index 05e56f923a8ae..f8fa6d3bf381b 100644 --- a/system/lib/libc/musl/src/stdio/__stdio_read.c +++ b/system/lib/libc/musl/src/stdio/__stdio_read.c @@ -1,12 +1,5 @@ #include "stdio_impl.h" #include -#include - -static void cleanup(void *p) -{ - FILE *f = p; - if (!f->lockcount) __unlockfile(f); -} size_t __stdio_read(FILE *f, unsigned char *buf, size_t len) { @@ -16,16 +9,9 @@ size_t __stdio_read(FILE *f, unsigned char *buf, size_t len) }; ssize_t cnt; - if (libc.main_thread) { - pthread_cleanup_push(cleanup, f); - cnt = syscall_cp(SYS_readv, f->fd, iov, 2); - pthread_cleanup_pop(0); - } else { - cnt = syscall(SYS_readv, f->fd, iov, 2); - } + cnt = syscall(SYS_readv, f->fd, iov, 2); if (cnt <= 0) { f->flags |= F_EOF ^ ((F_ERR^F_EOF) & cnt); - f->rpos = f->rend = 0; return cnt; } if (cnt <= iov[0].iov_len) return cnt; diff --git a/system/lib/libc/musl/src/stdio/__stdio_write.c b/system/lib/libc/musl/src/stdio/__stdio_write.c index e52e91ae0f5e0..d2d89475b0f94 100644 --- a/system/lib/libc/musl/src/stdio/__stdio_write.c +++ b/system/lib/libc/musl/src/stdio/__stdio_write.c @@ -1,12 +1,5 @@ #include "stdio_impl.h" #include -#include - -static void cleanup(void *p) -{ - FILE *f = p; - if (!f->lockcount) __unlockfile(f); -} size_t __stdio_write(FILE *f, const unsigned char *buf, size_t len) { @@ -19,13 +12,7 @@ size_t __stdio_write(FILE *f, const unsigned char *buf, size_t len) int iovcnt = 2; ssize_t cnt; for (;;) { - if (libc.main_thread) { - pthread_cleanup_push(cleanup, f); - cnt = syscall_cp(SYS_writev, f->fd, iov, iovcnt); - pthread_cleanup_pop(0); - } else { - cnt = syscall(SYS_writev, f->fd, iov, iovcnt); - } + cnt = syscall(SYS_writev, f->fd, iov, iovcnt); if (cnt == rem) { f->wend = f->buf + f->buf_size; f->wpos = f->wbase = f->buf; @@ -38,11 +25,8 @@ size_t __stdio_write(FILE *f, const unsigned char *buf, size_t len) } rem -= cnt; if (cnt > iov[0].iov_len) { - f->wpos = f->wbase = f->buf; cnt -= iov[0].iov_len; iov++; iovcnt--; - } else if (iovcnt == 2) { - f->wbase += cnt; } iov[0].iov_base = (char *)iov[0].iov_base + cnt; iov[0].iov_len -= cnt; diff --git a/system/lib/libc/musl/src/stdio/__stdout_write.c b/system/lib/libc/musl/src/stdio/__stdout_write.c index 200fe2c96f529..dd1ec60ff7034 100644 --- a/system/lib/libc/musl/src/stdio/__stdout_write.c +++ b/system/lib/libc/musl/src/stdio/__stdout_write.c @@ -1,12 +1,11 @@ #include "stdio_impl.h" -#include #include size_t __stdout_write(FILE *f, const unsigned char *buf, size_t len) { - struct termios tio; + struct winsize wsz; f->write = __stdio_write; - if (!(f->flags & F_SVB) && __syscall(SYS_ioctl, f->fd, TCGETS, &tio)) + if (!(f->flags & F_SVB) && __syscall(SYS_ioctl, f->fd, TIOCGWINSZ, &wsz)) f->lbf = -1; return __stdio_write(f, buf, len); } diff --git a/system/lib/libc/musl/src/stdio/__toread.c b/system/lib/libc/musl/src/stdio/__toread.c index 52624f3d4f237..35f67b8f8d938 100644 --- a/system/lib/libc/musl/src/stdio/__toread.c +++ b/system/lib/libc/musl/src/stdio/__toread.c @@ -3,14 +3,14 @@ int __toread(FILE *f) { f->mode |= f->mode-1; - if (f->wpos > f->buf) f->write(f, 0, 0); + if (f->wpos > f->wbase) f->write(f, 0, 0); f->wpos = f->wbase = f->wend = 0; - if (f->flags & (F_EOF|F_NORD)) { - if (f->flags & F_NORD) f->flags |= F_ERR; + if (f->flags & F_NORD) { + f->flags |= F_ERR; return EOF; } - f->rpos = f->rend = f->buf; - return 0; + f->rpos = f->rend = f->buf + f->buf_size; + return (f->flags & F_EOF) ? EOF : 0; } void __stdio_exit_needed(void); diff --git a/system/lib/libc/musl/src/stdio/__uflow.c b/system/lib/libc/musl/src/stdio/__uflow.c index e28922c2ff461..2a88bca6b123c 100644 --- a/system/lib/libc/musl/src/stdio/__uflow.c +++ b/system/lib/libc/musl/src/stdio/__uflow.c @@ -1,11 +1,11 @@ #include "stdio_impl.h" -/* This function will never be called if there is already data - * buffered for reading. Thus we can get by with very few branches. */ +/* This function assumes it will never be called if there is already + * data buffered for reading. */ int __uflow(FILE *f) { unsigned char c; - if ((f->rend || !__toread(f)) && f->read(f, &c, 1)==1) return c; + if (!__toread(f) && f->read(f, &c, 1)==1) return c; return EOF; } diff --git a/system/lib/libc/musl/src/stdio/fclose.c b/system/lib/libc/musl/src/stdio/fclose.c index 38e8a1e39dae9..d687a8779b64f 100644 --- a/system/lib/libc/musl/src/stdio/fclose.c +++ b/system/lib/libc/musl/src/stdio/fclose.c @@ -1,18 +1,24 @@ #include "stdio_impl.h" +#include "libc.h" + +static void dummy(FILE *f) { } +weak_alias(dummy, __unlist_locked_file); int fclose(FILE *f) { int r; int perm; - FFINALLOCK(f); + FLOCK(f); + + __unlist_locked_file(f); if (!(perm = f->flags & F_PERM)) { - OFLLOCK(); + FILE **head = __ofl_lock(); if (f->prev) f->prev->next = f->next; if (f->next) f->next->prev = f->prev; - if (libc.ofl_head == f) libc.ofl_head = f->next; - OFLUNLOCK(); + if (*head == f) *head = f->next; + __ofl_unlock(); } r = fflush(f); @@ -20,6 +26,7 @@ int fclose(FILE *f) if (f->getln_buf) free(f->getln_buf); if (!perm) free(f); - + else FUNLOCK(f); + return r; } diff --git a/system/lib/libc/musl/src/stdio/fflush.c b/system/lib/libc/musl/src/stdio/fflush.c index 7bf862a6ae5f5..3f462c80e8d12 100644 --- a/system/lib/libc/musl/src/stdio/fflush.c +++ b/system/lib/libc/musl/src/stdio/fflush.c @@ -35,13 +35,12 @@ int fflush(FILE *f) r = __stdout_used ? fflush(__stdout_used) : 0; - OFLLOCK(); - for (f=libc.ofl_head; f; f=f->next) { + for (f=*__ofl_lock(); f; f=f->next) { FLOCK(f); if (f->wpos > f->wbase) r |= __fflush_unlocked(f); FUNLOCK(f); } - OFLUNLOCK(); + __ofl_unlock(); return r; } diff --git a/system/lib/libc/musl/src/stdio/fgetwc.c b/system/lib/libc/musl/src/stdio/fgetwc.c index 8626d54caa5db..e455cfec408bc 100644 --- a/system/lib/libc/musl/src/stdio/fgetwc.c +++ b/system/lib/libc/musl/src/stdio/fgetwc.c @@ -1,8 +1,9 @@ #include "stdio_impl.h" +#include "locale_impl.h" #include #include -wint_t __fgetwc_unlocked(FILE *f) +static wint_t __fgetwc_unlocked_internal(FILE *f) { mbstate_t st = { 0 }; wchar_t wc; @@ -10,8 +11,6 @@ wint_t __fgetwc_unlocked(FILE *f) unsigned char b; size_t l; - f->mode |= f->mode+1; - /* Convert character from buffer if possible */ if (f->rpos < f->rend) { l = mbrtowc(&wc, (void *)f->rpos, f->rend - f->rpos, &st); @@ -39,6 +38,16 @@ wint_t __fgetwc_unlocked(FILE *f) return wc; } +wint_t __fgetwc_unlocked(FILE *f) +{ + locale_t *ploc = &CURRENT_LOCALE, loc = *ploc; + if (f->mode <= 0) fwide(f, 1); + *ploc = f->locale; + wchar_t wc = __fgetwc_unlocked_internal(f); + *ploc = loc; + return wc; +} + wint_t fgetwc(FILE *f) { wint_t c; diff --git a/system/lib/libc/musl/src/stdio/fmemopen.c b/system/lib/libc/musl/src/stdio/fmemopen.c index d78496091d255..7c193a579ba4b 100644 --- a/system/lib/libc/musl/src/stdio/fmemopen.c +++ b/system/lib/libc/musl/src/stdio/fmemopen.c @@ -110,11 +110,5 @@ FILE *fmemopen(void *restrict buf, size_t size, const char *restrict mode) if (!libc.threaded) f->lock = -1; - OFLLOCK(); - f->next = libc.ofl_head; - if (libc.ofl_head) libc.ofl_head->prev = f; - libc.ofl_head = f; - OFLUNLOCK(); - - return f; + return __ofl_add(f); } diff --git a/system/lib/libc/musl/src/stdio/fopen.c b/system/lib/libc/musl/src/stdio/fopen.c index da17ce8b48dc4..252f08241b3a3 100644 --- a/system/lib/libc/musl/src/stdio/fopen.c +++ b/system/lib/libc/musl/src/stdio/fopen.c @@ -18,8 +18,10 @@ FILE *fopen(const char *restrict filename, const char *restrict mode) /* Compute the flags to pass to open() */ flags = __fmodeflags(mode); - fd = syscall_cp(SYS_open, filename, flags|O_LARGEFILE, 0666); + fd = sys_open(filename, flags, 0666); if (fd < 0) return 0; + if (flags & O_CLOEXEC) + __syscall(SYS_fcntl, fd, F_SETFD, FD_CLOEXEC); f = __fdopen(fd, mode); if (f) return f; diff --git a/system/lib/libc/musl/src/stdio/fputs.c b/system/lib/libc/musl/src/stdio/fputs.c index 4737f448e934a..1cf344f28c6fe 100644 --- a/system/lib/libc/musl/src/stdio/fputs.c +++ b/system/lib/libc/musl/src/stdio/fputs.c @@ -3,7 +3,8 @@ int fputs(const char *restrict s, FILE *restrict f) { - return (int)fwrite(s, strlen(s), 1, f) - 1; + size_t l = strlen(s); + return (fwrite(s, 1, l, f)==l) - 1; } weak_alias(fputs, fputs_unlocked); diff --git a/system/lib/libc/musl/src/stdio/fputwc.c b/system/lib/libc/musl/src/stdio/fputwc.c index 7b621dd2ff9a8..789fe9c90e98e 100644 --- a/system/lib/libc/musl/src/stdio/fputwc.c +++ b/system/lib/libc/musl/src/stdio/fputwc.c @@ -1,4 +1,5 @@ #include "stdio_impl.h" +#include "locale_impl.h" #include #include #include @@ -7,8 +8,10 @@ wint_t __fputwc_unlocked(wchar_t c, FILE *f) { char mbc[MB_LEN_MAX]; int l; + locale_t *ploc = &CURRENT_LOCALE, loc = *ploc; - f->mode |= f->mode+1; + if (f->mode <= 0) fwide(f, 1); + *ploc = f->locale; if (isascii(c)) { c = putc_unlocked(c, f); @@ -20,6 +23,8 @@ wint_t __fputwc_unlocked(wchar_t c, FILE *f) l = wctomb(mbc, c); if (l < 0 || __fwritex((void *)mbc, l, f) < l) c = WEOF; } + if (c==WEOF) f->flags |= F_ERR; + *ploc = loc; return c; } diff --git a/system/lib/libc/musl/src/stdio/fputws.c b/system/lib/libc/musl/src/stdio/fputws.c index 5723cbcd7a573..0ed02f1c004e8 100644 --- a/system/lib/libc/musl/src/stdio/fputws.c +++ b/system/lib/libc/musl/src/stdio/fputws.c @@ -1,23 +1,28 @@ #include "stdio_impl.h" +#include "locale_impl.h" #include int fputws(const wchar_t *restrict ws, FILE *restrict f) { unsigned char buf[BUFSIZ]; size_t l=0; + locale_t *ploc = &CURRENT_LOCALE, loc = *ploc; FLOCK(f); - f->mode |= f->mode+1; + fwide(f, 1); + *ploc = f->locale; while (ws && (l = wcsrtombs((void *)buf, (void*)&ws, sizeof buf, 0))+1 > 1) if (__fwritex(buf, l, f) < l) { FUNLOCK(f); + *ploc = loc; return -1; } FUNLOCK(f); + *ploc = loc; return l; /* 0 or -1 */ } diff --git a/system/lib/libc/musl/src/stdio/fread.c b/system/lib/libc/musl/src/stdio/fread.c index 33a65f586ead4..aef75f7376f70 100644 --- a/system/lib/libc/musl/src/stdio/fread.c +++ b/system/lib/libc/musl/src/stdio/fread.c @@ -7,6 +7,7 @@ size_t fread(void *restrict destv, size_t size, size_t nmemb, FILE *restrict f) { unsigned char *dest = destv; size_t len = size*nmemb, l = len, k; + if (!size) nmemb = 0; FLOCK(f); diff --git a/system/lib/libc/musl/src/stdio/ftrylockfile.c b/system/lib/libc/musl/src/stdio/ftrylockfile.c index eef4e2502e56a..eb13c839bf818 100644 --- a/system/lib/libc/musl/src/stdio/ftrylockfile.c +++ b/system/lib/libc/musl/src/stdio/ftrylockfile.c @@ -2,9 +2,26 @@ #include "pthread_impl.h" #include +void __do_orphaned_stdio_locks() +{ + FILE *f; + for (f=__pthread_self()->stdio_locks; f; f=f->next_locked) + a_store(&f->lock, 0x40000000); +} + +void __unlist_locked_file(FILE *f) +{ + if (f->lockcount) { + if (f->next_locked) f->next_locked->prev_locked = f->prev_locked; + if (f->prev_locked) f->prev_locked->next_locked = f->next_locked; + else __pthread_self()->stdio_locks = f->next_locked; + } +} + int ftrylockfile(FILE *f) { - int tid = pthread_self()->tid; + pthread_t self = __pthread_self(); + int tid = self->tid; if (f->lock == tid) { if (f->lockcount == LONG_MAX) return -1; @@ -15,5 +32,9 @@ int ftrylockfile(FILE *f) if (f->lock || a_cas(&f->lock, 0, tid)) return -1; f->lockcount = 1; + f->prev_locked = 0; + f->next_locked = self->stdio_locks; + if (f->next_locked) f->next_locked->prev_locked = f; + self->stdio_locks = f; return 0; } diff --git a/system/lib/libc/musl/src/stdio/funlockfile.c b/system/lib/libc/musl/src/stdio/funlockfile.c index f8a2a071e6459..30a07ef4b3743 100644 --- a/system/lib/libc/musl/src/stdio/funlockfile.c +++ b/system/lib/libc/musl/src/stdio/funlockfile.c @@ -1,7 +1,15 @@ #include "stdio_impl.h" #include "pthread_impl.h" +void __unlist_locked_file(FILE *); + void funlockfile(FILE *f) { - if (!--f->lockcount) __unlockfile(f); + if (f->lockcount == 1) { + __unlist_locked_file(f); + f->lockcount = 0; + __unlockfile(f); + } else { + f->lockcount--; + } } diff --git a/system/lib/libc/musl/src/stdio/fwide.c b/system/lib/libc/musl/src/stdio/fwide.c index 8088e7ad4311f..8410b1530780d 100644 --- a/system/lib/libc/musl/src/stdio/fwide.c +++ b/system/lib/libc/musl/src/stdio/fwide.c @@ -1,13 +1,14 @@ -#include #include "stdio_impl.h" - -#define SH (8*sizeof(int)-1) -#define NORMALIZE(x) ((x)>>SH | -((-(x))>>SH)) +#include "locale_impl.h" int fwide(FILE *f, int mode) { FLOCK(f); - if (!f->mode) f->mode = NORMALIZE(mode); + if (mode) { + if (!f->locale) f->locale = MB_CUR_MAX==1 + ? C_LOCALE : UTF8_LOCALE; + if (!f->mode) f->mode = mode>0 ? 1 : -1; + } mode = f->mode; FUNLOCK(f); return mode; diff --git a/system/lib/libc/musl/src/stdio/fwrite.c b/system/lib/libc/musl/src/stdio/fwrite.c index 81ec271e1bcb7..7a567b2c55a94 100644 --- a/system/lib/libc/musl/src/stdio/fwrite.c +++ b/system/lib/libc/musl/src/stdio/fwrite.c @@ -13,8 +13,8 @@ size_t __fwritex(const unsigned char *restrict s, size_t l, FILE *restrict f) /* Match /^(.*\n|)/ */ for (i=l; i && s[i-1] != '\n'; i--); if (i) { - if (f->write(f, s, i) < i) - return i; + size_t n = f->write(f, s, i); + if (n < i) return n; s += i; l -= i; } @@ -28,6 +28,7 @@ size_t __fwritex(const unsigned char *restrict s, size_t l, FILE *restrict f) size_t fwrite(const void *restrict src, size_t size, size_t nmemb, FILE *restrict f) { size_t k, l = size*nmemb; + if (!size) nmemb = 0; FLOCK(f); k = __fwritex(src, l, f); FUNLOCK(f); diff --git a/system/lib/libc/musl/src/stdio/getdelim.c b/system/lib/libc/musl/src/stdio/getdelim.c index 26093a6cfa02a..1ccd802923898 100644 --- a/system/lib/libc/musl/src/stdio/getdelim.c +++ b/system/lib/libc/musl/src/stdio/getdelim.c @@ -13,29 +13,32 @@ ssize_t getdelim(char **restrict s, size_t *restrict n, int delim, FILE *restric size_t i=0; int c; + FLOCK(f); + if (!n || !s) { + f->flags |= F_ERR; + FUNLOCK(f); errno = EINVAL; return -1; } if (!*s) *n=0; - FLOCK(f); - for (;;) { z = memchr(f->rpos, delim, f->rend - f->rpos); k = z ? z - f->rpos + 1 : f->rend - f->rpos; - if (i+k >= *n) { + if (i+k+1 >= *n) { if (k >= SIZE_MAX/2-i) goto oom; - *n = i+k+2; - if (*n < SIZE_MAX/4) *n *= 2; - tmp = realloc(*s, *n); + size_t m = i+k+2; + if (!z && m < SIZE_MAX/4) m += m/2; + tmp = realloc(*s, m); if (!tmp) { - *n = i+k+2; - tmp = realloc(*s, *n); + m = i+k+2; + tmp = realloc(*s, m); if (!tmp) goto oom; } *s = tmp; + *n = m; } memcpy(*s+i, f->rpos, k); f->rpos += k; @@ -56,6 +59,7 @@ ssize_t getdelim(char **restrict s, size_t *restrict n, int delim, FILE *restric return i; oom: + f->flags |= F_ERR; FUNLOCK(f); errno = ENOMEM; return -1; diff --git a/system/lib/libc/musl/src/stdio/ofl.c b/system/lib/libc/musl/src/stdio/ofl.c new file mode 100644 index 0000000000000..b143999c278a6 --- /dev/null +++ b/system/lib/libc/musl/src/stdio/ofl.c @@ -0,0 +1,16 @@ +#include "stdio_impl.h" +#include "libc.h" + +static FILE *ofl_head; +static volatile int ofl_lock[2]; + +FILE **__ofl_lock() +{ + LOCK(ofl_lock); + return &ofl_head; +} + +void __ofl_unlock() +{ + UNLOCK(ofl_lock); +} diff --git a/system/lib/libc/musl/src/stdio/ofl_add.c b/system/lib/libc/musl/src/stdio/ofl_add.c new file mode 100644 index 0000000000000..d7de9f15a13ee --- /dev/null +++ b/system/lib/libc/musl/src/stdio/ofl_add.c @@ -0,0 +1,11 @@ +#include "stdio_impl.h" + +FILE *__ofl_add(FILE *f) +{ + FILE **head = __ofl_lock(); + f->next = *head; + if (*head) (*head)->prev = f; + *head = f; + __ofl_unlock(); + return f; +} diff --git a/system/lib/libc/musl/src/stdio/open_memstream.c b/system/lib/libc/musl/src/stdio/open_memstream.c index 9eafdfbaedce4..eab024da6cd17 100644 --- a/system/lib/libc/musl/src/stdio/open_memstream.c +++ b/system/lib/libc/musl/src/stdio/open_memstream.c @@ -59,14 +59,21 @@ FILE *open_memstream(char **bufp, size_t *sizep) { FILE *f; struct cookie *c; + char *buf; + if (!(f=malloc(sizeof *f + sizeof *c + BUFSIZ))) return 0; + if (!(buf=malloc(sizeof *buf))) { + free(f); + return 0; + } memset(f, 0, sizeof *f + sizeof *c); f->cookie = c = (void *)(f+1); c->bufp = bufp; c->sizep = sizep; - c->pos = c->len = c->space = 0; - c->buf = 0; + c->pos = c->len = c->space = *sizep = 0; + c->buf = *bufp = buf; + *buf = 0; f->flags = F_NORD; f->fd = -1; @@ -79,11 +86,5 @@ FILE *open_memstream(char **bufp, size_t *sizep) if (!libc.threaded) f->lock = -1; - OFLLOCK(); - f->next = libc.ofl_head; - if (libc.ofl_head) libc.ofl_head->prev = f; - libc.ofl_head = f; - OFLUNLOCK(); - - return f; + return __ofl_add(f); } diff --git a/system/lib/libc/musl/src/stdio/open_wmemstream.c b/system/lib/libc/musl/src/stdio/open_wmemstream.c index 35370309d6fd2..4d90cd971964f 100644 --- a/system/lib/libc/musl/src/stdio/open_wmemstream.c +++ b/system/lib/libc/musl/src/stdio/open_wmemstream.c @@ -61,14 +61,21 @@ FILE *open_wmemstream(wchar_t **bufp, size_t *sizep) { FILE *f; struct cookie *c; + wchar_t *buf; + if (!(f=malloc(sizeof *f + sizeof *c))) return 0; + if (!(buf=malloc(sizeof *buf))) { + free(f); + return 0; + } memset(f, 0, sizeof *f + sizeof *c); f->cookie = c = (void *)(f+1); c->bufp = bufp; c->sizep = sizep; - c->pos = c->len = c->space = 0; - c->buf = 0; + c->pos = c->len = c->space = *sizep = 0; + c->buf = *bufp = buf; + *buf = 0; f->flags = F_NORD; f->fd = -1; @@ -81,11 +88,5 @@ FILE *open_wmemstream(wchar_t **bufp, size_t *sizep) if (!libc.threaded) f->lock = -1; - OFLLOCK(); - f->next = libc.ofl_head; - if (libc.ofl_head) libc.ofl_head->prev = f; - libc.ofl_head = f; - OFLUNLOCK(); - - return f; + return __ofl_add(f); } diff --git a/system/lib/libc/musl/src/stdio/remove.c b/system/lib/libc/musl/src/stdio/remove.c index e147ba251440d..942e301a4c035 100644 --- a/system/lib/libc/musl/src/stdio/remove.c +++ b/system/lib/libc/musl/src/stdio/remove.c @@ -1,9 +1,19 @@ #include #include +#include #include "syscall.h" int remove(const char *path) { - int r = syscall(SYS_unlink, path); - return (r && errno == EISDIR) ? syscall(SYS_rmdir, path) : r; +#ifdef SYS_unlink + int r = __syscall(SYS_unlink, path); +#else + int r = __syscall(SYS_unlinkat, AT_FDCWD, path, 0); +#endif +#ifdef SYS_rmdir + if (r==-EISDIR) r = __syscall(SYS_rmdir, path); +#else + if (r==-EISDIR) r = __syscall(SYS_unlinkat, AT_FDCWD, path, AT_REMOVEDIR); +#endif + return __syscall_ret(r); } diff --git a/system/lib/libc/musl/src/stdio/rename.c b/system/lib/libc/musl/src/stdio/rename.c index 97f14535e0081..04c90c01343a4 100644 --- a/system/lib/libc/musl/src/stdio/rename.c +++ b/system/lib/libc/musl/src/stdio/rename.c @@ -1,7 +1,12 @@ #include +#include #include "syscall.h" int rename(const char *old, const char *new) { +#ifdef SYS_rename return syscall(SYS_rename, old, new); +#else + return syscall(SYS_renameat, AT_FDCWD, old, AT_FDCWD, new); +#endif } diff --git a/system/lib/libc/musl/src/stdio/tempnam.c b/system/lib/libc/musl/src/stdio/tempnam.c index f73ca9f9027f4..5a5597527c085 100644 --- a/system/lib/libc/musl/src/stdio/tempnam.c +++ b/system/lib/libc/musl/src/stdio/tempnam.c @@ -1,42 +1,49 @@ #include +#include +#include +#include +#include #include -#include -#include -#include -#include -#include "libc.h" -#include "atomic.h" +#include "syscall.h" #define MAXTRIES 100 +char *__randname(char *); + char *tempnam(const char *dir, const char *pfx) { - static int index; - char *s; - struct timespec ts; - int pid = getpid(); - size_t l; - int n; - int try=0; + char s[PATH_MAX]; + size_t l, dl, pl; + int try; + int r; if (!dir) dir = P_tmpdir; if (!pfx) pfx = "temp"; - if (access(dir, R_OK|W_OK|X_OK) != 0) - return NULL; - - l = strlen(dir) + 1 + strlen(pfx) + 3*(sizeof(int)*3+2) + 1; - s = malloc(l); - if (!s) return s; + dl = strlen(dir); + pl = strlen(pfx); + l = dl + 1 + pl + 1 + 6; - do { - clock_gettime(CLOCK_REALTIME, &ts); - n = ts.tv_nsec ^ (uintptr_t)&s ^ (uintptr_t)s; - snprintf(s, l, "%s/%s-%d-%d-%x", dir, pfx, pid, a_fetch_add(&index, 1), n); - } while (!access(s, F_OK) && try++=MAXTRIES) { - free(s); + if (l >= PATH_MAX) { + errno = ENAMETOOLONG; return 0; } - return s; + + memcpy(s, dir, dl); + s[dl] = '/'; + memcpy(s+dl+1, pfx, pl); + s[dl+1+pl] = '_'; + s[l] = 0; + + for (try=0; try #include -#include #include "stdio_impl.h" #define MAXTRIES 100 +char *__randname(char *); + FILE *tmpfile(void) { - char buf[L_tmpnam], *s; + char s[] = "/tmp/tmpfile_XXXXXX"; int fd; FILE *f; int try; for (try=0; try= 0) { - f = __fdopen(fd, "w+"); +#ifdef SYS_unlink __syscall(SYS_unlink, s); +#else + __syscall(SYS_unlinkat, AT_FDCWD, s, 0); +#endif + f = __fdopen(fd, "w+"); + if (!f) __syscall(SYS_close, fd); return f; } } diff --git a/system/lib/libc/musl/src/stdio/tmpnam.c b/system/lib/libc/musl/src/stdio/tmpnam.c index 2bd72b3b7a14b..449eb9b0708c2 100644 --- a/system/lib/libc/musl/src/stdio/tmpnam.c +++ b/system/lib/libc/musl/src/stdio/tmpnam.c @@ -1,31 +1,29 @@ #include -#include -#include -#include -#include -#include "libc.h" +#include +#include +#include +#include #include "syscall.h" -#include "atomic.h" #define MAXTRIES 100 -char *tmpnam(char *s) -{ - static int index; - static char s2[L_tmpnam]; - struct timespec ts; - int try = 0; - unsigned n; - - if (!s) s = s2; +char *__randname(char *); - if (__syscall(SYS_access, P_tmpdir, R_OK|W_OK|X_OK) != 0) - return NULL; - - do { - __syscall(SYS_clock_gettime, CLOCK_REALTIME, &ts, 0); - n = ts.tv_nsec ^ (uintptr_t)&s ^ (uintptr_t)s; - snprintf(s, L_tmpnam, "/tmp/t%x-%x", a_fetch_add(&index, 1), n); - } while (!__syscall(SYS_access, s, F_OK) && try++=MAXTRIES ? 0 : s; +char *tmpnam(char *buf) +{ + static char internal[L_tmpnam]; + char s[] = "/tmp/tmpnam_XXXXXX"; + int try; + int r; + for (try=0; tryrend && __toread(f)) || f->rpos <= f->buf - UNGET) { + if (!f->rpos) __toread(f); + if (!f->rpos || f->rpos <= f->buf - UNGET) { FUNLOCK(f); return EOF; } diff --git a/system/lib/libc/musl/src/stdio/ungetwc.c b/system/lib/libc/musl/src/stdio/ungetwc.c index 8cc85a6bfd2a0..9edf366f90d5c 100644 --- a/system/lib/libc/musl/src/stdio/ungetwc.c +++ b/system/lib/libc/musl/src/stdio/ungetwc.c @@ -1,4 +1,5 @@ #include "stdio_impl.h" +#include "locale_impl.h" #include #include #include @@ -7,21 +8,20 @@ wint_t ungetwc(wint_t c, FILE *f) { unsigned char mbc[MB_LEN_MAX]; - int l=1; - - if (c == WEOF) return c; - - /* Try conversion early so we can fail without locking if invalid */ - if (!isascii(c) && (l = wctomb((void *)mbc, c)) < 0) - return WEOF; + int l; + locale_t *ploc = &CURRENT_LOCALE, loc = *ploc; FLOCK(f); - f->mode |= f->mode+1; + if (f->mode <= 0) fwide(f, 1); + *ploc = f->locale; - if ((!f->rend && __toread(f)) || f->rpos < f->buf - UNGET + l) { + if (!f->rpos) __toread(f); + if (!f->rpos || c == WEOF || (l = wcrtomb((void *)mbc, c, 0)) < 0 || + f->rpos < f->buf - UNGET + l) { FUNLOCK(f); - return EOF; + *ploc = loc; + return WEOF; } if (isascii(c)) *--f->rpos = c; @@ -30,5 +30,6 @@ wint_t ungetwc(wint_t c, FILE *f) f->flags &= ~F_EOF; FUNLOCK(f); + *ploc = loc; return c; } diff --git a/system/lib/libc/musl/src/stdio/vasprintf.c b/system/lib/libc/musl/src/stdio/vasprintf.c index 68b7246b01362..08251bc20ecd2 100644 --- a/system/lib/libc/musl/src/stdio/vasprintf.c +++ b/system/lib/libc/musl/src/stdio/vasprintf.c @@ -3,26 +3,13 @@ #include #include -#define GUESS 240U - int vasprintf(char **s, const char *fmt, va_list ap) { va_list ap2; - char *a; - int l=GUESS; - - if (!(a=malloc(GUESS))) return -1; - va_copy(ap2, ap); - l=vsnprintf(a, GUESS, fmt, ap2); + int l = vsnprintf(0, 0, fmt, ap2); va_end(ap2); - if (l(b) ? (a) : (b)) #define MIN(a,b) ((a)<(b) ? (a) : (b)) -#define CONCAT2(x,y) x ## y -#define CONCAT(x,y) CONCAT2(x,y) /* Convenient bit representation for modifier flags, which all fall * within 31 codepoints of the space character. */ @@ -227,7 +225,7 @@ static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t) if (!isfinite(y)) { char *s = (t&32)?"inf":"INF"; - if (y!=y) s=(t&32)?"nan":"NAN", pl=0; + if (y!=y) s=(t&32)?"nan":"NAN"; pad(f, ' ', w, 3+pl, fl&~ZERO_PAD); out(f, prefix, pl); out(f, s, 3); @@ -343,7 +341,7 @@ static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t) x = *d % i; /* Are there any significant digits past j? */ if (x || d+1!=z) { - long double round = CONCAT(0x1p,LDBL_MANT_DIG); + long double round = 2/LDBL_EPSILON; long double small; if (*d/i & 1) round += 2; if (x0; bs+=i, l++); if (i<0) return -1; p=l; if (wmode |= f->mode+1; + fwide(f, 1); olderr = f->flags & F_ERR; f->flags &= ~F_ERR; ret = wprintf_core(f, fmt, &ap2, nl_arg, nl_type); diff --git a/system/lib/libc/musl/src/stdio/vfwscanf.c b/system/lib/libc/musl/src/stdio/vfwscanf.c index ac5c2c24f7018..223aad4f351c9 100644 --- a/system/lib/libc/musl/src/stdio/vfwscanf.c +++ b/system/lib/libc/musl/src/stdio/vfwscanf.c @@ -104,7 +104,7 @@ int vfwscanf(FILE *restrict f, const wchar_t *restrict fmt, va_list ap) FLOCK(f); - f->mode |= f->mode+1; + fwide(f, 1); for (p=fmt; *p; p++) { diff --git a/system/lib/libc/musl/src/string/memmem.c b/system/lib/libc/musl/src/string/memmem.c index d7e1221940b01..4be6a310a7618 100644 --- a/system/lib/libc/musl/src/string/memmem.c +++ b/system/lib/libc/musl/src/string/memmem.c @@ -140,6 +140,7 @@ void *memmem(const void *h0, size_t k, const void *n0, size_t l) h = memchr(h0, *n, k); if (!h || l==1) return (void *)h; k -= h - (const unsigned char *)h0; + if (k #include +#include "libc.h" int strcasecmp(const char *_l, const char *_r) { @@ -7,3 +8,10 @@ int strcasecmp(const char *_l, const char *_r) for (; *l && *r && (*l == *r || tolower(*l) == tolower(*r)); l++, r++); return tolower(*l) - tolower(*r); } + +int __strcasecmp_l(const char *l, const char *r, locale_t loc) +{ + return strcasecmp(l, r); +} + +weak_alias(__strcasecmp_l, strcasecmp_l); diff --git a/system/lib/libc/musl/src/string/strncasecmp.c b/system/lib/libc/musl/src/string/strncasecmp.c index 24659721d7c5e..3af5300878a45 100644 --- a/system/lib/libc/musl/src/string/strncasecmp.c +++ b/system/lib/libc/musl/src/string/strncasecmp.c @@ -1,5 +1,6 @@ #include #include +#include "libc.h" int strncasecmp(const char *_l, const char *_r, size_t n) { @@ -8,3 +9,10 @@ int strncasecmp(const char *_l, const char *_r, size_t n) for (; *l && *r && n && (*l == *r || tolower(*l) == tolower(*r)); l++, r++, n--); return tolower(*l) - tolower(*r); } + +int __strncasecmp_l(const char *l, const char *r, size_t n, locale_t loc) +{ + return strncasecmp(l, r, n); +} + +weak_alias(__strncasecmp_l, strncasecmp_l); diff --git a/system/lib/libc/musl/src/string/strsignal.c b/system/lib/libc/musl/src/string/strsignal.c index 905c0956184e0..96bfe841ff3f6 100644 --- a/system/lib/libc/musl/src/string/strsignal.c +++ b/system/lib/libc/musl/src/string/strsignal.c @@ -1,5 +1,6 @@ #include #include +#include "locale_impl.h" #if (SIGHUP == 1) && (SIGINT == 2) && (SIGQUIT == 3) && (SIGILL == 4) \ && (SIGTRAP == 5) && (SIGABRT == 6) && (SIGBUS == 7) && (SIGFPE == 8) \ @@ -104,12 +105,12 @@ static const char strings[] = char *strsignal(int signum) { - char *s = (char *)strings; + const char *s = strings; signum = sigmap(signum); if (signum - 1U >= _NSIG-1) signum = 0; for (; signum--; s++) for (; *s; s++); - return s; + return (char *)LCTRANS_CUR(s); } diff --git a/system/lib/libc/musl/src/string/strverscmp.c b/system/lib/libc/musl/src/string/strverscmp.c index 6f37cc6801fa8..4daf276d0cfeb 100644 --- a/system/lib/libc/musl/src/string/strverscmp.c +++ b/system/lib/libc/musl/src/string/strverscmp.c @@ -2,40 +2,33 @@ #include #include -int strverscmp(const char *l, const char *r) +int strverscmp(const char *l0, const char *r0) { - int haszero=1; - while (*l==*r) { - if (!*l) return 0; + const unsigned char *l = (const void *)l0; + const unsigned char *r = (const void *)r0; + size_t i, dp, j; + int z = 1; - if (*l=='0') { - if (haszero==1) { - haszero=0; - } - } else if (isdigit(*l)) { - if (haszero==1) { - haszero=2; - } - } else { - haszero=1; - } - l++; r++; + /* Find maximal matching prefix and track its maximal digit + * suffix and whether those digits are all zeros. */ + for (dp=i=0; l[i]==r[i]; i++) { + int c = l[i]; + if (!c) return 0; + if (!isdigit(c)) dp=i+1, z=1; + else if (c!='0') z=0; } - if (haszero==1 && (*l=='0' || *r=='0')) { - haszero=0; - } - if ((isdigit(*l) && isdigit(*r) ) && haszero) { - size_t lenl=0, lenr=0; - while (isdigit(l[lenl]) ) lenl++; - while (isdigit(r[lenr]) ) lenr++; - if (lenl==lenr) { - return (*l - *r); - } else if (lenl>lenr) { - return 1; - } else { - return -1; - } - } else { - return (*l - *r); + + if (l[dp]!='0' && r[dp]!='0') { + /* If we're not looking at a digit sequence that began + * with a zero, longest digit string is greater. */ + for (j=i; isdigit(l[j]); j++) + if (!isdigit(r[j])) return 1; + if (isdigit(r[j])) return -1; + } else if (z && dp #include diff --git a/system/lib/libc/musl/src/termios/cfsetospeed.c b/system/lib/libc/musl/src/termios/cfsetospeed.c index 80c790f1fda1b..b571f62e39cc1 100644 --- a/system/lib/libc/musl/src/termios/cfsetospeed.c +++ b/system/lib/libc/musl/src/termios/cfsetospeed.c @@ -1,3 +1,4 @@ +#define _BSD_SOURCE #include #include #include diff --git a/system/lib/libc/musl/src/thread/__syscall_cp.c b/system/lib/libc/musl/src/thread/__syscall_cp.c new file mode 100644 index 0000000000000..09a2be84f5839 --- /dev/null +++ b/system/lib/libc/musl/src/thread/__syscall_cp.c @@ -0,0 +1,21 @@ +#include "pthread_impl.h" +#include "syscall.h" + +__attribute__((__visibility__("hidden"))) +long __syscall_cp_c(); + +static long sccp(syscall_arg_t nr, + syscall_arg_t u, syscall_arg_t v, syscall_arg_t w, + syscall_arg_t x, syscall_arg_t y, syscall_arg_t z) +{ + return (__syscall)(nr, u, v, w, x, y, z); +} + +weak_alias(sccp, __syscall_cp_c); + +long (__syscall_cp)(syscall_arg_t nr, + syscall_arg_t u, syscall_arg_t v, syscall_arg_t w, + syscall_arg_t x, syscall_arg_t y, syscall_arg_t z) +{ + return __syscall_cp_c(nr, u, v, w, x, y, z); +} diff --git a/system/lib/libc/musl/src/thread/__timedwait.c b/system/lib/libc/musl/src/thread/__timedwait.c index d2a819f5ca053..9dae9e9b42f30 100644 --- a/system/lib/libc/musl/src/thread/__timedwait.c +++ b/system/lib/libc/musl/src/thread/__timedwait.c @@ -10,21 +10,28 @@ #include "futex.h" #endif #include "syscall.h" +#include "pthread_impl.h" + +int __pthread_setcancelstate(int, int *); +int __clock_gettime(clockid_t, struct timespec *); + #ifdef __EMSCRIPTEN__ double _pthread_msecs_until(const struct timespec *restrict at); int _pthread_isduecanceled(struct pthread *pthread_ptr); #endif -static int do_wait(volatile int *addr, int val, +int __timedwait_cp(volatile int *addr, int val, clockid_t clk, const struct timespec *at, int priv) { int r; struct timespec to, *top=0; + if (priv) priv = 128; + if (at) { if (at->tv_nsec >= 1000000000UL) return EINVAL; - if (clock_gettime(clk, &to)) return EINVAL; + if (__clock_gettime(clk, &to)) return EINVAL; to.tv_sec = at->tv_sec - to.tv_sec; if ((to.tv_nsec = at->tv_nsec - to.tv_nsec) < 0) { to.tv_sec--; @@ -62,31 +69,27 @@ static int do_wait(volatile int *addr, int val, r = -emscripten_futex_wait((void*)addr, val, waitMsecs); } #else - r = -__syscall_cp(SYS_futex, addr, FUTEX_WAIT, val, top); + r = -__syscall_cp(SYS_futex, addr, FUTEX_WAIT|priv, val, top); + if (r == ENOSYS) r = -__syscall_cp(SYS_futex, addr, FUTEX_WAIT, val, top); #endif - if (r == EINTR || r == EINVAL || r == ETIMEDOUT) return r; - return 0; + if (r != EINTR && r != ETIMEDOUT && r != ECANCELED) r = 0; + + return r; } int __timedwait(volatile int *addr, int val, - clockid_t clk, const struct timespec *at, - void (*cleanup)(void *), void *arg, int priv) + clockid_t clk, const struct timespec *at, int priv) { - int r, cs; - - if (!cleanup) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); - pthread_cleanup_push(cleanup, arg); - + int cs, r; + __pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); #ifdef __EMSCRIPTEN__ emscripten_conditional_set_current_thread_status(EM_THREAD_STATUS_RUNNING, EM_THREAD_STATUS_WAITMUTEX); #endif - r = do_wait(addr, val, clk, at, priv); + r = __timedwait_cp(addr, val, clk, at, priv); #ifdef __EMSCRIPTEN__ emscripten_conditional_set_current_thread_status(EM_THREAD_STATUS_WAITMUTEX, EM_THREAD_STATUS_RUNNING); #endif - - pthread_cleanup_pop(0); - if (!cleanup) pthread_setcancelstate(cs, 0); + __pthread_setcancelstate(cs, 0); return r; } diff --git a/system/lib/libc/musl/src/thread/__tls_get_addr.c b/system/lib/libc/musl/src/thread/__tls_get_addr.c new file mode 100644 index 0000000000000..6945faa060d75 --- /dev/null +++ b/system/lib/libc/musl/src/thread/__tls_get_addr.c @@ -0,0 +1,16 @@ +#include +#include "pthread_impl.h" +#include "libc.h" + +__attribute__((__visibility__("hidden"))) +void *__tls_get_new(size_t *); + +void *__tls_get_addr(size_t *v) +{ + pthread_t self = __pthread_self(); + if (v[0]<=(size_t)self->dtv[0]) + return (char *)self->dtv[v[0]]+v[1]+DTP_OFFSET; + return __tls_get_new(v); +} + +weak_alias(__tls_get_addr, __tls_get_new); diff --git a/system/lib/libc/musl/src/thread/__unmapself.c b/system/lib/libc/musl/src/thread/__unmapself.c index e69de29bb2d1d..1d3bee1d9b040 100644 --- a/system/lib/libc/musl/src/thread/__unmapself.c +++ b/system/lib/libc/musl/src/thread/__unmapself.c @@ -0,0 +1,29 @@ +#include "pthread_impl.h" +#include "atomic.h" +#include "syscall.h" +/* cheat and reuse CRTJMP macro from dynlink code */ +#include "dynlink.h" + +static volatile int lock; +static void *unmap_base; +static size_t unmap_size; +static char shared_stack[256]; + +static void do_unmap() +{ + __syscall(SYS_munmap, unmap_base, unmap_size); + __syscall(SYS_exit); +} + +void __unmapself(void *base, size_t size) +{ + int tid=__pthread_self()->tid; + char *stack = shared_stack + sizeof shared_stack; + stack -= (uintptr_t)stack % 16; + while (lock || a_cas(&lock, 0, tid)) + a_spin(); + __syscall(SYS_set_tid_address, &lock); + unmap_base = base; + unmap_size = size; + CRTJMP(do_unmap, stack); +} diff --git a/system/lib/libc/musl/src/thread/__wait.c b/system/lib/libc/musl/src/thread/__wait.c index 59a8a6fc47320..265451dadb069 100644 --- a/system/lib/libc/musl/src/thread/__wait.c +++ b/system/lib/libc/musl/src/thread/__wait.c @@ -8,9 +8,9 @@ int _pthread_isduecanceled(struct pthread *pthread_ptr); void __wait(volatile int *addr, volatile int *waiters, int val, int priv) { - int spins=10000; - if (priv) priv = 128; priv=0; - while (spins--) { + int spins=100; + if (priv) priv = FUTEX_PRIVATE; + while (spins-- && (!waiters || !*waiters)) { if (*addr==val) a_spin(); else return; } @@ -39,7 +39,8 @@ void __wait(volatile int *addr, volatile int *waiters, int val, int priv) } #else while (*addr==val) { - __syscall(SYS_futex, addr, FUTEX_WAIT|priv, val, 0); + __syscall(SYS_futex, addr, FUTEX_WAIT|priv, val, 0) != -ENOSYS + || __syscall(SYS_futex, addr, FUTEX_WAIT, val, 0); } #endif if (waiters) a_dec(waiters); diff --git a/system/lib/libc/musl/src/thread/call_once.c b/system/lib/libc/musl/src/thread/call_once.c new file mode 100644 index 0000000000000..a7bc93532bc5e --- /dev/null +++ b/system/lib/libc/musl/src/thread/call_once.c @@ -0,0 +1,8 @@ +#include + +int __pthread_once(once_flag *, void (*)(void)); + +void call_once(once_flag *flag, void (*func)(void)) +{ + __pthread_once(flag, func); +} diff --git a/system/lib/libc/musl/src/thread/cnd_broadcast.c b/system/lib/libc/musl/src/thread/cnd_broadcast.c new file mode 100644 index 0000000000000..85d4d3ead318a --- /dev/null +++ b/system/lib/libc/musl/src/thread/cnd_broadcast.c @@ -0,0 +1,10 @@ +#include + +int __private_cond_signal(cnd_t *, int); + +int cnd_broadcast(cnd_t *c) +{ + /* This internal function never fails, and always returns zero, + * which matches the value thrd_success is defined with. */ + return __private_cond_signal(c, -1); +} diff --git a/system/lib/libc/musl/src/thread/cnd_destroy.c b/system/lib/libc/musl/src/thread/cnd_destroy.c new file mode 100644 index 0000000000000..453c90be51072 --- /dev/null +++ b/system/lib/libc/musl/src/thread/cnd_destroy.c @@ -0,0 +1,6 @@ +#include + +void cnd_destroy(cnd_t *c) +{ + /* For private cv this is a no-op */ +} diff --git a/system/lib/libc/musl/src/thread/cnd_init.c b/system/lib/libc/musl/src/thread/cnd_init.c new file mode 100644 index 0000000000000..18c508557f817 --- /dev/null +++ b/system/lib/libc/musl/src/thread/cnd_init.c @@ -0,0 +1,7 @@ +#include + +int cnd_init(cnd_t *c) +{ + *c = (cnd_t){ 0 }; + return thrd_success; +} diff --git a/system/lib/libc/musl/src/thread/cnd_signal.c b/system/lib/libc/musl/src/thread/cnd_signal.c new file mode 100644 index 0000000000000..1211260b4b895 --- /dev/null +++ b/system/lib/libc/musl/src/thread/cnd_signal.c @@ -0,0 +1,10 @@ +#include + +int __private_cond_signal(cnd_t *, int); + +int cnd_signal(cnd_t *c) +{ + /* This internal function never fails, and always returns zero, + * which matches the value thrd_success is defined with. */ + return __private_cond_signal(c, 1); +} diff --git a/system/lib/libc/musl/src/thread/cnd_timedwait.c b/system/lib/libc/musl/src/thread/cnd_timedwait.c new file mode 100644 index 0000000000000..599767937d052 --- /dev/null +++ b/system/lib/libc/musl/src/thread/cnd_timedwait.c @@ -0,0 +1,15 @@ +#include +#include + +int __pthread_cond_timedwait(cnd_t *restrict, mtx_t *restrict, const struct timespec *restrict); + +int cnd_timedwait(cnd_t *restrict c, mtx_t *restrict m, const struct timespec *restrict ts) +{ + int ret = __pthread_cond_timedwait(c, m, ts); + switch (ret) { + /* May also return EINVAL or EPERM. */ + default: return thrd_error; + case 0: return thrd_success; + case ETIMEDOUT: return thrd_timedout; + } +} diff --git a/system/lib/libc/musl/src/thread/cnd_wait.c b/system/lib/libc/musl/src/thread/cnd_wait.c new file mode 100644 index 0000000000000..602796f85b5c3 --- /dev/null +++ b/system/lib/libc/musl/src/thread/cnd_wait.c @@ -0,0 +1,9 @@ +#include + +int cnd_wait(cnd_t *c, mtx_t *m) +{ + /* Calling cnd_timedwait with a null pointer is an extension. + * It is convenient here to avoid duplication of the logic + * for return values. */ + return cnd_timedwait(c, m, 0); +} diff --git a/system/lib/libc/musl/src/thread/mtx_destroy.c b/system/lib/libc/musl/src/thread/mtx_destroy.c new file mode 100644 index 0000000000000..40a089998f6c8 --- /dev/null +++ b/system/lib/libc/musl/src/thread/mtx_destroy.c @@ -0,0 +1,5 @@ +#include + +void mtx_destroy(mtx_t *mtx) +{ +} diff --git a/system/lib/libc/musl/src/thread/mtx_init.c b/system/lib/libc/musl/src/thread/mtx_init.c new file mode 100644 index 0000000000000..4826f76b11a8b --- /dev/null +++ b/system/lib/libc/musl/src/thread/mtx_init.c @@ -0,0 +1,10 @@ +#include "pthread_impl.h" +#include + +int mtx_init(mtx_t *m, int type) +{ + *m = (mtx_t){ + ._m_type = ((type&mtx_recursive) ? PTHREAD_MUTEX_RECURSIVE : PTHREAD_MUTEX_NORMAL), + }; + return thrd_success; +} diff --git a/system/lib/libc/musl/src/thread/mtx_lock.c b/system/lib/libc/musl/src/thread/mtx_lock.c new file mode 100644 index 0000000000000..5c2415c1acdbc --- /dev/null +++ b/system/lib/libc/musl/src/thread/mtx_lock.c @@ -0,0 +1,12 @@ +#include "pthread_impl.h" +#include + +int mtx_lock(mtx_t *m) +{ + if (m->_m_type == PTHREAD_MUTEX_NORMAL && !a_cas(&m->_m_lock, 0, EBUSY)) + return thrd_success; + /* Calling mtx_timedlock with a null pointer is an extension. + * It is convenient, here to avoid duplication of the logic + * for return values. */ + return mtx_timedlock(m, 0); +} diff --git a/system/lib/libc/musl/src/thread/mtx_timedlock.c b/system/lib/libc/musl/src/thread/mtx_timedlock.c new file mode 100644 index 0000000000000..bcc152c564348 --- /dev/null +++ b/system/lib/libc/musl/src/thread/mtx_timedlock.c @@ -0,0 +1,14 @@ +#include +#include + +int __pthread_mutex_timedlock(mtx_t *restrict, const struct timespec *restrict); + +int mtx_timedlock(mtx_t *restrict m, const struct timespec *restrict ts) +{ + int ret = __pthread_mutex_timedlock(m, ts); + switch (ret) { + default: return thrd_error; + case 0: return thrd_success; + case ETIMEDOUT: return thrd_timedout; + } +} diff --git a/system/lib/libc/musl/src/thread/mtx_trylock.c b/system/lib/libc/musl/src/thread/mtx_trylock.c new file mode 100644 index 0000000000000..61e7694edcda2 --- /dev/null +++ b/system/lib/libc/musl/src/thread/mtx_trylock.c @@ -0,0 +1,17 @@ +#include "pthread_impl.h" +#include + +int __pthread_mutex_trylock(mtx_t *); + +int mtx_trylock(mtx_t *m) +{ + if (m->_m_type == PTHREAD_MUTEX_NORMAL) + return (a_cas(&m->_m_lock, 0, EBUSY) & EBUSY) ? thrd_busy : thrd_success; + + int ret = __pthread_mutex_trylock(m); + switch (ret) { + default: return thrd_error; + case 0: return thrd_success; + case EBUSY: return thrd_busy; + } +} diff --git a/system/lib/libc/musl/src/thread/mtx_unlock.c b/system/lib/libc/musl/src/thread/mtx_unlock.c new file mode 100644 index 0000000000000..5033ace7f3292 --- /dev/null +++ b/system/lib/libc/musl/src/thread/mtx_unlock.c @@ -0,0 +1,11 @@ +#include + +int __pthread_mutex_unlock(mtx_t *); + +int mtx_unlock(mtx_t *mtx) +{ + /* The only cases where pthread_mutex_unlock can return an + * error are undefined behavior for C11 mtx_unlock, so we can + * assume it does not return an error and simply tail call. */ + return __pthread_mutex_unlock(mtx); +} diff --git a/system/lib/libc/musl/src/thread/pthread_atfork.c b/system/lib/libc/musl/src/thread/pthread_atfork.c index 95fce20798e83..a40d7f6328707 100644 --- a/system/lib/libc/musl/src/thread/pthread_atfork.c +++ b/system/lib/libc/musl/src/thread/pthread_atfork.c @@ -8,7 +8,7 @@ static struct atfork_funcs { struct atfork_funcs *prev, *next; } *funcs; -static int lock[2]; +static volatile int lock[2]; void __fork_handler(int who) { diff --git a/system/lib/libc/musl/src/thread/pthread_attr_get.c b/system/lib/libc/musl/src/thread/pthread_attr_get.c index 3bba19afc8d61..e2a44d19843f1 100644 --- a/system/lib/libc/musl/src/thread/pthread_attr_get.c +++ b/system/lib/libc/musl/src/thread/pthread_attr_get.c @@ -79,7 +79,7 @@ int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *restrict a, int *re } int pthread_mutexattr_getpshared(const pthread_mutexattr_t *restrict a, int *restrict pshared) { - *pshared = a->__attr>>31; + *pshared = a->__attr / 128U % 2; return 0; } diff --git a/system/lib/libc/musl/src/thread/pthread_barrier_destroy.c b/system/lib/libc/musl/src/thread/pthread_barrier_destroy.c index e0da197a442d2..4ce0b2e127849 100644 --- a/system/lib/libc/musl/src/thread/pthread_barrier_destroy.c +++ b/system/lib/libc/musl/src/thread/pthread_barrier_destroy.c @@ -1,7 +1,5 @@ #include "pthread_impl.h" -void __vm_lock(int), __vm_unlock(void); - int pthread_barrier_destroy(pthread_barrier_t *b) { if (b->_b_limit < 0) { @@ -11,8 +9,7 @@ int pthread_barrier_destroy(pthread_barrier_t *b) while ((v = b->_b_lock) & INT_MAX) __wait(&b->_b_lock, 0, v, 0); } - __vm_lock(-1); - __vm_unlock(); + __vm_wait(); } return 0; } diff --git a/system/lib/libc/musl/src/thread/pthread_barrier_wait.c b/system/lib/libc/musl/src/thread/pthread_barrier_wait.c index 0018f637614c5..46b856619829a 100644 --- a/system/lib/libc/musl/src/thread/pthread_barrier_wait.c +++ b/system/lib/libc/musl/src/thread/pthread_barrier_wait.c @@ -4,9 +4,6 @@ #include "pthread_impl.h" -void __vm_lock_impl(int); -void __vm_unlock_impl(void); - static int pshared_barrier_wait(pthread_barrier_t *b) { int limit = (b->_b_limit & INT_MAX) + 1; @@ -30,7 +27,7 @@ static int pshared_barrier_wait(pthread_barrier_t *b) __wait(&b->_b_count, &b->_b_waiters2, v, 0); } - __vm_lock_impl(+1); + __vm_lock(); /* Ensure all threads have a vm lock before proceeding */ if (a_fetch_add(&b->_b_count, -1)==1-limit) { @@ -51,17 +48,17 @@ static int pshared_barrier_wait(pthread_barrier_t *b) if (v==INT_MIN+1 || (v==1 && w)) __wake(&b->_b_lock, 1, 0); - __vm_unlock_impl(); + __vm_unlock(); return ret; } struct instance { - int count; - int last; - int waiters; - int finished; + volatile int count; + volatile int last; + volatile int waiters; + volatile int finished; }; int pthread_barrier_wait(pthread_barrier_t *b) @@ -83,7 +80,7 @@ int pthread_barrier_wait(pthread_barrier_t *b) /* First thread to enter the barrier becomes the "instance owner" */ if (!inst) { struct instance new_inst = { 0 }; - int spins = 10000; + int spins = 200; b->_b_inst = inst = &new_inst; a_store(&b->_b_lock, 0); if (b->_b_waiters) __wake(&b->_b_lock, 1, 1); @@ -94,7 +91,8 @@ int pthread_barrier_wait(pthread_barrier_t *b) #ifdef __EMSCRIPTEN__ emscripten_futex_wait(&inst->finished, 1, INFINITY); #else - __syscall(SYS_futex, &inst->finished, FUTEX_WAIT,1,0); + __syscall(SYS_futex,&inst->finished,FUTEX_WAIT|128,1,0) != -ENOSYS + || __syscall(SYS_futex,&inst->finished,FUTEX_WAIT,1,0); #endif } return PTHREAD_BARRIER_SERIAL_THREAD; diff --git a/system/lib/libc/musl/src/thread/pthread_cancel.c b/system/lib/libc/musl/src/thread/pthread_cancel.c new file mode 100644 index 0000000000000..3d229223ed1b0 --- /dev/null +++ b/system/lib/libc/musl/src/thread/pthread_cancel.c @@ -0,0 +1,97 @@ +#define _GNU_SOURCE +#include +#include "pthread_impl.h" +#include "syscall.h" +#include "libc.h" + +__attribute__((__visibility__("hidden"))) +long __cancel(), __syscall_cp_asm(), __syscall_cp_c(); + +long __cancel() +{ + pthread_t self = __pthread_self(); + if (self->canceldisable == PTHREAD_CANCEL_ENABLE || self->cancelasync) + pthread_exit(PTHREAD_CANCELED); + self->canceldisable = PTHREAD_CANCEL_DISABLE; + return -ECANCELED; +} + +long __syscall_cp_asm(volatile void *, syscall_arg_t, + syscall_arg_t, syscall_arg_t, syscall_arg_t, + syscall_arg_t, syscall_arg_t, syscall_arg_t); + +long __syscall_cp_c(syscall_arg_t nr, + syscall_arg_t u, syscall_arg_t v, syscall_arg_t w, + syscall_arg_t x, syscall_arg_t y, syscall_arg_t z) +{ + pthread_t self; + long r; + int st; + + if ((st=(self=__pthread_self())->canceldisable) + && (st==PTHREAD_CANCEL_DISABLE || nr==SYS_close)) + return __syscall(nr, u, v, w, x, y, z); + + r = __syscall_cp_asm(&self->cancel, nr, u, v, w, x, y, z); + if (r==-EINTR && nr!=SYS_close && self->cancel && + self->canceldisable != PTHREAD_CANCEL_DISABLE) + r = __cancel(); + return r; +} + +static void _sigaddset(sigset_t *set, int sig) +{ + unsigned s = sig-1; + set->__bits[s/8/sizeof *set->__bits] |= 1UL<<(s&8*sizeof *set->__bits-1); +} + +__attribute__((__visibility__("hidden"))) +extern const char __cp_begin[1], __cp_end[1], __cp_cancel[1]; + +static void cancel_handler(int sig, siginfo_t *si, void *ctx) +{ + pthread_t self = __pthread_self(); + ucontext_t *uc = ctx; + uintptr_t pc = uc->uc_mcontext.MC_PC; + + a_barrier(); + if (!self->cancel || self->canceldisable == PTHREAD_CANCEL_DISABLE) return; + + _sigaddset(&uc->uc_sigmask, SIGCANCEL); + + if (self->cancelasync || pc >= (uintptr_t)__cp_begin && pc < (uintptr_t)__cp_end) { + uc->uc_mcontext.MC_PC = (uintptr_t)__cp_cancel; + return; + } + + __syscall(SYS_tkill, self->tid, SIGCANCEL); +} + +void __testcancel() +{ + pthread_t self = __pthread_self(); + if (self->cancel && !self->canceldisable) + __cancel(); +} + +static void init_cancellation() +{ + struct sigaction sa = { + .sa_flags = SA_SIGINFO | SA_RESTART, + .sa_sigaction = cancel_handler + }; + memset(&sa.sa_mask, -1, _NSIG/8); + __libc_sigaction(SIGCANCEL, &sa, 0); +} + +int pthread_cancel(pthread_t t) +{ + static int init; + if (!init) { + init_cancellation(); + init = 1; + } + a_store(&t->cancel, 1); + if (t == pthread_self() && !t->cancelasync) return 0; + return pthread_kill(t, SIGCANCEL); +} diff --git a/system/lib/libc/musl/src/thread/pthread_cleanup_push.c b/system/lib/libc/musl/src/thread/pthread_cleanup_push.c new file mode 100644 index 0000000000000..9b21764b56b0b --- /dev/null +++ b/system/lib/libc/musl/src/thread/pthread_cleanup_push.c @@ -0,0 +1,20 @@ +#include "pthread_impl.h" + +static void dummy(struct __ptcb *cb) +{ +} +weak_alias(dummy, __do_cleanup_push); +weak_alias(dummy, __do_cleanup_pop); + +void _pthread_cleanup_push(struct __ptcb *cb, void (*f)(void *), void *x) +{ + cb->__f = f; + cb->__x = x; + __do_cleanup_push(cb); +} + +void _pthread_cleanup_pop(struct __ptcb *cb, int run) +{ + __do_cleanup_pop(cb); + if (run) cb->__f(cb->__x); +} diff --git a/system/lib/libc/musl/src/thread/pthread_cond_broadcast.c b/system/lib/libc/musl/src/thread/pthread_cond_broadcast.c index e7c066729c261..69f840fb4faee 100644 --- a/system/lib/libc/musl/src/thread/pthread_cond_broadcast.c +++ b/system/lib/libc/musl/src/thread/pthread_cond_broadcast.c @@ -1,56 +1,12 @@ #include "pthread_impl.h" +int __private_cond_signal(pthread_cond_t *, int); + int pthread_cond_broadcast(pthread_cond_t *c) { - pthread_mutex_t *m; - + if (!c->_c_shared) return __private_cond_signal(c, -1); if (!c->_c_waiters) return 0; - a_inc(&c->_c_seq); - -#ifdef __EMSCRIPTEN__ - // XXX Emscripten: TODO: This is suboptimal but works naively correctly for now. The Emscripten-specific code path below - // has a bug and does not work for some reason. Figure it out and remove this code block. __wake(&c->_c_seq, -1, 0); - return 0; -#endif - - /* If cond var is process-shared, simply wake all waiters. */ - if (c->_c_mutex == (void *)-1) { - __wake(&c->_c_seq, -1, 0); - return 0; - } - - /* Block waiters from returning so we can use the mutex. */ - while (a_swap(&c->_c_lock, 1)) - __wait(&c->_c_lock, &c->_c_lockwait, 1, 1); - if (!c->_c_waiters) - goto out; - m = c->_c_mutex; - - /* Move waiter count to the mutex */ - a_fetch_add(&m->_m_waiters, c->_c_waiters2); - c->_c_waiters2 = 0; - -#ifdef __EMSCRIPTEN__ - int futexResult; - do { - // We want to wake one and requeue all others, without comparing the value, but SAB spec doesn't - // have requeue without comparing, so implement it by spinning instead. - futexResult = emscripten_futex_wake_or_requeue(&c->_c_seq, !m->_m_type || (m->_m_lock&INT_MAX)!=pthread_self()->tid, - &m->_m_lock, c->_c_seq); - } while(futexResult == -EAGAIN); -#else - /* Perform the futex requeue, waking one waiter unless we know - * that the calling thread holds the mutex. */ - __syscall(SYS_futex, &c->_c_seq, FUTEX_REQUEUE, - !m->_m_type || (m->_m_lock&INT_MAX)!=pthread_self()->tid, - INT_MAX, &m->_m_lock); -#endif - -out: - a_store(&c->_c_lock, 0); - if (c->_c_lockwait) __wake(&c->_c_lock, 1, 0); - return 0; } diff --git a/system/lib/libc/musl/src/thread/pthread_cond_destroy.c b/system/lib/libc/musl/src/thread/pthread_cond_destroy.c index a096c5547fdb0..8c5551600e8c3 100644 --- a/system/lib/libc/musl/src/thread/pthread_cond_destroy.c +++ b/system/lib/libc/musl/src/thread/pthread_cond_destroy.c @@ -2,12 +2,13 @@ int pthread_cond_destroy(pthread_cond_t *c) { - int priv = c->_c_mutex != (void *)-1; - int cnt; - c->_c_destroy = 1; - if (c->_c_waiters) - __wake(&c->_c_seq, -1, priv); - while ((cnt = c->_c_waiters)) - __wait(&c->_c_waiters, 0, cnt, priv); + if (c->_c_shared && c->_c_waiters) { + int cnt; + a_or(&c->_c_waiters, 0x80000000); + a_inc(&c->_c_seq); + __wake(&c->_c_seq, -1, 0); + while ((cnt = c->_c_waiters) & 0x7fffffff) + __wait(&c->_c_waiters, 0, cnt, 0); + } return 0; } diff --git a/system/lib/libc/musl/src/thread/pthread_cond_init.c b/system/lib/libc/musl/src/thread/pthread_cond_init.c index 357ecd55ea878..8c484ddcded2a 100644 --- a/system/lib/libc/musl/src/thread/pthread_cond_init.c +++ b/system/lib/libc/musl/src/thread/pthread_cond_init.c @@ -5,7 +5,7 @@ int pthread_cond_init(pthread_cond_t *restrict c, const pthread_condattr_t *rest *c = (pthread_cond_t){0}; if (a) { c->_c_clock = a->__attr & 0x7fffffff; - if (a->__attr>>31) c->_c_mutex = (void *)-1; + if (a->__attr>>31) c->_c_shared = (void *)-1; } return 0; } diff --git a/system/lib/libc/musl/src/thread/pthread_cond_signal.c b/system/lib/libc/musl/src/thread/pthread_cond_signal.c index 71bcdcd99332f..119c00abcd990 100644 --- a/system/lib/libc/musl/src/thread/pthread_cond_signal.c +++ b/system/lib/libc/musl/src/thread/pthread_cond_signal.c @@ -1,9 +1,12 @@ #include "pthread_impl.h" +int __private_cond_signal(pthread_cond_t *, int); + int pthread_cond_signal(pthread_cond_t *c) { + if (!c->_c_shared) return __private_cond_signal(c, 1); if (!c->_c_waiters) return 0; a_inc(&c->_c_seq); - if (c->_c_waiters) __wake(&c->_c_seq, 1, 0); + __wake(&c->_c_seq, 1, 0); return 0; } diff --git a/system/lib/libc/musl/src/thread/pthread_cond_timedwait.c b/system/lib/libc/musl/src/thread/pthread_cond_timedwait.c index 16152e357d30a..9feb9b22e2f51 100644 --- a/system/lib/libc/musl/src/thread/pthread_cond_timedwait.c +++ b/system/lib/libc/musl/src/thread/pthread_cond_timedwait.c @@ -1,78 +1,184 @@ #include "pthread_impl.h" -struct cm { - pthread_cond_t *c; - pthread_mutex_t *m; +void __pthread_testcancel(void); +int __pthread_mutex_lock(pthread_mutex_t *); +int __pthread_mutex_unlock(pthread_mutex_t *); +int __pthread_setcancelstate(int, int *); + +/* + * struct waiter + * + * Waiter objects have automatic storage on the waiting thread, and + * are used in building a linked list representing waiters currently + * waiting on the condition variable or a group of waiters woken + * together by a broadcast or signal; in the case of signal, this is a + * degenerate list of one member. + * + * Waiter lists attached to the condition variable itself are + * protected by the lock on the cv. Detached waiter lists are never + * modified again, but can only be traversed in reverse order, and are + * protected by the "barrier" locks in each node, which are unlocked + * in turn to control wake order. + * + * Since process-shared cond var semantics do not necessarily allow + * one thread to see another's automatic storage (they may be in + * different processes), the waiter list is not used for the + * process-shared case, but the structure is still used to store data + * needed by the cancellation cleanup handler. + */ + +struct waiter { + struct waiter *prev, *next; + volatile int state, barrier; + volatile int *notify; }; -static void unwait(pthread_cond_t *c, pthread_mutex_t *m) -{ - /* Removing a waiter is non-trivial if we could be using requeue - * based broadcast signals, due to mutex access issues, etc. */ +/* Self-synchronized-destruction-safe lock functions */ - if (c->_c_mutex == (void *)-1) { - a_dec(&c->_c_waiters); - if (c->_c_destroy) __wake(&c->_c_waiters, 1, 0); - return; +static inline void lock(volatile int *l) +{ + if (a_cas(l, 0, 1)) { + a_cas(l, 1, 2); + do __wait(l, 0, 2, 1); + while (a_cas(l, 0, 2)); } +} - while (a_swap(&c->_c_lock, 1)) - __wait(&c->_c_lock, &c->_c_lockwait, 1, 1); - - if (c->_c_waiters2) c->_c_waiters2--; - else a_dec(&m->_m_waiters); - - a_store(&c->_c_lock, 0); - if (c->_c_lockwait) __wake(&c->_c_lock, 1, 1); - - a_dec(&c->_c_waiters); - if (c->_c_destroy) __wake(&c->_c_waiters, 1, 1); +static inline void unlock(volatile int *l) +{ + if (a_swap(l, 0)==2) + __wake(l, 1, 1); } -static void cleanup(void *p) +static inline void unlock_requeue(volatile int *l, volatile int *r, int w) { - struct cm *cm = p; - unwait(cm->c, cm->m); - pthread_mutex_lock(cm->m); + a_store(l, 0); +#ifdef __EMSCRIPTEN__ + int futexResult; + do { + // We want to wake one and requeue all others, without comparing the value, but SAB spec doesn't + // have requeue without comparing, so implement it by spinning instead. + futexResult = emscripten_futex_wake_or_requeue(l, 0, r, *l); + } while(futexResult == -EAGAIN); +#else + if (w) __wake(l, 1, 1); + else __syscall(SYS_futex, l, FUTEX_REQUEUE|128, 0, 1, r) != -ENOSYS + || __syscall(SYS_futex, l, FUTEX_REQUEUE, 0, 1, r); +#endif } -int pthread_cond_timedwait(pthread_cond_t *restrict c, pthread_mutex_t *restrict m, const struct timespec *restrict ts) +enum { + WAITING, + SIGNALED, + LEAVING, +}; + +int __pthread_cond_timedwait(pthread_cond_t *restrict c, pthread_mutex_t *restrict m, const struct timespec *restrict ts) { - struct cm cm = { .c=c, .m=m }; - int r, e=0, seq; + struct waiter node = { 0 }; + int e, seq, clock = c->_c_clock, cs, shared=0, oldstate, tmp; + volatile int *fut; - if (m->_m_type && (m->_m_lock&INT_MAX) != pthread_self()->tid) + if ((m->_m_type&15) && (m->_m_lock&INT_MAX) != __pthread_self()->tid) return EPERM; if (ts && ts->tv_nsec >= 1000000000UL) return EINVAL; - pthread_testcancel(); + __pthread_testcancel(); + + if (c->_c_shared) { + shared = 1; + fut = &c->_c_seq; + seq = c->_c_seq; + a_inc(&c->_c_waiters); + } else { + lock(&c->_c_lock); + + seq = node.barrier = 2; + fut = &node.barrier; + node.state = WAITING; + node.next = c->_c_head; + c->_c_head = &node; + if (!c->_c_tail) c->_c_tail = &node; + else node.next->prev = &node; + + unlock(&c->_c_lock); + } - a_inc(&c->_c_waiters); + __pthread_mutex_unlock(m); - if (c->_c_mutex != (void *)-1) { - c->_c_mutex = m; - while (a_swap(&c->_c_lock, 1)) - __wait(&c->_c_lock, &c->_c_lockwait, 1, 1); - c->_c_waiters2++; - a_store(&c->_c_lock, 0); - if (c->_c_lockwait) __wake(&c->_c_lock, 1, 1); - } + __pthread_setcancelstate(PTHREAD_CANCEL_MASKED, &cs); + if (cs == PTHREAD_CANCEL_DISABLE) __pthread_setcancelstate(cs, 0); - seq = c->_c_seq; + do e = __timedwait_cp(fut, seq, clock, ts, !shared); + while (*fut==seq && (!e || e==EINTR)); + if (e == EINTR) e = 0; - pthread_mutex_unlock(m); + if (shared) { + /* Suppress cancellation if a signal was potentially + * consumed; this is a legitimate form of spurious + * wake even if not. */ + if (e == ECANCELED && c->_c_seq != seq) e = 0; + if (a_fetch_add(&c->_c_waiters, -1) == -0x7fffffff) + __wake(&c->_c_waiters, 1, 0); + oldstate = WAITING; + goto relock; + } - do { - e = __timedwait(&c->_c_seq, seq, c->_c_clock, ts, cleanup, &cm, 0); + oldstate = a_cas(&node.state, WAITING, LEAVING); + + if (oldstate == WAITING) { + /* Access to cv object is valid because this waiter was not + * yet signaled and a new signal/broadcast cannot return + * after seeing a LEAVING waiter without getting notified + * via the futex notify below. */ + + lock(&c->_c_lock); + + if (c->_c_head == &node) c->_c_head = node.next; + else if (node.prev) node.prev->next = node.next; + if (c->_c_tail == &node) c->_c_tail = node.prev; + else if (node.next) node.next->prev = node.prev; + + unlock(&c->_c_lock); + + if (node.notify) { + if (a_fetch_add(node.notify, -1)==1) + __wake(node.notify, 1, 1); + } + } else { + /* Lock barrier first to control wake order. */ + lock(&node.barrier); } - while (c->_c_seq == seq && (!e || e==EINTR)); - if (e == EINTR) e = 0; - unwait(c, m); +relock: + /* Errors locking the mutex override any existing error or + * cancellation, since the caller must see them to know the + * state of the mutex. */ + if ((tmp = pthread_mutex_lock(m))) e = tmp; + + if (oldstate == WAITING) goto done; + + if (!node.next) a_inc(&m->_m_waiters); + + /* Unlock the barrier that's holding back the next waiter, and + * either wake it or requeue it to the mutex. */ + if (node.prev) + unlock_requeue(&node.prev->barrier, &m->_m_lock, m->_m_type & 128); + else + a_dec(&m->_m_waiters); - if ((r=pthread_mutex_lock(m))) return r; + /* Since a signal was consumed, cancellation is not permitted. */ + if (e == ECANCELED) e = 0; + +done: + __pthread_setcancelstate(cs, 0); + + if (e == ECANCELED) { + __pthread_testcancel(); + __pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0); + } #ifdef __EMSCRIPTEN__ pthread_testcancel(); @@ -80,3 +186,42 @@ int pthread_cond_timedwait(pthread_cond_t *restrict c, pthread_mutex_t *restrict return e; } + +int __private_cond_signal(pthread_cond_t *c, int n) +{ + struct waiter *p, *first=0; + volatile int ref = 0; + int cur; + + lock(&c->_c_lock); + for (p=c->_c_tail; n && p; p=p->prev) { + if (a_cas(&p->state, WAITING, SIGNALED) != WAITING) { + ref++; + p->notify = &ref; + } else { + n--; + if (!first) first=p; + } + } + /* Split the list, leaving any remainder on the cv. */ + if (p) { + if (p->next) p->next->prev = 0; + p->next = 0; + } else { + c->_c_head = 0; + } + c->_c_tail = p; + unlock(&c->_c_lock); + + /* Wait for any waiters in the LEAVING state to remove + * themselves from the list before returning or allowing + * signaled threads to proceed. */ + while ((cur = ref)) __wait(&ref, 0, cur, 1); + + /* Allow first signaled waiter, if any, to proceed. */ + if (first) unlock(&first->barrier); + + return 0; +} + +weak_alias(__pthread_cond_timedwait, pthread_cond_timedwait); diff --git a/system/lib/libc/musl/src/thread/pthread_create.c b/system/lib/libc/musl/src/thread/pthread_create.c index f1d286be92b7b..9f6b98e609863 100644 --- a/system/lib/libc/musl/src/thread/pthread_create.c +++ b/system/lib/libc/musl/src/thread/pthread_create.c @@ -4,6 +4,11 @@ #include "libc.h" #include #include +#include + +void *__mmap(void *, size_t, int, int, int, off_t); +int __munmap(void *, size_t); +int __mprotect(void *, size_t, int); static void dummy_0() { @@ -11,12 +16,16 @@ static void dummy_0() weak_alias(dummy_0, __acquire_ptc); weak_alias(dummy_0, __release_ptc); weak_alias(dummy_0, __pthread_tsd_run_dtors); +weak_alias(dummy_0, __do_orphaned_stdio_locks); +weak_alias(dummy_0, __dl_thread_cleanup); -_Noreturn void pthread_exit(void *result) +_Noreturn void __pthread_exit(void *result) { - pthread_t self = pthread_self(); + pthread_t self = __pthread_self(); sigset_t set; + self->canceldisable = 1; + self->cancelasync = 0; self->result = result; while (self->cancelbuf) { @@ -58,6 +67,28 @@ _Noreturn void pthread_exit(void *result) exit(0); } + /* Process robust list in userspace to handle non-pshared mutexes + * and the detached thread case where the robust list head will + * be invalid when the kernel would process it. */ + __vm_lock(); + volatile void *volatile *rp; + while ((rp=self->robust_list.head) && rp != &self->robust_list.head) { + pthread_mutex_t *m = (void *)((char *)rp + - offsetof(pthread_mutex_t, _m_next)); + int waiters = m->_m_waiters; + int priv = (m->_m_type & 128) ^ 128; + self->robust_list.pending = rp; + self->robust_list.head = *rp; + int cont = a_swap(&m->_m_lock, 0x40000000); + self->robust_list.pending = 0; + if (cont < 0 || waiters) + __wake(&m->_m_lock, 1, priv); + } + __vm_unlock(); + + __do_orphaned_stdio_locks(); + __dl_thread_cleanup(); + if (self->detached && self->map_base) { /* Detached threads must avoid the kernel clear_child_tid * feature, since the virtual address will have been @@ -68,6 +99,15 @@ _Noreturn void pthread_exit(void *result) * detached later (== 2), we need to clear it here. */ if (self->detached == 2) __syscall(SYS_set_tid_address, 0); + /* Robust list will no longer be valid, and was already + * processed above, so unregister it with the kernel. */ + if (self->robust_list.off) + __syscall(SYS_set_robust_list, 0, 3*sizeof(long)); + + /* Since __unmapself bypasses the normal munmap code path, + * explicitly wait for vmlock holders first. */ + __vm_wait(); + /* The following call unmaps the thread's stack mapping * and then exits without touching the stack. */ __unmapself(self->map_base, self->map_size); @@ -78,7 +118,7 @@ _Noreturn void pthread_exit(void *result) void __do_cleanup_push(struct __ptcb *cb) { - struct pthread *self = pthread_self(); + struct pthread *self = __pthread_self(); cb->__next = self->cancelbuf; self->cancelbuf = cb; } @@ -102,7 +142,15 @@ static int start(void *p) if (self->unblock_cancel) __syscall(SYS_rt_sigprocmask, SIG_UNBLOCK, SIGPT_SET, 0, _NSIG/8); - pthread_exit(self->start(self->start_arg)); + __pthread_exit(self->start(self->start_arg)); + return 0; +} + +static int start_c11(void *p) +{ + pthread_t self = p; + int (*start)(void*) = (int(*)(void*)) self->start; + __pthread_exit((void *)(uintptr_t)start(self->start_arg)); return 0; } @@ -114,6 +162,8 @@ weak_alias(dummy, __pthread_tsd_size); static void *dummy_tsd[1] = { 0 }; weak_alias(dummy_tsd, __pthread_tsd_main); +volatile int __block_new_threads = 0; + static FILE *volatile dummy_file = 0; weak_alias(dummy_file, __stdin_used); weak_alias(dummy_file, __stdout_used); @@ -126,11 +176,11 @@ static void init_file_lock(FILE *f) void *__copy_tls(unsigned char *); -int pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp, void *(*entry)(void *), void *restrict arg) +int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp, void *(*entry)(void *), void *restrict arg) { - int ret; + int ret, c11 = (attrp == __ATTRP_C11_THREAD); size_t size, guard; - struct pthread *self = pthread_self(), *new; + struct pthread *self, *new; unsigned char *map = 0, *stack = 0, *tsd = 0, *stack_limit; unsigned flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM | CLONE_SETTLS @@ -138,18 +188,23 @@ int pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp int do_sched = 0; pthread_attr_t attr = {0}; - if (!self) return ENOSYS; + if (!libc.can_do_threads) return ENOSYS; + self = __pthread_self(); if (!libc.threaded) { - for (FILE *f=libc.ofl_head; f; f=f->next) + for (FILE *f=*__ofl_lock(); f; f=f->next) init_file_lock(f); + __ofl_unlock(); init_file_lock(__stdin_used); init_file_lock(__stdout_used); init_file_lock(__stderr_used); + __syscall(SYS_rt_sigprocmask, SIG_UNBLOCK, SIGPT_SET, 0, _NSIG/8); + self->tsd = (void **)__pthread_tsd_main; libc.threaded = 1; } - if (attrp) attr = *attrp; + if (attrp && !c11) attr = *attrp; __acquire_ptc(); + if (__block_new_threads) __wait(&__block_new_threads, 0, 1, 1); if (attr._a_stackaddr) { size_t need = libc.tls_size + __pthread_tsd_size; @@ -175,14 +230,15 @@ int pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp if (!tsd) { if (guard) { - map = mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANON, -1, 0); + map = __mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANON, -1, 0); if (map == MAP_FAILED) goto fail; - if (mprotect(map+guard, size-guard, PROT_READ|PROT_WRITE)) { - munmap(map, size); + if (__mprotect(map+guard, size-guard, PROT_READ|PROT_WRITE) + && errno != ENOSYS) { + __munmap(map, size); goto fail; } } else { - map = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); + map = __mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); if (map == MAP_FAILED) goto fail; } tsd = map + size - __pthread_tsd_size; @@ -197,12 +253,11 @@ int pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp new->map_size = size; new->stack = stack; new->stack_size = stack - stack_limit; - new->pid = self->pid; - new->errno_ptr = &new->errno_val; new->start = entry; new->start_arg = arg; new->self = new; new->tsd = (void *)tsd; + new->locale = &libc.global_locale; if (attr._a_detach) { new->detached = 1; flags -= CLONE_CHILD_CLEARTID; @@ -211,11 +266,12 @@ int pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp do_sched = new->startlock[0] = 1; __block_app_sigs(new->sigmask); } + new->robust_list.head = &new->robust_list.head; new->unblock_cancel = self->cancel; - new->canary = self->canary; + new->CANARY = self->CANARY; a_inc(&libc.threads_minus_1); - ret = __clone(start, stack, flags, new, &new->tid, TP_ADJ(new), &new->tid); + ret = __clone((c11 ? start_c11 : start), stack, flags, new, &new->tid, TP_ADJ(new), &new->tid); __release_ptc(); @@ -225,7 +281,7 @@ int pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp if (ret < 0) { a_dec(&libc.threads_minus_1); - if (map) munmap(map, size); + if (map) __munmap(map, size); return EAGAIN; } @@ -243,3 +299,6 @@ int pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp __release_ptc(); return EAGAIN; } + +weak_alias(__pthread_exit, pthread_exit); +weak_alias(__pthread_create, pthread_create); diff --git a/system/lib/libc/musl/src/thread/pthread_detach.c b/system/lib/libc/musl/src/thread/pthread_detach.c index 651c38ebe86cc..ed77f74d520bf 100644 --- a/system/lib/libc/musl/src/thread/pthread_detach.c +++ b/system/lib/libc/musl/src/thread/pthread_detach.c @@ -1,11 +1,17 @@ #include "pthread_impl.h" +#include -int pthread_detach(pthread_t t) +int __pthread_join(pthread_t, void **); + +static int __pthread_detach(pthread_t t) { /* Cannot detach a thread that's already exiting */ if (a_swap(t->exitlock, 1)) - return pthread_join(t, 0); + return __pthread_join(t, 0); t->detached = 2; __unlock(t->exitlock); return 0; } + +weak_alias(__pthread_detach, pthread_detach); +weak_alias(__pthread_detach, thrd_detach); diff --git a/system/lib/libc/musl/src/thread/pthread_equal.c b/system/lib/libc/musl/src/thread/pthread_equal.c index 3e3df4fda37db..7c31482af3f8f 100644 --- a/system/lib/libc/musl/src/thread/pthread_equal.c +++ b/system/lib/libc/musl/src/thread/pthread_equal.c @@ -1,6 +1,11 @@ #include +#include +#include "libc.h" -int (pthread_equal)(pthread_t a, pthread_t b) +static int __pthread_equal(pthread_t a, pthread_t b) { return a==b; } + +weak_alias(__pthread_equal, pthread_equal); +weak_alias(__pthread_equal, thrd_equal); diff --git a/system/lib/libc/musl/src/thread/pthread_getspecific.c b/system/lib/libc/musl/src/thread/pthread_getspecific.c index b2a282c6e966c..d9342a560f7bc 100644 --- a/system/lib/libc/musl/src/thread/pthread_getspecific.c +++ b/system/lib/libc/musl/src/thread/pthread_getspecific.c @@ -1,7 +1,11 @@ #include "pthread_impl.h" +#include -void *pthread_getspecific(pthread_key_t k) +static void *__pthread_getspecific(pthread_key_t k) { struct pthread *self = __pthread_self(); return self->tsd[k]; } + +weak_alias(__pthread_getspecific, pthread_getspecific); +weak_alias(__pthread_getspecific, tss_get); diff --git a/system/lib/libc/musl/src/thread/pthread_join.c b/system/lib/libc/musl/src/thread/pthread_join.c index 719c91ca24f7b..52111489540ed 100644 --- a/system/lib/libc/musl/src/thread/pthread_join.c +++ b/system/lib/libc/musl/src/thread/pthread_join.c @@ -1,15 +1,36 @@ #include "pthread_impl.h" #include -static void dummy(void *p) -{ -} +int __munmap(void *, size_t); +void __pthread_testcancel(void); +int __pthread_setcancelstate(int, int *); -int pthread_join(pthread_t t, void **res) +int __pthread_timedjoin_np(pthread_t t, void **res, const struct timespec *at) { - int tmp; - while ((tmp = t->tid)) __timedwait(&t->tid, tmp, 0, 0, dummy, 0, 0); + int tmp, cs, r = 0; + __pthread_testcancel(); + __pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + if (cs == PTHREAD_CANCEL_ENABLE) __pthread_setcancelstate(cs, 0); + while ((tmp = t->tid) && r != ETIMEDOUT && r != EINVAL) + r = __timedwait_cp(&t->tid, tmp, CLOCK_REALTIME, at, 0); + __pthread_setcancelstate(cs, 0); + if (r == ETIMEDOUT || r == EINVAL) return r; + a_barrier(); if (res) *res = t->result; - if (t->map_base) munmap(t->map_base, t->map_size); + if (t->map_base) __munmap(t->map_base, t->map_size); return 0; } + +int __pthread_join(pthread_t t, void **res) +{ + return __pthread_timedjoin_np(t, res, 0); +} + +int __pthread_tryjoin_np(pthread_t t, void **res) +{ + return t->tid ? EBUSY : __pthread_join(t, res); +} + +weak_alias(__pthread_tryjoin_np, pthread_tryjoin_np); +weak_alias(__pthread_timedjoin_np, pthread_timedjoin_np); +weak_alias(__pthread_join, pthread_join); diff --git a/system/lib/libc/musl/src/thread/pthread_key_create.c b/system/lib/libc/musl/src/thread/pthread_key_create.c index 8acf51350f45b..e77deb1a3917b 100644 --- a/system/lib/libc/musl/src/thread/pthread_key_create.c +++ b/system/lib/libc/musl/src/thread/pthread_key_create.c @@ -7,20 +7,22 @@ volatile size_t __pthread_tsd_size = sizeof(void *) * PTHREAD_KEYS_MAX; void *__pthread_tsd_main[PTHREAD_KEYS_MAX] = { 0 }; -static void (*keys[PTHREAD_KEYS_MAX])(void *); +static void (*volatile keys[PTHREAD_KEYS_MAX])(void *); static void nodtor(void *dummy) { } -int pthread_key_create(pthread_key_t *k, void (*dtor)(void *)) +int __pthread_key_create(pthread_key_t *k, void (*dtor)(void *)) { unsigned i = (uintptr_t)&k / 16 % PTHREAD_KEYS_MAX; unsigned j = i; + pthread_t self = __pthread_self(); + + /* This can only happen in the main thread before + * pthread_create has been called. */ + if (!self->tsd) self->tsd = __pthread_tsd_main; -#ifndef __EMSCRIPTEN__ // XXX Emscripten does not need specific initialization for threads, the runtime has initialized everything prior to running. - __pthread_self_init(); -#endif if (!dtor) dtor = nodtor; do { if (!a_cas_p(keys+j, 0, (void *)dtor)) { @@ -31,7 +33,7 @@ int pthread_key_create(pthread_key_t *k, void (*dtor)(void *)) return EAGAIN; } -int pthread_key_delete(pthread_key_t k) +int __pthread_key_delete(pthread_key_t k) { keys[k] = 0; return 0; @@ -43,7 +45,7 @@ void EMSCRIPTEN_KEEPALIVE __pthread_tsd_run_dtors() void __pthread_tsd_run_dtors() #endif { - pthread_t self = pthread_self(); + pthread_t self = __pthread_self(); int i, j, not_finished = self->tsd_used; for (j=0; not_finished && jkilllock); - r = t->dead ? ESRCH : -__syscall(SYS_tgkill, t->pid, t->tid, sig); + r = t->dead ? ESRCH : -__syscall(SYS_tkill, t->tid, sig); __unlock(t->killlock); return r; } diff --git a/system/lib/libc/musl/src/thread/pthread_mutex_consistent.c b/system/lib/libc/musl/src/thread/pthread_mutex_consistent.c index 7dfb904f99a2d..96b83b52851b2 100644 --- a/system/lib/libc/musl/src/thread/pthread_mutex_consistent.c +++ b/system/lib/libc/musl/src/thread/pthread_mutex_consistent.c @@ -2,9 +2,9 @@ int pthread_mutex_consistent(pthread_mutex_t *m) { - if (m->_m_type < 8) return EINVAL; - if ((m->_m_lock & 0x3fffffff) != pthread_self()->tid) + if (!(m->_m_type & 8)) return EINVAL; + if ((m->_m_lock & 0x7fffffff) != __pthread_self()->tid) return EPERM; - m->_m_type -= 8; + m->_m_type &= ~8U; return 0; } diff --git a/system/lib/libc/musl/src/thread/pthread_mutex_init.c b/system/lib/libc/musl/src/thread/pthread_mutex_init.c index 9d85a35479461..acf45a74687bc 100644 --- a/system/lib/libc/musl/src/thread/pthread_mutex_init.c +++ b/system/lib/libc/musl/src/thread/pthread_mutex_init.c @@ -3,6 +3,6 @@ int pthread_mutex_init(pthread_mutex_t *restrict m, const pthread_mutexattr_t *restrict a) { *m = (pthread_mutex_t){0}; - if (a) m->_m_type = a->__attr & 7; + if (a) m->_m_type = a->__attr; return 0; } diff --git a/system/lib/libc/musl/src/thread/pthread_mutex_lock.c b/system/lib/libc/musl/src/thread/pthread_mutex_lock.c index 42b5af640c3f7..d0c93cab50119 100644 --- a/system/lib/libc/musl/src/thread/pthread_mutex_lock.c +++ b/system/lib/libc/musl/src/thread/pthread_mutex_lock.c @@ -1,9 +1,14 @@ #include "pthread_impl.h" -int pthread_mutex_lock(pthread_mutex_t *m) +int __pthread_mutex_timedlock(pthread_mutex_t *restrict, const struct timespec *restrict); + +int __pthread_mutex_lock(pthread_mutex_t *m) { - if (m->_m_type == PTHREAD_MUTEX_NORMAL && !a_cas(&m->_m_lock, 0, EBUSY)) + if ((m->_m_type&15) == PTHREAD_MUTEX_NORMAL + && !a_cas(&m->_m_lock, 0, EBUSY)) return 0; - return pthread_mutex_timedlock(m, 0); + return __pthread_mutex_timedlock(m, 0); } + +weak_alias(__pthread_mutex_lock, pthread_mutex_lock); diff --git a/system/lib/libc/musl/src/thread/pthread_mutex_timedlock.c b/system/lib/libc/musl/src/thread/pthread_mutex_timedlock.c index c24270d8f54ee..0a240e7913418 100644 --- a/system/lib/libc/musl/src/thread/pthread_mutex_timedlock.c +++ b/system/lib/libc/musl/src/thread/pthread_mutex_timedlock.c @@ -1,24 +1,34 @@ #include "pthread_impl.h" -int pthread_mutex_timedlock(pthread_mutex_t *restrict m, const struct timespec *restrict at) +int __pthread_mutex_timedlock(pthread_mutex_t *restrict m, const struct timespec *restrict at) { - int r, t; - - if (m->_m_type == PTHREAD_MUTEX_NORMAL && !a_cas(&m->_m_lock, 0, EBUSY)) + if ((m->_m_type&15) == PTHREAD_MUTEX_NORMAL + && !a_cas(&m->_m_lock, 0, EBUSY)) return 0; + int r, t, priv = (m->_m_type & 128) ^ 128; + + r = pthread_mutex_trylock(m); + if (r != EBUSY) return r; + + int spins = 100; + while (spins-- && m->_m_lock && !m->_m_waiters) a_spin(); + while ((r=pthread_mutex_trylock(m)) == EBUSY) { - if (!(r=m->_m_lock) || (r&0x40000000)) continue; + if (!(r=m->_m_lock) || ((r&0x40000000) && (m->_m_type&4))) + continue; if ((m->_m_type&3) == PTHREAD_MUTEX_ERRORCHECK - && (r&0x1fffffff) == pthread_self()->tid) + && (r&0x7fffffff) == __pthread_self()->tid) return EDEADLK; a_inc(&m->_m_waiters); t = r | 0x80000000; a_cas(&m->_m_lock, r, t); - r = __timedwait(&m->_m_lock, t, CLOCK_REALTIME, at, 0, 0, 0); + r = __timedwait(&m->_m_lock, t, CLOCK_REALTIME, at, priv); a_dec(&m->_m_waiters); if (r && r != EINTR) break; } return r; } + +weak_alias(__pthread_mutex_timedlock, pthread_mutex_timedlock); diff --git a/system/lib/libc/musl/src/thread/pthread_mutex_trylock.c b/system/lib/libc/musl/src/thread/pthread_mutex_trylock.c index 1cf3cb9ba1b02..fa530915aeeb2 100644 --- a/system/lib/libc/musl/src/thread/pthread_mutex_trylock.c +++ b/system/lib/libc/musl/src/thread/pthread_mutex_trylock.c @@ -1,54 +1,60 @@ #include "pthread_impl.h" -int pthread_mutex_trylock(pthread_mutex_t *m) +int __pthread_mutex_trylock_owner(pthread_mutex_t *m) { - int tid, old, own; - pthread_t self; - - if (m->_m_type == PTHREAD_MUTEX_NORMAL) - return a_cas(&m->_m_lock, 0, EBUSY) & EBUSY; - - self = pthread_self(); - tid = self->tid; - - if (m->_m_type >= 4) { -#ifndef __EMSCRIPTEN__ // XXX Emscripten does not have a concept of multiple processes or kernel space, so robust mutex lists don't need to register to kernel. - if (!self->robust_list.off) - __syscall(SYS_set_robust_list, - &self->robust_list, 3*sizeof(long)); -#endif - self->robust_list.off = (char*)&m->_m_lock-(char *)&m->_m_next; - self->robust_list.pending = &m->_m_next; - } + int old, own; + int type = m->_m_type & 15; + pthread_t self = __pthread_self(); + int tid = self->tid; old = m->_m_lock; own = old & 0x7fffffff; - if (own == tid && (m->_m_type&3) == PTHREAD_MUTEX_RECURSIVE) { + if (own == tid && (type&3) == PTHREAD_MUTEX_RECURSIVE) { if ((unsigned)m->_m_count >= INT_MAX) return EAGAIN; m->_m_count++; return 0; } + if (own == 0x7fffffff) return ENOTRECOVERABLE; - if ((own && !(own & 0x40000000)) || a_cas(&m->_m_lock, old, tid)!=old) - return EBUSY; - - if (m->_m_type < 4) return 0; + if (m->_m_type & 128) { + if (!self->robust_list.off) { + self->robust_list.off = (char*)&m->_m_lock-(char *)&m->_m_next; +#ifndef __EMSCRIPTEN__ // XXX Emscripten does not have a concept of multiple processes or kernel space, so robust mutex lists don't need to register to kernel. + __syscall(SYS_set_robust_list, &self->robust_list, 3*sizeof(long)); +#endif + } + if (m->_m_waiters) tid |= 0x80000000; + self->robust_list.pending = &m->_m_next; + } - if (m->_m_type >= 8) { - m->_m_lock = 0; - return ENOTRECOVERABLE; + if ((own && (!(own & 0x40000000) || !(type & 4))) + || a_cas(&m->_m_lock, old, tid) != old) { + self->robust_list.pending = 0; + return EBUSY; } - m->_m_next = self->robust_list.head; + + volatile void *next = self->robust_list.head; + m->_m_next = next; m->_m_prev = &self->robust_list.head; - if (self->robust_list.head) - self->robust_list.head[-1] = &m->_m_next; + if (next != &self->robust_list.head) *(volatile void *volatile *) + ((char *)next - sizeof(void *)) = &m->_m_next; self->robust_list.head = &m->_m_next; self->robust_list.pending = 0; + if (own) { m->_m_count = 0; - m->_m_type += 8; + m->_m_type |= 8; return EOWNERDEAD; } return 0; } + +int __pthread_mutex_trylock(pthread_mutex_t *m) +{ + if ((m->_m_type&15) == PTHREAD_MUTEX_NORMAL) + return a_cas(&m->_m_lock, 0, EBUSY) & EBUSY; + return __pthread_mutex_trylock_owner(m); +} + +weak_alias(__pthread_mutex_trylock, pthread_mutex_trylock); diff --git a/system/lib/libc/musl/src/thread/pthread_mutex_unlock.c b/system/lib/libc/musl/src/thread/pthread_mutex_unlock.c index 5fc0f4e56be4d..7dd00d275b6dd 100644 --- a/system/lib/libc/musl/src/thread/pthread_mutex_unlock.c +++ b/system/lib/libc/musl/src/thread/pthread_mutex_unlock.c @@ -1,37 +1,37 @@ #include "pthread_impl.h" -void __vm_lock_impl(int); -void __vm_unlock_impl(void); - -int pthread_mutex_unlock(pthread_mutex_t *m) +int __pthread_mutex_unlock(pthread_mutex_t *m) { pthread_t self; int waiters = m->_m_waiters; int cont; - int robust = 0; + int type = m->_m_type & 15; + int priv = (m->_m_type & 128) ^ 128; - if (m->_m_type != PTHREAD_MUTEX_NORMAL) { - if (!m->_m_lock) - return EPERM; - self = pthread_self(); - if ((m->_m_lock&0x1fffffff) != self->tid) + if (type != PTHREAD_MUTEX_NORMAL) { + self = __pthread_self(); + if ((m->_m_lock&0x7fffffff) != self->tid) return EPERM; - if ((m->_m_type&3) == PTHREAD_MUTEX_RECURSIVE && m->_m_count) + if ((type&3) == PTHREAD_MUTEX_RECURSIVE && m->_m_count) return m->_m_count--, 0; - if (m->_m_type >= 4) { - robust = 1; + if (!priv) { self->robust_list.pending = &m->_m_next; - *(void **)m->_m_prev = m->_m_next; - if (m->_m_next) ((void **)m->_m_next)[-1] = m->_m_prev; - __vm_lock_impl(+1); + __vm_lock(); } + volatile void *prev = m->_m_prev; + volatile void *next = m->_m_next; + *(volatile void *volatile *)prev = next; + if (next != &self->robust_list.head) *(volatile void *volatile *) + ((char *)next - sizeof(void *)) = prev; } - cont = a_swap(&m->_m_lock, 0); - if (robust) { + cont = a_swap(&m->_m_lock, (type & 8) ? 0x7fffffff : 0); + if (type != PTHREAD_MUTEX_NORMAL && !priv) { self->robust_list.pending = 0; - __vm_unlock_impl(); + __vm_unlock(); } if (waiters || cont<0) - __wake(&m->_m_lock, 1, 0); + __wake(&m->_m_lock, 1, priv); return 0; } + +weak_alias(__pthread_mutex_unlock, pthread_mutex_unlock); diff --git a/system/lib/libc/musl/src/thread/pthread_mutexattr_setpshared.c b/system/lib/libc/musl/src/thread/pthread_mutexattr_setpshared.c index 8c7a1e26b8943..100f6ff203f1b 100644 --- a/system/lib/libc/musl/src/thread/pthread_mutexattr_setpshared.c +++ b/system/lib/libc/musl/src/thread/pthread_mutexattr_setpshared.c @@ -3,7 +3,7 @@ int pthread_mutexattr_setpshared(pthread_mutexattr_t *a, int pshared) { if (pshared > 1U) return EINVAL; - a->__attr &= 0x7fffffff; - a->__attr |= pshared<<31; + a->__attr &= ~128U; + a->__attr |= pshared<<7; return 0; } diff --git a/system/lib/libc/musl/src/thread/pthread_once.c b/system/lib/libc/musl/src/thread/pthread_once.c index 7b9ccf252de67..a8f8aeb17a039 100644 --- a/system/lib/libc/musl/src/thread/pthread_once.c +++ b/system/lib/libc/musl/src/thread/pthread_once.c @@ -2,26 +2,19 @@ static void undo(void *control) { - a_store(control, 0); - __wake(control, 1, 0); + /* Wake all waiters, since the waiter status is lost when + * resetting control to the initial state. */ + if (a_swap(control, 0) == 3) + __wake(control, -1, 1); } -int pthread_once(pthread_once_t *control, void (*init)(void)) +int __pthread_once_full(pthread_once_t *control, void (*init)(void)) { - static int waiters; - - /* Return immediately if init finished before, but ensure that - * effects of the init routine are visible to the caller. */ - if (*control == 2) { - /* Otherwise-useless cas just to get a barrier. */ - a_cas(&(int){0},0,0); - return 0; - } - - /* Try to enter initializing state. Three possibilities: + /* Try to enter initializing state. Four possibilities: * 0 - we're the first or the other cancelled; run init * 1 - another thread is running init; wait - * 2 - another thread finished running init; just return */ + * 2 - another thread finished running init; just return + * 3 - another thread is running init, waiters present; wait */ for (;;) switch (a_cas(control, 0, 1)) { case 0: @@ -29,13 +22,29 @@ int pthread_once(pthread_once_t *control, void (*init)(void)) init(); pthread_cleanup_pop(0); - a_store(control, 2); - if (waiters) __wake(control, -1, 0); + if (a_swap(control, 2) == 3) + __wake(control, -1, 1); return 0; case 1: - __wait(control, &waiters, 1, 0); + /* If this fails, so will __wait. */ + a_cas(control, 1, 3); + case 3: + __wait(control, 0, 3, 1); continue; case 2: return 0; } } + +int __pthread_once(pthread_once_t *control, void (*init)(void)) +{ + /* Return immediately if init finished before, but ensure that + * effects of the init routine are visible to the caller. */ + if (*(volatile int *)control == 2) { + a_barrier(); + return 0; + } + return __pthread_once_full(control, init); +} + +weak_alias(__pthread_once, pthread_once); diff --git a/system/lib/libc/musl/src/thread/pthread_rwlock_init.c b/system/lib/libc/musl/src/thread/pthread_rwlock_init.c index 82df52e25b4df..a2c0b478c78cf 100644 --- a/system/lib/libc/musl/src/thread/pthread_rwlock_init.c +++ b/system/lib/libc/musl/src/thread/pthread_rwlock_init.c @@ -3,7 +3,6 @@ int pthread_rwlock_init(pthread_rwlock_t *restrict rw, const pthread_rwlockattr_t *restrict a) { *rw = (pthread_rwlock_t){0}; - if (a) { - } + if (a) rw->_rw_shared = a->__attr[0]*128; return 0; } diff --git a/system/lib/libc/musl/src/thread/pthread_rwlock_timedrdlock.c b/system/lib/libc/musl/src/thread/pthread_rwlock_timedrdlock.c index c0c94c9750579..0d5d0d6c05fe8 100644 --- a/system/lib/libc/musl/src/thread/pthread_rwlock_timedrdlock.c +++ b/system/lib/libc/musl/src/thread/pthread_rwlock_timedrdlock.c @@ -3,12 +3,19 @@ int pthread_rwlock_timedrdlock(pthread_rwlock_t *restrict rw, const struct timespec *restrict at) { int r, t; + + r = pthread_rwlock_tryrdlock(rw); + if (r != EBUSY) return r; + + int spins = 100; + while (spins-- && rw->_rw_lock && !rw->_rw_waiters) a_spin(); + while ((r=pthread_rwlock_tryrdlock(rw))==EBUSY) { if (!(r=rw->_rw_lock) || (r&0x7fffffff)!=0x7fffffff) continue; t = r | 0x80000000; a_inc(&rw->_rw_waiters); a_cas(&rw->_rw_lock, r, t); - r = __timedwait(&rw->_rw_lock, t, CLOCK_REALTIME, at, 0, 0, 0); + r = __timedwait(&rw->_rw_lock, t, CLOCK_REALTIME, at, rw->_rw_shared^128); a_dec(&rw->_rw_waiters); if (r && r != EINTR) return r; } diff --git a/system/lib/libc/musl/src/thread/pthread_rwlock_timedwrlock.c b/system/lib/libc/musl/src/thread/pthread_rwlock_timedwrlock.c index 5434f575d9c6f..e1d6162f3b1d6 100644 --- a/system/lib/libc/musl/src/thread/pthread_rwlock_timedwrlock.c +++ b/system/lib/libc/musl/src/thread/pthread_rwlock_timedwrlock.c @@ -8,12 +8,19 @@ int pthread_rwlock_timedwrlock(pthread_rwlock_t *restrict rw, const struct times if (rw->_rw_wr_owner == (int)pthread_self()) return EDEADLK; #endif int r, t; + + r = pthread_rwlock_trywrlock(rw); + if (r != EBUSY) return r; + + int spins = 100; + while (spins-- && rw->_rw_lock && !rw->_rw_waiters) a_spin(); + while ((r=pthread_rwlock_trywrlock(rw))==EBUSY) { if (!(r=rw->_rw_lock)) continue; t = r | 0x80000000; a_inc(&rw->_rw_waiters); a_cas(&rw->_rw_lock, r, t); - r = __timedwait(&rw->_rw_lock, t, CLOCK_REALTIME, at, 0, 0, 0); + r = __timedwait(&rw->_rw_lock, t, CLOCK_REALTIME, at, rw->_rw_shared^128); a_dec(&rw->_rw_waiters); if (r && r != EINTR) return r; } diff --git a/system/lib/libc/musl/src/thread/pthread_rwlock_unlock.c b/system/lib/libc/musl/src/thread/pthread_rwlock_unlock.c index 97e6a79bbc61a..61d5e38646255 100644 --- a/system/lib/libc/musl/src/thread/pthread_rwlock_unlock.c +++ b/system/lib/libc/musl/src/thread/pthread_rwlock_unlock.c @@ -2,7 +2,7 @@ int pthread_rwlock_unlock(pthread_rwlock_t *rw) { - int val, cnt, waiters, new; + int val, cnt, waiters, new, priv = rw->_rw_shared^128; #ifdef __EMSCRIPTEN__ /// XXX Emscripten: The spec allows detecting when multiple write locks would deadlock, which we do here to avoid hangs. @@ -18,7 +18,7 @@ int pthread_rwlock_unlock(pthread_rwlock_t *rw) } while (a_cas(&rw->_rw_lock, val, new) != val); if (!new && (waiters || val<0)) - __wake(&rw->_rw_lock, cnt, 0); + __wake(&rw->_rw_lock, cnt, priv); return 0; } diff --git a/system/lib/libc/musl/src/thread/pthread_self.c b/system/lib/libc/musl/src/thread/pthread_self.c index aed4b5f1ba1a7..241a6202d2ea5 100644 --- a/system/lib/libc/musl/src/thread/pthread_self.c +++ b/system/lib/libc/musl/src/thread/pthread_self.c @@ -1,45 +1,11 @@ #include "pthread_impl.h" +#include +#include "libc.h" -static struct pthread *main_thread = &(struct pthread){0}; - -/* pthread_key_create.c overrides this */ -static const void *dummy[1] = { 0 }; -weak_alias(dummy, __pthread_tsd_main); - -static int init_main_thread() -{ - __syscall(SYS_rt_sigprocmask, SIG_UNBLOCK, - SIGPT_SET, 0, _NSIG/8); - if (__set_thread_area(TP_ADJ(main_thread)) < 0) return -1; - main_thread->canceldisable = libc.canceldisable; - main_thread->tsd = (void **)__pthread_tsd_main; - main_thread->errno_ptr = __errno_location(); - main_thread->self = main_thread; - main_thread->tid = main_thread->pid = - __syscall(SYS_set_tid_address, &main_thread->tid); - if (!main_thread->dtv) - main_thread->dtv = (void *)dummy; - libc.main_thread = main_thread; - return 0; -} - -pthread_t __pthread_self_def() +static pthread_t __pthread_self_internal() { - static int init, failed; - if (!init) { - if (failed) return 0; - if (init_main_thread() < 0) failed = 1; - if (failed) return 0; - init = 1; - } return __pthread_self(); } -weak_alias(__pthread_self_def, pthread_self); -weak_alias(__pthread_self_def, __pthread_self_init); - -void *__install_initial_tls(void *p) -{ - main_thread = p; - return __pthread_self_def(); -} +weak_alias(__pthread_self_internal, pthread_self); +weak_alias(__pthread_self_internal, thrd_current); diff --git a/system/lib/libc/musl/src/thread/pthread_setcancelstate.c b/system/lib/libc/musl/src/thread/pthread_setcancelstate.c index ba2b231190436..5ab8c338f7969 100644 --- a/system/lib/libc/musl/src/thread/pthread_setcancelstate.c +++ b/system/lib/libc/musl/src/thread/pthread_setcancelstate.c @@ -1,15 +1,12 @@ #include "pthread_impl.h" -int pthread_setcancelstate(int new, int *old) +int __pthread_setcancelstate(int new, int *old) { - if (new > 1U) return EINVAL; - if (libc.main_thread) { - struct pthread *self = __pthread_self(); - if (old) *old = self->canceldisable; - self->canceldisable = new; - } else { - if (old) *old = libc.canceldisable; - libc.canceldisable = new; - } + if (new > 2U) return EINVAL; + struct pthread *self = __pthread_self(); + if (old) *old = self->canceldisable; + self->canceldisable = new; return 0; } + +weak_alias(__pthread_setcancelstate, pthread_setcancelstate); diff --git a/system/lib/libc/musl/src/thread/pthread_setcanceltype.c b/system/lib/libc/musl/src/thread/pthread_setcanceltype.c index ce2fff0735690..bf0a3f383dd34 100644 --- a/system/lib/libc/musl/src/thread/pthread_setcanceltype.c +++ b/system/lib/libc/musl/src/thread/pthread_setcanceltype.c @@ -2,7 +2,7 @@ int pthread_setcanceltype(int new, int *old) { - struct pthread *self = pthread_self(); + struct pthread *self = __pthread_self(); if (new > 1U) return EINVAL; if (old) *old = self->cancelasync; self->cancelasync = new; diff --git a/system/lib/libc/musl/src/thread/pthread_spin_lock.c b/system/lib/libc/musl/src/thread/pthread_spin_lock.c index df575f0858681..ded2b653c4751 100644 --- a/system/lib/libc/musl/src/thread/pthread_spin_lock.c +++ b/system/lib/libc/musl/src/thread/pthread_spin_lock.c @@ -1,7 +1,8 @@ #include "pthread_impl.h" +#include int pthread_spin_lock(pthread_spinlock_t *s) { - while (a_swap(s, 1)) a_spin(); + while (*(volatile int *)s || a_cas(s, 0, EBUSY)) a_spin(); return 0; } diff --git a/system/lib/libc/musl/src/thread/pthread_spin_trylock.c b/system/lib/libc/musl/src/thread/pthread_spin_trylock.c index 59de695ddad9e..5284fdac24d4a 100644 --- a/system/lib/libc/musl/src/thread/pthread_spin_trylock.c +++ b/system/lib/libc/musl/src/thread/pthread_spin_trylock.c @@ -1,6 +1,7 @@ #include "pthread_impl.h" +#include int pthread_spin_trylock(pthread_spinlock_t *s) { - return -a_swap(s, 1) & EBUSY; + return a_cas(s, 0, EBUSY); } diff --git a/system/lib/libc/musl/src/thread/pthread_testcancel.c b/system/lib/libc/musl/src/thread/pthread_testcancel.c index 33238c0f70c5a..ee48e6d8af6dc 100644 --- a/system/lib/libc/musl/src/thread/pthread_testcancel.c +++ b/system/lib/libc/musl/src/thread/pthread_testcancel.c @@ -1,8 +1,15 @@ #include "pthread_impl.h" +#include "libc.h" -void __testcancel(void); +static void dummy() +{ +} -void pthread_testcancel() +weak_alias(dummy, __testcancel); + +void __pthread_testcancel() { __testcancel(); } + +weak_alias(__pthread_testcancel, pthread_testcancel); diff --git a/system/lib/libc/musl/src/thread/sem_init.c b/system/lib/libc/musl/src/thread/sem_init.c index e8e419cf74976..55092434386f8 100644 --- a/system/lib/libc/musl/src/thread/sem_init.c +++ b/system/lib/libc/musl/src/thread/sem_init.c @@ -10,5 +10,6 @@ int sem_init(sem_t *sem, int pshared, unsigned value) } sem->__val[0] = value; sem->__val[1] = 0; + sem->__val[2] = pshared ? 0 : 128; return 0; } diff --git a/system/lib/libc/musl/src/thread/sem_open.c b/system/lib/libc/musl/src/thread/sem_open.c index 9a95d25717209..fda0acd35c717 100644 --- a/system/lib/libc/musl/src/thread/sem_open.c +++ b/system/lib/libc/musl/src/thread/sem_open.c @@ -20,7 +20,7 @@ static struct { sem_t *sem; int refcnt; } *semtab; -static int lock[2]; +static volatile int lock[2]; #define FLAGS (O_RDWR|O_NOFOLLOW|O_CLOEXEC|O_NONBLOCK) @@ -126,6 +126,7 @@ sem_t *sem_open(const char *name, int flags, ...) e = link(tmp, name) ? errno : 0; unlink(tmp); if (!e) break; + munmap(map, sizeof(sem_t)); /* Failure is only fatal when doing an exclusive open; * otherwise, next iteration will try to open the * existing file. */ diff --git a/system/lib/libc/musl/src/thread/sem_post.c b/system/lib/libc/musl/src/thread/sem_post.c index 14a2dfe23ca09..31e3293d20504 100644 --- a/system/lib/libc/musl/src/thread/sem_post.c +++ b/system/lib/libc/musl/src/thread/sem_post.c @@ -3,7 +3,7 @@ int sem_post(sem_t *sem) { - int val, waiters; + int val, waiters, priv = sem->__val[2]; do { val = sem->__val[0]; waiters = sem->__val[1]; @@ -12,6 +12,6 @@ int sem_post(sem_t *sem) return -1; } } while (a_cas(sem->__val, val, val+1+(val<0)) != val); - if (val<0 || waiters) __wake(sem->__val, 1, 0); + if (val<0 || waiters) __wake(sem->__val, 1, priv); return 0; } diff --git a/system/lib/libc/musl/src/thread/sem_timedwait.c b/system/lib/libc/musl/src/thread/sem_timedwait.c index 768b5f5f32948..9782e6ab5eac0 100644 --- a/system/lib/libc/musl/src/thread/sem_timedwait.c +++ b/system/lib/libc/musl/src/thread/sem_timedwait.c @@ -8,16 +8,24 @@ static void cleanup(void *p) int sem_timedwait(sem_t *restrict sem, const struct timespec *restrict at) { + pthread_testcancel(); + + if (!sem_trywait(sem)) return 0; + + int spins = 100; + while (spins-- && sem->__val[0] <= 0 && !sem->__val[1]) a_spin(); + while (sem_trywait(sem)) { int r; a_inc(sem->__val+1); a_cas(sem->__val, 0, -1); - r = __timedwait(sem->__val, -1, CLOCK_REALTIME, at, cleanup, sem->__val+1, 0); + pthread_cleanup_push(cleanup, (void *)(sem->__val+1)); + r = __timedwait_cp(sem->__val, -1, CLOCK_REALTIME, at, sem->__val[2]); + pthread_cleanup_pop(1); + if (r && r != EINTR) { #ifdef __EMSCRIPTEN__ - if (r == ECANCELED) r = EINTR; + if (r == ECANCELED) r = EINTR; #endif - a_dec(sem->__val+1); - if (r) { errno = r; return -1; } diff --git a/system/lib/libc/musl/src/thread/synccall.c b/system/lib/libc/musl/src/thread/synccall.c index a21578dc5745c..000ec4e353a47 100644 --- a/system/lib/libc/musl/src/thread/synccall.c +++ b/system/lib/libc/musl/src/thread/synccall.c @@ -1,90 +1,178 @@ #include "pthread_impl.h" #include +#include +#include +#include +#include +#include "futex.h" +#include "atomic.h" +#include "../dirent/__dirent.h" static struct chain { struct chain *next; - sem_t sem, sem2; -} *head, *cur; + int tid; + sem_t target_sem, caller_sem; +} *volatile head; +static volatile int synccall_lock[2]; +static volatile int target_tid; static void (*callback)(void *), *context; -static int chainlen; -static sem_t chainlock, chaindone; +static volatile int dummy = 0; +weak_alias(dummy, __block_new_threads); -static void handler(int sig, siginfo_t *si, void *ctx) +static void handler(int sig) { struct chain ch; - pthread_t self = __pthread_self(); int old_errno = errno; - if (chainlen == libc.threads_minus_1) return; + sem_init(&ch.target_sem, 0, 0); + sem_init(&ch.caller_sem, 0, 0); - sigqueue(self->pid, SIGSYNCCALL, (union sigval){0}); + ch.tid = __syscall(SYS_gettid); - sem_init(&ch.sem, 0, 0); - sem_init(&ch.sem2, 0, 0); + do ch.next = head; + while (a_cas_p(&head, ch.next, &ch) != ch.next); - while (sem_wait(&chainlock)); - ch.next = head; - head = &ch; - if (++chainlen == libc.threads_minus_1) sem_post(&chaindone); - sem_post(&chainlock); + if (a_cas(&target_tid, ch.tid, 0) == (ch.tid | 0x80000000)) + __syscall(SYS_futex, &target_tid, FUTEX_UNLOCK_PI|FUTEX_PRIVATE); - while (sem_wait(&ch.sem)); + sem_wait(&ch.target_sem); callback(context); - sem_post(&ch.sem2); - while (sem_wait(&ch.sem)); + sem_post(&ch.caller_sem); + sem_wait(&ch.target_sem); errno = old_errno; } void __synccall(void (*func)(void *), void *ctx) { - pthread_t self; - struct sigaction sa; - struct chain *next; sigset_t oldmask; + int cs, i, r, pid, self;; + DIR dir = {0}; + struct dirent *de; + struct sigaction sa = { .sa_flags = 0, .sa_handler = handler }; + struct chain *cp, *next; + struct timespec ts; + + /* Blocking signals in two steps, first only app-level signals + * before taking the lock, then all signals after taking the lock, + * is necessary to achieve AS-safety. Blocking them all first would + * deadlock if multiple threads called __synccall. Waiting to block + * any until after the lock would allow re-entry in the same thread + * with the lock already held. */ + __block_app_sigs(&oldmask); + LOCK(synccall_lock); + __block_all_sigs(0); + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); - if (!libc.threads_minus_1) { - func(ctx); - return; - } - - __inhibit_ptc(); + head = 0; - __block_all_sigs(&oldmask); + if (!libc.threaded) goto single_threaded; - sem_init(&chaindone, 0, 0); - sem_init(&chainlock, 0, 1); - chainlen = 0; - head = 0; callback = func; context = ctx; - sa.sa_flags = SA_SIGINFO | SA_RESTART; - sa.sa_sigaction = handler; - sigfillset(&sa.sa_mask); + /* This atomic store ensures that any signaled threads will see the + * above stores, and prevents more than a bounded number of threads, + * those already in pthread_create, from creating new threads until + * the value is cleared to zero again. */ + a_store(&__block_new_threads, 1); + + /* Block even implementation-internal signals, so that nothing + * interrupts the SIGSYNCCALL handlers. The main possible source + * of trouble is asynchronous cancellation. */ + memset(&sa.sa_mask, -1, sizeof sa.sa_mask); __libc_sigaction(SIGSYNCCALL, &sa, 0); - self = __pthread_self(); - sigqueue(self->pid, SIGSYNCCALL, (union sigval){0}); - while (sem_wait(&chaindone)); + pid = __syscall(SYS_getpid); + self = __syscall(SYS_gettid); + + /* Since opendir is not AS-safe, the DIR needs to be setup manually + * in automatic storage. Thankfully this is easy. */ + dir.fd = open("/proc/self/task", O_RDONLY|O_DIRECTORY|O_CLOEXEC); + if (dir.fd < 0) goto out; + + /* Initially send one signal per counted thread. But since we can't + * synchronize with thread creation/exit here, there could be too + * few signals. This initial signaling is just an optimization, not + * part of the logic. */ + for (i=libc.threads_minus_1; i; i--) + __syscall(SYS_kill, pid, SIGSYNCCALL); + + /* Loop scanning the kernel-provided thread list until it shows no + * threads that have not already replied to the signal. */ + for (;;) { + int miss_cnt = 0; + while ((de = readdir(&dir))) { + if (!isdigit(de->d_name[0])) continue; + int tid = atoi(de->d_name); + if (tid == self || !tid) continue; + + /* Set the target thread as the PI futex owner before + * checking if it's in the list of caught threads. If it + * adds itself to the list after we check for it, then + * it will see its own tid in the PI futex and perform + * the unlock operation. */ + a_store(&target_tid, tid); + + /* Thread-already-caught is a success condition. */ + for (cp = head; cp && cp->tid != tid; cp=cp->next); + if (cp) continue; + + r = -__syscall(SYS_tgkill, pid, tid, SIGSYNCCALL); + + /* Target thread exit is a success condition. */ + if (r == ESRCH) continue; + + /* The FUTEX_LOCK_PI operation is used to loan priority + * to the target thread, which otherwise may be unable + * to run. Timeout is necessary because there is a race + * condition where the tid may be reused by a different + * process. */ + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_nsec += 10000000; + if (ts.tv_nsec >= 1000000000) { + ts.tv_sec++; + ts.tv_nsec -= 1000000000; + } + r = -__syscall(SYS_futex, &target_tid, + FUTEX_LOCK_PI|FUTEX_PRIVATE, 0, &ts); + + /* Obtaining the lock means the thread responded. ESRCH + * means the target thread exited, which is okay too. */ + if (!r || r == ESRCH) continue; + + miss_cnt++; + } + if (!miss_cnt) break; + rewinddir(&dir); + } + close(dir.fd); + + /* Serialize execution of callback in caught threads. */ + for (cp=head; cp; cp=cp->next) { + sem_post(&cp->target_sem); + sem_wait(&cp->caller_sem); + } - sa.sa_flags = 0; sa.sa_handler = SIG_IGN; __libc_sigaction(SIGSYNCCALL, &sa, 0); - for (cur=head; cur; cur=cur->next) { - sem_post(&cur->sem); - while (sem_wait(&cur->sem2)); - } +single_threaded: func(ctx); - for (cur=head; cur; cur=next) { - next = cur->next; - sem_post(&cur->sem); + /* Only release the caught threads once all threads, including the + * caller, have returned from the callback function. */ + for (cp=head; cp; cp=next) { + next = cp->next; + sem_post(&cp->target_sem); } - __restore_sigs(&oldmask); +out: + a_store(&__block_new_threads, 0); + __wake(&__block_new_threads, -1, 1); - __release_ptc(); + pthread_setcancelstate(cs, 0); + UNLOCK(synccall_lock); + __restore_sigs(&oldmask); } diff --git a/system/lib/libc/musl/src/thread/thrd_create.c b/system/lib/libc/musl/src/thread/thrd_create.c new file mode 100644 index 0000000000000..e033669526571 --- /dev/null +++ b/system/lib/libc/musl/src/thread/thrd_create.c @@ -0,0 +1,14 @@ +#include "pthread_impl.h" +#include + +int __pthread_create(pthread_t *restrict, const pthread_attr_t *restrict, void *(*)(void *), void *restrict); + +int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) +{ + int ret = __pthread_create(thr, __ATTRP_C11_THREAD, (void *(*)(void *))func, arg); + switch (ret) { + case 0: return thrd_success; + case EAGAIN: return thrd_nomem; + default: return thrd_error; + } +} diff --git a/system/lib/libc/musl/src/thread/thrd_exit.c b/system/lib/libc/musl/src/thread/thrd_exit.c new file mode 100644 index 0000000000000..b66bd99695ca6 --- /dev/null +++ b/system/lib/libc/musl/src/thread/thrd_exit.c @@ -0,0 +1,9 @@ +#include "pthread_impl.h" +#include + +_Noreturn void __pthread_exit(void *); + +_Noreturn void thrd_exit(int result) +{ + __pthread_exit((void*)(intptr_t)result); +} diff --git a/system/lib/libc/musl/src/thread/thrd_join.c b/system/lib/libc/musl/src/thread/thrd_join.c new file mode 100644 index 0000000000000..ac6678939f6b3 --- /dev/null +++ b/system/lib/libc/musl/src/thread/thrd_join.c @@ -0,0 +1,12 @@ +#include +#include + +int __pthread_join(thrd_t, void**); + +int thrd_join(thrd_t t, int *res) +{ + void *pthread_res; + __pthread_join(t, &pthread_res); + if (res) *res = (int)(intptr_t)pthread_res; + return thrd_success; +} diff --git a/system/lib/libc/musl/src/thread/thrd_sleep.c b/system/lib/libc/musl/src/thread/thrd_sleep.c new file mode 100644 index 0000000000000..e8dfe400cb701 --- /dev/null +++ b/system/lib/libc/musl/src/thread/thrd_sleep.c @@ -0,0 +1,13 @@ +#include +#include +#include "syscall.h" + +int thrd_sleep(const struct timespec *req, struct timespec *rem) +{ + int ret = __syscall(SYS_nanosleep, req, rem); + switch (ret) { + case 0: return 0; + case -EINTR: return -1; /* value specified by C11 */ + default: return -2; + } +} diff --git a/system/lib/libc/musl/src/thread/thrd_yield.c b/system/lib/libc/musl/src/thread/thrd_yield.c new file mode 100644 index 0000000000000..f7ad13219ce0d --- /dev/null +++ b/system/lib/libc/musl/src/thread/thrd_yield.c @@ -0,0 +1,7 @@ +#include +#include "syscall.h" + +void thrd_yield() +{ + __syscall(SYS_sched_yield); +} diff --git a/system/lib/libc/musl/src/thread/tss_create.c b/system/lib/libc/musl/src/thread/tss_create.c new file mode 100644 index 0000000000000..251d22b9abe52 --- /dev/null +++ b/system/lib/libc/musl/src/thread/tss_create.c @@ -0,0 +1,11 @@ +#include + +int __pthread_key_create(tss_t *, void (*)(void *)); + +int tss_create(tss_t *tss, tss_dtor_t dtor) +{ + /* Different error returns are possible. C glues them together into + * just failure notification. Can't be optimized to a tail call, + * unless thrd_error equals EAGAIN. */ + return __pthread_key_create(tss, dtor) ? thrd_error : thrd_success; +} diff --git a/system/lib/libc/musl/src/thread/tss_delete.c b/system/lib/libc/musl/src/thread/tss_delete.c new file mode 100644 index 0000000000000..35db1032dc4aa --- /dev/null +++ b/system/lib/libc/musl/src/thread/tss_delete.c @@ -0,0 +1,8 @@ +#include + +int __pthread_key_delete(tss_t k); + +void tss_delete(tss_t key) +{ + __pthread_key_delete(key); +} diff --git a/system/lib/libc/musl/src/thread/tss_set.c b/system/lib/libc/musl/src/thread/tss_set.c new file mode 100644 index 0000000000000..70c4fb723cf68 --- /dev/null +++ b/system/lib/libc/musl/src/thread/tss_set.c @@ -0,0 +1,13 @@ +#include "pthread_impl.h" +#include + +int tss_set(tss_t k, void *x) +{ + struct pthread *self = __pthread_self(); + /* Avoid unnecessary COW */ + if (self->tsd[k] != x) { + self->tsd[k] = x; + self->tsd_used = 1; + } + return thrd_success; +} diff --git a/system/lib/libc/musl/src/thread/vmlock.c b/system/lib/libc/musl/src/thread/vmlock.c index aba9e31147de3..75f3cb76190fe 100644 --- a/system/lib/libc/musl/src/thread/vmlock.c +++ b/system/lib/libc/musl/src/thread/vmlock.c @@ -1,22 +1,21 @@ #include "pthread_impl.h" -static int vmlock[2]; +static volatile int vmlock[2]; -void __vm_lock(int inc) +void __vm_wait() { - for (;;) { - int v = vmlock[0]; - if (inc*v < 0) __wait(vmlock, vmlock+1, v, 1); - else if (a_cas(vmlock, v, v+inc)==v) break; - } + int tmp; + while ((tmp=vmlock[0])) + __wait(vmlock, vmlock+1, tmp, 1); } -void __vm_unlock(void) +void __vm_lock() { - int inc = vmlock[0]>0 ? -1 : 1; - if (a_fetch_add(vmlock, inc)==-inc && vmlock[1]) - __wake(vmlock, -1, 1); + a_inc(vmlock); } -weak_alias(__vm_lock, __vm_lock_impl); -weak_alias(__vm_unlock, __vm_unlock_impl); +void __vm_unlock() +{ + if (a_fetch_add(vmlock, -1)==1 && vmlock[1]) + __wake(vmlock, -1, 1); +} diff --git a/system/lib/libc/musl/src/time/__map_file.c b/system/lib/libc/musl/src/time/__map_file.c index 84ae839f5e1d6..b91eb8edb9864 100644 --- a/system/lib/libc/musl/src/time/__map_file.c +++ b/system/lib/libc/musl/src/time/__map_file.c @@ -9,12 +9,12 @@ const char unsigned *__map_file(const char *pathname, size_t *size) { struct stat st; const unsigned char *map = MAP_FAILED; - int flags = O_RDONLY|O_LARGEFILE|O_CLOEXEC|O_NONBLOCK; - int fd = __syscall(SYS_open, pathname, flags); + int fd = __sys_open(pathname, O_RDONLY|O_CLOEXEC|O_NONBLOCK); if (fd < 0) return 0; - if (!__syscall(SYS_fstat, fd, &st)) + if (!__syscall(SYS_fstat, fd, &st)) { map = __mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + *size = st.st_size; + } __syscall(SYS_close, fd); - *size = st.st_size; return map == MAP_FAILED ? 0 : map; } diff --git a/system/lib/libc/musl/src/time/__secs_to_tm.c b/system/lib/libc/musl/src/time/__secs_to_tm.c index f3c1cf923e8c5..3a3123a1b457b 100644 --- a/system/lib/libc/musl/src/time/__secs_to_tm.c +++ b/system/lib/libc/musl/src/time/__secs_to_tm.c @@ -10,10 +10,10 @@ int __secs_to_tm(long long t, struct tm *tm) { - long long days, secs; + long long days, secs, years; int remdays, remsecs, remyears; int qc_cycles, c_cycles, q_cycles; - int years, months; + int months; int wday, yday, leap; static const char days_in_month[] = {31,30,31,30,31,31,30,31,30,31,31,29}; @@ -55,7 +55,7 @@ int __secs_to_tm(long long t, struct tm *tm) yday = remdays + 31 + 28 + leap; if (yday >= 365+leap) yday -= 365+leap; - years = remyears + 4*q_cycles + 100*c_cycles + 400*qc_cycles; + years = remyears + 4*q_cycles + 100*c_cycles + 400LL*qc_cycles; for (months=0; days_in_month[months] <= remdays; months++) remdays -= days_in_month[months]; diff --git a/system/lib/libc/musl/src/time/__tz.c b/system/lib/libc/musl/src/time/__tz.c index 17d1adff09323..8b84b9bd12cf9 100644 --- a/system/lib/libc/musl/src/time/__tz.c +++ b/system/lib/libc/musl/src/time/__tz.c @@ -27,7 +27,7 @@ static char old_tz_buf[32]; static char *old_tz = old_tz_buf; static size_t old_tz_size = sizeof old_tz_buf; -static int lock[2]; +static volatile int lock[2]; static int getint(const char **p) { @@ -118,14 +118,15 @@ int __munmap(void *, size_t); static void do_tzset() { char buf[NAME_MAX+25], *pathname=buf+24; - const char *try, *s; + const char *try, *s, *p; const unsigned char *map = 0; size_t i; static const char search[] = "/usr/share/zoneinfo/\0/share/zoneinfo/\0/etc/zoneinfo/\0"; s = getenv("TZ"); - if (!s || !*s) s = __gmt; + if (!s) s = "/etc/localtime"; + if (!*s) s = __gmt; if (old_tz && !strcmp(s, old_tz)) return; @@ -144,19 +145,17 @@ static void do_tzset() } if (old_tz) memcpy(old_tz, s, i+1); - if (*s == ':') s++; - /* Non-suid can use an absolute tzfile pathname or a relative * pathame beginning with "."; in secure mode, only the * standard path will be searched. */ - if (*s == '/' || *s == '.') { - if (!libc.secure) map = __map_file(s, &map_size); - } else { - for (i=0; s[i] && s[i]!=','; i++) { - if (s[i]=='/') { - size_t l = strlen(s); - if (l > NAME_MAX || strchr(s, '.')) - break; + if (*s == ':' || ((p=strchr(s, '/')) && !memchr(s, ',', p-s))) { + if (*s == ':') s++; + if (*s == '/' || *s == '.') { + if (!libc.secure || !strcmp(s, "/etc/localtime")) + map = __map_file(s, &map_size); + } else { + size_t l = strlen(s); + if (l <= NAME_MAX && !strchr(s, '.')) { memcpy(pathname, s, l+1); pathname[l] = 0; for (try=search; !map && *try; try+=l+1) { @@ -164,9 +163,9 @@ static void do_tzset() memcpy(pathname-l, try, l); map = __map_file(pathname-l, &map_size); } - break; } } + if (!map) s = __gmt; } if (map && (map_size < 44 || memcmp(map, "TZif", 4))) { __munmap((void *)map, map_size); @@ -355,9 +354,9 @@ void __secs_to_zone(long long t, int local, int *isdst, long *offset, long *oppo size_t alt, i = scan_trans(t, local, &alt); if (i != -1) { *isdst = types[6*i+4]; - *offset = -(int32_t)zi_read32(types+6*i); + *offset = (int32_t)zi_read32(types+6*i); *zonename = (const char *)abbrevs + types[6*i+5]; - if (oppoff) *oppoff = -(int32_t)zi_read32(types+6*alt); + if (oppoff) *oppoff = (int32_t)zi_read32(types+6*alt); UNLOCK(lock); return; } @@ -391,15 +390,15 @@ void __secs_to_zone(long long t, int local, int *isdst, long *offset, long *oppo } std: *isdst = 0; - *offset = __timezone; - if (oppoff) *oppoff = dst_off; + *offset = -__timezone; + if (oppoff) *oppoff = -dst_off; *zonename = __tzname[0]; UNLOCK(lock); return; dst: *isdst = 1; - *offset = dst_off; - if (oppoff) *oppoff = __timezone; + *offset = -dst_off; + if (oppoff) *oppoff = -__timezone; *zonename = __tzname[1]; UNLOCK(lock); } diff --git a/system/lib/libc/musl/src/time/clock_gettime.c b/system/lib/libc/musl/src/time/clock_gettime.c index ce9f22090a8ef..241288042d64c 100644 --- a/system/lib/libc/musl/src/time/clock_gettime.c +++ b/system/lib/libc/musl/src/time/clock_gettime.c @@ -3,11 +3,47 @@ #include #include "syscall.h" #include "libc.h" +#include "atomic.h" -static int sc_clock_gettime(clockid_t clk, struct timespec *ts) +#ifdef VDSO_CGT_SYM + +void *__vdsosym(const char *, const char *); + +static void *volatile vdso_func; + +static int cgt_init(clockid_t clk, struct timespec *ts) +{ + void *p = __vdsosym(VDSO_CGT_VER, VDSO_CGT_SYM); + int (*f)(clockid_t, struct timespec *) = + (int (*)(clockid_t, struct timespec *))p; + a_cas_p(&vdso_func, (void *)cgt_init, p); + return f ? f(clk, ts) : -ENOSYS; +} + +static void *volatile vdso_func = (void *)cgt_init; + +#endif + +int __clock_gettime(clockid_t clk, struct timespec *ts) { - int r = __syscall(SYS_clock_gettime, clk, ts); - if (!r) return r; + int r; + +#ifdef VDSO_CGT_SYM + int (*f)(clockid_t, struct timespec *) = + (int (*)(clockid_t, struct timespec *))vdso_func; + if (f) { + r = f(clk, ts); + if (!r) return r; + if (r == -EINVAL) return __syscall_ret(r); + /* Fall through on errors other than EINVAL. Some buggy + * vdso implementations return ENOSYS for clocks they + * can't handle, rather than making the syscall. This + * also handles the case where cgt_init fails to find + * a vdso function to use. */ + } +#endif + + r = __syscall(SYS_clock_gettime, clk, ts); if (r == -ENOSYS) { if (clk == CLOCK_REALTIME) { __syscall(SYS_gettimeofday, ts, 0); @@ -16,18 +52,7 @@ static int sc_clock_gettime(clockid_t clk, struct timespec *ts) } r = -EINVAL; } - errno = -r; - return -1; -} - -weak_alias(sc_clock_gettime, __vdso_clock_gettime); - -int (*__cgt)(clockid_t, struct timespec *) = __vdso_clock_gettime; - -int __clock_gettime(clockid_t clk, struct timespec *ts) -{ - /* Conditional is to make this work prior to dynamic linking */ - return __cgt ? __cgt(clk, ts) : sc_clock_gettime(clk, ts); + return __syscall_ret(r); } weak_alias(__clock_gettime, clock_gettime); diff --git a/system/lib/libc/musl/src/time/localtime_r.c b/system/lib/libc/musl/src/time/localtime_r.c index 1d43d9f4be411..2e62c29fb2ac1 100644 --- a/system/lib/libc/musl/src/time/localtime_r.c +++ b/system/lib/libc/musl/src/time/localtime_r.c @@ -11,7 +11,7 @@ struct tm *__localtime_r(const time_t *restrict t, struct tm *restrict tm) return 0; } __secs_to_zone(*t, 0, &tm->tm_isdst, &tm->__tm_gmtoff, 0, &tm->__tm_zone); - if (__secs_to_tm((long long)*t - tm->__tm_gmtoff, tm) < 0) { + if (__secs_to_tm((long long)*t + tm->__tm_gmtoff, tm) < 0) { errno = EOVERFLOW; return 0; } diff --git a/system/lib/libc/musl/src/time/mktime.c b/system/lib/libc/musl/src/time/mktime.c index 0ab478029c3a2..bad3f0765a089 100644 --- a/system/lib/libc/musl/src/time/mktime.c +++ b/system/lib/libc/musl/src/time/mktime.c @@ -10,14 +10,14 @@ time_t mktime(struct tm *tm) __secs_to_zone(t, 1, &new.tm_isdst, &new.__tm_gmtoff, &opp, &new.__tm_zone); if (tm->tm_isdst>=0 && new.tm_isdst!=tm->tm_isdst) - t += opp - new.__tm_gmtoff; + t -= opp - new.__tm_gmtoff; - t += new.__tm_gmtoff; + t -= new.__tm_gmtoff; if ((time_t)t != t) goto error; __secs_to_zone(t, 0, &new.tm_isdst, &new.__tm_gmtoff, &opp, &new.__tm_zone); - if (__secs_to_tm(t - new.__tm_gmtoff, &new) < 0) goto error; + if (__secs_to_tm(t + new.__tm_gmtoff, &new) < 0) goto error; *tm = new; return t; diff --git a/system/lib/libc/musl/src/time/strftime.c b/system/lib/libc/musl/src/time/strftime.c index 75ebca6294498..f1ccc4dd5e848 100644 --- a/system/lib/libc/musl/src/time/strftime.c +++ b/system/lib/libc/musl/src/time/strftime.c @@ -5,6 +5,7 @@ #include #include #include +#include "locale_impl.h" #include "libc.h" #include "time_impl.h" @@ -20,24 +21,24 @@ static int is_leap(int y) static int week_num(const struct tm *tm) { - int val = (tm->tm_yday + 7 - (tm->tm_wday+6)%7) / 7; + int val = (tm->tm_yday + 7U - (tm->tm_wday+6U)%7) / 7; /* If 1 Jan is just 1-3 days past Monday, * the previous week is also in this year. */ - if ((tm->tm_wday - tm->tm_yday - 2 + 371) % 7 <= 2) + if ((tm->tm_wday + 371U - tm->tm_yday - 2) % 7 <= 2) val++; if (!val) { val = 52; /* If 31 December of prev year a Thursday, * or Friday of a leap year, then the * prev year has 53 weeks. */ - int dec31 = (tm->tm_wday - tm->tm_yday - 1 + 7) % 7; + int dec31 = (tm->tm_wday + 7U - tm->tm_yday - 1) % 7; if (dec31 == 4 || (dec31 == 5 && is_leap(tm->tm_year%400-1))) val++; } else if (val == 53) { /* If 1 January is not a Thursday, and not * a Wednesday of a leap year, then this * year has only 52 weeks. */ - int jan1 = (tm->tm_wday - tm->tm_yday + 371) % 7; + int jan1 = (tm->tm_wday + 371U - tm->tm_yday) % 7; if (jan1 != 4 && (jan1 != 3 || !is_leap(tm->tm_year))) val = 1; } @@ -51,21 +52,25 @@ const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm * { nl_item item; long long val; - const char *fmt; + const char *fmt = "-"; int width = 2; switch (f) { case 'a': + if (tm->tm_wday > 6U) goto string; item = ABDAY_1 + tm->tm_wday; goto nl_strcat; case 'A': + if (tm->tm_wday > 6U) goto string; item = DAY_1 + tm->tm_wday; goto nl_strcat; case 'h': case 'b': + if (tm->tm_mon > 11U) goto string; item = ABMON_1 + tm->tm_mon; goto nl_strcat; case 'B': + if (tm->tm_mon > 11U) goto string; item = MON_1 + tm->tm_mon; goto nl_strcat; case 'c': @@ -125,7 +130,7 @@ const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm * fmt = "%H:%M"; goto recu_strftime; case 's': - val = __tm_to_secs(tm) + tm->__tm_gmtoff; + val = __tm_to_secs(tm) - tm->__tm_gmtoff; width = 1; goto number; case 'S': @@ -142,10 +147,10 @@ const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm * width = 1; goto number; case 'U': - val = (tm->tm_yday + 7 - tm->tm_wday) / 7; + val = (tm->tm_yday + 7U - tm->tm_wday) / 7; goto number; case 'W': - val = (tm->tm_yday + 7 - (tm->tm_wday+6)%7) / 7; + val = (tm->tm_yday + 7U - (tm->tm_wday+6U)%7) / 7; goto number; case 'V': val = week_num(tm); @@ -164,7 +169,7 @@ const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm * val = tm->tm_year % 100; goto number; case 'Y': - val = tm->tm_year + 1900; + val = tm->tm_year + 1900LL; if (val >= 10000) { *l = snprintf(*s, sizeof *s, "+%lld", val); return *s; @@ -177,7 +182,7 @@ const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm * return ""; } *l = snprintf(*s, sizeof *s, "%+.2d%.2d", - (-tm->__tm_gmtoff)/3600, + (tm->__tm_gmtoff)/3600, abs(tm->__tm_gmtoff%3600)/60); return *s; case 'Z': @@ -263,7 +268,7 @@ size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const st size_t strftime(char *restrict s, size_t n, const char *restrict f, const struct tm *restrict tm) { - return __strftime_l(s, n, f, tm, 0); + return __strftime_l(s, n, f, tm, CURRENT_LOCALE); } weak_alias(__strftime_l, strftime_l); diff --git a/system/lib/libc/musl/src/time/strptime.c b/system/lib/libc/musl/src/time/strptime.c index 4d9eea41c2d3e..f41f55f24cf4b 100644 --- a/system/lib/libc/musl/src/time/strptime.c +++ b/system/lib/libc/musl/src/time/strptime.c @@ -11,6 +11,7 @@ char *strptime(const char *restrict s, const char *restrict f, struct tm *restri int i, w, neg, adj, min, range, *dest, dummy; const char *ex; size_t len; + int want_century = 0, century = 0; while (*f) { if (*f != '%') { if (isspace(*f)) for (; *s && isspace(*s); s++); @@ -40,9 +41,9 @@ char *strptime(const char *restrict s, const char *restrict f, struct tm *restri if (!s) return 0; break; case 'C': - /* FIXME */ - dest = &dummy; + dest = ¢ury; if (w<0) w=2; + want_century |= 2; goto numeric_digits; case 'd': case 'e': dest = &tm->tm_mday; @@ -135,14 +136,15 @@ char *strptime(const char *restrict s, const char *restrict f, struct tm *restri if (!s) return 0; break; case 'y': - /* FIXME */ - dest = &dummy; + dest = &tm->tm_year; w = 2; + want_century |= 1; goto numeric_digits; case 'Y': dest = &tm->tm_year; if (w<0) w=4; adj = 1900; + want_century = 0; goto numeric_digits; case '%': if (*s++ != '%') return 0; @@ -187,5 +189,9 @@ char *strptime(const char *restrict s, const char *restrict f, struct tm *restri ; } } + if (want_century) { + if (want_century & 2) tm->tm_year += century * 100 - 1900; + else if (tm->tm_year <= 68) tm->tm_year += 100; + } return (char *)s; } diff --git a/system/lib/libc/musl/src/time/timespec_get.c b/system/lib/libc/musl/src/time/timespec_get.c new file mode 100644 index 0000000000000..03c5a77b7b099 --- /dev/null +++ b/system/lib/libc/musl/src/time/timespec_get.c @@ -0,0 +1,12 @@ +#include + +int __clock_gettime(clockid_t, struct timespec *); + +/* There is no other implemented value than TIME_UTC; all other values + * are considered erroneous. */ +int timespec_get(struct timespec * ts, int base) +{ + if (base != TIME_UTC) return 0; + int ret = __clock_gettime(CLOCK_REALTIME, ts); + return ret < 0 ? 0 : base; +} diff --git a/system/lib/libc/musl/src/time/utime.c b/system/lib/libc/musl/src/time/utime.c index b2b5741b32099..e7592b297809c 100644 --- a/system/lib/libc/musl/src/time/utime.c +++ b/system/lib/libc/musl/src/time/utime.c @@ -1,14 +1,11 @@ #include -#include -#include "syscall.h" +#include +#include +#include int utime(const char *path, const struct utimbuf *times) { - if (times) { - struct timeval tv[2] = { - { .tv_sec = times->actime }, - { .tv_sec = times->modtime } }; - return syscall(SYS_utimes, path, tv); - } - return syscall(SYS_utimes, path, 0); + return utimensat(AT_FDCWD, path, times ? ((struct timespec [2]){ + { .tv_sec = times->actime }, { .tv_sec = times->modtime }}) + : 0, 0); } diff --git a/system/lib/libc/musl/src/time/wcsftime.c b/system/lib/libc/musl/src/time/wcsftime.c index 8d2a2ebc3fa18..638e64f6b4457 100644 --- a/system/lib/libc/musl/src/time/wcsftime.c +++ b/system/lib/libc/musl/src/time/wcsftime.c @@ -1,6 +1,7 @@ #include #include #include +#include "locale_impl.h" #include "libc.h" const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm *tm, locale_t loc); @@ -64,7 +65,7 @@ size_t __wcsftime_l(wchar_t *restrict s, size_t n, const wchar_t *restrict f, co size_t wcsftime(wchar_t *restrict wcs, size_t n, const wchar_t *restrict f, const struct tm *restrict tm) { - return __wcsftime_l(wcs, n, f, tm, 0); + return __wcsftime_l(wcs, n, f, tm, CURRENT_LOCALE); } weak_alias(__wcsftime_l, wcsftime_l); diff --git a/system/lib/libc/musl/src/unistd/access.c b/system/lib/libc/musl/src/unistd/access.c index e7ce73a2a7ab9..d6eed6839822f 100644 --- a/system/lib/libc/musl/src/unistd/access.c +++ b/system/lib/libc/musl/src/unistd/access.c @@ -1,7 +1,12 @@ #include +#include #include "syscall.h" int access(const char *filename, int amode) { +#ifdef SYS_access return syscall(SYS_access, filename, amode); +#else + return syscall(SYS_faccessat, AT_FDCWD, filename, amode, 0); +#endif } diff --git a/system/lib/libc/musl/src/unistd/chown.c b/system/lib/libc/musl/src/unistd/chown.c index 95f6f61e9eb14..14b032550d675 100644 --- a/system/lib/libc/musl/src/unistd/chown.c +++ b/system/lib/libc/musl/src/unistd/chown.c @@ -1,7 +1,12 @@ #include +#include #include "syscall.h" int chown(const char *path, uid_t uid, gid_t gid) { +#ifdef SYS_chown return syscall(SYS_chown, path, uid, gid); +#else + return syscall(SYS_fchownat, AT_FDCWD, path, uid, gid, 0); +#endif } diff --git a/system/lib/libc/musl/src/unistd/close.c b/system/lib/libc/musl/src/unistd/close.c index e8f813d648dfa..fa3c6cab7e981 100644 --- a/system/lib/libc/musl/src/unistd/close.c +++ b/system/lib/libc/musl/src/unistd/close.c @@ -3,9 +3,17 @@ #include "syscall.h" #include "libc.h" +static int dummy(int fd) +{ + return fd; +} + +weak_alias(dummy, __aio_close); + int close(int fd) { + fd = __aio_close(fd); int r = __syscall_cp(SYS_close, fd); - if (r == -EINTR) r = -EINPROGRESS; + if (r == -EINTR) r = 0; return __syscall_ret(r); } diff --git a/system/lib/libc/musl/src/unistd/ctermid.c b/system/lib/libc/musl/src/unistd/ctermid.c index 77684050e6f93..1612770af158c 100644 --- a/system/lib/libc/musl/src/unistd/ctermid.c +++ b/system/lib/libc/musl/src/unistd/ctermid.c @@ -1,19 +1,7 @@ #include -#include -#include -#include -#include "syscall.h" +#include char *ctermid(char *s) { - static char s2[L_ctermid]; - int fd; - if (!s) s = s2; - *s = 0; - fd = open("/dev/tty", O_WRONLY | O_NOCTTY | O_CLOEXEC); - if (fd >= 0) { - ttyname_r(fd, s, L_ctermid); - __syscall(SYS_close, fd); - } - return s; + return s ? strcpy(s, "/dev/tty") : "/dev/tty"; } diff --git a/system/lib/libc/musl/src/unistd/dup2.c b/system/lib/libc/musl/src/unistd/dup2.c index 87a0d44538eb4..8f43c6ddfe898 100644 --- a/system/lib/libc/musl/src/unistd/dup2.c +++ b/system/lib/libc/musl/src/unistd/dup2.c @@ -1,10 +1,20 @@ #include #include +#include #include "syscall.h" int dup2(int old, int new) { int r; +#ifdef SYS_dup2 while ((r=__syscall(SYS_dup2, old, new))==-EBUSY); +#else + if (old==new) { + r = __syscall(SYS_fcntl, old, F_GETFD); + if (r >= 0) return old; + } else { + while ((r=__syscall(SYS_dup3, old, new, 0))==-EBUSY); + } +#endif return __syscall_ret(r); } diff --git a/system/lib/libc/musl/src/unistd/dup3.c b/system/lib/libc/musl/src/unistd/dup3.c index 1f7134b3dcbf7..0eb6caf59e6e1 100644 --- a/system/lib/libc/musl/src/unistd/dup3.c +++ b/system/lib/libc/musl/src/unistd/dup3.c @@ -8,6 +8,7 @@ int __dup3(int old, int new, int flags) { int r; +#ifdef SYS_dup2 if (old==new) return __syscall_ret(-EINVAL); if (flags & O_CLOEXEC) { while ((r=__syscall(SYS_dup3, old, new, flags))==-EBUSY); @@ -15,6 +16,9 @@ int __dup3(int old, int new, int flags) } while ((r=__syscall(SYS_dup2, old, new))==-EBUSY); if (flags & O_CLOEXEC) __syscall(SYS_fcntl, new, F_SETFD, FD_CLOEXEC); +#else + while ((r=__syscall(SYS_dup3, old, new, flags))==-EBUSY); +#endif return __syscall_ret(r); } diff --git a/system/lib/libc/musl/src/unistd/fchown.c b/system/lib/libc/musl/src/unistd/fchown.c index 36633b0e95f31..03459849e50a3 100644 --- a/system/lib/libc/musl/src/unistd/fchown.c +++ b/system/lib/libc/musl/src/unistd/fchown.c @@ -13,5 +13,10 @@ int fchown(int fd, uid_t uid, gid_t gid) char buf[15+3*sizeof(int)]; __procfdname(buf, fd); +#ifdef SYS_chown return syscall(SYS_chown, buf, uid, gid); +#else + return syscall(SYS_fchownat, AT_FDCWD, buf, uid, gid); +#endif + } diff --git a/system/lib/libc/musl/src/unistd/fdatasync.c b/system/lib/libc/musl/src/unistd/fdatasync.c index dd4d41c75c7e7..3895ae530c75d 100644 --- a/system/lib/libc/musl/src/unistd/fdatasync.c +++ b/system/lib/libc/musl/src/unistd/fdatasync.c @@ -3,5 +3,5 @@ int fdatasync(int fd) { - return syscall(SYS_fdatasync, fd); + return syscall_cp(SYS_fdatasync, fd); } diff --git a/system/lib/libc/musl/src/unistd/fsync.c b/system/lib/libc/musl/src/unistd/fsync.c index dc4727cc1d17c..7a1c80b5de0d8 100644 --- a/system/lib/libc/musl/src/unistd/fsync.c +++ b/system/lib/libc/musl/src/unistd/fsync.c @@ -3,5 +3,5 @@ int fsync(int fd) { - return syscall(SYS_fsync, fd); + return syscall_cp(SYS_fsync, fd); } diff --git a/system/lib/libc/musl/src/unistd/getpgrp.c b/system/lib/libc/musl/src/unistd/getpgrp.c index 433f42e8f8161..90e9bb07f6e3e 100644 --- a/system/lib/libc/musl/src/unistd/getpgrp.c +++ b/system/lib/libc/musl/src/unistd/getpgrp.c @@ -3,5 +3,5 @@ pid_t getpgrp(void) { - return __syscall(SYS_getpgrp); + return __syscall(SYS_getpgid, 0); } diff --git a/system/lib/libc/musl/src/unistd/isatty.c b/system/lib/libc/musl/src/unistd/isatty.c index cff6e9fe4334f..98732ba0e01e8 100644 --- a/system/lib/libc/musl/src/unistd/isatty.c +++ b/system/lib/libc/musl/src/unistd/isatty.c @@ -1,8 +1,9 @@ #include -#include +#include +#include "syscall.h" int isatty(int fd) { - struct termios t; - return tcgetattr(fd, &t) == 0; + struct winsize wsz; + return !syscall(SYS_ioctl, fd, TIOCGWINSZ, &wsz); } diff --git a/system/lib/libc/musl/src/unistd/lchown.c b/system/lib/libc/musl/src/unistd/lchown.c index de871aebb2155..ccd5ee0255eea 100644 --- a/system/lib/libc/musl/src/unistd/lchown.c +++ b/system/lib/libc/musl/src/unistd/lchown.c @@ -1,7 +1,12 @@ #include +#include #include "syscall.h" int lchown(const char *path, uid_t uid, gid_t gid) { +#ifdef SYS_lchown return syscall(SYS_lchown, path, uid, gid); +#else + return syscall(SYS_fchownat, AT_FDCWD, path, uid, gid, AT_SYMLINK_NOFOLLOW); +#endif } diff --git a/system/lib/libc/musl/src/unistd/link.c b/system/lib/libc/musl/src/unistd/link.c index 20193f2ac831b..feec18e533d95 100644 --- a/system/lib/libc/musl/src/unistd/link.c +++ b/system/lib/libc/musl/src/unistd/link.c @@ -1,7 +1,12 @@ #include +#include #include "syscall.h" int link(const char *existing, const char *new) { +#ifdef SYS_link return syscall(SYS_link, existing, new); +#else + return syscall(SYS_linkat, AT_FDCWD, existing, AT_FDCWD, new, 0); +#endif } diff --git a/system/lib/libc/musl/src/unistd/lseek.c b/system/lib/libc/musl/src/unistd/lseek.c index 0a5ed392bc03c..51166e5d4760f 100644 --- a/system/lib/libc/musl/src/unistd/lseek.c +++ b/system/lib/libc/musl/src/unistd/lseek.c @@ -6,7 +6,13 @@ off_t lseek(int fd, off_t offset, int whence) { #ifdef SYS__llseek off_t result; - return syscall(SYS__llseek, fd, offset>>32, offset, &result, whence) ? -1 : result; + off_t offset_hi = +#ifndef __EMSCRIPTEN__ + offset >> 32; +#else + 0; +#endif + return syscall(SYS__llseek, fd, offset_hi, offset, &result, whence) ? -1 : result; #else return syscall(SYS_lseek, fd, offset, whence); #endif diff --git a/system/lib/libc/musl/src/unistd/pause.c b/system/lib/libc/musl/src/unistd/pause.c index f7ed17d16f0fd..56eb171e0ac48 100644 --- a/system/lib/libc/musl/src/unistd/pause.c +++ b/system/lib/libc/musl/src/unistd/pause.c @@ -1,8 +1,13 @@ #include +#include #include "syscall.h" #include "libc.h" int pause(void) { +#ifdef SYS_pause return syscall_cp(SYS_pause); +#else + return syscall_cp(SYS_ppoll, 0, 0, 0, 0); +#endif } diff --git a/system/lib/libc/musl/src/unistd/pipe.c b/system/lib/libc/musl/src/unistd/pipe.c index 36c6f13e7a168..d07b8d24ae3b1 100644 --- a/system/lib/libc/musl/src/unistd/pipe.c +++ b/system/lib/libc/musl/src/unistd/pipe.c @@ -3,5 +3,9 @@ int pipe(int fd[2]) { +#ifdef SYS_pipe return syscall(SYS_pipe, fd); +#else + return syscall(SYS_pipe2, fd, 0); +#endif } diff --git a/system/lib/libc/musl/src/unistd/readlink.c b/system/lib/libc/musl/src/unistd/readlink.c index ec291e3dfd320..a152d52492ed7 100644 --- a/system/lib/libc/musl/src/unistd/readlink.c +++ b/system/lib/libc/musl/src/unistd/readlink.c @@ -1,7 +1,12 @@ #include +#include #include "syscall.h" ssize_t readlink(const char *restrict path, char *restrict buf, size_t bufsize) { +#ifdef SYS_readlink return syscall(SYS_readlink, path, buf, bufsize); +#else + return syscall(SYS_readlinkat, AT_FDCWD, path, buf, bufsize); +#endif } diff --git a/system/lib/libc/musl/src/unistd/rmdir.c b/system/lib/libc/musl/src/unistd/rmdir.c index dfe1605d05173..6825ffc8359a5 100644 --- a/system/lib/libc/musl/src/unistd/rmdir.c +++ b/system/lib/libc/musl/src/unistd/rmdir.c @@ -1,7 +1,12 @@ #include +#include #include "syscall.h" int rmdir(const char *path) { +#ifdef SYS_rmdir return syscall(SYS_rmdir, path); +#else + return syscall(SYS_unlinkat, AT_FDCWD, path, AT_REMOVEDIR); +#endif } diff --git a/system/lib/libc/musl/src/unistd/setxid.c b/system/lib/libc/musl/src/unistd/setxid.c index 43ecc0d641e92..dc1377f7ab88c 100644 --- a/system/lib/libc/musl/src/unistd/setxid.c +++ b/system/lib/libc/musl/src/unistd/setxid.c @@ -1,54 +1,43 @@ #include #include -#include #include "syscall.h" #include "libc.h" +#include "pthread_impl.h" struct ctx { int id, eid, sid; - int nr, rlim, err; + int nr, err; }; -/* We jump through hoops to eliminate the possibility of partial failures. */ - -int __setrlimit(int, const struct rlimit *); - static void do_setxid(void *p) { struct ctx *c = p; - if (c->err) return; - if (c->rlim && c->id >= 0 && c->id != getuid()) { - struct rlimit inf = { RLIM_INFINITY, RLIM_INFINITY }, old; - getrlimit(RLIMIT_NPROC, &old); - if ((c->err = -__setrlimit(RLIMIT_NPROC, &inf)) && libc.threads_minus_1) - return; -#ifndef __EMSCRIPTEN__ - c->err = -__syscall(c->nr, c->id, c->eid, c->sid); + if (c->err>0) return; +#ifdef __EMSCRIPTEN__ + c->err = EPERM; // we don't allow dynamic syscalls, and don't need to support these anyhow + return; #else - c->err = EPERM; // we don't allow dynamic syscalls, and don't need to support these anyhow -#endif - __setrlimit(RLIMIT_NPROC, &old); - return; + int ret = -__syscall(c->nr, c->id, c->eid, c->sid); + if (ret && !c->err) { + /* If one thread fails to set ids after another has already + * succeeded, forcibly killing the process is the only safe + * thing to do. State is inconsistent and dangerous. Use + * SIGKILL because it is uncatchable. */ + __block_all_sigs(0); + __syscall(SYS_kill, __syscall(SYS_getpid), SIGKILL); } -#ifndef __EMSCRIPTEN__ - c->err = -__syscall(c->nr, c->id, c->eid, c->sid); -#else - c->err = EPERM; // we don't allow dynamic syscalls, and don't need to support these anyhow + c->err = ret; #endif } int __setxid(int nr, int id, int eid, int sid) { - struct ctx c = { .nr = nr, .id = id, .eid = eid, .sid = sid }; - switch (nr) { - case SYS_setuid: - case SYS_setreuid: - case SYS_setresuid: - c.rlim = 1; - } + /* err is initially nonzero so that failure of the first thread does not + * trigger the safety kill above. */ + struct ctx c = { .nr = nr, .id = id, .eid = eid, .sid = sid, .err = -1 }; __synccall(do_setxid, &c); if (c.err) { - errno = c.err; + if (c.err>0) errno = c.err; return -1; } return 0; diff --git a/system/lib/libc/musl/src/unistd/symlink.c b/system/lib/libc/musl/src/unistd/symlink.c index 5902d45a1af55..0973d78a8936b 100644 --- a/system/lib/libc/musl/src/unistd/symlink.c +++ b/system/lib/libc/musl/src/unistd/symlink.c @@ -1,7 +1,12 @@ #include +#include #include "syscall.h" int symlink(const char *existing, const char *new) { +#ifdef SYS_symlink return syscall(SYS_symlink, existing, new); +#else + return syscall(SYS_symlinkat, existing, AT_FDCWD, new); +#endif } diff --git a/system/lib/libc/musl/src/unistd/unlink.c b/system/lib/libc/musl/src/unistd/unlink.c index bdb37bea02d7b..c40c28d50be4e 100644 --- a/system/lib/libc/musl/src/unistd/unlink.c +++ b/system/lib/libc/musl/src/unistd/unlink.c @@ -1,7 +1,12 @@ #include +#include #include "syscall.h" int unlink(const char *path) { +#ifdef SYS_unlink return syscall(SYS_unlink, path); +#else + return syscall(SYS_unlinkat, AT_FDCWD, path, 0); +#endif } diff --git a/system/lib/pthread/library_pthread.c b/system/lib/pthread/library_pthread.c index b14a77107fb13..1a9f69e266e29 100644 --- a/system/lib/pthread/library_pthread.c +++ b/system/lib/pthread/library_pthread.c @@ -18,6 +18,7 @@ #include #include #include +#include "../internal/libc.h" #include "../internal/pthread_impl.h" #include @@ -31,6 +32,8 @@ char *gets(char *); // Extra pthread_attr_t field: #define _a_transferredcanvases __u.__s[9] +void __pthread_testcancel(); + int emscripten_pthread_attr_gettransferredcanvases(const pthread_attr_t *a, const char **str) { *str = (const char *)a->_a_transferredcanvases; @@ -54,7 +57,7 @@ static void inline __pthread_mutex_locked(pthread_mutex_t *mutex) assert(mutex); assert(mutex->_m_lock == 0); mutex->_m_lock = pthread_self()->tid; - if (_pthread_getcanceltype() == PTHREAD_CANCEL_ASYNCHRONOUS) pthread_testcancel(); + if (_pthread_getcanceltype() == PTHREAD_CANCEL_ASYNCHRONOUS) __pthread_testcancel(); } double _pthread_msecs_until(const struct timespec *restrict at) @@ -93,7 +96,7 @@ int pthread_mutex_lock(pthread_mutex_t *mutex) double msecs = INFINITY; if (threadCancelType == PTHREAD_CANCEL_ASYNCHRONOUS) { // Sleep in small slices so that we can test cancellation to honor PTHREAD_CANCEL_ASYNCHRONOUS. - pthread_testcancel(); + __pthread_testcancel(); msecs = 100; } emscripten_futex_wait(&mutex->_m_addr, 2, msecs); @@ -174,7 +177,7 @@ int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex, const struct timesp // Sleep in small slices if thread type is PTHREAD_CANCEL_ASYNCHRONOUS // so that we can honor PTHREAD_CANCEL_ASYNCHRONOUS requests. if (threadCancelType == PTHREAD_CANCEL_ASYNCHRONOUS) { - pthread_testcancel(); + __pthread_testcancel(); if (msecs > 100) msecs = 100; } int ret = emscripten_futex_wait(&mutex->_m_addr, 2, msecs); @@ -227,7 +230,7 @@ int _pthread_isduecanceled(struct pthread *pthread_ptr) return pthread_ptr->threadStatus == 2/*canceled*/; } -void pthread_testcancel() +void __pthread_testcancel() { struct pthread *self = pthread_self(); if (self->canceldisable) return; @@ -257,7 +260,7 @@ static void do_sleep(double msecs) #endif while(now < target) { if (is_main_thread) emscripten_main_thread_process_queued_calls(); // Assist other threads by executing proxied operations that are effectively singlethreaded. - pthread_testcancel(); // pthreads spec: usleep is a cancellation point, so it must test if this thread is cancelled during the sleep. + __pthread_testcancel(); // pthreads spec: usleep is a cancellation point, so it must test if this thread is cancelled during the sleep. now = emscripten_get_now(); double msecsToSleep = target - now; if (msecsToSleep > 1.0) { @@ -884,3 +887,5 @@ uint64_t __atomic_fetch_xor_8(void *ptr, uint64_t value, int memmodel) { return _emscripten_atomic_fetch_and_xor_u64(ptr, value); } + +weak_alias(__pthread_testcancel, pthread_testcancel); diff --git a/tests/core/test_simd_float32x4.c b/tests/core/test_simd_float32x4.c index c299bf97fdf5b..37dcdbf143321 100644 --- a/tests/core/test_simd_float32x4.c +++ b/tests/core/test_simd_float32x4.c @@ -5,9 +5,25 @@ #include #include +void printFloat(float n) { + if (isnan(n)) { + printf("nan"); + } else { + printf("%f", n); + } +} + void dump(const char *name, float32x4 vec) { - printf("%s: %f %f %f %f\n", name, emscripten_float32x4_extractLane(vec, 0), emscripten_float32x4_extractLane(vec, 1), emscripten_float32x4_extractLane(vec, 2), emscripten_float32x4_extractLane(vec, 3)); + printf("%s: ", name); + printFloat(emscripten_float32x4_extractLane(vec, 0)); + printf(" "); + printFloat(emscripten_float32x4_extractLane(vec, 1)); + printf(" "); + printFloat(emscripten_float32x4_extractLane(vec, 2)); + printf(" "); + printFloat(emscripten_float32x4_extractLane(vec, 3)); + printf("\n"); } #define DUMP(V) dump(#V, (V)) diff --git a/tests/core/test_simd_float64x2.c b/tests/core/test_simd_float64x2.c index 7a2c87feafbf3..5454df280811c 100644 --- a/tests/core/test_simd_float64x2.c +++ b/tests/core/test_simd_float64x2.c @@ -5,9 +5,21 @@ #include #include +void printFloat(double n) { + if (isnan(n)) { + printf("nan"); + } else { + printf("%f", n); + } +} + void dump(const char *name, float64x2 vec) { - printf("%s: %f %f\n", name, emscripten_float64x2_extractLane(vec, 0), emscripten_float64x2_extractLane(vec, 1)); + printf("%s: ", name); + printFloat(emscripten_float64x2_extractLane(vec, 0)); + printf(" "); + printFloat(emscripten_float64x2_extractLane(vec, 1)); + printf("\n"); } #define DUMP(V) dump(#V, (V)) diff --git a/tests/core/test_strftime.c b/tests/core/test_strftime.cpp similarity index 97% rename from tests/core/test_strftime.c rename to tests/core/test_strftime.cpp index 020fece3cb39f..04bc8968cfde6 100644 --- a/tests/core/test_strftime.c +++ b/tests/core/test_strftime.cpp @@ -7,6 +7,9 @@ void test(int result, const char* comment, const char* parsed = "") { printf("%s: %d\n", comment, result); if (!result) { printf("\nERROR: %s (\"%s\")\n", comment, parsed); +#ifdef REPORT_RESULT + abort(); +#endif } } @@ -171,4 +174,8 @@ int main() { size = strftime(s, 10, "%I %M %p", &tm); test(!cmp(s, "12 01 PM"), "strftime test #35", s); +#ifdef REPORT_RESULT + int result = 0; + REPORT_RESULT(); +#endif } diff --git a/tests/core/test_wprintf.c b/tests/core/test_wprintf.cpp similarity index 100% rename from tests/core/test_wprintf.c rename to tests/core/test_wprintf.cpp diff --git a/tests/core/test_zerodiv.c b/tests/core/test_zerodiv.c index 2143077247aa8..dce51ff32dbdc 100644 --- a/tests/core/test_zerodiv.c +++ b/tests/core/test_zerodiv.c @@ -1,4 +1,14 @@ +#include #include + +void printCanonicalizedNan(char* name, float value) { + if (!isnan(value)) { + printf("%s: %f\n", name, value); + } else { + printf("%s: nan\n", name); + } +} + int main(int argc, const char* argv[]) { float f1 = 1.0f; float f2 = 0.0f; @@ -9,10 +19,10 @@ int main(int argc, const char* argv[]) { float f5 = f2 / f2; float f6 = f2 / f_zero; - printf("f3: %f\n", f3); - printf("f4: %f\n", f4); - printf("f5: %f\n", f5); - printf("f6: %f\n", f6); + printCanonicalizedNan("f3", f3); + printCanonicalizedNan("f4", f4); + printCanonicalizedNan("f5", f5); + printCanonicalizedNan("f6", f6); return 0; } diff --git a/tests/hyperbolic/src.c b/tests/hyperbolic/src.c index 4644f2d35f538..95dc4d3c1f6d0 100644 --- a/tests/hyperbolic/src.c +++ b/tests/hyperbolic/src.c @@ -1,6 +1,15 @@ #include #include +// Canonicalize nan output: wasm and asm encode negative nans differently +void printCanonicalizedNan(char* funcName, double value) { + if (!isnan(value)) { + printf("%s: %g\n", funcName, value); + } else { + printf("%s: nan\n", funcName); + } +} + int main() { double i; for (i = -10; i < 10; i += 0.125) { @@ -8,9 +17,9 @@ int main() { printf("sinh: %g\n", sinh(i)); printf("cosh: %g\n", cosh(i)); printf("tanh: %g\n", tanh(i)); - printf("asinh: %g\n", asinh(i)); - printf("acosh: %g\n", acosh(i)); - printf("atanh: %g\n", atanh(i)); + printCanonicalizedNan("asinh", asinh(i)); + printCanonicalizedNan("acosh", acosh(i)); + printCanonicalizedNan("atanh", atanh(i)); printf("\n"); } return 0; diff --git a/tests/langinfo/output.txt b/tests/langinfo/output.txt index 07fb77f27075a..07f3b73186bc8 100644 --- a/tests/langinfo/output.txt +++ b/tests/langinfo/output.txt @@ -1,4 +1,4 @@ - CODESET: "UTF-8" + CODESET: "ASCII" D_T_FMT: "%a %b %e %T %Y" D_FMT: "%m/%d/%y" T_FMT: "%H:%M:%S" @@ -52,5 +52,5 @@ THOUSEP: "" YESEXPR: "^[yY]" NOEXPR: "^[nN]" - CRNCYSTR: "(null)" - (bad value): "(null)" + CRNCYSTR: "" + (bad value): "" diff --git a/tests/pthread/test_pthread_locale.c b/tests/pthread/test_pthread_locale.c new file mode 100644 index 0000000000000..01c330431b6ae --- /dev/null +++ b/tests/pthread/test_pthread_locale.c @@ -0,0 +1,54 @@ +#include +#include +#include +// #include +#include +#include "../../system/lib/libc/musl/src/internal/pthread_impl.h" + +#define NUM_THREADS 1 + +locale_t do_test() { + pthread_t thread = pthread_self(); + locale_t loc = thread->locale; + printf(" pthread_self() = %p\n", thread); + printf(" pthread_self()->locale = %p\n", loc); + + if (!loc) { + puts("ERROR: loc is null"); + } + return loc; +} + +void *thread_test(void *t) +{ + puts("Doing test in child thread"); + pthread_exit((void*)do_test()); +} + +int main (int argc, char *argv[]) +{ + puts("Doing test in main thread"); + locale_t main_loc = do_test(); + locale_t child_loc; + + if (!emscripten_has_threading_support()) + { + child_loc = main_loc; + } + else + { + long id = 1; + pthread_t thread; + + pthread_create(&thread, NULL, thread_test, (void *)id); + + pthread_join(thread, (void**)&child_loc); + } + +#ifdef REPORT_RESULT + int result = (main_loc == child_loc); + REPORT_RESULT(); +#endif + + pthread_exit(NULL); +} diff --git a/tests/test_browser.py b/tests/test_browser.py index 12ce0c08daa1b..fc451b18c80f8 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -3420,3 +3420,12 @@ def test_asmfs_test_fcntl_open(self): def test_asmfs_relative_paths(self): self.btest('asmfs/relative_paths.cpp', expected='0', args=['-s', 'ASMFS=1', '-s', 'USE_PTHREADS=1', '-s', 'FETCH_DEBUG=1', '--proxy-to-worker']) + + def test_pthread_locale(self): + for args in [ + [], + ['-s', 'USE_PTHREADS=1', '-s', 'PTHREAD_POOL_SIZE=2'], + ['-s', 'USE_PTHREADS=1', '--proxy-to-worker', '-s', 'PTHREAD_POOL_SIZE=2'], + ]: + print "Testing with: ", args + self.btest('pthread/test_pthread_locale.c', expected='1', args=args) diff --git a/tests/test_core.py b/tests/test_core.py index 0eb8454001c76..6b9e87d2b9158 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -224,7 +224,6 @@ def test_asmjs_unknown_emscripten(self): # No other configuration is supported, so always run this. self.do_run(open(path_from_root('tests', 'asmjs-unknown-emscripten.c')).read(), '') - @no_wasm_backend('printf is incorrectly handling float values') def test_cube2md5(self): self.emcc_args += ['--embed-file', 'cube2md5.txt'] shutil.copyfile(path_from_root('tests', 'cube2md5.txt'), os.path.join(self.get_dir(), 'cube2md5.txt')) @@ -381,8 +380,8 @@ def test(): printf("Alignment: %d addr: 0x%x\n", ((int)&v) % 16, (int)&v); printf("Alignment: %d addr: 0x%x\n", ((int)&m) % 16, (int)&m); } - ''', ('Alignment: 0 addr: 0xa20\nAlignment: 0 addr: 0xa60\n', # asmjs - 'Alignment: 0 addr: 0xe10\nAlignment: 0 addr: 0xe50\n', # asm2wasm + ''', ('Alignment: 0 addr: 0xb20\nAlignment: 0 addr: 0xb60\n', # asmjs + 'Alignment: 0 addr: 0xf10\nAlignment: 0 addr: 0xf50\n', # asm2wasm 'Alignment: 0 addr: 0x410\nAlignment: 0 addr: 0x450\n',)) # wasm_backend test() @@ -1658,7 +1657,14 @@ def test_memorygrowth(self): if '-O2' in self.emcc_args: # Make sure ALLOW_MEMORY_GROWTH generates different code (should be less optimized) - code_start = 'var TOTAL_MEMORY' + possible_starts = ['// EMSCRIPTEN_START_FUNCS', 'var TOTAL_MEMORY'] + code_start = None + for s in possible_starts: + if fail.find(s) >= 0: + code_start = s + break + assert code_start is not None, 'Generated code must contain one of ' + str(possible_starts) + fail = fail[fail.find(code_start):] win = win[win.find(code_start):] assert len(fail) < len(win), 'failing code - without memory growth on - is more optimized, and smaller' + str([len(fail), len(win)]) @@ -2666,7 +2672,7 @@ def post(filename): raise Exception('Could not find symbol table!') table = table[table.find('{'):table.find('}')+1] # ensure there aren't too many globals; we don't want unnamed_addr - assert table.count(',') <= 23, table.count(',') + assert table.count(',') <= 27, table.count(',') test_path = path_from_root('tests', 'core', 'test_dlfcn_self') src, output = (test_path + s for s in ('.c', '.out')) @@ -3951,11 +3957,9 @@ def test_fnmatch(self): print 'flip assertions off' self.do_run_in_out_file_test('tests', 'core', 'fnmatch') - @no_wasm_backend('sscanf seems to be misreading float values') def test_sscanf(self): self.do_run_in_out_file_test('tests', 'core', 'test_sscanf') - @no_wasm_backend('sscanf seems to be misreading float values') def test_sscanf_2(self): # doubles for ftype in ['float', 'double']: @@ -4037,14 +4041,12 @@ def test_sscanf_6(self): def test_sscanf_skip(self): self.do_run_in_out_file_test('tests', 'core', 'test_sscanf_skip') - @no_wasm_backend('sscanf seems to be misreading float values') def test_sscanf_caps(self): self.do_run_in_out_file_test('tests', 'core', 'test_sscanf_caps') def test_sscanf_hex(self): self.do_run_in_out_file_test('tests', 'core', 'test_sscanf_hex') - @no_wasm_backend('sscanf seems to be misreading float values') def test_sscanf_float(self): self.do_run_in_out_file_test('tests', 'core', 'test_sscanf_float') @@ -4201,7 +4203,6 @@ def test_fgets_eol(self): self.emcc_args += ['--embed-file', 'eol.txt'] self.do_run(src, 'SUCCESS\n') - @no_wasm_backend('printf is incorrectly handling float values') def test_fscanf(self): open(os.path.join(self.get_dir(), 'three_numbers.txt'), 'w').write('''-1 0.1 -.1''') src = r''' @@ -4273,7 +4274,6 @@ def test_fileno(self): self.do_run(src, '3\n') def test_readdir(self): - self.banned_js_engines = [V8_ENGINE] # stderr printing limitations in v8 src = open(path_from_root('tests', 'dirent', 'test_readdir.c'), 'r').read() self.do_run(src, '''SIGILL: Illegal instruction success @@ -4392,7 +4392,7 @@ def test_utf16_textdecoder(self): @no_wasm_backend('printf is incorrectly handling float values') def test_wprintf(self): test_path = path_from_root('tests', 'core', 'test_wprintf') - src, output = (test_path + s for s in ('.c', '.out')) + src, output = (test_path + s for s in ('.cpp', '.out')) orig_args = self.emcc_args for mode in [[], ['-s', 'MEMFS_APPEND_TO_TYPED_ARRAYS=1']]: self.emcc_args = orig_args + mode @@ -6140,6 +6140,7 @@ def test_demangle_stacks(self): self.do_run_in_out_file_test('tests', 'core', 'test_demangle_stacks') @no_emterpreter + @no_wasm_backend('Need support for -g in wasm backend') def test_demangle_stacks_symbol_map(self): Settings.DEMANGLE_SUPPORT = 1 if '-O' in str(self.emcc_args) and '-O0' not in self.emcc_args and '-O1' not in self.emcc_args and '-g' not in self.emcc_args: diff --git a/tests/test_other.py b/tests/test_other.py index 2f9297dd96ca3..e3b301fdf5cb4 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -4616,7 +4616,6 @@ def test_force_exit(self): assert 'callback post()' not in output def test_bad_locale(self): - logging.warning('TODO: check with upstream musl if this is correct behavior or not') open('src.cpp', 'w').write(r''' #include @@ -4639,8 +4638,10 @@ def test_bad_locale(self): ''') Popen([PYTHON, EMCC, 'src.cpp']).communicate() - self.assertContained('locale set to C: C', run_js('a.out.js', args=['C'])) - self.assertContained('locale set to waka: C.UTF-8', run_js('a.out.js', args=['waka'])) # the call still succeeds in musl, even if the locale requested was not selected + self.assertContained('locale set to C: C;C;C;C;C;C', + run_js('a.out.js', args=['C'])) + self.assertContained('locale set to waka: waka;waka;waka;waka;waka;waka', + run_js('a.out.js', args=['waka'])) def test_js_malloc(self): open('src.cpp', 'w').write(r''' @@ -6271,16 +6272,23 @@ def test_emterpreter_file_suggestion(self): def test_llvm_lto(self): sizes = {} - for lto in [0, 1, 2, 3]: + lto_levels = [0, 1, 2, 3] + for lto in lto_levels: cmd = [PYTHON, EMCC, path_from_root('tests', 'hello_libcxx.cpp'), '-O2', '--llvm-lto', str(lto)] print cmd check_execute(cmd) self.assertContained('hello, world!', run_js('a.out.js')) sizes[lto] = os.stat('a.out.js').st_size print sizes - assert sizes[1] < sizes[0] # lto reduces size - assert sizes[2] > sizes[0] # fake lto is aggressive at increasing code size - assert sizes[3] not in set([sizes[0], sizes[1], sizes[2]]) # mode 3 is different (deterministic builds means this tests an actual change) + + # LTO sizes should be distinct + for i in lto_levels: + assert sizes[i] not in set(sizes).difference(set([sizes[i]])) + + # LTO should reduce code size + # Skip mode 2 because it has historically increased code size, but not always + assert sizes[1] < sizes[0] + assert sizes[3] < sizes[0] def test_split_memory(self): # make sure multiple split memory chunks get used open('src.c', 'w').write(r''' diff --git a/tools/shared.py b/tools/shared.py index 64af117e4216f..5824a6f076362 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -2607,7 +2607,7 @@ def read_and_preprocess(filename): def make_fetch_worker(source_file, output_file): src = open(source_file, 'r').read() funcs_to_import = ['alignUp', 'getTotalMemory', 'stringToUTF8', 'intArrayFromString', 'lengthBytesUTF8', 'stringToUTF8Array', '_emscripten_is_main_runtime_thread', '_emscripten_futex_wait'] - asm_funcs_to_import = ['_malloc', '_free', '_sbrk', '_pthread_mutex_lock', '_pthread_mutex_unlock'] + asm_funcs_to_import = ['_malloc', '_free', '_sbrk', '___pthread_mutex_lock', '___pthread_mutex_unlock'] function_prologue = '''this.onerror = function(e) { console.error(e); }