[musl][crashsvc] Noisily fail when IO functions are not implemented in
libc.

Currently, if an app does not link in an implementation for POSIX IO
functions e.g. read/write, they automatically fallback to a dummy
implementation, which does nothing except silently fail.

This change explores if it is better to just crash in those scenarios.
The rationale is that in production, we should not be depending on these
dummy implementations. And currently because of the build system, it is
quite easy to forget to explicitly link in an implementation e.g. FDIO.

After opting to explicitly crash, the following cases have been
uncovered:
1. system/utest/util/listnode does not link FDIO. Hence it has no
console output whatsoever.
2. system/core/crashsvc also does not link FDIO, but calls fprintf.
Hence when we crash on unimplemented functions, it will forever
recursively crash in the crash handler. This has also been fixed.

TEST: Run all tests with the crashing behavior. And also try randomly
removing FDIO from any test and verifies that it noisily crashes.

Global Integration Test: integration/+/78875

Change-Id: I710e512068c2926f8ff09a2b71c806b7bf6f87df
diff --git a/system/core/crashsvc/rules.mk b/system/core/crashsvc/rules.mk
index a887528..1cf242e 100644
--- a/system/core/crashsvc/rules.mk
+++ b/system/core/crashsvc/rules.mk
@@ -21,6 +21,7 @@
 
 MODULE_LIBS := \
     system/ulib/zircon \
+    system/ulib/fdio \
     system/ulib/c
 
 include make/module.mk
diff --git a/system/utest/util/rules.mk b/system/utest/util/rules.mk
index 5197390..826cdaa 100644
--- a/system/utest/util/rules.mk
+++ b/system/utest/util/rules.mk
@@ -4,7 +4,7 @@
 
 LOCAL_DIR := $(GET_LOCAL_DIR)
 LOCAL_SRCS = \
-	$(LOCAL_DIR)/listnode.cpp
+    $(LOCAL_DIR)/listnode.cpp
 
 # User test
 
@@ -13,9 +13,10 @@
 MODULE_NAME := listnode-test
 MODULE_SRCS := $(LOCAL_SRCS)
 MODULE_LIBS := \
-	system/ulib/c \
-	system/ulib/unittest \
-	system/ulib/zircon
+    system/ulib/c \
+    system/ulib/fdio \
+    system/ulib/unittest \
+    system/ulib/zircon
 
 include make/module.mk
 
@@ -28,7 +29,7 @@
 MODULE_COMPILEFLAGS := \
     -Isystem/ulib/unittest/include
 MODULE_HOST_LIBS += \
-	system/ulib/pretty.hostlib \
+    system/ulib/pretty.hostlib \
     system/ulib/unittest.hostlib \
 
 include make/module.mk
diff --git a/third_party/ulib/musl/stubs/iostubs.c b/third_party/ulib/musl/stubs/iostubs.c
index 08c640c..37d7cb2 100644
--- a/third_party/ulib/musl/stubs/iostubs.c
+++ b/third_party/ulib/musl/stubs/iostubs.c
@@ -12,13 +12,23 @@
 #include "libc.h"
 #include "stdio_impl.h"
 
+// Temporary handler for IO functions not being implemented.
+// Long term solution is to split out POSIX-dependent parts from libc.
+// By marking this function noinline, its name will appear in the crash stack trace,
+// indicating that the program did not link in a working IO function implementation.
+static void __attribute__((noinline)) libc_io_functions_not_implemented(void) {
+    __builtin_trap();
+}
+
 static ssize_t stub_read(int fd, void* buf, size_t count) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_read, read);
 
 static ssize_t stub_write(int fd, const void* buf, size_t count) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
