From 9edd4a9979f520abc6a3f5c0029966b5cc0f280e Mon Sep 17 00:00:00 2001
From: Jari Vetoniemi <mailroxas@gmail.com>
Date: Sat, 2 Jun 2018 22:00:18 +0300
Subject: libc: Wrap low level glibc io calls for stdio

This is much less work and actually works better.
---
 Makefile         |   3 +-
 src/libc-stdio.c |  42 +++++++++++++++++++++++
 src/libc-stdio.h | 102 -------------------------------------------------------
 src/libc.c       |   9 ++++-
 4 files changed, 52 insertions(+), 104 deletions(-)
 create mode 100644 src/libc-stdio.c
 delete mode 100644 src/libc-stdio.h

diff --git a/Makefile b/Makefile
index d5dc142..c7d0515 100644
--- a/Makefile
+++ b/Makefile
@@ -34,9 +34,10 @@ runtime/libdl.so: private override CPPFLAGS += -D_GNU_SOURCE -DLINKER_DEBUG=1
 runtime/libdl.so: private override CFLAGS += -Wno-pedantic -Wno-variadic-macros -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast
 runtime/libdl.so: wrapper.a src/linker/dlfcn.c src/linker/linker.c src/linker/linker_environ.c src/linker/rt.c src/linker/strlcpy.c
 runtime/libc.so: private override CPPFLAGS += -D_GNU_SOURCE
+runtime/libc.so: private override LDFLAGS += -Wl,-wrap,_IO_file_xsputn
 runtime/libc.so: private override CFLAGS += -Wno-deprecated-declarations
 runtime/libc.so: private override LDLIBS += `pkg-config --libs libbsd libunwind`
-runtime/libc.so: verbose src/libc.c
+runtime/libc.so: verbose src/libc.c src/libc-stdio.c
 runtime/libpthread.so: private override CPPFLAGS += -D_GNU_SOURCE
 runtime/libpthread.so: private override LDLIBS += -lpthread
 runtime/libpthread.so: src/libpthread.c
