main.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. /*
  2. * Copyright (C) 2019 Intel Corporation. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #ifndef _GNU_SOURCE
  6. #define _GNU_SOURCE
  7. #endif
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include "bh_platform.h"
  11. #include "bh_read_file.h"
  12. #include "wasm_export.h"
  13. static int app_argc;
  14. static char **app_argv;
  15. #define MODULE_PATH ("--module-path=")
  16. static int
  17. print_help()
  18. {
  19. printf("Usage: iwasm [-options] wasm_file [args...]\n");
  20. printf("options:\n");
  21. printf(" -f|--function name Specify a function name of the module to run rather\n"
  22. " than main\n");
  23. #if WASM_ENABLE_LOG != 0
  24. printf(" -v=n Set log verbose level (0 to 5, default is 2) larger\n"
  25. " level with more log\n");
  26. #endif
  27. printf(" --stack-size=n Set maximum stack size in bytes, default is 16 KB\n");
  28. printf(" --heap-size=n Set maximum heap size in bytes, default is 16 KB\n");
  29. printf(" --repl Start a very simple REPL (read-eval-print-loop) mode\n"
  30. " that runs commands in the form of `FUNC ARG...`\n");
  31. #if WASM_ENABLE_LIBC_WASI != 0
  32. printf(" --env=<env> Pass wasi environment variables with \"key=value\"\n");
  33. printf(" to the program, for example:\n");
  34. printf(" --env=\"key1=value1\" --env=\"key2=value2\"\n");
  35. printf(" --dir=<dir> Grant wasi access to the given host directories\n");
  36. printf(" to the program, for example:\n");
  37. printf(" --dir=<dir1> --dir=<dir2>\n");
  38. #endif
  39. #if WASM_ENABLE_MULTI_MODULE != 0
  40. printf(" --module-path= Indicate a module search path. default is current\n"
  41. " directory('./')\n");
  42. #endif
  43. #if WASM_ENABLE_LIB_PTHREAD != 0
  44. printf(" --max-threads=n Set maximum thread number per cluster, default is 4\n");
  45. #endif
  46. return 1;
  47. }
  48. static void *
  49. app_instance_main(wasm_module_inst_t module_inst)
  50. {
  51. const char *exception;
  52. wasm_application_execute_main(module_inst, app_argc, app_argv);
  53. if ((exception = wasm_runtime_get_exception(module_inst)))
  54. printf("%s\n", exception);
  55. return NULL;
  56. }
  57. static void *
  58. app_instance_func(wasm_module_inst_t module_inst, const char *func_name)
  59. {
  60. wasm_application_execute_func(module_inst, func_name, app_argc - 1,
  61. app_argv + 1);
  62. /* The result of wasm function or exception info was output inside
  63. wasm_application_execute_func(), here we don't output them again. */
  64. return NULL;
  65. }
  66. /**
  67. * Split a space separated strings into an array of strings
  68. * Returns NULL on failure
  69. * Memory must be freed by caller
  70. * Based on: http://stackoverflow.com/a/11198630/471795
  71. */
  72. static char **
  73. split_string(char *str, int *count)
  74. {
  75. char **res = NULL;
  76. char *p;
  77. int idx = 0;
  78. /* split string and append tokens to 'res' */
  79. do {
  80. p = strtok(str, " ");
  81. str = NULL;
  82. res = (char **)realloc(res, sizeof(char *) * (uint32)(idx + 1));
  83. if (res == NULL) {
  84. return NULL;
  85. }
  86. res[idx++] = p;
  87. } while (p);
  88. /**
  89. * since the function name,
  90. * res[0] might be contains a '\' to indicate a space
  91. * func\name -> func name
  92. */
  93. p = strchr(res[0], '\\');
  94. while (p) {
  95. *p = ' ';
  96. p = strchr(p, '\\');
  97. }
  98. if (count) {
  99. *count = idx - 1;
  100. }
  101. return res;
  102. }
  103. static void *
  104. app_instance_repl(wasm_module_inst_t module_inst)
  105. {
  106. char *cmd = NULL;
  107. size_t len = 0;
  108. ssize_t n;
  109. while ((printf("webassembly> "), n = getline(&cmd, &len, stdin)) != -1) {
  110. bh_assert(n > 0);
  111. if (cmd[n - 1] == '\n') {
  112. if (n == 1)
  113. continue;
  114. else
  115. cmd[n - 1] = '\0';
  116. }
  117. if (!strcmp(cmd, "__exit__")) {
  118. printf("exit repl mode\n");
  119. break;
  120. }
  121. app_argv = split_string(cmd, &app_argc);
  122. if (app_argv == NULL) {
  123. LOG_ERROR("Wasm prepare param failed: split string failed.\n");
  124. break;
  125. }
  126. if (app_argc != 0) {
  127. wasm_application_execute_func(module_inst, app_argv[0],
  128. app_argc - 1, app_argv + 1);
  129. }
  130. free(app_argv);
  131. }
  132. free(cmd);
  133. return NULL;
  134. }
  135. #if WASM_ENABLE_LIBC_WASI != 0
  136. static bool
  137. validate_env_str(char *env)
  138. {
  139. char *p = env;
  140. int key_len = 0;
  141. while (*p != '\0' && *p != '=') {
  142. key_len++;
  143. p++;
  144. }
  145. if (*p != '=' || key_len == 0)
  146. return false;
  147. return true;
  148. }
  149. #endif
  150. #define USE_GLOBAL_HEAP_BUF 0
  151. #if USE_GLOBAL_HEAP_BUF != 0
  152. static char global_heap_buf[10 * 1024 * 1024] = { 0 };
  153. #endif
  154. #if WASM_ENABLE_MULTI_MODULE != 0
  155. static char *
  156. handle_module_path(const char *module_path)
  157. {
  158. // next character after =
  159. return (strchr(module_path, '=')) + 1;
  160. }
  161. static char *module_search_path = ".";
  162. static bool
  163. module_reader_callback(const char *module_name, uint8 **p_buffer,
  164. uint32 *p_size)
  165. {
  166. const char *format = "%s/%s.wasm";
  167. int sz = strlen(module_search_path) + strlen("/") + strlen(module_name) +
  168. strlen(".wasm") + 1;
  169. char *wasm_file_name = BH_MALLOC(sz);
  170. if (!wasm_file_name) {
  171. return false;
  172. }
  173. snprintf(wasm_file_name, sz, format, module_search_path, module_name);
  174. *p_buffer = (uint8_t *)bh_read_file_to_buffer(wasm_file_name, p_size);
  175. wasm_runtime_free(wasm_file_name);
  176. return *p_buffer != NULL;
  177. }
  178. static void
  179. moudle_destroyer(uint8 *buffer, uint32 size)
  180. {
  181. if (!buffer) {
  182. return;
  183. }
  184. wasm_runtime_free(buffer);
  185. buffer = NULL;
  186. }
  187. #endif /* WASM_ENABLE_MULTI_MODULE */
  188. int
  189. main(int argc, char *argv[])
  190. {
  191. char *wasm_file = NULL;
  192. const char *func_name = NULL;
  193. uint8 *wasm_file_buf = NULL;
  194. uint32 wasm_file_size;
  195. uint32 stack_size = 16 * 1024, heap_size = 16 * 1024;
  196. wasm_module_t wasm_module = NULL;
  197. wasm_module_inst_t wasm_module_inst = NULL;
  198. RuntimeInitArgs init_args;
  199. char error_buf[128] = { 0 };
  200. #if WASM_ENABLE_LOG != 0
  201. int log_verbose_level = 2;
  202. #endif
  203. bool is_repl_mode = false;
  204. #if WASM_ENABLE_LIBC_WASI != 0
  205. const char *dir_list[8] = { NULL };
  206. uint32 dir_list_size = 0;
  207. const char *env_list[8] = { NULL };
  208. uint32 env_list_size = 0;
  209. #endif
  210. /* Process options. */
  211. // TODO: use a option name and option handler pair table to
  212. // optimize
  213. for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) {
  214. if (!strcmp(argv[0], "-f") || !strcmp(argv[0], "--function")) {
  215. argc--, argv++;
  216. if (argc < 2) {
  217. print_help();
  218. return 0;
  219. }
  220. func_name = argv[0];
  221. }
  222. #if WASM_ENABLE_LOG != 0
  223. else if (!strncmp(argv[0], "-v=", 3)) {
  224. log_verbose_level = atoi(argv[0] + 3);
  225. if (log_verbose_level < 0 || log_verbose_level > 5)
  226. return print_help();
  227. }
  228. #endif
  229. else if (!strcmp(argv[0], "--repl")) {
  230. is_repl_mode = true;
  231. }
  232. else if (!strncmp(argv[0], "--stack-size=", 13)) {
  233. if (argv[0][13] == '\0')
  234. return print_help();
  235. stack_size = atoi(argv[0] + 13);
  236. }
  237. else if (!strncmp(argv[0], "--heap-size=", 12)) {
  238. if (argv[0][12] == '\0')
  239. return print_help();
  240. heap_size = atoi(argv[0] + 12);
  241. }
  242. #if WASM_ENABLE_LIBC_WASI != 0
  243. else if (!strncmp(argv[0], "--dir=", 6)) {
  244. if (argv[0][6] == '\0')
  245. return print_help();
  246. if (dir_list_size >= sizeof(dir_list) / sizeof(char *)) {
  247. printf("Only allow max dir number %d\n",
  248. (int)(sizeof(dir_list) / sizeof(char *)));
  249. return -1;
  250. }
  251. dir_list[dir_list_size++] = argv[0] + 6;
  252. }
  253. else if (!strncmp(argv[0], "--env=", 6)) {
  254. char *tmp_env;
  255. if (argv[0][6] == '\0')
  256. return print_help();
  257. if (env_list_size >= sizeof(env_list) / sizeof(char *)) {
  258. printf("Only allow max env number %d\n",
  259. (int)(sizeof(env_list) / sizeof(char *)));
  260. return -1;
  261. }
  262. tmp_env = argv[0] + 6;
  263. if (validate_env_str(tmp_env))
  264. env_list[env_list_size++] = tmp_env;
  265. else {
  266. printf("Wasm parse env string failed: expect \"key=value\", "
  267. "got \"%s\"\n",
  268. tmp_env);
  269. return print_help();
  270. }
  271. }
  272. #endif /* WASM_ENABLE_LIBC_WASI */
  273. #if WASM_ENABLE_MULTI_MODULE != 0
  274. else if (!strncmp(argv[0], MODULE_PATH, strlen(MODULE_PATH))) {
  275. module_search_path = handle_module_path(argv[0]);
  276. if (!strlen(module_search_path)) {
  277. return print_help();
  278. }
  279. }
  280. #endif
  281. #if WASM_ENABLE_LIB_PTHREAD != 0
  282. else if (!strncmp(argv[0], "--max-threads=", 14)) {
  283. if (argv[0][14] == '\0')
  284. return print_help();
  285. wasm_runtime_set_max_thread_num(atoi(argv[0] + 14));
  286. }
  287. #endif
  288. else
  289. return print_help();
  290. }
  291. if (argc == 0)
  292. return print_help();
  293. wasm_file = argv[0];
  294. app_argc = argc;
  295. app_argv = argv;
  296. memset(&init_args, 0, sizeof(RuntimeInitArgs));
  297. #if USE_GLOBAL_HEAP_BUF != 0
  298. init_args.mem_alloc_type = Alloc_With_Pool;
  299. init_args.mem_alloc_option.pool.heap_buf = global_heap_buf;
  300. init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf);
  301. #else
  302. init_args.mem_alloc_type = Alloc_With_Allocator;
  303. init_args.mem_alloc_option.allocator.malloc_func = malloc;
  304. init_args.mem_alloc_option.allocator.realloc_func = realloc;
  305. init_args.mem_alloc_option.allocator.free_func = free;
  306. #endif
  307. /* initialize runtime environment */
  308. if (!wasm_runtime_full_init(&init_args)) {
  309. printf("Init runtime environment failed.\n");
  310. return -1;
  311. }
  312. #if WASM_ENABLE_LOG != 0
  313. bh_log_set_verbose_level(log_verbose_level);
  314. #endif
  315. /* load WASM byte buffer from WASM bin file */
  316. if (!(wasm_file_buf =
  317. (uint8 *)bh_read_file_to_buffer(wasm_file, &wasm_file_size)))
  318. goto fail1;
  319. #if WASM_ENABLE_MULTI_MODULE != 0
  320. wasm_runtime_set_module_reader(module_reader_callback, moudle_destroyer);
  321. #endif
  322. /* load WASM module */
  323. if (!(wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size,
  324. error_buf, sizeof(error_buf)))) {
  325. printf("%s\n", error_buf);
  326. goto fail2;
  327. }
  328. #if WASM_ENABLE_LIBC_WASI != 0
  329. wasm_runtime_set_wasi_args(wasm_module, dir_list, dir_list_size, NULL, 0,
  330. env_list, env_list_size, argv, argc);
  331. #endif
  332. /* instantiate the module */
  333. if (!(wasm_module_inst =
  334. wasm_runtime_instantiate(wasm_module, stack_size, heap_size,
  335. error_buf, sizeof(error_buf)))) {
  336. printf("%s\n", error_buf);
  337. goto fail3;
  338. }
  339. if (is_repl_mode)
  340. app_instance_repl(wasm_module_inst);
  341. else if (func_name)
  342. app_instance_func(wasm_module_inst, func_name);
  343. else
  344. app_instance_main(wasm_module_inst);
  345. /* destroy the module instance */
  346. wasm_runtime_deinstantiate(wasm_module_inst);
  347. fail3:
  348. /* unload the module */
  349. wasm_runtime_unload(wasm_module);
  350. fail2:
  351. /* free the file buffer */
  352. wasm_runtime_free(wasm_file_buf);
  353. fail1:
  354. /* destroy runtime environment */
  355. wasm_runtime_destroy();
  356. return 0;
  357. }