@@ -26,390 +36,456 @@
 
 static zx_status_t stub__mmap_file(size_t offset, size_t len, uint32_t zx_flags, int flags, int fd,
                                   off_t fd_off, uintptr_t* out) {
+    libc_io_functions_not_implemented();
     return ZX_ERR_NOT_SUPPORTED;
 }
 weak_alias(stub__mmap_file, _mmap_file);
 
 static int stub_close(int fd) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_close, close);
 
 static int stub_open(const char* path, int flags, ...) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_open, open);
 
 static int stub_openat(int fd, const char* filename, int flags, ...) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_openat, openat);
 
 static off_t stub_lseek(int fd, off_t offset, int whence) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_lseek, lseek);
 
 static int stub_isatty(int fd) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return 0;
 }
 weak_alias(stub_isatty, isatty);
 
 static ssize_t stub_readv(int fd, const struct iovec* iov, int num) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_readv, readv);
 
 static ssize_t stub_writev(int fd, const struct iovec* iov, int num) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_writev, writev);
 
 static ssize_t stub_preadv(int fd, const struct iovec* iov, int count, off_t ofs) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_preadv, preadv);
 
 static ssize_t stub_pread(int fd, void* buf, size_t size, off_t ofs) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_pread, pread);
 
 static ssize_t stub_pwritev(int fd, const struct iovec* iov, int count, off_t ofs) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_pwritev, pwritev);
 
 static ssize_t stub_pwrite(int fd, const void* buf, size_t size, off_t ofs) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_pwrite, pwrite);
 
 static int stub_link(const char* oldpath, const char* newpath) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_link, link);
 
 static int stub_linkat(int fd1, const char* existing, int fd2, const char* new, int flag) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_linkat, linkat);
 
 static int stub_unlinkat(int fd, const char* path, int flag) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_unlinkat, unlinkat);
 
 static int stub_unlink(const char* path) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_unlink, unlink);
 
 static ssize_t stub_readlink(const char* path, char* buf, size_t bufsiz) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_readlink, readlink);
 
 static ssize_t stub_readlinkat(int fd, const char* restrict path, char* restrict buf, size_t bufsize) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_readlinkat, readlinkat);
 
 static char* stub_realpath(const char* restrict filename, char* restrict resolved) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return NULL;
 }
 weak_alias(stub_realpath, realpath);
 
 static int stub_mkdir(const char* path, mode_t mode) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_mkdir, mkdir);
 
 static int stub_mkdirat(int fd, const char* path, mode_t mode) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_mkdirat, mkdirat);
 
 static int stub_rmdir(const char* path) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_rmdir, rmdir);
 
 static char* stub_getcwd(char* buf, size_t size) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return NULL;
 }
 weak_alias(stub_getcwd, getcwd);
 
 static int stub_fstat(int fd, struct stat* s) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_fstat, fstat);
 
 static int stub_fstatat(int fd, const char* restrict path, struct stat* restrict buf, int flag) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_fstatat, fstatat);
 
 static int stub_stat(const char* fn, struct stat* s) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_stat, stat);
 
 static int stub_lstat(const char* restrict path, struct stat* restrict buf) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_lstat, lstat);
 
 static int stub_dup(int oldfd) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_dup, dup);
 
 static int stub_dup2(int oldfd, int newfd) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_dup2, dup2);
 
 static int stub_dup3(int oldfd, int newfd, int flags) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_dup3, dup3);
 
 static int stub_pipe(int pipefd[2]) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_pipe, pipe);
 
 static int stub_pipe2(int pipe2fd[2], int flags) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_pipe2, pipe2);
 
 static int stub_futimens(int fd, const struct timespec times[2]) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_futimens, futimens);
 
 static int stub_utimensat(int fd, const char* path, const struct timespec times[2], int flags) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_utimensat, utimensat);
 
 static int stub_chdir(const char* path) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_chdir, chdir);
 
 static DIR* stub_opendir(const char* name) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return NULL;
 }
 weak_alias(stub_opendir, opendir);
 
 static DIR* stub_fdopendir(int fd) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return NULL;
 }
 weak_alias(stub_fdopendir, fdopendir);
 
 static int stub_closedir(DIR* dir) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_closedir, closedir);
 
 static struct dirent* stub_readdir(DIR* dir) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return NULL;
 }
 weak_alias(stub_readdir, readdir);
 
 static int stub_readdir_r(DIR* dir, struct dirent* entry, struct dirent** result) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_readdir_r, readdir_r);
 
 static void stub_rewinddir(DIR* dir) {
+    libc_io_functions_not_implemented();
 }
 weak_alias(stub_rewinddir, rewinddir);
 
 static void stub_seekdir(DIR* dir, long loc) {
+    libc_io_functions_not_implemented();
 }
 weak_alias(stub_seekdir, seekdir);
 
 static long stub_telldir(DIR* dir) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_telldir, telldir);
 
 static int stub_access(const char* path, int mode) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_access, access);
 
 static int stub_faccessat(int fd, const char* path, int amode, int flags) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_faccessat, faccessat);
 
 static int stub_chmod(const char* path, mode_t mode) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_chmod, chmod);
 
 static int stub_fchmod(int fd, mode_t mode) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_fchmod, fchmod);
 
 static int stub_fchmodat(int fd, const char* path, mode_t mode, int flag) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_fchmodat, fchmodat);
 
 static int stub_chown(const char* path, uid_t owner, gid_t group) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_chown, chown);
 
 static int stub_fchown(int fd, uid_t owner, gid_t group) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_fchown, fchown);
 
 static int stub_fchownat(int fd, const char* path, uid_t uid, gid_t gid, int flag) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_fchownat, fchownat);
 
 static int stub_lchown(const char* path, uid_t owner, gid_t group) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_lchown, lchown);
 
 static int stub_fcntl(int fd, int cmd, ...) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_fcntl, fcntl);
 
 static int stub_fdatasync(int fd) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_fdatasync, fdatasync);
 
 static int stub_fsync(int fd) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_fsync, fsync);
 
 static int stub_ftruncate(int fd, off_t length) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_ftruncate, ftruncate);
 
 static int stub_truncate(const char* path, off_t length) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_truncate, truncate);
 
 static int stub_mkfifo(const char* path, mode_t mode) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_mkfifo, mkfifo);
 
 static int stub_mknod(const char* path, mode_t mode, dev_t dev) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_mknod, mknod);
 
 static int stub_rename(const char* oldpath, const char* newpath) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_rename, rename);
 
 static int stub_renameat(int oldfd, const char* old, int newfd, const char* new) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_renameat, renameat);
 
 static int stub_symlink(const char* oldpath, const char* newpath) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_symlink, symlink);
 
 static int stub_symlinkat(const char* existing, int fd, const char* new) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_symlinkat, symlinkat);
 
 static void stub_sync(void) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
 }
 weak_alias(stub_sync, sync);
 
 static int stub_syncfs(int fd) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_syncfs, syncfs);
 
 static mode_t stub_umask(mode_t mask) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
