diff --git a/options/ansi/include/inttypes.h b/options/ansi/include/inttypes.h index be9b8742d3..968a849ab2 100644 --- a/options/ansi/include/inttypes.h +++ b/options/ansi/include/inttypes.h @@ -95,6 +95,7 @@ #define SCNx32 "x" #define SCNx64 "lx" #define SCNxMAX "lx" +#define SCNxPTR "lx" #define SCNd64 "ld" diff --git a/options/internal/include/mlibc/thread.hpp b/options/internal/include/mlibc/thread.hpp index 0781966f11..0909e18cd3 100644 --- a/options/internal/include/mlibc/thread.hpp +++ b/options/internal/include/mlibc/thread.hpp @@ -1,9 +1,11 @@ #pragma once #include +#include namespace mlibc { Tcb *get_current_tcb(); +uintptr_t get_sp(); } // namespace mlibc diff --git a/options/internal/x86_64/thread.cpp b/options/internal/x86_64/thread.cpp index ae0b02302c..6b320cd075 100644 --- a/options/internal/x86_64/thread.cpp +++ b/options/internal/x86_64/thread.cpp @@ -10,4 +10,10 @@ Tcb *get_current_tcb() { return reinterpret_cast(ptr); } +uintptr_t get_sp() { + uintptr_t rsp; + asm ("mov %%rsp, %0" : "=r"(rsp)); + return rsp; +} + } // namespace mlibc diff --git a/options/posix/generic/pthread-stubs.cpp b/options/posix/generic/pthread-stubs.cpp index 0e11680692..8a79be7269 100644 --- a/options/posix/generic/pthread-stubs.cpp +++ b/options/posix/generic/pthread-stubs.cpp @@ -1,10 +1,12 @@ #include #include +#include #include #include #include #include +#include #include #include @@ -188,11 +190,45 @@ int pthread_attr_setschedpolicy(pthread_attr_t *__restrict attr, int policy) { return 0; } +namespace { + void get_own_stackinfo(void **stack_addr, size_t *stack_size) { + auto fp = fopen("/proc/self/maps", "r"); + if (!fp) { + mlibc::infoLogger() << "mlibc pthreads: /proc/self/maps does not exist! Producing incorrect" + " stack results!" << frg::endlog; + return; + } + + char line[256]; + auto sp = mlibc::get_sp(); + while (fgets(line, 128, fp)) { + uintptr_t from, to; + if(sscanf(line, "%lx-%lx", &from, &to) != 2) + continue; + if (sp < to && sp > from) { + // We need to return the lowest byte of the stack. + *stack_addr = reinterpret_cast(from); + *stack_size = to - from; + fclose(fp); + return; + } + } + + fclose(fp); + } +} + int pthread_getattr_np(pthread_t thread, pthread_attr_t *attr) { auto tcb = reinterpret_cast(thread); *attr = pthread_attr_t{}; - attr->__mlibc_stacksize = tcb->stackSize; - attr->__mlibc_stackaddr = tcb->stackAddr; + + if (!tcb->stackAddr || !tcb->stackSize) { + get_own_stackinfo(&attr->__mlibc_stackaddr, &attr->__mlibc_stacksize); + } else { + attr->__mlibc_stacksize = tcb->stackSize; + attr->__mlibc_stackaddr = tcb->stackAddr; + } + attr->__mlibc_guardsize = tcb->guardSize; attr->__mlibc_detachstate = tcb->isJoinable ? PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED; mlibc::infoLogger() << "pthread_getattr_np(): Implementation is incomplete!" << frg::endlog; diff --git a/tests/posix/pthread_attr.c b/tests/posix/pthread_attr.c index a316c94284..c7bf327ae0 100644 --- a/tests/posix/pthread_attr.c +++ b/tests/posix/pthread_attr.c @@ -130,6 +130,36 @@ static void test_stack() { assert(new_size == stacksize); } +static void *getattr_worker(void *arg) { + return NULL; +} + +static void test_getattrnp() { + pthread_attr_t attr; + size_t stacksize = PTHREAD_STACK_MIN; + assert(!pthread_attr_init(&attr)); + assert(!pthread_attr_setstacksize(&attr, stacksize)); + + pthread_t thread; + assert(!pthread_create(&thread, &attr, getattr_worker, NULL)); + assert(!pthread_getattr_np(thread, &attr)); + size_t other_stacksize; + assert(!pthread_attr_getstacksize(&attr, &other_stacksize)); + assert(other_stacksize == stacksize); + assert(!pthread_join(thread, NULL)); + + pthread_t own_thread = pthread_self(); + void *stack; + assert(!pthread_getattr_np(own_thread, &attr)); + assert(!pthread_attr_getstack(&attr, &stack, &other_stacksize)); + assert(stack); + assert(other_stacksize); + // Check that we can read from the highest byte returned. + // pthread_getattr_np() should return the lowest byte + // of the stack. + assert(!*(char*)(stack + other_stacksize - 1)); +} + int main() { test_detachstate(); test_stacksize(); @@ -140,4 +170,5 @@ int main() { test_schedpolicy(); test_stackaddr(); test_stack(); + test_getattrnp(); }