summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJari Vetoniemi <mailroxas@gmail.com>2018-04-18 16:06:36 +0300
committerJari Vetoniemi <mailroxas@gmail.com>2018-04-18 16:06:36 +0300
commit729566b9db41a4425c26ee7fad8c5d1f48355f4c (patch)
tree8ce0fcaeb1ce51e884f3f88166c8e079e6b7ff3d
parent793d5888769a7351fc699a31f6caa73bcbcbe338 (diff)
libc: stdio must be wrapped
Bionic libc does stupid stuff and defines standard streams as macros to reference of an array element. Thus we can't just point standard streams to their respective correct addresses. (Why does both glibc and bionic even expose the internal FILE structs??) So we have to wrap every function that takes FILE* as argument and mangle it with bionic_file_to_glibc_file. We can't just check addresses because gnu's libstdc++ copies the FILE*. I assume same thing happens with the c++ locale support, and we need to do more complex ctype wrapping.
-rw-r--r--src/libc-stdio.h72
-rw-r--r--src/libc-verbose.h20
-rw-r--r--src/libc.c13
3 files changed, 79 insertions, 26 deletions
diff --git a/src/libc-stdio.h b/src/libc-stdio.h
new file mode 100644
index 0000000..7f09c74
--- /dev/null
+++ b/src/libc-stdio.h
@@ -0,0 +1,72 @@
+#pragma once
+
+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)
+{
+ // Can't compare just memory addresses because GNU libstdc++ copies the FILE struct...
+ // Maybe there could be a cleaner solution, this may in practice break if standard streams
+ // are opened with different flags in C++.
+ if (memcmp(f, "stdin", sizeof("stdin")))
+ return stdin;
+ else if (memcmp(f, "stdout", sizeof("stdout")))
+ return stdout;
+ else if (memcmp(f, "stderr", sizeof("stderr")))
+ 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));
+}
+
+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-verbose.h b/src/libc-verbose.h
index 190f0b1..2d46f17 100644
--- a/src/libc-verbose.h
+++ b/src/libc-verbose.h
@@ -144,26 +144,6 @@ bionic_unlink(const char *path)
return unlink(path);
}
-size_t
-bionic_fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
-{
- char buf[256], fname[256] = {0};
- 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};
- 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);
-}
-
char*
bionic_getenv(const char *name)
{
diff --git a/src/libc.c b/src/libc.c
index 66b0d8d..447220e 100644
--- a/src/libc.c
+++ b/src/libc.c
@@ -14,10 +14,6 @@
#include <netdb.h> // h_errno
#include "wrapper/verbose.h"
-#ifdef VERBOSE_FUNCTIONS
-# include "libc-verbose.h"
-#endif
-
struct bionic_dirent {
uint64_t d_ino;
int64_t d_off;
@@ -74,9 +70,10 @@ 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"
+
const char *bionic__ctype_, *bionic__tolower_tab_, *bionic__toupper_tab_;
-char bionic___sF[0x54] = {0};
-unsigned int bionic___page_size = PAGE_SIZE;
+const unsigned int bionic___page_size = PAGE_SIZE;
__attribute_const__
int*
@@ -378,3 +375,7 @@ bionic___futex_wake(volatile void* ftx, int count)
return syscall(SYS_futex, ftx, FUTEX_WAKE, count, NULL, 0);
}
#endif
+
+#ifdef VERBOSE_FUNCTIONS
+# include "libc-verbose.h"
+#endif