main.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. /*
  2. * Copyright (C) 2019 Intel Corporation. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include "bh_platform.h"
  8. #include "bh_read_file.h"
  9. #include "wasm_export.h"
  10. static int app_argc;
  11. static char **app_argv;
  12. #define MODULE_PATH ("--module-path=")
  13. /* clang-format off */
  14. static int
  15. print_help()
  16. {
  17. printf("Usage: iwasm [-options] wasm_file [args...]\n");
  18. printf("options:\n");
  19. printf(" -f|--function name Specify a function name of the module to run rather\n"
  20. " than main\n");
  21. #if WASM_ENABLE_LOG != 0
  22. printf(" -v=n Set log verbose level (0 to 5, default is 2) larger\n"
  23. " level with more log\n");
  24. #endif
  25. #if WASM_ENABLE_INTERP != 0
  26. printf(" --interp Run the wasm app with interpreter mode\n");
  27. #endif
  28. #if WASM_ENABLE_FAST_JIT != 0
  29. printf(" --fast-jit Run the wasm app with fast jit mode\n");
  30. #endif
  31. #if WASM_ENABLE_JIT != 0
  32. printf(" --llvm-jit Run the wasm app with llvm jit mode\n");
  33. #endif
  34. #if WASM_ENABLE_JIT != 0 && WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0
  35. printf(" --multi-tier-jit Run the wasm app with multi-tier jit mode\n");
  36. #endif
  37. printf(" --stack-size=n Set maximum stack size in bytes, default is 64 KB\n");
  38. printf(" --heap-size=n Set maximum heap size in bytes, default is 16 KB\n");
  39. #if WASM_ENABLE_JIT != 0
  40. printf(" --llvm-jit-size-level=n Set LLVM JIT size level, default is 3\n");
  41. printf(" --llvm-jit-opt-level=n Set LLVM JIT optimization level, default is 3\n");
  42. #endif
  43. printf(" --repl Start a very simple REPL (read-eval-print-loop) mode\n"
  44. " that runs commands in the form of `FUNC ARG...`\n");
  45. #if WASM_ENABLE_LIBC_WASI != 0
  46. printf(" --env=<env> Pass wasi environment variables with \"key=value\"\n");
  47. printf(" to the program, for example:\n");
  48. printf(" --env=\"key1=value1\" --env=\"key2=value2\"\n");
  49. printf(" --dir=<dir> Grant wasi access to the given host directories\n");
  50. printf(" to the program, for example:\n");
  51. printf(" --dir=<dir1> --dir=<dir2>\n");
  52. #endif
  53. #if WASM_ENABLE_MULTI_MODULE != 0
  54. printf(" --module-path=<path> Indicate a module search path. default is current\n"
  55. " directory('./')\n");
  56. #endif
  57. #if WASM_ENABLE_LIB_PTHREAD != 0 || WASM_ENABLE_LIB_WASI_THREADS != 0
  58. printf(" --max-threads=n Set maximum thread number per cluster, default is 4\n");
  59. #endif
  60. #if WASM_ENABLE_DEBUG_INTERP != 0
  61. printf(" -g=ip:port Set the debug sever address, default is debug disabled\n");
  62. printf(" if port is 0, then a random port will be used\n");
  63. #endif
  64. printf(" --version Show version information\n");
  65. return 1;
  66. }
  67. /* clang-format on */
  68. static const void *
  69. app_instance_main(wasm_module_inst_t module_inst)
  70. {
  71. const char *exception;
  72. wasm_application_execute_main(module_inst, app_argc, app_argv);
  73. if ((exception = wasm_runtime_get_exception(module_inst)))
  74. printf("%s\n", exception);
  75. return exception;
  76. }
  77. static const void *
  78. app_instance_func(wasm_module_inst_t module_inst, const char *func_name)
  79. {
  80. wasm_application_execute_func(module_inst, func_name, app_argc - 1,
  81. app_argv + 1);
  82. /* The result of wasm function or exception info was output inside
  83. wasm_application_execute_func(), here we don't output them again. */
  84. return wasm_runtime_get_exception(module_inst);
  85. }
  86. /**
  87. * Split a space separated strings into an array of strings
  88. * Returns NULL on failure
  89. * Memory must be freed by caller
  90. * Based on: http://stackoverflow.com/a/11198630/471795
  91. */
  92. static char **
  93. split_string(char *str, int *count)
  94. {
  95. char **res = NULL, **res1;
  96. char *p, *next_token;
  97. int idx = 0;
  98. /* split string and append tokens to 'res' */
  99. do {
  100. p = strtok_s(str, " ", &next_token);
  101. str = NULL;
  102. res1 = res;
  103. res = (char **)realloc(res1, sizeof(char *) * (uint32)(idx + 1));
  104. if (res == NULL) {
  105. free(res1);
  106. return NULL;
  107. }
  108. res[idx++] = p;
  109. } while (p);
  110. /**
  111. * Due to the function name,
  112. * res[0] might contain a '\' to indicate a space
  113. * func\name -> func name
  114. */
  115. p = strchr(res[0], '\\');
  116. while (p) {
  117. *p = ' ';
  118. p = strchr(p, '\\');
  119. }
  120. if (count) {
  121. *count = idx - 1;
  122. }
  123. return res;
  124. }
  125. static void *
  126. app_instance_repl(wasm_module_inst_t module_inst)
  127. {
  128. char buffer[4096];
  129. char *cmd;
  130. size_t n;
  131. while ((printf("webassembly> "), cmd = fgets(buffer, sizeof(buffer), stdin))
  132. != NULL) {
  133. bh_assert(cmd);
  134. n = strlen(cmd);
  135. if (cmd[n - 1] == '\n') {
  136. if (n == 1)
  137. continue;
  138. else
  139. cmd[n - 1] = '\0';
  140. }
  141. if (!strcmp(cmd, "__exit__")) {
  142. printf("exit repl mode\n");
  143. break;
  144. }
  145. app_argv = split_string(cmd, &app_argc);
  146. if (app_argv == NULL) {
  147. LOG_ERROR("Wasm prepare param failed: split string failed.\n");
  148. break;
  149. }
  150. if (app_argc != 0) {
  151. wasm_application_execute_func(module_inst, app_argv[0],
  152. app_argc - 1, app_argv + 1);
  153. }
  154. free(app_argv);
  155. }
  156. return NULL;
  157. }
  158. #if WASM_ENABLE_LIBC_WASI != 0
  159. static bool
  160. validate_env_str(char *env)
  161. {
  162. char *p = env;
  163. int key_len = 0;
  164. while (*p != '\0' && *p != '=') {
  165. key_len++;
  166. p++;
  167. }
  168. if (*p != '=' || key_len == 0)
  169. return false;
  170. return true;
  171. }
  172. #endif
  173. #if WASM_ENABLE_GLOBAL_HEAP_POOL != 0
  174. static char global_heap_buf[WASM_GLOBAL_HEAP_SIZE] = { 0 };
  175. #endif
  176. #if WASM_ENABLE_MULTI_MODULE != 0
  177. static char *
  178. handle_module_path(const char *module_path)
  179. {
  180. /* next character after '=' */
  181. return (strchr(module_path, '=')) + 1;
  182. }
  183. static char *module_search_path = ".";
  184. static bool
  185. module_reader_callback(package_type_t module_type, const char *module_name,
  186. uint8 **p_buffer, uint32 *p_size)
  187. {
  188. char *file_format;
  189. #if WASM_ENABLE_INTERP != 0
  190. if (module_type == Wasm_Module_Bytecode)
  191. file_format = ".wasm";
  192. #endif
  193. #if WASM_ENABLE_AOT != 0
  194. if (module_type == Wasm_Module_AoT)
  195. file_format = ".aot";
  196. #endif
  197. const char *format = "%s/%s%s";
  198. int sz = strlen(module_search_path) + strlen("/") + strlen(module_name)
  199. + strlen(file_format) + 1;
  200. char *wasm_file_name = BH_MALLOC(sz);
  201. if (!wasm_file_name) {
  202. return false;
  203. }
  204. snprintf(wasm_file_name, sz, format, module_search_path, module_name,
  205. file_format);
  206. *p_buffer = (uint8_t *)bh_read_file_to_buffer(wasm_file_name, p_size);
  207. wasm_runtime_free(wasm_file_name);
  208. return *p_buffer != NULL;
  209. }
  210. static void
  211. moudle_destroyer(uint8 *buffer, uint32 size)
  212. {
  213. if (!buffer) {
  214. return;
  215. }
  216. wasm_runtime_free(buffer);
  217. buffer = NULL;
  218. }
  219. #endif /* WASM_ENABLE_MULTI_MODULE */
  220. int
  221. main(int argc, char *argv[])
  222. {
  223. int32 ret = -1;
  224. char *wasm_file = NULL;
  225. const char *func_name = NULL;
  226. uint8 *wasm_file_buf = NULL;
  227. uint32 wasm_file_size;
  228. uint32 stack_size = 64 * 1024;
  229. #if WASM_ENABLE_LIBC_WASI != 0
  230. uint32 heap_size = 0;
  231. #else
  232. uint32 heap_size = 16 * 1024;
  233. #endif
  234. #if WASM_ENABLE_JIT != 0
  235. uint32 llvm_jit_size_level = 3;
  236. uint32 llvm_jit_opt_level = 3;
  237. #endif
  238. wasm_module_t wasm_module = NULL;
  239. wasm_module_inst_t wasm_module_inst = NULL;
  240. RunningMode running_mode = 0;
  241. RuntimeInitArgs init_args;
  242. char error_buf[128] = { 0 };
  243. #if WASM_ENABLE_LOG != 0
  244. int log_verbose_level = 2;
  245. #endif
  246. bool is_repl_mode = false;
  247. bool is_xip_file = false;
  248. #if WASM_ENABLE_LIBC_WASI != 0
  249. const char *dir_list[8] = { NULL };
  250. uint32 dir_list_size = 0;
  251. const char *env_list[8] = { NULL };
  252. uint32 env_list_size = 0;
  253. #endif
  254. #if WASM_ENABLE_DEBUG_INTERP != 0
  255. char *ip_addr = NULL;
  256. int instance_port = 0;
  257. #endif
  258. /* Process options. */
  259. for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) {
  260. if (!strcmp(argv[0], "-f") || !strcmp(argv[0], "--function")) {
  261. argc--, argv++;
  262. if (argc < 2) {
  263. return print_help();
  264. }
  265. func_name = argv[0];
  266. }
  267. #if WASM_ENABLE_INTERP != 0
  268. else if (!strcmp(argv[0], "--interp")) {
  269. running_mode = Mode_Interp;
  270. }
  271. #endif
  272. #if WASM_ENABLE_FAST_JIT != 0
  273. else if (!strcmp(argv[0], "--fast-jit")) {
  274. running_mode = Mode_Fast_JIT;
  275. }
  276. #endif
  277. #if WASM_ENABLE_JIT != 0
  278. else if (!strcmp(argv[0], "--llvm-jit")) {
  279. running_mode = Mode_LLVM_JIT;
  280. }
  281. #endif
  282. #if WASM_ENABLE_JIT != 0 && WASM_ENABLE_FAST_JIT != 0
  283. else if (!strcmp(argv[0], "--multi-tier-jit")) {
  284. running_mode = Mode_Multi_Tier_JIT;
  285. }
  286. #endif
  287. #if WASM_ENABLE_LOG != 0
  288. else if (!strncmp(argv[0], "-v=", 3)) {
  289. log_verbose_level = atoi(argv[0] + 3);
  290. if (log_verbose_level < 0 || log_verbose_level > 5)
  291. return print_help();
  292. }
  293. #endif
  294. else if (!strcmp(argv[0], "--repl")) {
  295. is_repl_mode = true;
  296. }
  297. else if (!strncmp(argv[0], "--stack-size=", 13)) {
  298. if (argv[0][13] == '\0')
  299. return print_help();
  300. stack_size = atoi(argv[0] + 13);
  301. }
  302. else if (!strncmp(argv[0], "--heap-size=", 12)) {
  303. if (argv[0][12] == '\0')
  304. return print_help();
  305. heap_size = atoi(argv[0] + 12);
  306. }
  307. #if WASM_ENABLE_JIT != 0
  308. else if (!strncmp(argv[0], "--llvm-jit-size-level=", 22)) {
  309. if (argv[0][22] == '\0')
  310. return print_help();
  311. llvm_jit_size_level = atoi(argv[0] + 22);
  312. if (llvm_jit_size_level < 1) {
  313. printf("LLVM JIT size level shouldn't be smaller than 1, "
  314. "setting it to 1\n");
  315. llvm_jit_size_level = 1;
  316. }
  317. else if (llvm_jit_size_level > 3) {
  318. printf("LLVM JIT size level shouldn't be greater than 3, "
  319. "setting it to 3\n");
  320. llvm_jit_size_level = 3;
  321. }
  322. }
  323. else if (!strncmp(argv[0], "--llvm-jit-opt-level=", 21)) {
  324. if (argv[0][21] == '\0')
  325. return print_help();
  326. llvm_jit_opt_level = atoi(argv[0] + 21);
  327. if (llvm_jit_opt_level < 1) {
  328. printf("LLVM JIT opt level shouldn't be smaller than 1, "
  329. "setting it to 1\n");
  330. llvm_jit_opt_level = 1;
  331. }
  332. else if (llvm_jit_opt_level > 3) {
  333. printf("LLVM JIT opt level shouldn't be greater than 3, "
  334. "setting it to 3\n");
  335. llvm_jit_opt_level = 3;
  336. }
  337. }
  338. #endif
  339. #if WASM_ENABLE_LIBC_WASI != 0
  340. else if (!strncmp(argv[0], "--dir=", 6)) {
  341. if (argv[0][6] == '\0')
  342. return print_help();
  343. if (dir_list_size >= sizeof(dir_list) / sizeof(char *)) {
  344. printf("Only allow max dir number %d\n",
  345. (int)(sizeof(dir_list) / sizeof(char *)));
  346. return 1;
  347. }
  348. dir_list[dir_list_size++] = argv[0] + 6;
  349. }
  350. else if (!strncmp(argv[0], "--env=", 6)) {
  351. char *tmp_env;
  352. if (argv[0][6] == '\0')
  353. return print_help();
  354. if (env_list_size >= sizeof(env_list) / sizeof(char *)) {
  355. printf("Only allow max env number %d\n",
  356. (int)(sizeof(env_list) / sizeof(char *)));
  357. return 1;
  358. }
  359. tmp_env = argv[0] + 6;
  360. if (validate_env_str(tmp_env))
  361. env_list[env_list_size++] = tmp_env;
  362. else {
  363. printf("Wasm parse env string failed: expect \"key=value\", "
  364. "got \"%s\"\n",
  365. tmp_env);
  366. return print_help();
  367. }
  368. }
  369. #endif /* WASM_ENABLE_LIBC_WASI */
  370. #if WASM_ENABLE_MULTI_MODULE != 0
  371. else if (!strncmp(argv[0], MODULE_PATH, strlen(MODULE_PATH))) {
  372. module_search_path = handle_module_path(argv[0]);
  373. if (!strlen(module_search_path)) {
  374. return print_help();
  375. }
  376. }
  377. #endif
  378. #if WASM_ENABLE_LIB_PTHREAD != 0 || WASM_ENABLE_LIB_WASI_THREADS != 0
  379. else if (!strncmp(argv[0], "--max-threads=", 14)) {
  380. if (argv[0][14] == '\0')
  381. return print_help();
  382. wasm_runtime_set_max_thread_num(atoi(argv[0] + 14));
  383. }
  384. #endif
  385. #if WASM_ENABLE_DEBUG_INTERP != 0
  386. else if (!strncmp(argv[0], "-g=", 3)) {
  387. char *port_str = strchr(argv[0] + 3, ':');
  388. char *port_end;
  389. if (port_str == NULL)
  390. return print_help();
  391. *port_str = '\0';
  392. instance_port = strtoul(port_str + 1, &port_end, 10);
  393. if (port_str[1] == '\0' || *port_end != '\0')
  394. return print_help();
  395. ip_addr = argv[0] + 3;
  396. }
  397. #endif
  398. else if (!strncmp(argv[0], "--version", 9)) {
  399. uint32 major, minor, patch;
  400. wasm_runtime_get_version(&major, &minor, &patch);
  401. printf("iwasm %" PRIu32 ".%" PRIu32 ".%" PRIu32 "\n", major, minor,
  402. patch);
  403. return 0;
  404. }
  405. else
  406. return print_help();
  407. }
  408. if (argc == 0)
  409. return print_help();
  410. wasm_file = argv[0];
  411. app_argc = argc;
  412. app_argv = argv;
  413. memset(&init_args, 0, sizeof(RuntimeInitArgs));
  414. init_args.running_mode = running_mode;
  415. #if WASM_ENABLE_GLOBAL_HEAP_POOL != 0
  416. init_args.mem_alloc_type = Alloc_With_Pool;
  417. init_args.mem_alloc_option.pool.heap_buf = global_heap_buf;
  418. init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf);
  419. #else
  420. init_args.mem_alloc_type = Alloc_With_Allocator;
  421. init_args.mem_alloc_option.allocator.malloc_func = malloc;
  422. init_args.mem_alloc_option.allocator.realloc_func = realloc;
  423. init_args.mem_alloc_option.allocator.free_func = free;
  424. #endif
  425. #if WASM_ENABLE_JIT != 0
  426. init_args.llvm_jit_size_level = llvm_jit_size_level;
  427. init_args.llvm_jit_opt_level = llvm_jit_opt_level;
  428. #endif
  429. #if WASM_ENABLE_DEBUG_INTERP != 0
  430. init_args.instance_port = instance_port;
  431. if (ip_addr)
  432. strcpy(init_args.ip_addr, ip_addr);
  433. #endif
  434. /* initialize runtime environment */
  435. if (!wasm_runtime_full_init(&init_args)) {
  436. printf("Init runtime environment failed.\n");
  437. return -1;
  438. }
  439. #if WASM_ENABLE_LOG != 0
  440. bh_log_set_verbose_level(log_verbose_level);
  441. #endif
  442. /* load WASM byte buffer from WASM bin file */
  443. if (!(wasm_file_buf =
  444. (uint8 *)bh_read_file_to_buffer(wasm_file, &wasm_file_size)))
  445. goto fail1;
  446. #if WASM_ENABLE_AOT != 0
  447. if (wasm_runtime_is_xip_file(wasm_file_buf, wasm_file_size)) {
  448. uint8 *wasm_file_mapped;
  449. int map_prot = MMAP_PROT_READ | MMAP_PROT_WRITE | MMAP_PROT_EXEC;
  450. int map_flags = MMAP_MAP_32BIT;
  451. if (!(wasm_file_mapped =
  452. os_mmap(NULL, (uint32)wasm_file_size, map_prot, map_flags))) {
  453. printf("mmap memory failed\n");
  454. wasm_runtime_free(wasm_file_buf);
  455. goto fail1;
  456. }
  457. bh_memcpy_s(wasm_file_mapped, wasm_file_size, wasm_file_buf,
  458. wasm_file_size);
  459. wasm_runtime_free(wasm_file_buf);
  460. wasm_file_buf = wasm_file_mapped;
  461. is_xip_file = true;
  462. }
  463. #endif
  464. #if WASM_ENABLE_MULTI_MODULE != 0
  465. wasm_runtime_set_module_reader(module_reader_callback, moudle_destroyer);
  466. #endif
  467. /* load WASM module */
  468. if (!(wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size,
  469. error_buf, sizeof(error_buf)))) {
  470. printf("%s\n", error_buf);
  471. goto fail2;
  472. }
  473. #if WASM_ENABLE_LIBC_WASI != 0
  474. wasm_runtime_set_wasi_args(wasm_module, dir_list, dir_list_size, NULL, 0,
  475. env_list, env_list_size, argv, argc);
  476. #endif
  477. /* instantiate the module */
  478. if (!(wasm_module_inst =
  479. wasm_runtime_instantiate(wasm_module, stack_size, heap_size,
  480. error_buf, sizeof(error_buf)))) {
  481. printf("%s\n", error_buf);
  482. goto fail3;
  483. }
  484. #if WASM_ENABLE_DEBUG_INTERP != 0
  485. if (ip_addr != NULL) {
  486. wasm_exec_env_t exec_env =
  487. wasm_runtime_get_exec_env_singleton(wasm_module_inst);
  488. uint32_t debug_port;
  489. if (exec_env == NULL) {
  490. printf("%s\n", wasm_runtime_get_exception(wasm_module_inst));
  491. goto fail4;
  492. }
  493. debug_port = wasm_runtime_start_debug_instance(exec_env);
  494. if (debug_port == 0) {
  495. printf("Failed to start debug instance\n");
  496. goto fail4;
  497. }
  498. }
  499. #endif
  500. ret = 0;
  501. if (is_repl_mode) {
  502. app_instance_repl(wasm_module_inst);
  503. }
  504. else if (func_name) {
  505. if (app_instance_func(wasm_module_inst, func_name)) {
  506. /* got an exception */
  507. ret = 1;
  508. }
  509. }
  510. else {
  511. if (app_instance_main(wasm_module_inst)) {
  512. /* got an exception */
  513. ret = 1;
  514. }
  515. }
  516. #if WASM_ENABLE_LIBC_WASI != 0
  517. if (ret == 0) {
  518. /* propagate wasi exit code. */
  519. ret = wasm_runtime_get_wasi_exit_code(wasm_module_inst);
  520. }
  521. #endif
  522. #if WASM_ENABLE_DEBUG_INTERP != 0
  523. fail4:
  524. #endif
  525. /* destroy the module instance */
  526. wasm_runtime_deinstantiate(wasm_module_inst);
  527. fail3:
  528. /* unload the module */
  529. wasm_runtime_unload(wasm_module);
  530. fail2:
  531. /* free the file buffer */
  532. if (!is_xip_file)
  533. wasm_runtime_free(wasm_file_buf);
  534. else
  535. os_munmap(wasm_file_buf, wasm_file_size);
  536. fail1:
  537. /* destroy runtime environment */
  538. wasm_runtime_destroy();
  539. return ret;
  540. }