diff options
author | Jari Vetoniemi <mailroxas@gmail.com> | 2018-04-18 16:06:36 +0300 |
---|---|---|
committer | Jari Vetoniemi <mailroxas@gmail.com> | 2018-04-18 16:06:36 +0300 |
commit | 729566b9db41a4425c26ee7fad8c5d1f48355f4c (patch) | |
tree | 8ce0fcaeb1ce51e884f3f88166c8e079e6b7ff3d /src/libc-stdio.h | |
parent | 793d5888769a7351fc699a31f6caa73bcbcbe338 (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.
Diffstat (limited to 'src/libc-stdio.h')
-rw-r--r-- | src/libc-stdio.h | 72 |
1 files changed, 72 insertions, 0 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)); +} |