// -*- C++ -*- (c) 2016 Jan Mrázek // 2016 Vladimir Still #include #include #include #include #include namespace __dios { struct CtorDtorEntry { int32_t prio; void (*fn)(); void *ignored; // should be used only by linker to discard entries }; template< typename Sort > static void runCtorsDtors( const char *name, Sort sort ) { auto *meta = __md_get_global_meta( name ); if ( !meta ) return; auto *begin = reinterpret_cast< CtorDtorEntry * >( meta->address ), *end = begin + meta->size / sizeof( CtorDtorEntry ); std::sort( begin, end, sort ); for ( ; begin != end; ++begin ) begin->fn(); } void runCtors() { runCtorsDtors( "llvm.global_ctors", []( CtorDtorEntry &a, CtorDtorEntry &b ) { return a.prio < b.prio; } ); } void runDtors() { runCtorsDtors( "llvm.global_dtors", []( CtorDtorEntry &a, CtorDtorEntry &b ) { return a.prio > b.prio; } ); } char *env_to_string( const _VM_Env *env ) noexcept { auto arg = static_cast< char * >( __vm_obj_make( env->size + 1 ) ); memcpy( arg, env->value, env->size ); arg[ env->size ] = '\0'; return arg; } bool getSysOpts( const _VM_Env *e, SysOpts& res ) { const char *prefix = "sys."; int pref_len = strlen( prefix ); res.clear(); for( ; e->key != nullptr; e++ ) { if ( memcmp( prefix, e->key, pref_len ) != 0 ) continue; // Add sugar for help command String s( e->value, e->size ); if ( s == "help") { res.emplace_back( "debug", "help" ); continue; } auto p = std::find( s.begin(), s.end(), ':' ); if ( p == s.end() ) { __dios_trace_f( "Missing ':' in parameter '%.*s'", e->size, e->value ); return false; } if ( std::find( ++p, s.end(), ':') != s.end() ) { __dios_trace_f( "Multiple ':' in parameter '%.*s'", e->size, e->value ); return false; } String val( p, s.end() ); String key( s.begin(), --p ); res.emplace_back( key, val ); } return true; } const _VM_Env *get_env_key( const char* key, const _VM_Env *e ) noexcept { for ( ; e->key; e++ ) { if ( strcmp( e->key, key ) == 0) return e; } return nullptr; } std::pair construct_main_arg( const char* prefix, const _VM_Env *env, bool prepend_name) noexcept { int argc = prepend_name ? 1 : 0; int pref_len = strlen( prefix ); const _VM_Env *name = nullptr; const _VM_Env *e = env; for ( ; e->key; e++ ) { if ( memcmp( prefix, e->key, pref_len ) == 0 ) { argc++; } else if ( strcmp( e->key, "divine.bcname" ) == 0 ) { __dios_assert_v( !name, "Multiple divine.bcname provided" ); name = e; } } auto argv = static_cast< char ** >( __vm_obj_make( ( argc + 1 ) * sizeof( char * ) ) ); char **arg = argv; if (prepend_name) { __dios_assert_v( name, "Missing binary name: divine.bcname" ); *argv = env_to_string( name ); arg++; } for ( ; env->key; env++ ) { if ( memcmp( prefix, env->key, pref_len ) == 0 ) { *arg = env_to_string( env ); arg++; } } *arg = nullptr; return { argc, argv }; } void free_main_arg( char** argv ) noexcept { char **orig = argv; while( *argv ) { __vm_obj_free( *argv ); ++argv; } __vm_obj_free( orig ); } void trace_main_arg( int indent, String name, std::pair args ) { __dios_trace_i( indent, "%s:", name.c_str() ); for (int i = 0; i != args.first; i++ ) __dios_trace_i( indent + 1, "%d: %s", i, args.second[i] ); } } // namespace __dios void _start( int l, int argc, char **argv, char **envp ) { __vm_control( _VM_CA_Bit, _VM_CR_Flags, _VM_CF_Mask, _VM_CF_Mask ); __pthread_initialize(); // must run before constructors, constructors can // use pthreads (such as pthread_once or thread // local storage) __dios::runCtors(); int res; switch (l) { case 0: __vm_control( _VM_CA_Bit, _VM_CR_Flags, _VM_CF_Mask, _VM_CF_None ); res = main(); break; case 2: __vm_control( _VM_CA_Bit, _VM_CR_Flags, _VM_CF_Mask, _VM_CF_None ); res = main( argc, argv ); break; case 3: __vm_control( _VM_CA_Bit, _VM_CR_Flags, _VM_CF_Mask, _VM_CF_None ); res = main( argc, argv, envp ); break; default: __dios_assert_v( false, "Unexpected prototype of main" ); res = 256; } __vm_control( _VM_CA_Bit, _VM_CR_Flags, _VM_CF_Mask, _VM_CF_Mask ); __dios::free_main_arg( argv ); __dios::free_main_arg( envp ); exit( res ); }