diff --git a/cpu/native/Makefile.include b/cpu/native/Makefile.include index 63b2fa3a9a01..1a2ba36a69fc 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 eff3c135fc52..91744bab5066 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 030819c07b5b..c5e404115ae4 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 8c4d81f0f206..c2c1a39ca4af 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 +#define _GNU_SOURCE + +#include #include -#undef __USE_GNU +#include +#include +#include +#if USE_LIBUCONTEXT +#include +#else #include -#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 5014e0c70141..bb3431a7ed42 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 382183d23aa7..76a13e9f814a 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);