PLUGIN library lang: "C++" version: "1.0" date: "2024-08-06" author: "Julien BRUGUIER" maintainer: "Julien BRUGUIER " synopsis: "Libraries helper" description: %{ The virtual machine is able to load libraries written in machine language. .P This plugin enhances library loading and provides some tools around libraries. %} example: "Basic handling" %{ Main code .nf #!/usr/bin/env svm LOG PLUGIN "===PLUGINLIB===" PLUGIN "svmcom.so" PLUGIN "svmstr.so" PROCESS "basic" CODE "main" INLINE :memory LIB/lib, PTR/entries, INT*3/p :library.load "library.lib.svm" -> &lib :library.entries @&lib -> &entries [ 12 , 5 , ] -> p :call $(@&lib/@&@&entries) p :com.message @(p/2) END END .fi Library code .nf :shutdown :symbol concat :str.join "" @&P "" -> &P :return :symbol add @&P -> (P/2) :shift @(P/1) (P/2) :return .fi %} includes: %{ #include %} test: initialisation %{ cat > correct.svm << EOM :shutdown :symbol test :str.join "" @&P "" -> (P/1) :return :symbol extra :return :label internal :return EOM cat > incorrect.svm << EOM :shutdown :symbol test :com.message "" @&P "" :return EOM %} test: finalisation %{ rm correct.svm incorrect.svm %} test: "Invalid_file" %{ PROCESS "test" CODE "main" INLINE :interruption FAILURE fail :memory LIB/l, STR/s :library.load "unknown.svm" -> &l :shutdown 1 :label fail END END %} test: "Invalid_library" %{ PROCESS "test" CODE "main" INLINE :interruption FAILURE fail :memory LIB/l, STR/s :library.load "incorrect.svm" -> &l :shutdown 1 :label fail END END %} test: "Simple" %{ PLUGIN "svmstr.so" PROCESS "test" CODE "main" INLINE :memory LIB/l, STR*2/s, BLN/b :library.load "correct.svm" -> &l "bla" -> &s :call $(@&l/"test") s :str.cmp @(s/1) = "bla" -> &b :shutdown 1 :unless @&b TRUE END END %} test: "Entries" %{ PLUGIN "svmstr.so" PLUGIN "svmint.so" PROCESS "test" CODE "main" INLINE :memory LIB/l, PTR/p, BLN/b :library.load "correct.svm" -> &l :library.entries @&l -> &p :shutdown 1 :unless (&0+SIZE @&p) IN &2*1 :str.cmp @(@&p/0) = "extra" -> &b :shutdown 2 :unless @&b TRUE :str.cmp @(@&p/1) = "test" -> &b :shutdown 3 :unless @&b TRUE END END %} test: "Get_other" %{ PLUGIN "svmstr.so" PROCESS "test" CODE "main" INLINE :memory LIB/l, STR*2/s, BLN/b, SYM/sym, LIB/sl :library.load "correct.svm" -> &l $(@&l/"extra") -> &sym :library.get @&sym -> &sl "bla" -> &s :call $(@&sl/"test") s :str.cmp @(s/1) = "bla" -> &b :shutdown 1 :unless @&b TRUE END END %} test: "Get_current" %{ PLUGIN "svmstr.so" PROCESS "test" CODE "main" INLINE :symbol start :memory STR*2/s, BLN/b, LIB/sl :library.get $"start" -> &sl "bla" -> &s :call $(@&sl/"join") s :str.cmp @(s/1) = "bla" -> &b :shutdown 1 :unless @&b TRUE :shutdown :symbol join :str.join "" @&P "" -> (P/1) :return END END %} test: "Name" %{ PLUGIN "svmstr.so" PROCESS "test" CODE "main" INLINE :symbol start :memory STR/s, BLN/b, LIB/sl :library.get $"start" -> &sl :library.name @&sl -> &s :str.cmp @&s = "main" -> &b :shutdown 1 :unless @&b TRUE END END %} test: "Source" %{ PLUGIN "svmstr.so" PROCESS "test" CODE "main" INLINE :symbol start :memory STR/s, LIB/sl, PTR/p :library.get $"start" -> &sl :library.code @&sl -> &s :str.regex @&s CONST str.pattern ":library" -> &p :shutdown 1 :unless (&0+SIZE @&p) IN &3*1 END END %} test: "Current" %{ PLUGIN "svmstr.so" PROCESS "test" CODE "main" INLINE :memory LIB/l :library.current -> &l :goto $(@&l/"end") :shutdown 1 :symbol end END END %} DEFINE INSTRUCTION library.load STR:filename -> LIB %{ auto fn = ARGV_VALUE(0,string); std::fstream f; f.open(RAW_STRING(fn).c_str(),std::fstream::in); if(not f.is_open()) { std::ostringstream oss; oss << "Can not open " << RAW_STRING(fn) << " library"; ERROR_INTERNAL(FAILURE,oss.str().c_str()); } f.seekg (0, f.end); int length = f.tellg(); f.seekg (0, f.beg); char * buffer = new char [length]; f.read (buffer,length); if(not f) { delete [] buffer; std::ostringstream oss; oss << "Can not read " << RAW_STRING(fn) << " library"; ERROR_INTERNAL(DEVICE,oss.str().c_str()); } SVM_Variable code = ::svm_code_compile__string(svm,fn,::svm_string_new(svm,buffer,length)); delete [] buffer; if(not ::svm_variable_type_is_code(svm,code)) { SVM_String e = ::svm_value_string_get(svm,code); std::ostringstream oss; oss << "Can not compile " << RAW_STRING(fn) << " library: " << RAW_STRING(e); ERROR_INTERNAL(FAILURE,oss.str().c_str()); } return ::svm_value_library_new(svm,code); %} help: %{ This instructions opens the file specified in argument in read-only, reads the full content of the file and compile the code within the file and returns the library. .P The name of the library is the file name. %} INSTRUCTION library.entries LIB -> PTR %{ SVM_Value_Library l = ::svm_parameter_value_get(svm,argv[0]); SVM_Code code = ::svm_value_library_get_code(svm,l); SVM_Value_String *s = ::svm_code_symbol_list(svm,code); SVM_Size ls = 0; for(SVM_Value_String* it=s ; *it ; ++it) { ::svm_value_state_is_movable(svm,*it); ++ls; } SVM_Memory_Zone z = ::svm_memory_zone_new(svm); ::svm_memory_zone_append_internal__raw(svm,z,STRING,ls); SVM_Value_Pointer p = ::svm_memory_allocate(svm,CURRENT(kernel),z); ::svm_memory_write_pointer(svm,CURRENT(kernel),p,s); return p; %} help: %{ This instruction returns the name of all symbols of the library, as an array of strings. %} SYSTEM INSTRUCTION library.get SYM -> LIB %{ SVM_Value_Symbol s = ::svm_parameter_value_get(svm,argv[0]); SVM_Code code = ::svm_value_symbol_get_code(svm,s); return ::svm_value_library_new(svm,code); %} help: %{ This instruction returns the library contained into a symbol. .P As this instruction can allow code to run unexpected code, it is limited to non-protected kernels. %} INSTRUCTION library.name LIB -> STR %{ SVM_Value_Library l = ::svm_parameter_value_get(svm,argv[0]); SVM_Code code = ::svm_value_library_get_code(svm,l); SVM_String n = ::svm_code_get_name(svm,code); return NEW_VALUE(string,n); %} help: %{ This instruction returns the name of the given library. %} SYSTEM INSTRUCTION library.code LIB -> STR %{ SVM_Value_Library l = ::svm_parameter_value_get(svm,argv[0]); SVM_Code code = ::svm_value_library_get_code(svm,l); SVM_String n = ::svm_code_get_source(svm,code); return NEW_VALUE(string,n); %} help: %{ This instruction returns the source code of the given library. .P As this instruction can allow code to run unexpected code, it is limited to non-protected kernels. %} SYSTEM INSTRUCTION library.current -> LIB %{ SVM_Code code = ::svm_processor_get_currentcode(svm,CURRENT(kernel)); return ::svm_value_library_new(svm,code); %} help: %{ This instruction returns the current code executed by the processor. .P As this instruction can allow code to run unexpected code, it is limited to non-protected kernels. %}