Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 32 additions & 17 deletions docs/workflow/building/coreclr/wasm.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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": [
"<node_internals>/**"
],
"program": "corewasmrun.js",
"cwd": "${workspaceFolder}/artifacts/bin/coreclr/browser.wasm.Debug/corewasmrun/"
}
]
}
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "corerun",
"skipFiles": [
"<node_internals>/**"
],
"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`
12 changes: 6 additions & 6 deletions src/coreclr/hosts/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
18 changes: 18 additions & 0 deletions src/coreclr/hosts/corerun/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
16 changes: 16 additions & 0 deletions src/coreclr/hosts/corerun/corerun.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
9 changes: 8 additions & 1 deletion src/coreclr/hosts/corerun/corerun.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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); }
Expand Down Expand Up @@ -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);

Expand All @@ -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)
Expand All @@ -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);
Expand All @@ -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;
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/coreclr/hosts/corerun/corerun.js
Original file line number Diff line number Diff line change
@@ -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());
};
3 changes: 2 additions & 1 deletion src/coreclr/pal/src/arch/wasm/stubs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "pal/dbgmsg.h"
#include "pal/signal.hpp"
#include <emscripten/emscripten.h>

SET_DEFAULT_DEBUG_CHANNEL(EXCEPT); // some headers have code with asserts, so do this first

Expand All @@ -18,7 +19,7 @@ DBG_DebugBreak()
#ifdef _DEBUG
DBG_PrintInterpreterStack();
#endif // _DEBUG
asm volatile ("unreachable");
emscripten_debugger();
}

/* context */
Expand Down