@@ -417,6 +493,7 @@
 
 int stub_select(int n, fd_set* restrict rfds, fd_set* restrict wfds, fd_set* restrict efds,
                 struct timeval* restrict tv) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
@@ -424,12 +501,14 @@
 
 int stub_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) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_pselect, pselect);
 
 static int stub_poll(struct pollfd* fds, nfds_t n, int timeout) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
@@ -437,42 +516,49 @@
 
 static int stub_ppoll(struct pollfd* fds, nfds_t n, const struct timespec* timeout_ts,
                       const sigset_t* sigmask) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_ppoll, ppoll);
 
 static int stub_ioctl(int fd, int req, ...) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_ioctl, ioctl);
 
 static int stub_posix_fadvise(int fd, off_t base, off_t len, int advice) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_posix_fadvise, posix_fadvise);
 
 static int stub_posix_fallocate(int fd, off_t base, off_t len) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_posix_fallocate, posix_fallocate);
 
 static int stub_ttyname_r(int fd, char* name, size_t size) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_ttyname_r, ttyname_r);
 
 static int stub_uname(struct utsname* uts) {
+    libc_io_functions_not_implemented();
     errno = ENOSYS;
     return -1;
 }
 weak_alias(stub_uname, uname);
 
 static int stub__fd_open_max(void) {
+    libc_io_functions_not_implemented();
     return -1;
 }
 weak_alias (stub__fd_open_max, _fd_open_max);