diff --git a/docs/workflow/building/coreclr/wasm.md b/docs/workflow/building/coreclr/wasm.md index b05ce9d02dad14..18fed88e372514 100644 --- a/docs/workflow/building/coreclr/wasm.md +++ b/docs/workflow/building/coreclr/wasm.md @@ -63,10 +63,12 @@ This will start a local HTTP server and you can open the provided URL in your br You can also run the runtime directly in Node.js: ```bash -cd artifacts/bin/coreclr/browser.wasm.Debug/corewasmrun/ -node corewasmrun.js +cd artifacts/bin/coreclr/browser.wasm.Debug/ +node ./corerun.js -c /runtime3/artifacts/bin/coreclr/browser.wasm.Debug/IL /runtime3/artifacts/bin/coreclr/browser.wasm.Debug/helloworld.dll ``` +Note that path in the `args` need to be absolute path on your host file system in unix format (even on Windows). + ## Debugging ### Chrome DevTools with DWARF Support @@ -94,25 +96,38 @@ VS Code, through Node.js, provides a good debugging option for WebAssembly CoreC 2. **Create a launch.json configuration:** ```json - { - "version": "0.2.0", - "configurations": [ - { - "type": "node", - "request": "launch", - "name": "corewasmrun", - "skipFiles": [ - "/**" - ], - "program": "corewasmrun.js", - "cwd": "${workspaceFolder}/artifacts/bin/coreclr/browser.wasm.Debug/corewasmrun/" - } - ] - } + { + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "corerun", + "skipFiles": [ + "/**" + ], + "outputCapture": "std", + "program": "corerun.js", + "env": { + "PAL_DBG_CHANNELS": "+all.all" + }, + "args": [ + "-c", + "/runtime3/artifacts/bin/coreclr/browser.wasm.Debug/IL/", + "/runtime3/artifacts/bin/coreclr/browser.wasm.Debug/IL/helloworld.dll" + ], + "cwd": "${workspaceFolder}/artifacts/bin/coreclr/browser.wasm.Debug/" + } + ] + } ``` +Note that path in the `args` need to be absolute path on your host file system in unix format (even on Windows). + 3. **Set breakpoints** in `corewasmrun.js` in one of the `put_char` functions (the `stdout`/`stderr` implementation) 4. **Start debugging** and step through the WebAssembly code using the call stack This approach allows you to debug the JavaScript host and step into WebAssembly code or into the C/C++ code if the Dwarf Debugging extension was installed. + +5. to display `WCHAR *` strings in debugger watch window, cast it to `char16_t*` like `(char16_t*)pLoaderModule->m_fileName` \ No newline at end of file diff --git a/src/coreclr/hosts/CMakeLists.txt b/src/coreclr/hosts/CMakeLists.txt index 4be3bbe8b95805..529a06b916760a 100644 --- a/src/coreclr/hosts/CMakeLists.txt +++ b/src/coreclr/hosts/CMakeLists.txt @@ -1,11 +1,11 @@ include_directories(inc) +if(CLR_CMAKE_HOST_WIN32) + add_subdirectory(coreshim) +endif(CLR_CMAKE_HOST_WIN32) + if (CLR_CMAKE_TARGET_ARCH_WASM) add_subdirectory(corewasmrun) -else() - if(CLR_CMAKE_HOST_WIN32) - add_subdirectory(coreshim) - endif(CLR_CMAKE_HOST_WIN32) - - add_subdirectory(corerun) endif() + +add_subdirectory(corerun) \ No newline at end of file diff --git a/src/coreclr/hosts/corerun/CMakeLists.txt b/src/coreclr/hosts/corerun/CMakeLists.txt index b3baaaa70fc287..97d472a270583f 100644 --- a/src/coreclr/hosts/corerun/CMakeLists.txt +++ b/src/coreclr/hosts/corerun/CMakeLists.txt @@ -11,6 +11,10 @@ endif(CLR_CMAKE_HOST_WIN32) #Required to expose symbols for global symbol discovery. set(CLR_CMAKE_KEEP_NATIVE_SYMBOLS TRUE) +if (DEFINED CLR_CMAKE_ICU_DIR) + link_directories(${CLR_CMAKE_ICU_DIR}/lib) +endif(DEFINED CLR_CMAKE_ICU_DIR) + add_executable_clr(corerun corerun.cpp dotenv.cpp @@ -42,6 +46,20 @@ else(CLR_CMAKE_HOST_WIN32) if(NOT CLR_CMAKE_TARGET_ANDROID) target_link_libraries(corerun PRIVATE pthread) endif() + # Static linking + if (CLR_CMAKE_TARGET_ARCH_WASM) + target_link_libraries(corerun PRIVATE + coreclr_static + clrinterpreter + icuuc + icui18n + icudata) + # linker options for NodeJs, link in JavaScript helper, access to local filesystem + if (CLR_CMAKE_TARGET_BROWSER) + target_compile_options(corerun PRIVATE -fwasm-exceptions) + target_link_options(corerun PRIVATE -fwasm-exceptions -sEXPORTED_RUNTIME_METHODS=FS -sEXIT_RUNTIME=1 -sINITIAL_MEMORY=134217728 -sSTACK_SIZE=5MB -lnoderawfs.js -lnodefs.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/corerun.js -Wl,-error-limit=0) + endif() + endif() endif(CLR_CMAKE_HOST_WIN32) if (CLR_CMAKE_HOST_APPLE) diff --git a/src/coreclr/hosts/corerun/corerun.cpp b/src/coreclr/hosts/corerun/corerun.cpp index 7286a4dec89515..4bbb2cbf846303 100644 --- a/src/coreclr/hosts/corerun/corerun.cpp +++ b/src/coreclr/hosts/corerun/corerun.cpp @@ -158,10 +158,26 @@ static string_t build_tpa(const string_t& core_root, const string_t& core_librar static bool try_get_export(pal::mod_t mod, const char* symbol, void** fptr) { +#ifndef TARGET_WASM assert(mod != nullptr && symbol != nullptr && fptr != nullptr); *fptr = pal::get_module_symbol(mod, symbol); if (*fptr != nullptr) return true; +#else // !TARGET_WASM + if (!strcmp(symbol, "coreclr_initialize")){ + *fptr = (void*)coreclr_initialize; + return true; + } else if (!strcmp(symbol, "coreclr_execute_assembly")){ + *fptr = (void*)coreclr_execute_assembly; + return true; + } else if (!strcmp(symbol, "coreclr_shutdown_2")){ + *fptr = (void*)coreclr_shutdown_2; + return true; + } else if (!strcmp(symbol, "coreclr_set_error_writer")){ + *fptr = (void*)coreclr_set_error_writer; + return true; + } +#endif // !TARGET_WASM pal::fprintf(stderr, W("Export '%s' not found.\n"), symbol); return false; diff --git a/src/coreclr/hosts/corerun/corerun.hpp b/src/coreclr/hosts/corerun/corerun.hpp index 48e6ed4c1295e0..09d6086e983d9c 100644 --- a/src/coreclr/hosts/corerun/corerun.hpp +++ b/src/coreclr/hosts/corerun/corerun.hpp @@ -375,12 +375,14 @@ namespace pal const char_t dir_delim = W('/'); const char_t env_path_delim = W(':'); +#ifndef TARGET_WASM #if defined(__APPLE__) const char_t nativelib_ext[] = W(".dylib"); #else // Various Linux-related OS-es const char_t nativelib_ext[] = W(".so"); #endif const char_t coreclr_lib[] = W("libcoreclr"); +#endif // !TARGET_WASM inline int strcmp(const char_t* str1, const char_t* str2) { return ::strcmp(str1, str2); } inline size_t strlen(const char_t* str) { return ::strlen(str); } @@ -568,6 +570,7 @@ namespace pal inline bool try_load_hostpolicy(pal::string_t mock_hostpolicy_value) { +#ifndef TARGET_WASM if (!string_ends_with(mock_hostpolicy_value, pal::nativelib_ext)) mock_hostpolicy_value.append(pal::nativelib_ext); @@ -576,6 +579,9 @@ namespace pal pal::fprintf(stderr, W("Failed to load mock hostpolicy at path '%s'. Error: %s\n"), mock_hostpolicy_value.c_str(), dlerror()); return hMod != nullptr; +#else // !TARGET_WASM + return false; +#endif // !TARGET_WASM } inline bool try_load_library(const pal::string_t& path, pal::mod_t& hMod) @@ -592,6 +598,7 @@ namespace pal inline bool try_load_coreclr(const pal::string_t& core_root, pal::mod_t& hMod) { +#ifndef TARGET_WASM pal::string_t coreclr_path = core_root; pal::ensure_trailing_delimiter(coreclr_path); coreclr_path.append(pal::coreclr_lib); @@ -603,7 +610,7 @@ namespace pal pal::fprintf(stderr, W("Failed to load: '%s'. Error: %s\n"), coreclr_path.c_str(), dlerror()); return false; } - +#endif // !TARGET_WASM return true; } } diff --git a/src/coreclr/hosts/corerun/corerun.js b/src/coreclr/hosts/corerun/corerun.js new file mode 100644 index 00000000000000..5b54a39e77899a --- /dev/null +++ b/src/coreclr/hosts/corerun/corerun.js @@ -0,0 +1,7 @@ +Module.preRun = () => { + // copy all node/shell env variables to emscripten env + for (const [key, value] of Object.entries(process.env)) { + ENV[key] = value; + } + console.log("corerun.js preRun: " + Module.FS.cwd()); +}; \ No newline at end of file diff --git a/src/coreclr/pal/src/arch/wasm/stubs.cpp b/src/coreclr/pal/src/arch/wasm/stubs.cpp index 5f7c99e408474f..096cb431336a3e 100644 --- a/src/coreclr/pal/src/arch/wasm/stubs.cpp +++ b/src/coreclr/pal/src/arch/wasm/stubs.cpp @@ -3,6 +3,7 @@ #include "pal/dbgmsg.h" #include "pal/signal.hpp" +#include SET_DEFAULT_DEBUG_CHANNEL(EXCEPT); // some headers have code with asserts, so do this first @@ -18,7 +19,7 @@ DBG_DebugBreak() #ifdef _DEBUG DBG_PrintInterpreterStack(); #endif // _DEBUG - asm volatile ("unreachable"); + emscripten_debugger(); } /* context */