summaryrefslogtreecommitdiff
path: root/lib/mlibc/sysdeps/keyronex/generic/entry.cpp
blob: ff15c62c6f21b43e1c0cb4b849fbd79a540188ab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include <bits/ensure.h>
#include <bits/posix/posix_signal.h>
#include <keyronex/syscall.h>
#include <mlibc/all-sysdeps.hpp>
#include <mlibc/debug.hpp>
#include <mlibc/elf/startup.h>
#include <stdint.h>
#include <stdlib.h>

// defined by the POSIX library
void __mlibc_initLocale();

extern "C" uintptr_t *__dlapi_entrystack();

extern char **environ;
static mlibc::exec_stack_data __mlibc_stack_data;

struct LibraryGuard {
	LibraryGuard();
};

static LibraryGuard guard;

LibraryGuard::LibraryGuard()
{
	__mlibc_initLocale();

	// Parse the exec() stack.
	mlibc::parse_exec_stack(__dlapi_entrystack(), &__mlibc_stack_data);
	mlibc::set_startup_data(__mlibc_stack_data.argc,
	    __mlibc_stack_data.argv, __mlibc_stack_data.envp);
}

namespace mlibc {
int
sys_sigentry(void *sigentry)
{
	uintptr_t ret = syscall1(kPXSysSigEntry, (uintptr_t)sigentry, NULL);
	if (int e = sc_error(ret); e)
		return e;
	return 0;
}

[[noreturn]] int
sys_sigreturn(ucontext_t *context)
{
	syscall1(kPXSysSigReturn, (uintptr_t)context, NULL);
	__builtin_unreachable();
}
}

static void
do_stacktrace(ucontext_t *ctx)
{
	size_t *base_ptr = (size_t *)ctx->uc_mcontext.gregs[REG_RBP];

	mlibc::infoLogger() << "Stacktrace:" << frg::endlog;
	mlibc::infoLogger() << "  [" << (void *)ctx->uc_mcontext.gregs[REG_RIP]
			    << "]" << frg::endlog;
	for (;;) {
		size_t old_bp = base_ptr[0];
		size_t ret_addr = base_ptr[1];
		if (!ret_addr)
			break;
		mlibc::infoLogger()
		    << "  [" << (void *)ret_addr << "]" << frg::endlog;
		if (!old_bp)
			break;
		base_ptr = (size_t *)old_bp;
	}
}

static void
__mlibc_sigentry(int which, siginfo_t *siginfo, void *handler,
    bool is_sigaction, ucontext_t *ret_context)
{
	if ((uintptr_t)handler == (uintptr_t)SIG_DFL) {
		mlibc::infoLogger()
		    << "mlibc: Unhandled signal " << which << frg::endlog;
		do_stacktrace(ret_context);
		mlibc::sys_exit(128 + which);
	} else if ((uintptr_t)handler == (uintptr_t)SIG_IGN) {
		/* epsilon */
	} else {
		if (is_sigaction)
			((void (*)(int, siginfo_t *, void *))handler)(which,
			    siginfo, ret_context);
		else
			((void (*)(int))handler)(which);
	}

	mlibc::sys_sigreturn(ret_context);

	__builtin_unreachable();
}

extern "C" void
__mlibc_entry(int (*main_fn)(int argc, char *argv[], char *env[]))
{
	/* communicate the signal handler entry point to the kernel */
	mlibc::sys_sigentry((void *)__mlibc_sigentry);

	// TODO: call __dlapi_enter, otherwise static builds will break (see
	// Linux sysdeps)
	auto result = main_fn(__mlibc_stack_data.argc, __mlibc_stack_data.argv,
	    environ);
	exit(result);
}