iwasm.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  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. if (!filename || !size) {
  175. rt_set_errno(-EINVAL);
  176. return RT_NULL;
  177. }
  178. if (stat(filename, &f_stat) != 0) {
  179. rt_set_errno(errno);
  180. return RT_NULL;
  181. }
  182. if (f_stat.st_size <= 0) {
  183. rt_set_errno(-EINVAL);
  184. return RT_NULL;
  185. }
  186. rt_uint8_t *buff = rt_malloc(f_stat.st_size);
  187. *size = 0;
  188. if (!buff) {
  189. rt_set_errno(-ENOMEM);
  190. return RT_NULL;
  191. }
  192. int fd = open(filename, O_RDONLY);
  193. if (fd < 0) {
  194. rt_free(buff);
  195. rt_set_errno(fd);
  196. return RT_NULL;
  197. }
  198. *size = read(fd, buff, f_stat.st_size);
  199. close(fd);
  200. if (*size != f_stat.st_size) {
  201. rt_free(buff);
  202. rt_set_errno(-EBADF);
  203. return RT_NULL;
  204. }
  205. return buff;
  206. }
  207. void
  208. iwasm_help(void)
  209. {
  210. #ifdef WAMR_ENABLE_IWASM_PARAMS
  211. rt_kputs("Usage: iwasm [-options] wasm_file [args...]\n");
  212. rt_kputs("options:\n");
  213. rt_kputs(" -t Show time taking to run this app.\n");
  214. rt_kputs(" -m Show memory taking to run this app\n");
  215. rt_kputs(" -f|--function name Specify a function name of the module "
  216. "to run rather than main\n");
  217. rt_kputs(" --max-threads=n Set maximum thread number per "
  218. "cluster, default is 4\n");
  219. #else
  220. rt_kputs("Usage: iwasm wasm_file [args...]\n");
  221. #endif /* WAMR_ENABLE_PARAMS */
  222. }
  223. int
  224. iwasm(int argc, char **argv)
  225. {
  226. const char *exception = NULL;
  227. const char *func_name = NULL;
  228. rt_uint8_t *wasm_file_buf = NULL;
  229. rt_uint32_t wasm_file_size;
  230. rt_uint32_t stack_size = 64 * 1024, heap_size = 256 * 1024;
  231. wasm_module_t wasm_module = NULL;
  232. wasm_module_inst_t wasm_module_inst = NULL;
  233. RuntimeInitArgs init_args;
  234. struct InstantiationArgs2 *inst_args;
  235. static char error_buf[128] = { 0 };
  236. /* avoid stack overflow */
  237. #if WASM_ENABLE_LIBC_WASI != 0
  238. libc_wasi_parse_context_t wasi_parse_ctx;
  239. memset(&wasi_parse_ctx, 0, sizeof(wasi_parse_ctx));
  240. #endif
  241. #ifdef WAMR_ENABLE_IWASM_PARAMS
  242. int i_arg_begin;
  243. bool show_mem = false;
  244. bool show_stack = false;
  245. bool show_time_exec = false;
  246. for (i_arg_begin = 1; i_arg_begin < argc; i_arg_begin++) {
  247. if (argv[i_arg_begin][0] != '-') {
  248. break;
  249. }
  250. if (argv[i_arg_begin][1] == 'm') {
  251. show_mem = true;
  252. }
  253. else if (argv[i_arg_begin][1] == 's') {
  254. show_stack = true;
  255. }
  256. else if (argv[i_arg_begin][1] == 't') {
  257. show_time_exec = true;
  258. }
  259. else if (argv[i_arg_begin][1] == 'h') {
  260. iwasm_help();
  261. return 0;
  262. }
  263. else if (argv[i_arg_begin][1] == 'f') {
  264. func_name = argv[++i_arg_begin];
  265. }
  266. else if (!strncmp(argv[i_arg_begin], "--max-threads=", 14)) {
  267. if (argv[0][14] != '\0')
  268. wasm_runtime_set_max_thread_num(atoi(argv[0] + 14));
  269. else {
  270. iwasm_help();
  271. return 0;
  272. }
  273. }
  274. else if (argv[i_arg_begin][1] == 0x00) {
  275. continue;
  276. }
  277. else {
  278. rt_kprintf("[iwasm] unknown param: %s\n", argv[i_arg_begin]);
  279. }
  280. }
  281. #else /* WAMR_ENABLE_PARAMS */
  282. #define i_arg_begin 1
  283. #endif /* WAMR_ENABLE_PARAMS */
  284. if (argc - i_arg_begin < 1) {
  285. iwasm_help();
  286. return -1;
  287. }
  288. rt_memset(&init_args, 0, sizeof(RuntimeInitArgs));
  289. init_args.mem_alloc_type = Alloc_With_Allocator;
  290. init_args.mem_alloc_option.allocator.malloc_func = os_malloc;
  291. init_args.mem_alloc_option.allocator.realloc_func = os_realloc;
  292. init_args.mem_alloc_option.allocator.free_func = os_free;
  293. #ifdef WAMR_ENABLE_RTT_EXPORT
  294. init_args.native_symbols = native_export_symbols;
  295. init_args.n_native_symbols =
  296. sizeof(native_export_symbols) / sizeof(NativeSymbol);
  297. init_args.native_module_name = "env";
  298. #endif /* WAMR_ENABLE_RTT_EXPORT */
  299. #ifdef WAMR_ENABLE_IWASM_PARAMS
  300. #if defined(RT_USING_HEAP) && defined(RT_USING_MEMHEAP_AS_HEAP)
  301. extern long list_memheap(void);
  302. if (show_mem) {
  303. list_memheap();
  304. }
  305. #else
  306. rt_uint32_t total, max, used;
  307. if (show_mem) {
  308. rt_memory_info(&total, &used, &max);
  309. }
  310. #endif
  311. rt_thread_t tid;
  312. if (show_stack) {
  313. tid = rt_thread_self();
  314. rt_kprintf("thread stack addr: %p, size: %u, sp: %p\n", tid->stack_addr,
  315. tid->stack_size, tid->sp);
  316. }
  317. #endif /* WAMR_ENABLE_PARAMS */
  318. if (wasm_runtime_full_init(&init_args) == false) {
  319. rt_kprintf("Init WASM runtime environment failed.\n");
  320. return -1;
  321. }
  322. wasm_file_buf = my_read_file_to_buffer(argv[i_arg_begin], &wasm_file_size);
  323. if (!wasm_file_buf) {
  324. rt_err_t err = rt_get_errno();
  325. rt_kprintf("WASM load file to RAM failed: %d\n", err);
  326. goto fail1;
  327. }
  328. rt_memset(error_buf, 0x00, sizeof(error_buf));
  329. wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf,
  330. sizeof(error_buf));
  331. if (!wasm_module) {
  332. rt_kprintf("%s\n", error_buf);
  333. goto fail2;
  334. }
  335. if (!wasm_runtime_instantiation_args_create(&inst_args)) {
  336. rt_kprintf("failed to create instantiate args\n");
  337. goto fail3;
  338. }
  339. wasm_runtime_instantiation_args_set_default_stack_size(inst_args,
  340. stack_size);
  341. wasm_runtime_instantiation_args_set_host_managed_heap_size(inst_args,
  342. heap_size);
  343. #if WASM_ENABLE_LIBC_WASI != 0
  344. libc_wasi_set_init_args(wasm_module, argc, argv, &wasi_parse_ctx);
  345. #endif
  346. rt_memset(error_buf, 0x00, sizeof(error_buf));
  347. wasm_module_inst = wasm_runtime_instantiate_ex2(
  348. wasm_module, inst_args, error_buf, sizeof(error_buf));
  349. wasm_runtime_instantiation_args_destroy(inst_args);
  350. if (!wasm_module_inst) {
  351. rt_kprintf("%s\n", error_buf);
  352. goto fail3;
  353. }
  354. #ifdef WAMR_ENABLE_IWASM_PARAMS
  355. rt_tick_t ticks_exec;
  356. if (show_time_exec) {
  357. ticks_exec = rt_tick_get();
  358. }
  359. #endif /* WAMR_ENABLE_PARAMS */
  360. if (func_name) {
  361. exception = app_instance_func(wasm_module_inst, func_name,
  362. argc - i_arg_begin, &argv[i_arg_begin]);
  363. }
  364. else {
  365. exception = app_instance_main(wasm_module_inst, argc - i_arg_begin,
  366. &argv[i_arg_begin]);
  367. rt_kprintf("finished run app_instance_main\n");
  368. }
  369. if (exception)
  370. rt_kprintf("%s\n", exception);
  371. #if WASM_ENABLE_LIBC_WASI != 0
  372. if (!exception) {
  373. /* propagate wasi exit code. */
  374. wasm_runtime_get_wasi_exit_code(wasm_module_inst);
  375. }
  376. #endif
  377. #ifdef WAMR_ENABLE_IWASM_PARAMS
  378. if (show_time_exec) {
  379. ticks_exec = rt_tick_get() - ticks_exec;
  380. rt_kprintf("[iwasm] execute ticks took: %u [ticks/s = %u]\n",
  381. ticks_exec, RT_TICK_PER_SECOND);
  382. }
  383. #if defined(RT_USING_HEAP) && defined(RT_USING_MEMHEAP_AS_HEAP)
  384. if (show_mem) {
  385. list_memheap();
  386. }
  387. #else
  388. rt_uint32_t total_after, max_after, used_after;
  389. if (show_mem) {
  390. rt_memory_info(&total_after, &used_after, &max_after);
  391. rt_kprintf("[iwasm] memory took: %u\n", used_after - used);
  392. }
  393. #endif
  394. if (show_stack) {
  395. rt_kprintf("[iwasm] thread stack addr: %p, size: %u, sp: %p\n",
  396. tid->stack_addr, tid->stack_size, tid->sp);
  397. }
  398. #endif /* WAMR_ENABLE_PARAMS */
  399. /* destroy the module instance */
  400. wasm_runtime_deinstantiate(wasm_module_inst);
  401. fail3:
  402. /* unload the module */
  403. wasm_runtime_unload(wasm_module);
  404. fail2:
  405. /* free the file buffer */
  406. rt_free(wasm_file_buf);
  407. fail1:
  408. /* destroy runtime environment */
  409. wasm_runtime_destroy();
  410. return 0;
  411. }
  412. MSH_CMD_EXPORT(iwasm, Embedded VM of WebAssembly);