iwasm.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. /*
  2. * Copyright (c) 2021, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  5. */
  6. #include <rtthread.h>
  7. #include "wasm_export.h"
  8. #include "platform_api_vmcore.h"
  9. #include <dfs.h>
  10. #include <dfs_file.h>
  11. #include <dfs_fs.h>
  12. #if WASM_ENABLE_LIBC_WASI != 0
  13. #include "../common/libc_wasi.c"
  14. #endif
  15. #ifdef WAMR_ENABLE_RTT_EXPORT
  16. #ifdef WAMR_RTT_EXPORT_VPRINTF
  17. static int
  18. wasm_vprintf(wasm_exec_env_t env, const char *fmt, va_list va)
  19. {
  20. return vprintf(fmt, va);
  21. }
  22. static int
  23. wasm_vsprintf(wasm_exec_env_t env, char *buf, const char *fmt, va_list va)
  24. {
  25. return vsprintf(buf, fmt, va);
  26. }
  27. static int
  28. wasm_vsnprintf(wasm_exec_env_t env, char *buf, int n, const char *fmt,
  29. va_list va)
  30. {
  31. return vsnprintf(buf, n, fmt, va);
  32. }
  33. #endif /* WAMR_RTT_EXPORT_VPRINTF */
  34. #ifdef WAMR_RTT_EXPORT_DEVICE_OPS
  35. static rt_device_t
  36. wasm_rt_device_find(wasm_exec_env_t env, const char *name)
  37. {
  38. return rt_device_find(name);
  39. }
  40. static rt_err_t
  41. wasm_rt_device_open(wasm_exec_env_t env, rt_device_t dev, rt_uint16_t o_flag)
  42. {
  43. return rt_device_open(dev, o_flag);
  44. }
  45. static rt_size_t
  46. wasm_rt_device_write(wasm_exec_env_t env, rt_device_t dev, rt_off_t offset,
  47. const void *buf, rt_size_t size)
  48. {
  49. return rt_device_write(dev, offset, buf, size);
  50. }
  51. static rt_size_t
  52. wasm_rt_device_read(wasm_exec_env_t env, rt_device_t dev, rt_off_t offset,
  53. void *buf, rt_size_t size)
  54. {
  55. return rt_device_read(dev, offset, buf, size);
  56. }
  57. static rt_err_t
  58. wasm_rt_device_close(wasm_exec_env_t env, rt_device_t dev)
  59. {
  60. return rt_device_close(dev);
  61. }
  62. static rt_err_t
  63. wasm_rt_device_control(wasm_exec_env_t env, rt_device_t dev, int cmd, void *arg)
  64. {
  65. return rt_device_control(dev, cmd, arg);
  66. }
  67. #endif /* WAMR_RTT_EXPORT_DEVICE_OPS */
  68. /* clang-format off */
  69. static NativeSymbol native_export_symbols[] = {
  70. #ifdef WAMR_RTT_EXPORT_VPRINTF
  71. {
  72. "vprintf",
  73. wasm_vprintf,
  74. "($*)i"
  75. },
  76. {
  77. "vsprintf",
  78. wasm_vsprintf,
  79. "($$*)i"
  80. },
  81. {
  82. "vsnprintf",
  83. wasm_vsnprintf,
  84. "($i$*)i"
  85. },
  86. #endif /* WAMR_RTT_EXPORT_VPRINTF */
  87. #ifdef WAMR_RTT_EXPORT_DEVICE_OPS
  88. {
  89. "rt_device_find",
  90. wasm_rt_device_find,
  91. "($)i"
  92. },
  93. {
  94. "rt_device_open",
  95. wasm_rt_device_open,
  96. "(ii)i"
  97. },
  98. {
  99. "rt_device_write",
  100. wasm_rt_device_write,
  101. "(ii*~)i"
  102. },
  103. {
  104. "rt_device_read",
  105. wasm_rt_device_read,
  106. "(ii*~)i"
  107. },
  108. {
  109. "rt_device_close",
  110. wasm_rt_device_close,
  111. "(i)i"
  112. },
  113. {
  114. "rt_device_control",
  115. wasm_rt_device_control,
  116. "(ii*)i"
  117. },
  118. #ifdef WAMR_RTT_EXPORT_DEVICE_OPS_CPP
  119. {
  120. "_Z15rt_device_closeP9rt_device",
  121. wasm_rt_device_close,
  122. "(i)i"
  123. },
  124. {
  125. "_Z14rt_device_readP9rt_devicejPvj",
  126. wasm_rt_device_read,
  127. "(ii*~)i"
  128. },
  129. {
  130. "_Z15rt_device_writeP9rt_devicejPKvj",
  131. wasm_rt_device_write,
  132. "(ii*~)i"
  133. },
  134. {
  135. "_Z14rt_device_openP9rt_devicet",
  136. wasm_rt_device_open,
  137. "(ii)i"
  138. },
  139. {
  140. "_Z14rt_device_findPKc",
  141. wasm_rt_device_find,
  142. "($)i"
  143. },
  144. #endif /* WAMR_RTT_EXPORT_DEVICE_OPS_CPP */
  145. #endif /* WAMR_RTT_EXPORT_DEVICE_OPS */
  146. };
  147. /* clang-format on */
  148. #endif /* WAMR_ENABLE_RTT_EXPORT */
  149. static void *
  150. app_instance_func(wasm_module_inst_t module_inst, const char *func_name,
  151. int app_argc, char **app_argv)
  152. {
  153. wasm_application_execute_func(module_inst, func_name, app_argc - 1,
  154. app_argv + 1);
  155. return wasm_runtime_get_exception(module_inst);
  156. }
  157. /**
  158. * run WASM module instance.
  159. * @param module_inst instance of wasm module
  160. * @param app_argc wasm argument count
  161. * @param app_argv wasm arguments
  162. * @return NULL
  163. */
  164. static void *
  165. app_instance_main(wasm_module_inst_t module_inst, int app_argc, char **app_argv)
  166. {
  167. wasm_application_execute_main(module_inst, app_argc, app_argv);
  168. return wasm_runtime_get_exception(module_inst);
  169. }
  170. rt_uint8_t *
  171. my_read_file_to_buffer(char *filename, rt_uint32_t *size)
  172. {
  173. struct stat f_stat;
  174. rt_uint8_t *buff = rt_malloc(f_stat.st_size);
  175. *size = 0;
  176. if (!buff) {
  177. rt_set_errno(-ENOMEM);
  178. return RT_NULL;
  179. }
  180. int fd = open(filename, O_RDONLY);
  181. if (fd < 0) {
  182. rt_free(buff);
  183. rt_set_errno(fd);
  184. return RT_NULL;
  185. }
  186. *size = read(fd, buff, f_stat.st_size);
  187. close(fd);
  188. if (*size != f_stat.st_size) {
  189. rt_free(buff);
  190. rt_set_errno(-EBADF);
  191. return RT_NULL;
  192. }
  193. return buff;
  194. }
  195. void
  196. iwasm_help(void)
  197. {
  198. #ifdef WAMR_ENABLE_IWASM_PARAMS
  199. rt_kputs("Usage: iwasm [-options] wasm_file [args...]\n");
  200. rt_kputs("options:\n");
  201. rt_kputs(" -t Show time taking to run this app.\n");
  202. rt_kputs(" -m Show memory taking to run this app\n");
  203. rt_kputs(" -f|--function name Specify a function name of the module "
  204. "to run rather than main\n");
  205. rt_kputs(" --max-threads=n Set maximum thread number per "
  206. "cluster, default is 4\n");
  207. #else
  208. rt_kputs("Usage: iwasm wasm_file [args...]\n");
  209. #endif /* WAMR_ENABLE_PARAMS */
  210. }
  211. int
  212. iwasm(int argc, char **argv)
  213. {
  214. const char *exception = NULL;
  215. const char *func_name = NULL;
  216. rt_uint8_t *wasm_file_buf = NULL;
  217. rt_uint32_t wasm_file_size;
  218. rt_uint32_t stack_size = 64 * 1024, heap_size = 256 * 1024;
  219. wasm_module_t wasm_module = NULL;
  220. wasm_module_inst_t wasm_module_inst = NULL;
  221. RuntimeInitArgs init_args;
  222. static char error_buf[128] = { 0 };
  223. /* avoid stack overflow */
  224. #if WASM_ENABLE_LIBC_WASI != 0
  225. libc_wasi_parse_context_t wasi_parse_ctx;
  226. memset(&wasi_parse_ctx, 0, sizeof(wasi_parse_ctx));
  227. #endif
  228. #ifdef WAMR_ENABLE_IWASM_PARAMS
  229. int i_arg_begin;
  230. bool show_mem = false;
  231. bool show_stack = false;
  232. bool show_time_exec = false;
  233. for (i_arg_begin = 1; i_arg_begin < argc; i_arg_begin++) {
  234. if (argv[i_arg_begin][0] != '-') {
  235. break;
  236. }
  237. if (argv[i_arg_begin][1] == 'm') {
  238. show_mem = true;
  239. }
  240. else if (argv[i_arg_begin][1] == 's') {
  241. show_stack = true;
  242. }
  243. else if (argv[i_arg_begin][1] == 't') {
  244. show_time_exec = true;
  245. }
  246. else if (argv[i_arg_begin][1] == 'h') {
  247. iwasm_help();
  248. return 0;
  249. }
  250. else if (argv[i_arg_begin][1] == 'f') {
  251. func_name = argv[++i_arg_begin];
  252. }
  253. else if (!strncmp(argv[i_arg_begin], "--max-threads=", 14)) {
  254. if (argv[0][14] != '\0')
  255. wasm_runtime_set_max_thread_num(atoi(argv[0] + 14));
  256. else {
  257. iwasm_help();
  258. return 0;
  259. }
  260. }
  261. else if (argv[i_arg_begin][1] == 0x00) {
  262. continue;
  263. }
  264. else {
  265. rt_kprintf("[iwasm] unknown param: %s\n", argv[i_arg_begin]);
  266. }
  267. }
  268. #else /* WAMR_ENABLE_PARAMS */
  269. #define i_arg_begin 1
  270. #endif /* WAMR_ENABLE_PARAMS */
  271. if (argc - i_arg_begin < 1) {
  272. iwasm_help();
  273. return -1;
  274. }
  275. rt_memset(&init_args, 0, sizeof(RuntimeInitArgs));
  276. init_args.mem_alloc_type = Alloc_With_Allocator;
  277. init_args.mem_alloc_option.allocator.malloc_func = os_malloc;
  278. init_args.mem_alloc_option.allocator.realloc_func = os_realloc;
  279. init_args.mem_alloc_option.allocator.free_func = os_free;
  280. #ifdef WAMR_ENABLE_RTT_EXPORT
  281. init_args.native_symbols = native_export_symbols;
  282. init_args.n_native_symbols =
  283. sizeof(native_export_symbols) / sizeof(NativeSymbol);
  284. init_args.native_module_name = "env";
  285. #endif /* WAMR_ENABLE_RTT_EXPORT */
  286. #ifdef WAMR_ENABLE_IWASM_PARAMS
  287. #if defined(RT_USING_HEAP) && defined(RT_USING_MEMHEAP_AS_HEAP)
  288. extern long list_memheap(void);
  289. if (show_mem) {
  290. list_memheap();
  291. }
  292. #else
  293. rt_uint32_t total, max, used;
  294. if (show_mem) {
  295. rt_memory_info(&total, &used, &max);
  296. }
  297. #endif
  298. rt_thread_t tid;
  299. if (show_stack) {
  300. tid = rt_thread_self();
  301. rt_kprintf("thread stack addr: %p, size: %u, sp: %p\n", tid->stack_addr,
  302. tid->stack_size, tid->sp);
  303. }
  304. #endif /* WAMR_ENABLE_PARAMS */
  305. if (wasm_runtime_full_init(&init_args) == false) {
  306. rt_kprintf("Init WASM runtime environment failed.\n");
  307. return -1;
  308. }
  309. wasm_file_buf = my_read_file_to_buffer(argv[i_arg_begin], &wasm_file_size);
  310. if (!wasm_file_buf) {
  311. rt_err_t err = rt_get_errno();
  312. rt_kprintf("WASM load file to RAM failed: %d\n", err);
  313. goto fail1;
  314. }
  315. rt_memset(error_buf, 0x00, sizeof(error_buf));
  316. wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf,
  317. sizeof(error_buf));
  318. if (!wasm_module) {
  319. rt_kprintf("%s\n", error_buf);
  320. goto fail2;
  321. }
  322. #if WASM_ENABLE_LIBC_WASI != 0
  323. libc_wasi_init(wasm_module, argc, argv, &wasi_parse_ctx);
  324. #endif
  325. rt_memset(error_buf, 0x00, sizeof(error_buf));
  326. wasm_module_inst = wasm_runtime_instantiate(
  327. wasm_module, stack_size, heap_size, error_buf, sizeof(error_buf));
  328. if (!wasm_module_inst) {
  329. rt_kprintf("%s\n", error_buf);
  330. goto fail3;
  331. }
  332. #ifdef WAMR_ENABLE_IWASM_PARAMS
  333. rt_tick_t ticks_exec;
  334. if (show_time_exec) {
  335. ticks_exec = rt_tick_get();
  336. }
  337. #endif /* WAMR_ENABLE_PARAMS */
  338. if (func_name) {
  339. exception = app_instance_func(wasm_module_inst, func_name,
  340. argc - i_arg_begin, &argv[i_arg_begin]);
  341. }
  342. else {
  343. exception = app_instance_main(wasm_module_inst, argc - i_arg_begin,
  344. &argv[i_arg_begin]);
  345. rt_kprintf("finshed run app_instance_main\n");
  346. }
  347. if (exception)
  348. rt_kprintf("%s\n", exception);
  349. #if WASM_ENABLE_LIBC_WASI != 0
  350. if (!exception) {
  351. /* propagate wasi exit code. */
  352. wasm_runtime_get_wasi_exit_code(wasm_module_inst);
  353. }
  354. #endif
  355. #ifdef WAMR_ENABLE_IWASM_PARAMS
  356. if (show_time_exec) {
  357. ticks_exec = rt_tick_get() - ticks_exec;
  358. rt_kprintf("[iwasm] execute ticks took: %u [ticks/s = %u]\n",
  359. ticks_exec, RT_TICK_PER_SECOND);
  360. }
  361. #if defined(RT_USING_HEAP) && defined(RT_USING_MEMHEAP_AS_HEAP)
  362. if (show_mem) {
  363. list_memheap();
  364. }
  365. #else
  366. rt_uint32_t total_after, max_after, used_after;
  367. if (show_mem) {
  368. rt_memory_info(&total_after, &used_after, &max_after);
  369. rt_kprintf("[iwasm] memory took: %u\n", used_after - used);
  370. }
  371. #endif
  372. if (show_stack) {
  373. rt_kprintf("[iwasm] thread stack addr: %p, size: %u, sp: %p\n",
  374. tid->stack_addr, tid->stack_size, tid->sp);
  375. }
  376. #endif /* WAMR_ENABLE_PARAMS */
  377. /* destroy the module instance */
  378. wasm_runtime_deinstantiate(wasm_module_inst);
  379. fail3:
  380. /* unload the module */
  381. wasm_runtime_unload(wasm_module);
  382. fail2:
  383. /* free the file buffer */
  384. rt_free(wasm_file_buf);
  385. fail1:
  386. /* destroy runtime environment */
  387. wasm_runtime_destroy();
  388. return 0;
  389. }
  390. MSH_CMD_EXPORT(iwasm, Embeded VM of WebAssembly);