diff --git a/src/libc-stdio.c b/src/libc-stdio.c
new file mode 100644
index 0000000..713497b
--- /dev/null
+++ b/src/libc-stdio.c
@@ -0,0 +1,42 @@
+#include <stdio.h>
+
+struct bionic___sFILE {
+#if defined(__LP64__)
+   char __private[152];
+#else
+   char __private[84];
+#endif
+} __attribute__((aligned(sizeof(void*))));
+
+// Bionic standard stream support pre-M Android
+// Post-M it's saner and they point to stdin/stdout/stderr symbols instead
+const struct bionic___sFILE bionic___sF[3] = {
+   {{ 's', 't', 'd', 'i', 'n' }},
+   {{ 's', 't', 'd', 'o', 'u', 't' }},
+   {{ 's', 't', 'd', 'e', 'r', 'r' }}
+};
+
+static inline FILE*
+bionic_file_to_glibc_file(FILE *f)
+{
+   if (f == (void*)&bionic___sF[0])
+      return stdin;
+   else if (f == (void*)&bionic___sF[1])
+      return stdout;
+   else if (f == (void*)&bionic___sF[2])
+      return stderr;
+   return f;
+}
+
+// Wrapping internal glibc VTABLE functions to handle bionic's pre-M crap
+// We define __real_IO_file_xsputn in libc.c so linker will link our library,
+// it's not used however for anything.
+
+extern size_t
+__real_IO_file_xsputn(FILE *f, const void *buf, size_t n);
+
+size_t
+__wrap_IO_file_xsputn(FILE *f, const void *buf, size_t n)
+{
+   return __real_IO_file_xsputn(bionic_file_to_glibc_file(f), buf, n);
+}
diff --git a/src/libc-stdio.h b/src/libc-stdio.h
deleted file mode 100644
index 9dacd21..0000000
--- a/src/libc-stdio.h
+++ /dev/null
@@ -1,102 +0,0 @@
-#pragma once
-
-#include <wchar.h>
-
-struct bionic___sFILE {
-#if defined(__LP64__)
-   char __private[152];
-#else
-   char __private[84];
-#endif
-} __attribute__((aligned(sizeof(void*))));
-
-// Bionic standard stream support pre-M Android
-// Post-M it's saner and they point to stdin/stdout/stderr symbols instead
-const struct bionic___sFILE bionic___sF[3] = {
-   {{ 's', 't', 'd', 'i', 'n' }},
-   {{ 's', 't', 'd', 'o', 'u', 't' }},
-   {{ 's', 't', 'd', 'e', 'r', 'r' }}
-};
-
-static inline FILE*
-bionic_file_to_glibc_file(FILE *f)
-{
-   if (f == (void*)&bionic___sF[0])
-      return stdin;
-   else if (f == (void*)&bionic___sF[1])
-      return stdout;
-   else if (f == (void*)&bionic___sF[2])
-      return stderr;
-   return f;
-}
-
-FILE*
-bionic_freopen(const char *filename, const char *modes, FILE *stream)
-{
-   return freopen(filename, modes, bionic_file_to_glibc_file(stream));
-}
-
-int
-bionic_fclose(FILE *stream)
-{
-   return fclose(bionic_file_to_glibc_file(stream));
-}
-
-int
-bionic_fputc(int c, FILE *stream)
-{
-   return fputc(c, bionic_file_to_glibc_file(stream));
-}
-
-int
-bionic_putc(int c, FILE *stream)
-{
-   return putc(c, bionic_file_to_glibc_file(stream));
-}
-
-
-int
-bionic_fputs(const char *c, FILE *stream)
-{
-   return fputs(c, bionic_file_to_glibc_file(stream));
-}
-
-wint_t
-bionic_fputwc(wchar_t wc, FILE *stream)
-{
-   return fputwc(wc, bionic_file_to_glibc_file(stream));
-}
-
-wint_t
-bionic_putwc(wchar_t wc, FILE *stream)
-{
-   return putwc(wc, bionic_file_to_glibc_file(stream));
-}
-
-size_t
-bionic_fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
-{
-   char buf[256], fname[256] = {0};
-   stream = bionic_file_to_glibc_file(stream);
-   snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fileno(stream));
-   readlink(buf, fname, sizeof(fname));
-   verbose("%s (%d)\n%p, %zu, %zu, %p", fname, fileno(stream), ptr, size, nmemb, (void*)stream);
-   return fread(ptr, size, nmemb, stream);
-}
-
-size_t
-bionic_fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream)
-{
-   char buf[256], fname[256] = {0};
-   stream = bionic_file_to_glibc_file(stream);
-   snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fileno(stream));
-   readlink(buf, fname, sizeof(fname));
-   verbose("%s (%d)\n%p, %zu, %zu, %p", fname, fileno(stream), ptr, size, nmemb, (void*)stream);
-   return fwrite(ptr, size, nmemb, stream);
-}
-
-int
-bionic_fflush(FILE *stream)
-{
-   return fflush(bionic_file_to_glibc_file(stream));
-}
diff --git a/src/libc.c b/src/libc.c
index a61acd0..7d24275 100644
--- a/src/libc.c
+++ b/src/libc.c
@@ -72,7 +72,14 @@ tkill(int tid, int sig)
 // Stuff needed for runtime compatibility, but not neccessary for linking
 // Also stuff that exists in glibc, but needs to be wrapped for runtime compatibility
 
-#include "libc-stdio.h"
+// Some defines from app-stdio.c as per GNU linker's manual for --wrap:
+//    You may wish to provide a __real_malloc function as well, so that links without the
+//    --wrap option will succeed. If you do this, you should not put the definition of
+//    __real_malloc in the same file as __wrap_malloc; if you do, the assembler may resolve
+//    the call before the linker has a chance to wrap it to malloc.
+
+size_t __real_IO_file_xsputn(FILE *f, const void *buf, size_t n) {}
+
 #include "libc-ctype.h"
 
 const unsigned int bionic___page_size = PAGE_SIZE;
-- 
cgit v1.2.3-70-g09d2