From f67416822a54109bd9cfa0fd210d7d8f53412ced Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Wed, 14 Jun 2017 13:09:23 -0500 Subject: move all compatibility library stuff into libgcompat/ --- libgcompat/backtrace.c | 44 +++++++++++++++++ libgcompat/dlmopen.c | 15 ++++++ libgcompat/dlvsym.c | 14 ++++++ libgcompat/gnulib.c | 8 +++ libgcompat/malloc.c | 46 +++++++++++++++++ libgcompat/math.c | 21 ++++++++ libgcompat/pthread.c | 31 ++++++++++++ libgcompat/resource.c | 37 ++++++++++++++ libgcompat/setjmp.c | 7 +++ libgcompat/stdio.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++ libgcompat/stdlib.c | 14 ++++++ libgcompat/string.c | 84 ++++++++++++++++++++++++++++++++ libgcompat/version.c | 14 ++++++ 13 files changed, 465 insertions(+) create mode 100644 libgcompat/backtrace.c create mode 100644 libgcompat/dlmopen.c create mode 100644 libgcompat/dlvsym.c create mode 100644 libgcompat/gnulib.c create mode 100644 libgcompat/malloc.c create mode 100644 libgcompat/math.c create mode 100644 libgcompat/pthread.c create mode 100644 libgcompat/resource.c create mode 100644 libgcompat/setjmp.c create mode 100644 libgcompat/stdio.c create mode 100644 libgcompat/stdlib.c create mode 100644 libgcompat/string.c create mode 100644 libgcompat/version.c (limited to 'libgcompat') diff --git a/libgcompat/backtrace.c b/libgcompat/backtrace.c new file mode 100644 index 0000000..2ceb334 --- /dev/null +++ b/libgcompat/backtrace.c @@ -0,0 +1,44 @@ +#include +#include +#include + +#define _frame_level(addr_buf, curr, frame, size) \ + if(__builtin_frame_address(frame) != NULL && (curr = __builtin_return_address(frame)) > 0x1000 && frame <= size) addr_buf[frame] = curr; \ + else return size; + +int backtrace(void **addr_buf, int size) +{ + void *curr; + _frame_level(addr_buf, curr, 0, size) + _frame_level(addr_buf, curr, 1, size) + _frame_level(addr_buf, curr, 2, size) + _frame_level(addr_buf, curr, 3, size) + _frame_level(addr_buf, curr, 4, size) + _frame_level(addr_buf, curr, 5, size) + _frame_level(addr_buf, curr, 6, size) + _frame_level(addr_buf, curr, 7, size) + _frame_level(addr_buf, curr, 8, size) + _frame_level(addr_buf, curr, 9, size) + return 9; +} + +char **backtrace_symbols(void * const *addr_buf, int size) +{ + char **result = calloc(sizeof(char *), size); + if(result == NULL) return result; + + for(int next = 0; next < size; next++) + { + Dl_info info; + int err = dladdr(addr_buf[next], &info); + + if(err != 0) + { + result[next] = "??:0"; + } else { + result[next] = info.dli_sname; + } + } + + return result; +} diff --git a/libgcompat/dlmopen.c b/libgcompat/dlmopen.c new file mode 100644 index 0000000..fecb29c --- /dev/null +++ b/libgcompat/dlmopen.c @@ -0,0 +1,15 @@ +#include // dlopen +#include // fprintf +#include // getenv + +void *dlmopen(long lmid, const char *pathname, int mode) +{ + if(getenv("GLIBC_FAKE_DEBUG")) + { + fprintf(stderr, "library %s was requested to load in %ld namespace", + pathname, lmid); + } + + return dlopen(pathname, mode); +} + diff --git a/libgcompat/dlvsym.c b/libgcompat/dlvsym.c new file mode 100644 index 0000000..3d744ea --- /dev/null +++ b/libgcompat/dlvsym.c @@ -0,0 +1,14 @@ +#include // dlsym +#include // fprintf +#include // getenv + +void *dlvsym(void *handle, char *symbol, char *version) +{ + if(getenv("GLIBC_FAKE_DEBUG")) + { + fprintf(stderr, "symbol %s with version %s is being redirected", + symbol, version); + } + + return dlsym(handle, symbol); +} diff --git a/libgcompat/gnulib.c b/libgcompat/gnulib.c new file mode 100644 index 0000000..08544fc --- /dev/null +++ b/libgcompat/gnulib.c @@ -0,0 +1,8 @@ +#include +#include + +unsigned long __fdelt_chk(unsigned long size) +{ + assert(size < FD_SETSIZE); + return size / (sizeof(unsigned long)<<3); +} diff --git a/libgcompat/malloc.c b/libgcompat/malloc.c new file mode 100644 index 0000000..3a5818c --- /dev/null +++ b/libgcompat/malloc.c @@ -0,0 +1,46 @@ +/* struct mallinfo pulled from mallinfo.3: + * + * Copyright (c) 2012 by Michael Kerrisk + * + * Permission is granted to make and distribute verbatim copies of this + * manual provided the copyright notice and this permission notice are + * preserved on all copies. + * + * Permission is granted to copy and distribute modified versions of this + * manual under the conditions for verbatim copying, provided that the + * entire resulting derived work is distributed under the terms of a + * permission notice identical to this one. + * + * Since the Linux kernel and libraries are constantly changing, this + * manual page may be incorrect or out-of-date. The author(s) assume no + * responsibility for errors or omissions, or for damages resulting from + * the use of the information contained herein. The author(s) may not + * have taken the same level of care in the production of this manual, + * which is licensed free of charge, as they might when working + * professionally. + * + * Formatted or processed versions of this manual, if unaccompanied by + * the source, must acknowledge the copyright and authors of this work. + */ + +#include /* memset */ + +struct mallinfo { + int arena; /* Non-mmapped space allocated (bytes) */ + int ordblks; /* Number of free chunks */ + int smblks; /* Number of free fastbin blocks */ + int hblks; /* Number of mmapped regions */ + int hblkhd; /* Space allocated in mmapped regions (bytes) */ + int usmblks; /* Maximum total allocated space (bytes) */ + int fsmblks; /* Space in freed fastbin blocks (bytes) */ + int uordblks; /* Total allocated space (bytes) */ + int fordblks; /* Total free space (bytes) */ + int keepcost; /* Top-most, releasable space (bytes) */ +}; + +struct mallinfo mallinfo(void) +{ + struct mallinfo my_info; + memset(&my_info, 0, sizeof(struct mallinfo)); + return my_info; +} diff --git a/libgcompat/math.c b/libgcompat/math.c new file mode 100644 index 0000000..bacec36 --- /dev/null +++ b/libgcompat/math.c @@ -0,0 +1,21 @@ +#include // isinf, isnan + +int __isinff(float number) +{ + return isinf(number); +} + +int __isinf(double number) +{ + return isinf(number); +} + +int __isnanf(float number) +{ + return isnan(number); +} + +int __isnan(double number) +{ + return isnan(number); +} diff --git a/libgcompat/pthread.c b/libgcompat/pthread.c new file mode 100644 index 0000000..b4ea054 --- /dev/null +++ b/libgcompat/pthread.c @@ -0,0 +1,31 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* "Now we are all sons of bitches." */ +int pthread_setname_np(pthread_t thread, const char *name) +{ + char path[PATH_MAX]; + int fd; + /* Cthulhu have mercy */ + pid_t *my_pid = (pid_t *)((void *)thread + (sizeof(uintptr_t) * 7)); + size_t len = strlen(name); + + if(len > 15) + { + return -ERANGE; + } + + snprintf(path, PATH_MAX, "/proc/self/tid/%u/name", *my_pid); + fd = open(path, O_RDWR); + write(fd, name, len + 1); + close(fd); + + return 0; +} diff --git a/libgcompat/resource.c b/libgcompat/resource.c new file mode 100644 index 0000000..029b31e --- /dev/null +++ b/libgcompat/resource.c @@ -0,0 +1,37 @@ +#include /* setrlimit, struct rlimit */ +#include /* assert */ +#include /* dlsym, RTLD_NEXT */ +#include /* NULL */ +#include /* memcpy */ + +/* Sigh. + * Valve compiled Steam against the glibc2.2 version of setrlimit. + * This broken version aliased 0 to RLIM_INFINITY. + * + * So, what you have to do is: if you want to run steam with this gcompat, + * ensure you compile *without* defining NO_BROKEN_SHADOW_SETRLIMIT. + * If you do *not* want to run steam with this gcompat, define it. + * + * The only problem with enabling this all the time is that if a binary + * really does need a ulimit to be 0 for any reason (such as coredumps), it + * very obviously won't work here. + */ +#ifndef NO_BROKEN_SHADOW_SETRLIMIT +int (*real_rlimit)(int, const struct rlimit *); + +int setrlimit(int resource, const struct rlimit *rlim) +{ + struct rlimit my_rlim; + real_rlimit = dlsym(RTLD_NEXT, "setrlimit"); + assert(real_rlimit != NULL); + + memcpy(&my_rlim, rlim, sizeof(struct rlimit)); + + if(my_rlim.rlim_cur == 0) + { + my_rlim.rlim_cur = my_rlim.rlim_max; + } + + return real_rlimit(resource, &my_rlim); +} +#endif diff --git a/libgcompat/setjmp.c b/libgcompat/setjmp.c new file mode 100644 index 0000000..306868f --- /dev/null +++ b/libgcompat/setjmp.c @@ -0,0 +1,7 @@ +#include +#include + +void __longjmp_chk(jmp_buf env, int val) +{ + longjmp(env, val); +} diff --git a/libgcompat/stdio.c b/libgcompat/stdio.c new file mode 100644 index 0000000..89bd677 --- /dev/null +++ b/libgcompat/stdio.c @@ -0,0 +1,130 @@ +#include +#include +#include +#include + +size_t __fread_chk(void *ptr, size_t size, size_t nmemb, FILE *stream) +{ + assert(ptr != NULL); + assert(stream != NULL); + return fread(ptr, size, nmemb, stream); +} + +int __printf_chk(int flag, const char *format, ...) +{ + va_list argp; + int result; + + if(flag > 0) + { + assert(format != NULL); + } + + va_start(argp, format); + result = vprintf(format, argp); + va_end(argp); + + return result; +} + +int __fprintf_chk(FILE *stream, int flag, const char *format, ...) +{ + va_list argp; + int result; + + if(flag > 0) + { + assert(stream != NULL); + assert(format != NULL); + } + + va_start(argp, format); + result = vfprintf(stream, format, argp); + va_end(argp); + + return result; +} + +int __sprintf_chk(char *str, int flag, size_t strlen, const char *format, ...) +{ + va_list argp; + int result; + + assert(strlen > 0); + + va_start(argp, format); + result = vsnprintf(str, strlen, format, argp); + va_end(argp); + + return result; +} + +int __snprintf_chk(char *str, size_t size, int flag, size_t strlen, const char *format, ...) +{ + va_list argp; + int result; + + if(flag > 0) + { + assert(format != NULL); + } + // must always be done per LFS + assert(size <= strlen); + + va_start(argp, format); + result = vsnprintf(str, size, format, argp); + va_end(argp); + + return result; +} + +int __swprintf_chk(wchar_t *wcs, size_t maxlen, int flag, size_t wcslen, const wchar_t *format, ...) +{ + va_list argp; + int result; + + if(flag > 0) + { + assert(format != NULL); + } + // must always be done per LFS + assert(maxlen <= wcslen); + + va_start(argp, format); + result = vswprintf(wcs, maxlen, format, argp); + va_end(argp); + + return result; +} + +int __vasprintf_chk(char **strp, int flag, const char *fmt, va_list ap) +{ + if(flag > 0) + { + assert(strp != NULL); + assert(fmt != NULL); + } + return vasprintf(strp, fmt, ap); +} + +int __vfprintf_chk(FILE *stream, int flag, const char *format, va_list ap) +{ + if(flag > 0) + { + assert(stream != NULL); + assert(format != NULL); + } + return vfprintf(stream, format, ap); +} + +int __vsnprintf_chk(char *str, size_t size, int flag, size_t strlen, const char *format, va_list ap) +{ + if(flag > 0) + { + assert(format != NULL); + } + // must always be done per LFS + assert(size <= strlen); + return vsnprintf(str, size, format, ap); +} + diff --git a/libgcompat/stdlib.c b/libgcompat/stdlib.c new file mode 100644 index 0000000..30c904e --- /dev/null +++ b/libgcompat/stdlib.c @@ -0,0 +1,14 @@ +#include // assert +#include // strtod + +char *__realpath_chk(const char *path, char *resolved_path) +{ + assert(path != NULL); + return realpath(path, resolved_path); +} + +double __strtod_internal(const char *__nptr, char **__endptr, int __group) +{ + assert(__group == 0); + return strtod(__nptr, __endptr); +} diff --git a/libgcompat/string.c b/libgcompat/string.c new file mode 100644 index 0000000..9a1cb60 --- /dev/null +++ b/libgcompat/string.c @@ -0,0 +1,84 @@ +#include /* assert */ +#include /* memcpy, strcpy, strncat, strndup */ + +/* "Checked" memcpy */ +void *__memcpy_chk(void *dest, const void *src, size_t len, size_t destlen) +{ + assert(dest != NULL); + assert(src != NULL); + assert(len <= destlen); + if(src < dest) + { + assert(!(src + len >= dest)); + } else { + assert(!(dest + len >= src)); + } + return memcpy(dest, src, len); +} + +/* "Checked" strncat */ +char *__strncat_chk(char *dest, const char *src, size_t n, size_t destlen) +{ + assert(dest != NULL); + assert(src != NULL); + assert(n <= destlen); + + return strncat(dest, src, n); +} + +/* "Checked" strcat */ +char *__strcat_chk(char *dest, const char *src, size_t destlen) +{ + return strncat(dest, src, destlen - 1); +} + +/* "Checked" strncpy */ +char *__strncpy_chk(char *dest, const char *src, size_t n, size_t destlen) +{ + assert(dest != NULL); + assert(src != NULL); + assert(strlen(src) < destlen); + + return strncpy(dest, src, n); +} + +/* "Checked" strcpy */ +char *__strcpy_chk(char *dest, const char *src, size_t destlen) +{ + assert(dest != NULL); + assert(src != NULL); + assert(strlen(src) < destlen); + + return strcpy(dest, src); +} + +/* Literally a useless __ alias. */ +char *__strndup(const char *str, size_t count) +{ + return strndup(str, count); +} + +/* The existance of this method, and the fact it is used in real code, gives + * me nightmares. */ +void *rawmemchr(const void *s, int c) +{ + const unsigned char *haystack = s; + unsigned char needle = (unsigned char)c; + while(*haystack++ != needle); + return (void *)haystack; +} + +extern __typeof(rawmemchr) __rawmemchr __attribute__((weak, alias("rawmemchr"))); + +/* Another useless __ alias */ +char *__strtok_r(char *str, const char *delim, char **saveptr) +{ + return strtok_r(str, delim, saveptr); +} + +/* The "global" definition of strsep in glibc, used when architecture dependent + * assembler versions aren't good enough. */ +char *__strsep_g(char **stringp, const char *delim) +{ + return strsep(stringp, delim); +} diff --git a/libgcompat/version.c b/libgcompat/version.c new file mode 100644 index 0000000..63146f8 --- /dev/null +++ b/libgcompat/version.c @@ -0,0 +1,14 @@ +#include // getenv + +const char *gnu_get_libc_version(void) +{ + char *ver = getenv("GLIBC_FAKE_VERSION"); + if(ver == NULL) ver = "2.8"; + + return ver; +} + +const char *gnu_get_libc_release(void) +{ + return "stable"; +} -- cgit v1.2.3-70-g09d2