WAMR Analysis

 August 13, 2021 at 7:55 pm

SGX Environment App Code

Big Picture

  • An ecall ecall_handle_command to serve incoming commands from the app part
  • Memory management? runtime_malloc
void
ecall_handle_command(unsigned cmd,
                     unsigned char *cmd_buf,
                     unsigned cmd_buf_size)
{
    uint64 *args = (uint64 *)cmd_buf;
    uint32 argc = cmd_buf_size / sizeof(uint64);

    switch (cmd) {
        case CMD_INIT_RUNTIME:
            handle_cmd_init_runtime(args, argc);
            break;
        case CMD_LOAD_MODULE:
            handle_cmd_load_module(args, argc);
            break;
        case CMD_SET_WASI_ARGS:
            handle_cmd_set_wasi_args(args, argc);
            break;
        case CMD_INSTANTIATE_MODULE:
            handle_cmd_instantiate_module(args, argc);
            break;
        case CMD_LOOKUP_FUNCTION:
            break;
        case CMD_CREATE_EXEC_ENV:
            break;
        case CMD_CALL_WASM:
            break;
        case CMD_EXEC_APP_FUNC:
            handle_cmd_exec_app_func(args, argc);
            break;
        case CMD_EXEC_APP_MAIN:
            handle_cmd_exec_app_main(args, argc);
            break;
        case CMD_GET_EXCEPTION:
            handle_cmd_get_exception(args, argc);
            break;
        case CMD_DEINSTANTIATE_MODULE:
            handle_cmd_deinstantiate_module(args, argc);
            break;
        case CMD_UNLOAD_MODULE:
            handle_cmd_unload_module(args, argc);
            break;
        case CMD_DESTROY_RUNTIME:
            handle_cmd_destroy_runtime();
            break;
        case CMD_SET_LOG_LEVEL:
            handle_cmd_set_log_level(args, argc);
            break;
        default:
            LOG_ERROR("Unknown command %d\n", cmd);
            break;
    }
}

Initialization Steps

  1. enclave_init
  2. Argument parsing
  3. WAMR `init_runtime` (in enclave)
  4. Set log level
  5. Read in WASM file to a buffer and load it as a module into the enclave
  6. Instantiate the module
  7. Execute the main function
  8. Do cleaning jobs: wasm_runtime_deinstantiate, wasm_runtime_unload and wasm_runtime_destroy
int
main(int argc, char *argv[])
{
    char *wasm_file = NULL;
    const char *func_name = NULL;
    uint8_t *wasm_file_buf = NULL;
    uint32_t wasm_file_size;
    uint32_t stack_size = 16 * 1024, heap_size = 16 * 1024;
    void *wasm_module = NULL;
    void *wasm_module_inst = NULL;
    char error_buf[128] = { 0 };
    int log_verbose_level = 2;
    bool is_repl_mode = false, alloc_with_pool = false;
    const char *dir_list[8] = { NULL };
    uint32_t dir_list_size = 0;
    const char *env_list[8] = { NULL };
    uint32_t env_list_size = 0;
    uint32_t max_thread_num = 4;

    if (enclave_init(&g_eid) < 0) {
        std::cout << "Fail to initialize enclave." << std::endl;
        return 1;
    }

#if TEST_OCALL_API != 0
    {
        if (!init_runtime(alloc_with_pool, max_thread_num)) {
            return -1;
        }
        ecall_iwasm_test(g_eid);
        destroy_runtime();
        return 0;
    }
#endif

    /* Process options. */
    for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) {
        if (!strcmp(argv[0], "-f") || !strcmp(argv[0], "--function")) {
            argc--, argv++;
            if (argc < 2) {
                print_help();
                return 0;
            }
            func_name = argv[0];
        }
        else if (!strncmp(argv[0], "-v=", 3)) {
            log_verbose_level = atoi(argv[0] + 3);
            if (log_verbose_level < 0 || log_verbose_level > 5)
                return print_help();
        }
        else if (!strcmp(argv[0], "--repl")) {
            is_repl_mode = true;
        }
        else if (!strncmp(argv[0], "--stack-size=", 13)) {
            if (argv[0][13] == '\0')
                return print_help();
            stack_size = atoi(argv[0] + 13);
        }
        else if (!strncmp(argv[0], "--heap-size=", 12)) {
            if (argv[0][12] == '\0')
                return print_help();
            heap_size = atoi(argv[0] + 12);
        }
        else if (!strncmp(argv[0], "--dir=", 6)) {
            if (argv[0][6] == '\0')
                return print_help();
            if (dir_list_size >= sizeof(dir_list) / sizeof(char *)) {
                printf("Only allow max dir number %d\n",
                       (int)(sizeof(dir_list) / sizeof(char *)));
                return -1;
            }
            dir_list[dir_list_size++] = argv[0] + 6;
        }
        else if (!strncmp(argv[0], "--env=", 6)) {
            char *tmp_env;

            if (argv[0][6] == '\0')
                return print_help();
            if (env_list_size >= sizeof(env_list) / sizeof(char *)) {
                printf("Only allow max env number %d\n",
                       (int)(sizeof(env_list) / sizeof(char *)));
                return -1;
            }
            tmp_env = argv[0] + 6;
            if (validate_env_str(tmp_env))
                env_list[env_list_size++] = tmp_env;
            else {
                printf("Wasm parse env string failed: expect \"key=value\", "
                       "got \"%s\"\n",
                       tmp_env);
                return print_help();
            }
        }
        else if (!strncmp(argv[0], "--max-threads=", 14)) {
            if (argv[0][14] == '\0')
                return print_help();
            max_thread_num = atoi(argv[0] + 14);
        }
        else
            return print_help();
    }

    if (argc == 0)
        return print_help();

    wasm_file = argv[0];

    /* Init runtime */
    if (!init_runtime(alloc_with_pool, max_thread_num)) {
        return -1;
    }

    /* Set log verbose level */
    if (!set_log_verbose_level(log_verbose_level)) {
        goto fail1;
    }

    /* Load WASM byte buffer from WASM bin file */
    if (!(wasm_file_buf =
            (uint8_t *)read_file_to_buffer(wasm_file, &wasm_file_size))) {
        goto fail1;
    }

    /* Load module */
    if (!(wasm_module = load_module(wasm_file_buf, wasm_file_size,
                                    error_buf, sizeof(error_buf)))) {
        printf("%s\n", error_buf);
        goto fail2;
    }

    /* Set wasi arguments */
    if (!set_wasi_args(wasm_module, dir_list, dir_list_size,
                       env_list, env_list_size, argv, argc)) {
        printf("%s\n", "set wasi arguments failed.\n");
        goto fail3;
    }

    /* Instantiate module */
    if (!(wasm_module_inst = instantiate_module(wasm_module,
                                                stack_size, heap_size,
                                                error_buf,
                                                sizeof(error_buf)))) {
        printf("%s\n", error_buf);
        goto fail3;
    }

    if (is_repl_mode)
        app_instance_repl(wasm_module_inst, argc, argv);
    else if (func_name)
        app_instance_func(wasm_module_inst, func_name,
                          argc - 1, argv + 1);
    else
        app_instance_main(wasm_module_inst, argc, argv);

    /* Deinstantiate module */
    deinstantiate_module(wasm_module_inst);

fail3:
    /* Unload module */
    unload_module(wasm_module);

fail2:
    /* Free the file buffer */
    free(wasm_file_buf);

fail1:
    /* Destroy runtime environment */
    destroy_runtime();

    return 0;
}