16#include <boost/hana/equal.hpp>
20#include <sys/syscall.h>
23#if defined(__has_feature)
24#if __has_feature(shadow_call_stack)
25#error SYS VM OC is not compatible with Clang ShadowCallStack
31namespace sysio {
namespace chain {
namespace eosvmoc {
33static constexpr auto signal_sentinel = 0x4D56534F45534559ul;
35static void(*chained_handler)(int,siginfo_t*,
void*);
36static void segv_handler(
int sig, siginfo_t* info,
void* ctx) {
41 syscall(SYS_arch_prctl, ARCH_GET_GS, ¤t_gs);
48 if(cb_in_main_segment->magic != signal_sentinel)
52 if(cb_in_main_segment->is_running ==
false)
56 if((
uintptr_t)info->si_addr >= cb_in_main_segment->execution_thread_code_start &&
57 (
uintptr_t)info->si_addr < cb_in_main_segment->execution_thread_code_start+cb_in_main_segment->execution_thread_code_length)
61 if((
uintptr_t)info->si_addr >= cb_in_main_segment->execution_thread_memory_start &&
62 (
uintptr_t)info->si_addr < cb_in_main_segment->execution_thread_memory_start+cb_in_main_segment->execution_thread_memory_length)
67 chained_handler(sig, info, ctx);
70 ::signal(sig, SIG_DFL);
72 __builtin_unreachable();
81static void sysio_exit(
int32_t code) {
83 __builtin_unreachable();
89static void throw_internal_exception(
const char*
const s) {
92 __builtin_unreachable();
95#define DEFINE_SYSVMOC_TRAP_INTRINSIC(module,name) \
97 static intrinsic name##Function SYSVMOC_INTRINSIC_INIT_PRIORITY(#module "." #name,IR::FunctionType::get(),(void*)&name, \
98 std::integral_constant<std::size_t, find_intrinsic_index(#module "." #name)>::value \
103 throw_internal_exception(
"Exceeded call depth maximum");
107 throw_internal_exception(
"Division by 0 or integer overflow trapped");
111 throw_internal_exception(
"Indirect call function type mismatch");
115 throw_internal_exception(
"Indirect call index out of bounds");
119 throw_internal_exception(
"Unreachable reached");
124 struct sigaction sig_action, old_sig_action;
125 sig_action.sa_sigaction = segv_handler;
126 sigemptyset(&sig_action.sa_mask);
127 sig_action.sa_flags = SA_SIGINFO | SA_NODEFER;
128 sigaction(SIGSEGV, &sig_action, &old_sig_action);
129 if(old_sig_action.sa_flags & SA_SIGINFO)
130 chained_handler = old_sig_action.sa_sigaction;
131 else if(old_sig_action.sa_handler != SIG_IGN && old_sig_action.sa_handler != SIG_DFL)
132 chained_handler = (void (*)(int,siginfo_t*,
void*))old_sig_action.sa_handler;
141 if(
arch_prctl(ARCH_GET_GS, ¤t_gs) || current_gs)
142 wlog(
"x86_64 GS register is not set as expected. SYS VM OC may not run correctly on this platform");
145 FC_ASSERT(fstat(cc.
fd(), &
s) == 0,
"executor failed to get code cache size");
146 code_mapping = (
uint8_t*)mmap(
nullptr,
s.st_size, PROT_EXEC|PROT_READ, MAP_SHARED, cc.
fd(), 0);
147 FC_ASSERT(code_mapping != MAP_FAILED,
"failed to map code cache in to executor");
148 code_mapping_size =
s.st_size;
149 mapping_is_executable =
true;
153 if(mapping_is_executable ==
false) {
154 mprotect(code_mapping, code_mapping_size, PROT_EXEC|PROT_READ);
155 mapping_is_executable =
true;
162 max_call_depth =
config.max_call_depth;
163 max_pages =
config.max_pages;
165 stack.
reset(max_call_depth);
166 SYS_ASSERT(code.starting_memory_pages <= (
int)max_pages, wasm_execution_error,
"Initial memory out of range");
169 if(code.starting_memory_pages > 0 ) {
171 if(initial_page_offset <
static_cast<uint64_t>(code.starting_memory_pages)) {
172 mprotect(mem.
full_page_memory_base() + initial_page_offset * sysio::chain::wasm_constraints::wasm_page_size,
173 (code.starting_memory_pages - initial_page_offset) * sysio::chain::wasm_constraints::wasm_page_size, PROT_READ | PROT_WRITE);
183 globals_buffer.resize(code.initdata_prologue_size);
184 memcpy(globals_buffer.data(), code_mapping + code.initdata_begin, code.initdata_prologue_size);
188 globals = globals_buffer.data() + globals_buffer.size();
195 cb->
magic = signal_sentinel;
201 executors_exception_ptr =
nullptr;
202 cb->
eptr = &executors_exception_ptr;
208 cb->
jmp = &executors_sigjmp_buf;
214 context.trx_context.transaction_timer.set_expiration_callback([](
void* user) {
216 syscall(SYS_mprotect,
self->code_mapping,
self->code_mapping_size, PROT_NONE);
217 self->mapping_is_executable =
false;
219 context.trx_context.checktime();
222 cb->is_running = false;
223 cb->bounce_buffers->clear();
224 tt.set_expiration_callback(nullptr, nullptr);
226 uint64_t base_pages = mem.size_of_memory_slice_mapping()/memory::stride - 1;
227 if(cb->current_linear_memory_pages > base_pages) {
228 mprotect(mem.full_page_memory_base() + base_pages * sysio::chain::wasm_constraints::wasm_page_size,
229 (cb->current_linear_memory_pages - base_pages) * sysio::chain::wasm_constraints::wasm_page_size, PROT_NONE);
235 switch(sigsetjmp(*cb->jmp, 0)) {
240 [&](
const intrinsic_ordinal& i) {
244 [&](
const code_offset& offs) {
245 void(*start_func)() = (
void(*)())(cb->running_code_base + offs.offset);
249 apply_func(
context.get_receiver().to_uint64_t(),
context.get_action().account.to_uint64_t(),
context.get_action().name.to_uint64_t());
254 context.trx_context.checktime();
257 SYS_ASSERT(
false, wasm_execution_error,
"access violation");
260 std::rethrow_exception(*cb->eptr);
265executor::~executor() {
#define SYS_ASSERT(expr, exc_type, FORMAT,...)
void execute(const code_descriptor &code, memory &mem, apply_context &context)
executor(const code_cache_base &cc)
static constexpr size_t stride
uint8_t *const full_page_memory_base() const
static constexpr uintptr_t first_intrinsic_offset
uint8_t *const zero_page_memory_base() const
uint8_t *const start_of_memory_slices() const
static constexpr uintptr_t cb_offset
control_block *const get_control_block() const
size_t size_of_memory_slice_mapping() const
static constexpr uintptr_t max_prologue_size
#define FC_ASSERT(TEST,...)
Checks a condition and throws an assert_exception if the test is FALSE.
int arch_prctl(int code, unsigned long *addr)
#define DEFINE_SYSVMOC_TRAP_INTRINSIC(module, name)
sigjmp_buf * eos_vm_oc_get_jmp_buf()
void * eos_vm_oc_get_exception_ptr()
int32_t eos_vm_oc_grow_memory(int32_t grow, int32_t max)
#define FC_LOG_MESSAGE(LOG_LEVEL, FORMAT,...)
A helper method for generating log messages.
scoped_exit< Callback > make_scoped_exit(Callback &&c)
@ SYSVMOC_EXIT_CLEAN_EXIT
@ SYSVMOC_EXIT_CHECKTIME_FAIL
constexpr std::size_t find_intrinsic_index(std::string_view hf)
eos_vm_oc_control_block control_block
constexpr unsigned maximum_linear_memory
constexpr unsigned maximum_call_depth
@ configurable_wasm_limits
@ self
the connection is to itself
sysio::client::http::http_context context
_W64 unsigned int uintptr_t
unsigned __int64 uint64_t
static IR_API const FunctionType * get(ResultType ret, const std::initializer_list< ValueType > ¶meters)
int64_t current_linear_memory_pages
uintptr_t running_code_base
unsigned current_call_depth_remaining
char * full_linear_memory_start
size_t execution_thread_code_length
int64_t max_linear_memory_pages
size_t execution_thread_memory_length
uintptr_t execution_thread_code_start
uintptr_t execution_thread_memory_start
int64_t first_invalid_memory_address
void reset(std::size_t max_call_depth)
#define SYSVMOC_INTRINSIC_INIT_PRIORITY
memset(pInfo->slotDescription, ' ', 64)
memcpy((char *) pInfo->slotDescription, s, l)