diff --git a/core/include/thread.h b/core/include/thread.h index 023626c986..b77ea5606d 100644 --- a/core/include/thread.h +++ b/core/include/thread.h @@ -450,15 +450,20 @@ static inline const char *thread_getname(kernel_pid_t pid) #endif /** - * @brief Measures the stack usage of a stack + * @brief Measures the stack usage of a stack + * @internal Should not be used externally * - * Only works if the thread was created with the flag THREAD_CREATE_STACKTEST. + * Only works if the stack is filled with canaries + * (`*((uintptr_t *)ptr) == (uintptr_t)ptr` for naturally aligned `ptr` within + * the stack). * - * @param[in] stack the stack you want to measure. Try `thread_get_stackstart(thread_get_active())` + * @param[in] stack the stack you want to measure. Try + * `thread_get_stackstart(thread_get_active())` + * @param[in] size size of @p stack in bytes * - * @return the amount of unused space of the thread's stack + * @return the amount of unused space of the thread's stack */ -uintptr_t thread_measure_stack_free(const char *stack); +uintptr_t measure_stack_free_internal(const char *stack, size_t size); /** * @brief Get the number of bytes used on the ISR stack @@ -621,6 +626,24 @@ static inline const char *thread_get_name(const thread_t *thread) #endif } +/** + * @brief Measures the stack usage of a stack + * + * @pre Only works if the thread was created with the flag + * `THREAD_CREATE_STACKTEST`. + * + * @param[in] thread The thread to measure the stack of + * + * @return the amount of unused space of the thread's stack + */ +static inline uintptr_t thread_measure_stack_free(const thread_t *thread) +{ + /* explicitly casting void pointers is bad code style, but needed for C++ + * compatibility */ + return measure_stack_free_internal((const char *)thread_get_stackstart(thread), + thread_get_stacksize(thread)); +} + #ifdef __cplusplus } #endif diff --git a/core/thread.c b/core/thread.c index 6ce6042e2d..cd97c38d60 100644 --- a/core/thread.c +++ b/core/thread.c @@ -171,15 +171,18 @@ void thread_add_to_list(list_node_t *list, thread_t *thread) list->next = new_node; } -uintptr_t thread_measure_stack_free(const char *stack) +uintptr_t measure_stack_free_internal(const char *stack, size_t size) { /* Alignment of stack has been fixed (if needed) by thread_create(), so * we can silence -Wcast-align here */ uintptr_t *stackp = (uintptr_t *)(uintptr_t)stack; + uintptr_t end = (uintptr_t)stack + size; + + /* better be safe than sorry: align end of stack just in case */ + end &= (sizeof(uintptr_t) - 1); - /* assume that the comparison fails before or after end of stack */ /* assume that the stack grows "downwards" */ - while (*stackp == (uintptr_t)stackp) { + while (((uintptr_t)stackp < end) && (*stackp == (uintptr_t)stackp)) { stackp++; } diff --git a/cpu/esp_common/freertos/task.c b/cpu/esp_common/freertos/task.c index 2c3c8b12a5..0563dc339b 100644 --- a/cpu/esp_common/freertos/task.c +++ b/cpu/esp_common/freertos/task.c @@ -197,7 +197,7 @@ UBaseType_t uxTaskGetStackHighWaterMark(TaskHandle_t xTask) thread_t *thread = thread_get((xTask == NULL) ? (uint32_t)thread_getpid() : (uint32_t)xTask); assert(thread != NULL); - return thread_measure_stack_free(thread->stack_start); + return thread_measure_stack_free(thread); } void *pvTaskGetThreadLocalStoragePointer(TaskHandle_t xTaskToQuery, diff --git a/cpu/esp_common/thread_arch.c b/cpu/esp_common/thread_arch.c index d9bb7d4c37..4dcff88eee 100644 --- a/cpu/esp_common/thread_arch.c +++ b/cpu/esp_common/thread_arch.c @@ -92,10 +92,9 @@ void thread_isr_stack_init(void) int thread_isr_stack_usage(void) { - /* cppcheck-suppress comparePointers - * (reason: comes from ESP-SDK, so should be valid) */ - return &port_IntStackTop - &port_IntStack - - thread_measure_stack_free((char*)&port_IntStack); + size_t stack_size = (uintptr_t)&port_IntStackTop - (uintptr_t)&port_IntStack; + return stack_size - + measure_stack_free_internal((char *)&port_IntStack, stack_size); } void *thread_isr_stack_pointer(void) diff --git a/cpu/native/Makefile.include b/cpu/native/Makefile.include index 63b2fa3a9a..1a2ba36a69 100644 --- a/cpu/native/Makefile.include +++ b/cpu/native/Makefile.include @@ -19,3 +19,10 @@ ifeq ($(OS) $(OS_ARCH),Linux x86_64) endif include $(RIOTMAKE)/arch/native.inc.mk + +USE_LIBUCONTEXT := $(shell pkg-config libucontext 2> /dev/null && echo 1 || echo 0) + +ifeq ($(USE_LIBUCONTEXT),1) + CFLAGS += $(pkg-config libucontext --cflags) -DUSE_LIBUCONTEXT=1 + LINKFLAGS += $(shell pkg-config libucontext --libs) +endif diff --git a/cpu/native/include/native_internal.h b/cpu/native/include/native_internal.h index eff3c135fc..91744bab50 100644 --- a/cpu/native/include/native_internal.h +++ b/cpu/native/include/native_internal.h @@ -172,7 +172,7 @@ extern volatile int _native_in_isr; extern volatile int _native_in_syscall; extern char __isr_stack[]; -extern char __end_stack[]; +extern const size_t __isr_stack_size; extern ucontext_t native_isr_context; extern ucontext_t end_context; extern ucontext_t *_native_cur_ctx, *_native_isr_ctx; diff --git a/cpu/native/irq_cpu.c b/cpu/native/irq_cpu.c index 030819c07b..c5e404115a 100644 --- a/cpu/native/irq_cpu.c +++ b/cpu/native/irq_cpu.c @@ -13,10 +13,16 @@ * @author Ludwig Knüpfer */ +/* __USE_GNU for gregs[REG_EIP] access under glibc + * _GNU_SOURCE for REG_EIP and strsignal() under musl */ +#define __USE_GNU +#define _GNU_SOURCE + #include +#include +#include #include #include -#include #ifdef HAVE_VALGRIND_H #include @@ -29,16 +35,12 @@ #define VALGRIND_DEBUG(...) #endif -/* __USE_GNU for gregs[REG_EIP] access under Linux */ -#define __USE_GNU -#include -#undef __USE_GNU - #include "irq.h" #include "cpu.h" #include "periph/pm.h" #include "native_internal.h" +#include "test_utils/expect.h" #define ENABLE_DEBUG 0 #include "debug.h" @@ -50,6 +52,7 @@ volatile int _native_in_syscall; static sigset_t _native_sig_set, _native_sig_set_dint; char __isr_stack[THREAD_STACKSIZE_DEFAULT]; +const size_t __isr_stack_size = sizeof(__isr_stack); ucontext_t native_isr_context; ucontext_t *_native_cur_ctx, *_native_isr_ctx; @@ -58,7 +61,6 @@ volatile int _native_sigpend; int _sig_pipefd[2]; static _native_callback_t native_irq_handlers[255]; -char sigalt_stk[SIGSTKSZ]; void *thread_isr_stack_pointer(void) { @@ -523,8 +525,9 @@ void native_interrupt_init(void) _native_isr_ctx = &native_isr_context; static stack_t sigstk; - sigstk.ss_sp = sigalt_stk; - sigstk.ss_size = sizeof(sigalt_stk); + sigstk.ss_sp = malloc(SIGSTKSZ); + expect(sigstk.ss_sp != NULL); + sigstk.ss_size = SIGSTKSZ; sigstk.ss_flags = 0; if (sigaltstack(&sigstk, NULL) < 0) { diff --git a/cpu/native/native_cpu.c b/cpu/native/native_cpu.c index 8c4d81f0f2..c2c1a39ca4 100644 --- a/cpu/native/native_cpu.c +++ b/cpu/native/native_cpu.c @@ -21,16 +21,22 @@ * @author Kaspar Schleiser */ -#include -#include -#include - +/* __USE_GNU for gregs[REG_EIP] access under glibc + * _GNU_SOURCE for REG_EIP and strsignal() under musl */ #define __USE_GNU -#include -#undef __USE_GNU +#define _GNU_SOURCE -#include #include +#include +#include +#include +#include + +#if USE_LIBUCONTEXT +#include +#else +#include +#endif #ifdef HAVE_VALGRIND_H #include @@ -45,11 +51,11 @@ #include -#include "irq.h" -#include "sched.h" - #include "cpu.h" #include "cpu_conf.h" +#include "irq.h" +#include "sched.h" +#include "test_utils/expect.h" #ifdef MODULE_NETDEV_TAP #include "netdev_tap.h" @@ -62,7 +68,6 @@ extern netdev_tap_t netdev_tap; #include "debug.h" ucontext_t end_context; -char __end_stack[SIGSTKSZ]; /** * make the new context assign `_native_in_isr = 0` before resuming @@ -194,7 +199,7 @@ void cpu_switch_context_exit(void) irq_disable(); _native_in_isr = 1; native_isr_context.uc_stack.ss_sp = __isr_stack; - native_isr_context.uc_stack.ss_size = SIGSTKSZ; + native_isr_context.uc_stack.ss_size = __isr_stack_size; native_isr_context.uc_stack.ss_flags = 0; makecontext(&native_isr_context, isr_cpu_switch_context_exit, 0); if (setcontext(&native_isr_context) == -1) { @@ -247,7 +252,7 @@ void thread_yield_higher(void) _native_in_isr = 1; irq_disable(); native_isr_context.uc_stack.ss_sp = __isr_stack; - native_isr_context.uc_stack.ss_size = SIGSTKSZ; + native_isr_context.uc_stack.ss_size = __isr_stack_size; native_isr_context.uc_stack.ss_flags = 0; makecontext(&native_isr_context, isr_thread_yield, 0); if (swapcontext(ctx, &native_isr_context) == -1) { @@ -263,13 +268,16 @@ void native_cpu_init(void) err(EXIT_FAILURE, "native_cpu_init: getcontext"); } - end_context.uc_stack.ss_sp = __end_stack; + end_context.uc_stack.ss_sp = malloc(SIGSTKSZ); + expect(end_context.uc_stack.ss_sp != NULL); end_context.uc_stack.ss_size = SIGSTKSZ; end_context.uc_stack.ss_flags = 0; makecontext(&end_context, sched_task_exit, 0); - (void) VALGRIND_STACK_REGISTER(__end_stack, __end_stack + sizeof(__end_stack)); + (void)VALGRIND_STACK_REGISTER(end_context.uc_stack.ss_sp, + (char *)end_context.uc_stack.ss_sp + end_context.uc_stack.ss_size); VALGRIND_DEBUG("VALGRIND_STACK_REGISTER(%p, %p)\n", - (void*)__end_stack, (void*)(__end_stack + sizeof(__end_stack))); + (void*)end_context.uc_stack.ss_sp, + (void*)((char *)end_context.uc_stack.ss_sp + end_context.uc_stack.ss_size)); DEBUG("RIOT native cpu initialized.\n"); } diff --git a/cpu/native/startup.c b/cpu/native/startup.c index 5014e0c701..bb3431a7ed 100644 --- a/cpu/native/startup.c +++ b/cpu/native/startup.c @@ -22,30 +22,28 @@ #else #include #endif -#include "byteorder.h" #include +#include +#include +#include +#include #include #include #include #include -#include -#include #include -#include -#include #include +#include +#include -#include "kernel_init.h" -#include "cpu.h" +#include "byteorder.h" #include "irq.h" - -#include "board_internal.h" +#include "kernel_init.h" #include "native_internal.h" -#include "stdio_base.h" -#include "tty_uart.h" - #include "periph/init.h" #include "periph/pm.h" +#include "test_utils/expect.h" +#include "tty_uart.h" #define ENABLE_DEBUG 0 #include "debug.h" @@ -121,6 +119,12 @@ static const char short_opts[] = ":hi:s:deEoc:" #endif ""; +#if __GLIBC__ +static const bool _is_glibc = true; +#else +static const bool _is_glibc = false; +#endif + static const struct option long_opts[] = { { "help", no_argument, NULL, 'h' }, { "id", required_argument, NULL, 'i' }, @@ -468,6 +472,49 @@ __attribute__((constructor)) static void startup(int argc, char **argv, char **e /* initialize stdio as early as possible */ early_init(); + /* Passing argc, argv, and envp to init_fini handlers is a glibc + * extension. If we are not running glibc, we parse /proc/self/cmdline + * to populate argc and argv by hand */ + if (!_is_glibc) { + const size_t bufsize = 4096; + const size_t argc_max = 32; + size_t cmdlen = 0; + char *cmdline = malloc(bufsize); + argv = calloc(sizeof(char *), argc_max); + argc = 0; + envp = NULL; + expect(cmdline != NULL); + int cmdfd = real_open("/proc/self/cmdline", O_RDONLY); + expect(cmdfd != -1); + ssize_t count; + do { + count = real_read(cmdfd, cmdline + cmdlen, bufsize - cmdlen); + if (count < 0) { + if ((errno == EWOULDBLOCK) || (errno == EAGAIN)) { + continue; + } + expect(0); + } + cmdlen += count; + } while (count > 0); + real_close(cmdfd); + cmdline = realloc(cmdline, cmdlen); + + char *argpos = cmdline; + while ((size_t)argc < argc_max) { + if (argpos == cmdline + cmdlen) { + argv[argc] = NULL; + break; + } + size_t len = strlen(argpos); + + argv[argc++] = argpos; + argpos += len + 1; + } + expect((size_t)argc < argc_max); + argv = realloc(argv, sizeof(char *) * (argc + 1)); + } + _native_argv = argv; _progname = argv[0]; _native_pid = real_getpid(); diff --git a/cpu/native/syscalls.c b/cpu/native/syscalls.c index 382183d23a..76a13e9f81 100644 --- a/cpu/native/syscalls.c +++ b/cpu/native/syscalls.c @@ -143,7 +143,7 @@ void _native_syscall_leave(void) * stacks are manually word aligned in thread_static_init() */ _native_cur_ctx = (ucontext_t *)(uintptr_t)thread_get_active()->sp; native_isr_context.uc_stack.ss_sp = __isr_stack; - native_isr_context.uc_stack.ss_size = SIGSTKSZ; + native_isr_context.uc_stack.ss_size = __isr_stack_size; native_isr_context.uc_stack.ss_flags = 0; native_interrupts_enabled = 0; makecontext(&native_isr_context, native_irq_handler, 0); diff --git a/examples/rust-gcoap/Cargo.lock b/examples/rust-gcoap/Cargo.lock index 06855c8813..3ef8978faa 100644 --- a/examples/rust-gcoap/Cargo.lock +++ b/examples/rust-gcoap/Cargo.lock @@ -785,7 +785,7 @@ dependencies = [ [[package]] name = "riot-wrappers" version = "0.8.3" -source = "git+https://github.com/RIOT-OS/rust-riot-wrappers#ea8d7fad95c8cb256ba9bc178f7779d266cc0def" +source = "git+https://github.com/RIOT-OS/rust-riot-wrappers#87ba1141e093a97d1999e3c48ab276dd0e9c6529" dependencies = [ "bare-metal", "coap-handler 0.1.6", diff --git a/examples/rust-hello-world/Cargo.lock b/examples/rust-hello-world/Cargo.lock index 0af45438d9..02622b9acf 100644 --- a/examples/rust-hello-world/Cargo.lock +++ b/examples/rust-hello-world/Cargo.lock @@ -574,7 +574,7 @@ dependencies = [ [[package]] name = "riot-wrappers" version = "0.8.3" -source = "git+https://github.com/RIOT-OS/rust-riot-wrappers#ea8d7fad95c8cb256ba9bc178f7779d266cc0def" +source = "git+https://github.com/RIOT-OS/rust-riot-wrappers#87ba1141e093a97d1999e3c48ab276dd0e9c6529" dependencies = [ "bare-metal", "coap-handler 0.1.6", diff --git a/sys/ps/ps.c b/sys/ps/ps.c index 5663bdd29d..25aee76bb7 100644 --- a/sys/ps/ps.c +++ b/sys/ps/ps.c @@ -98,7 +98,7 @@ void ps(void) #ifdef DEVELHELP int stacksz = thread_get_stacksize(p); /* get stack size */ overall_stacksz += stacksz; - int stack_free = thread_measure_stack_free(thread_get_stackstart(p)); + int stack_free = thread_measure_stack_free(p); stacksz -= stack_free; overall_used += stacksz; #endif diff --git a/sys/rust_riotmodules_standalone/Cargo.lock b/sys/rust_riotmodules_standalone/Cargo.lock index 95b0899c05..b9de4caa75 100644 --- a/sys/rust_riotmodules_standalone/Cargo.lock +++ b/sys/rust_riotmodules_standalone/Cargo.lock @@ -600,7 +600,7 @@ dependencies = [ [[package]] name = "riot-wrappers" version = "0.8.3" -source = "git+https://github.com/RIOT-OS/rust-riot-wrappers#ea8d7fad95c8cb256ba9bc178f7779d266cc0def" +source = "git+https://github.com/RIOT-OS/rust-riot-wrappers#87ba1141e093a97d1999e3c48ab276dd0e9c6529" dependencies = [ "bare-metal", "coap-handler 0.1.6", diff --git a/sys/test_utils/print_stack_usage/print_stack_usage.c b/sys/test_utils/print_stack_usage/print_stack_usage.c index b4e8f7c776..04aca85614 100644 --- a/sys/test_utils/print_stack_usage/print_stack_usage.c +++ b/sys/test_utils/print_stack_usage/print_stack_usage.c @@ -34,7 +34,7 @@ void print_stack_usage_metric(const char *name, void *stack, unsigned max_size) { - unsigned free = thread_measure_stack_free(stack); + unsigned free = measure_stack_free_internal(stack, max_size); if ((LOG_LEVEL >= LOG_INFO) && (thread_get_stacksize(thread_get_active()) >= MIN_SIZE)) { diff --git a/tests/rust_minimal/Cargo.lock b/tests/rust_minimal/Cargo.lock index 19c3997743..f2c19055b6 100644 --- a/tests/rust_minimal/Cargo.lock +++ b/tests/rust_minimal/Cargo.lock @@ -574,7 +574,7 @@ dependencies = [ [[package]] name = "riot-wrappers" version = "0.8.3" -source = "git+https://github.com/RIOT-OS/rust-riot-wrappers#ea8d7fad95c8cb256ba9bc178f7779d266cc0def" +source = "git+https://github.com/RIOT-OS/rust-riot-wrappers#87ba1141e093a97d1999e3c48ab276dd0e9c6529" dependencies = [ "bare-metal", "coap-handler 0.1.6",