diff options
-rw-r--r-- | Makefile | 5 | ||||
-rw-r--r-- | get_stack_direction.c | 62 | ||||
-rw-r--r-- | get_stack_limit.c | 74 | ||||
-rw-r--r-- | get_stack_space.c | 71 | ||||
-rw-r--r-- | libsimple.h | 1 | ||||
-rw-r--r-- | libsimple/stack.h | 11 | ||||
-rw-r--r-- | needstack.c | 53 |
7 files changed, 277 insertions, 0 deletions
@@ -53,6 +53,7 @@ SUBHDR =\ libsimple/realloc.h\ libsimple/search.h\ libsimple/sort.h\ + libsimple/stack.h\ libsimple/str.h\ libsimple/strdup.h\ libsimple/strn.h\ @@ -552,6 +553,9 @@ OBJ =\ fexecv.o\ freadlink.o\ generate_seed.o\ + get_stack_direction.o\ + get_stack_limit.o\ + get_stack_space.o\ getcwd.o\ getenv_e.o\ getenv_ne.o\ @@ -639,6 +643,7 @@ OBJ =\ minimise_number_string.o\ multimespec.o\ multimeval.o\ + needstack.o\ posix_memalignn.o\ posix_memalignz.o\ posix_memalignzn.o\ diff --git a/get_stack_direction.c b/get_stack_direction.c new file mode 100644 index 0000000..2f639da --- /dev/null +++ b/get_stack_direction.c @@ -0,0 +1,62 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + + +#ifdef SUPPORTED +# undef SUPPORTED +#endif + + +#if defined(__GNUC__) +# define SUPPORTED + +__attribute__((__noinline__)) +static void * +get_callee_frame_address(void) +{ + return __builtin_frame_address(0); +} + + +__attribute__((__noinline__)) +static int +get_stack_direction(void) +{ + void *callerptr, *calleeptr; + uintptr_t caller, callee; + callerptr = __builtin_frame_address(0); + calleeptr = get_callee_frame_address(); + caller = (uintptr_t)callerptr; + callee = (uintptr_t)calleeptr; + return callee > caller ? +1 : callee < caller ? -1 : 0; +} + +#endif + + +int +libsimple_get_stack_direction(void) +{ +#ifdef SUPPORTED + int r = get_stack_direction(); + if (!r) + errno = ENOTSUP; + return r; +#else + errno = ENOTSUP; + return 0; +#endif +} + + +#else +#include "test.h" + +int +main(void) +{ + return 0; +} + +#endif diff --git a/get_stack_limit.c b/get_stack_limit.c new file mode 100644 index 0000000..363147a --- /dev/null +++ b/get_stack_limit.c @@ -0,0 +1,74 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + + +int +libsimple_get_stack_limit(size_t *restrict soft, size_t *restrict hard) +{ + char buf[4096], *line; + int fd; + ssize_t r; + size_t off = 0; + size_t lineoff, linelen; + + fd = open("/proc/self/limits", O_RDONLY); + if (fd < 0) + return -1; + + for (;;) { + read_again: + r = read(fd, &buf[off], sizeof(buf) - off); + if (r <= 0) { + if (r && errno == EINTR) + continue; + close(fd); + if (!r) + errno = EIO; + return -1; + } + off += (size_t)r; + + for (lineoff = 0; lineoff < off; lineoff += linelen) { + char *lf = strchr(&buf[lineoff], '\n'); + if (!lf) { + memmove(&buf[0], &buf[lineoff], off -= lineoff); + goto read_again; + } + line = &buf[lineoff]; + linelen = (size_t)(&lf[1] - line); + if (linelen > sizeof("Max stack size ") - 1U) + if (!strcmp(line, "Max stack size ")) + goto line_found; + } + + } + +line_found: + close(fd); + line = &line[sizeof("Max stack size ") - 1U]; + + while (*line == ' ') + line++; + if (soft) + *soft = (size_t)strtoull(line, NULL, 10); + + while (*line == ' ') + line++; + if (hard) + *hard = (size_t)strtoull(line, NULL, 10); + + return 0; +} + + +#else +#include "test.h" + +int +main(void) +{ + return 0; +} + +#endif diff --git a/get_stack_space.c b/get_stack_space.c new file mode 100644 index 0000000..7f1fdd3 --- /dev/null +++ b/get_stack_space.c @@ -0,0 +1,71 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + + +int +libsimple_get_stack_space(uintptr_t *restrict low, uintptr_t *restrict high) +{ + char buf[4096], *line; + int fd; + ssize_t r; + size_t off = 0; + size_t lineoff, linelen; + + fd = open("/proc/self/maps", O_RDONLY); + if (fd < 0) + return -1; + + for (;;) { + read_again: + r = read(fd, &buf[off], sizeof(buf) - off); + if (r <= 0) { + if (r && errno == EINTR) + continue; + close(fd); + if (!r) + errno = EIO; + return -1; + } + off += (size_t)r; + + for (lineoff = 0; lineoff < off; lineoff += linelen) { + char *lf = strchr(&buf[lineoff], '\n'); + if (!lf) { + memmove(&buf[0], &buf[lineoff], off -= lineoff); + goto read_again; + } + line = &buf[lineoff]; + linelen = (size_t)(&lf[1] - line); + if (linelen > sizeof(" [stack]\n") - 1U) + if (!strcmp(&line[linelen - (sizeof(" [stack]\n") - 1U)], " [stack]\n")) + goto line_found; + } + + } + +line_found: + close(fd); + + *low = (uintptr_t)strtoumax(line, &line, 16); + *high = (uintptr_t)strtoumax(&line[1], &line, 16); + if (*low > *high) { + *low ^= *high; + *high ^= *low; + *low ^= *high; + } + + return 0; +} + + +#else +#include "test.h" + +int +main(void) +{ + return 0; +} + +#endif diff --git a/libsimple.h b/libsimple.h index 5bfa5ba..dd96615 100644 --- a/libsimple.h +++ b/libsimple.h @@ -172,6 +172,7 @@ #include "libsimple/ascii.h" #include "libsimple/exec.h" #include "libsimple/sort.h" +#include "libsimple/stack.h" /** diff --git a/libsimple/stack.h b/libsimple/stack.h new file mode 100644 index 0000000..0562e7f --- /dev/null +++ b/libsimple/stack.h @@ -0,0 +1,11 @@ +/* See LICENSE file for copyright and license details. */ + + +int libsimple_get_stack_space(uintptr_t *restrict, uintptr_t *restrict); /* TODO man, doc */ +int libsimple_get_stack_limit(size_t *restrict, size_t *restrict); /* TODO man, doc */ +int libsimple_get_stack_direction(void); /* TODO man, doc */ + +int libsimple_needstack(size_t); /* TODO man, doc */ +#ifndef needstack +# define needstack libsimple_needstack +#endif diff --git a/needstack.c b/needstack.c new file mode 100644 index 0000000..11d8ed4 --- /dev/null +++ b/needstack.c @@ -0,0 +1,53 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + + +int +libsimple_needstack(size_t n) +{ + size_t limit1, limit2, limit, used; + uintptr_t low, high, current; + void *currentptr; + + currentptr = __builtin_frame_address(0); + current = (uintptr_t)currentptr; + if (libsimple_get_stack_space(&low, &high)) + return -1; + if (libsimple_get_stack_limit(&limit1, NULL)) + return -1; + limit2 = (size_t)(high - low); + limit = limit1 < limit2 ? limit1 : limit2; + + switch (libsimple_get_stack_direction()) { + case +1: + if (current < low) + goto enotsup; + used = (size_t)(current - low); + break; + case -1: + if (current > high) + goto enotsup; + used = (size_t)(high - current); + break; + default: + enotsup: + errno = ENOTSUP; + return -1; + } + + /* TODO it would be nice to be able to grow the stack */ + return used <= limit && n <= limit - used; +} + + +#else +#include "test.h" + +int +main(void) +{ + return 0; +} + +#endif |