summaryrefslogtreecommitdiff
path: root/libgcompat
diff options
context:
space:
mode:
Diffstat (limited to 'libgcompat')
-rw-r--r--libgcompat/backtrace.c44
-rw-r--r--libgcompat/dlmopen.c15
-rw-r--r--libgcompat/dlvsym.c14
-rw-r--r--libgcompat/gnulib.c8
-rw-r--r--libgcompat/malloc.c46
-rw-r--r--libgcompat/math.c21
-rw-r--r--libgcompat/pthread.c31
-rw-r--r--libgcompat/resource.c37
-rw-r--r--libgcompat/setjmp.c7
-rw-r--r--libgcompat/stdio.c130
-rw-r--r--libgcompat/stdlib.c14
-rw-r--r--libgcompat/string.c84
-rw-r--r--libgcompat/version.c14
13 files changed, 465 insertions, 0 deletions
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 <dlfcn.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#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 <dlfcn.h> // dlopen
+#include <stdio.h> // fprintf
+#include <stdlib.h> // 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 <dlfcn.h> // dlsym
+#include <stdio.h> // fprintf
+#include <stdlib.h> // 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 <assert.h>
+#include <sys/select.h>
+
+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 <mtk.manpages@gmail.com>
+ *
+ * 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 <string.h> /* 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 <math.h> // 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 <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+/* "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 <sys/resource.h> /* setrlimit, struct rlimit */
+#include <assert.h> /* assert */
+#include <dlfcn.h> /* dlsym, RTLD_NEXT */
+#include <stdlib.h> /* NULL */
+#include <string.h> /* 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 <assert.h>
+#include <setjmp.h>
+
+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 <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <wchar.h>
+
+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.h> // assert
+#include <stdlib.h> // 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.h> /* assert */
+#include <string.h> /* 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 <stdlib.h> // 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";
+}