mirror of https://github.com/status-im/evmc.git
148 lines
3.8 KiB
C
148 lines
3.8 KiB
C
/* EVMC: Ethereum Client-VM Connector API.
|
|
* Copyright 2018 Pawel Bylica.
|
|
* Licensed under the MIT License. See the LICENSE file.
|
|
*/
|
|
|
|
#include <evmc/loader.h>
|
|
#include <evmc/evmc.h>
|
|
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
#if _WIN32
|
|
#include <Windows.h>
|
|
#define DLL_HANDLE HMODULE
|
|
#define DLL_OPEN(filename) LoadLibrary(filename)
|
|
#define DLL_CLOSE(handle) FreeLibrary(handle)
|
|
#define DLL_GET_CREATE_FN(handle, name) (evmc_create_fn) GetProcAddress(handle, name)
|
|
#define HAVE_STRCPY_S 1
|
|
#else
|
|
#include <dlfcn.h>
|
|
#define DLL_HANDLE void*
|
|
#define DLL_OPEN(filename) dlopen(filename, RTLD_LAZY)
|
|
#define DLL_CLOSE(handle) dlclose(handle)
|
|
#define DLL_GET_CREATE_FN(handle, name) (evmc_create_fn)(uintptr_t) dlsym(handle, name)
|
|
#define HAVE_STRCPY_S 0
|
|
#endif
|
|
|
|
#define PATH_MAX_LENGTH 4096
|
|
|
|
#if !HAVE_STRCPY_S
|
|
static void strcpy_s(char* dest, size_t destsz, const char* src)
|
|
{
|
|
size_t len = strlen(src);
|
|
if (len > destsz - 1)
|
|
len = destsz - 1;
|
|
memcpy(dest, src, len);
|
|
dest[len] = 0;
|
|
}
|
|
#endif
|
|
|
|
|
|
evmc_create_fn evmc_load(const char* filename, enum evmc_loader_error_code* error_code)
|
|
{
|
|
enum evmc_loader_error_code ec = EVMC_LOADER_SUCCESS;
|
|
evmc_create_fn create_fn = NULL;
|
|
|
|
if (!filename)
|
|
{
|
|
ec = EVMC_LOADER_INVALID_ARGUMENT;
|
|
goto exit;
|
|
}
|
|
|
|
const size_t length = strlen(filename);
|
|
if (length == 0 || length > PATH_MAX_LENGTH)
|
|
{
|
|
ec = EVMC_LOADER_INVALID_ARGUMENT;
|
|
goto exit;
|
|
}
|
|
|
|
DLL_HANDLE handle = DLL_OPEN(filename);
|
|
if (!handle)
|
|
{
|
|
ec = EVMC_LOADER_CANNOT_OPEN;
|
|
goto exit;
|
|
}
|
|
|
|
// Create name buffer with the prefix.
|
|
const char prefix[] = "evmc_create_";
|
|
const size_t prefix_length = strlen(prefix);
|
|
char name[sizeof(prefix) + PATH_MAX_LENGTH];
|
|
strcpy_s(name, sizeof(name), prefix);
|
|
|
|
// Find filename in the path.
|
|
const char* sep_pos = strrchr(filename, '/');
|
|
#if _WIN32
|
|
// On Windows check also Windows classic path separator.
|
|
const char* sep_pos_windows = strrchr(filename, '\\');
|
|
sep_pos = sep_pos_windows > sep_pos ? sep_pos_windows : sep_pos;
|
|
#endif
|
|
const char* name_pos = sep_pos ? sep_pos + 1 : filename;
|
|
|
|
// Skip "lib" prefix if present.
|
|
const char lib_prefix[] = "lib";
|
|
const size_t lib_prefix_length = strlen(lib_prefix);
|
|
if (strncmp(name_pos, lib_prefix, lib_prefix_length) == 0)
|
|
name_pos += lib_prefix_length;
|
|
|
|
strcpy_s(name + prefix_length, PATH_MAX_LENGTH, name_pos);
|
|
|
|
// Trim the file extension.
|
|
char* ext_pos = strrchr(name, '.');
|
|
if (ext_pos)
|
|
*ext_pos = 0;
|
|
|
|
// Replace all "-" with "_".
|
|
char* dash_pos = name;
|
|
while ((dash_pos = strchr(dash_pos, '-')) != NULL)
|
|
*dash_pos++ = '_';
|
|
|
|
// Search for the "full name" based function name.
|
|
create_fn = DLL_GET_CREATE_FN(handle, name);
|
|
if (!create_fn)
|
|
{
|
|
// Try the "short name" based function name.
|
|
const char* short_name_pos = strrchr(name, '_');
|
|
if (short_name_pos)
|
|
{
|
|
short_name_pos += 1;
|
|
memmove(name + prefix_length, short_name_pos, strlen(short_name_pos) + 1);
|
|
create_fn = DLL_GET_CREATE_FN(handle, name);
|
|
}
|
|
}
|
|
|
|
if (!create_fn)
|
|
{
|
|
DLL_CLOSE(handle);
|
|
ec = EVMC_LOADER_SYMBOL_NOT_FOUND;
|
|
}
|
|
|
|
exit:
|
|
if (error_code)
|
|
*error_code = ec;
|
|
return create_fn;
|
|
}
|
|
|
|
struct evmc_instance* evmc_load_and_create(const char* filename, enum evmc_loader_error_code* error_code)
|
|
{
|
|
evmc_create_fn create_fn = evmc_load(filename, error_code);
|
|
|
|
if (!create_fn)
|
|
return NULL;
|
|
|
|
struct evmc_instance* instance = create_fn();
|
|
if (!instance)
|
|
{
|
|
*error_code = EVMC_LOADER_INSTANCE_CREATION_FAILURE;
|
|
return NULL;
|
|
}
|
|
|
|
if (instance->abi_version != EVMC_ABI_VERSION)
|
|
{
|
|
*error_code = EVMC_LOADER_ABI_VERSION_MISMATCH;
|
|
return NULL;
|
|
}
|
|
|
|
return instance;
|
|
}
|