Coverage Report

Created: 2025-07-01 06:18

/src/WasmEdge/lib/plugin/plugin.cpp
Line
Count
Source (jump to first uncovered line)
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: 2019-2024 Second State INC
3
4
#include "plugin/plugin.h"
5
#include "common/errcode.h"
6
#include "common/version.h"
7
#include "wasmedge/wasmedge.h"
8
9
// BUILTIN-PLUGIN: Headers for built-in plug-ins.
10
#include "plugin/wasi_logging/module.h"
11
12
#include <type_traits>
13
#include <variant>
14
15
#if WASMEDGE_OS_LINUX || WASMEDGE_OS_MACOS
16
#include <dlfcn.h>
17
#include <pwd.h>
18
#include <unistd.h>
19
#elif WASMEDGE_OS_WINDOWS
20
#include "system/winapi.h"
21
22
static bool GetFunctionModuleFileName(void *FuncPtr,
23
                                      std::filesystem::path &Path) {
24
  WasmEdge::winapi::HMODULE_ Module = nullptr;
25
26
  if (!WasmEdge::winapi::GetModuleHandleExW(
27
          WasmEdge::winapi::GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS_ |
28
              WasmEdge::winapi::GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT_,
29
          reinterpret_cast<WasmEdge::winapi::LPCWSTR_>(FuncPtr), &Module)) {
30
    return false;
31
  }
32
33
  std::vector<wchar_t> Buffer;
34
  WasmEdge::winapi::DWORD_ CopiedSize;
35
  do {
36
    Buffer.resize(Buffer.size() + WasmEdge::winapi::MAX_PATH_);
37
    CopiedSize = WasmEdge::winapi::GetModuleFileNameW(
38
        Module, Buffer.data(),
39
        static_cast<WasmEdge::winapi::DWORD_>(Buffer.size()));
40
    if (CopiedSize == 0) {
41
      return false;
42
    }
43
  } while (CopiedSize >= Buffer.size());
44
45
  Path.assign(std::wstring_view(Buffer.data(), CopiedSize));
46
  return true;
47
}
48
#endif
49
50
namespace WasmEdge {
51
52
namespace PO {
53
template <> struct Parser<WasmEdge_String> {
54
  static cxx20::expected<WasmEdge_String, Error>
55
0
  parse(std::string Value) noexcept {
56
0
    if (!Value.empty()) {
57
0
      const uint32_t Length = static_cast<uint32_t>(Value.size());
58
0
      char *Buf = new char[Value.size()];
59
0
      std::copy_n(Value.data(), Value.size(), Buf);
60
0
      return WasmEdge_String{/* Length */ Length, /* Buf */ Buf};
61
0
    }
62
0
    return WasmEdge_String{/* Length */ 0, /* Buf */ nullptr};
63
0
  }
64
};
65
} // namespace PO
66
67
namespace Plugin {
68
69
namespace {
70
71
class CAPIPluginRegister {
72
public:
73
  CAPIPluginRegister(const CAPIPluginRegister &) = delete;
74
  CAPIPluginRegister &operator=(const CAPIPluginRegister &) = delete;
75
76
0
  CAPIPluginRegister(const WasmEdge_PluginDescriptor *Desc) noexcept {
77
0
    ModuleDescriptions.resize(Desc->ModuleCount);
78
0
    for (size_t I = 0; I < ModuleDescriptions.size(); ++I) {
79
0
      ModuleDescriptions[I].Name = Desc->ModuleDescriptions[I].Name;
80
0
      ModuleDescriptions[I].Description =
81
0
          Desc->ModuleDescriptions[I].Description;
82
0
      ModuleDescriptions[I].Create = &createWrapper;
83
0
      DescriptionLookup.emplace(&ModuleDescriptions[I],
84
0
                                &Desc->ModuleDescriptions[I]);
85
0
    }
86
87
0
    Descriptor.Name = Desc->Name;
88
0
    Descriptor.Description = Desc->Description;
89
0
    Descriptor.APIVersion = Desc->APIVersion;
90
0
    Descriptor.Version.Major = Desc->Version.Major;
91
0
    Descriptor.Version.Minor = Desc->Version.Minor;
92
0
    Descriptor.Version.Patch = Desc->Version.Patch;
93
0
    Descriptor.Version.Build = Desc->Version.Build;
94
0
    Descriptor.ModuleCount = Desc->ModuleCount;
95
0
    Descriptor.ModuleDescriptions = ModuleDescriptions.data();
96
0
    Descriptor.AddOptions = &addOptionsWrapper;
97
98
0
    for (size_t I = 0; I < Desc->ProgramOptionCount; ++I) {
99
0
      const auto *OptionDesc = &Desc->ProgramOptions[I];
100
0
      auto Emplace = [OptionDesc, this](auto InPlaceType, auto *Storage,
101
0
                                        auto *DefaultValue) {
102
0
        Options.emplace_back(
103
0
            std::piecewise_construct, std::tuple{OptionDesc},
104
0
            std::tuple{InPlaceType, PO::Description(OptionDesc->Description),
105
0
                       Storage, DefaultValue});
106
0
      };
Unexecuted instantiation: plugin.cpp:auto WasmEdge::Plugin::(anonymous namespace)::CAPIPluginRegister::CAPIPluginRegister(WasmEdge_PluginDescriptor const*)::{lambda(auto:1, auto:2*, auto:3*)#1}::operator()<std::__1::in_place_type_t<WasmEdge::PO::Option<std::__1::in_place_type_t::Toggle*, std::__1::in_place_type_t::Parser<bool> > >, bool, bool const>(std::__1::in_place_type_t<WasmEdge::PO::Option<std::__1::in_place_type_t::Toggle*, std::__1::in_place_type_t::Parser<bool> > >, bool*, bool const*) const
Unexecuted instantiation: plugin.cpp:auto WasmEdge::Plugin::(anonymous namespace)::CAPIPluginRegister::CAPIPluginRegister(WasmEdge_PluginDescriptor const*)::{lambda(auto:1, auto:2*, auto:3*)#1}::operator()<std::__1::in_place_type_t<WasmEdge::PO::Option<signed char*, std::__1::in_place_type_t::Parser<signed char> > >, signed char, signed char const>(std::__1::in_place_type_t<WasmEdge::PO::Option<signed char*, std::__1::in_place_type_t::Parser<signed char> > >, signed char*, signed char const*) const
Unexecuted instantiation: plugin.cpp:auto WasmEdge::Plugin::(anonymous namespace)::CAPIPluginRegister::CAPIPluginRegister(WasmEdge_PluginDescriptor const*)::{lambda(auto:1, auto:2*, auto:3*)#1}::operator()<std::__1::in_place_type_t<WasmEdge::PO::Option<short*, std::__1::in_place_type_t::Parser<short> > >, short, short const>(std::__1::in_place_type_t<WasmEdge::PO::Option<short*, std::__1::in_place_type_t::Parser<short> > >, short*, short const*) const
Unexecuted instantiation: plugin.cpp:auto WasmEdge::Plugin::(anonymous namespace)::CAPIPluginRegister::CAPIPluginRegister(WasmEdge_PluginDescriptor const*)::{lambda(auto:1, auto:2*, auto:3*)#1}::operator()<std::__1::in_place_type_t<WasmEdge::PO::Option<int*, std::__1::in_place_type_t::Parser<int> > >, int, int const>(std::__1::in_place_type_t<WasmEdge::PO::Option<int*, std::__1::in_place_type_t::Parser<int> > >, int*, int const*) const
Unexecuted instantiation: plugin.cpp:auto WasmEdge::Plugin::(anonymous namespace)::CAPIPluginRegister::CAPIPluginRegister(WasmEdge_PluginDescriptor const*)::{lambda(auto:1, auto:2*, auto:3*)#1}::operator()<std::__1::in_place_type_t<WasmEdge::PO::Option<long*, std::__1::in_place_type_t::Parser<long> > >, long, long const>(std::__1::in_place_type_t<WasmEdge::PO::Option<long*, std::__1::in_place_type_t::Parser<long> > >, long*, long const*) const
Unexecuted instantiation: plugin.cpp:auto WasmEdge::Plugin::(anonymous namespace)::CAPIPluginRegister::CAPIPluginRegister(WasmEdge_PluginDescriptor const*)::{lambda(auto:1, auto:2*, auto:3*)#1}::operator()<std::__1::in_place_type_t<WasmEdge::PO::Option<unsigned char*, std::__1::in_place_type_t::Parser<unsigned char> > >, unsigned char, unsigned char const>(std::__1::in_place_type_t<WasmEdge::PO::Option<unsigned char*, std::__1::in_place_type_t::Parser<unsigned char> > >, unsigned char*, unsigned char const*) const
Unexecuted instantiation: plugin.cpp:auto WasmEdge::Plugin::(anonymous namespace)::CAPIPluginRegister::CAPIPluginRegister(WasmEdge_PluginDescriptor const*)::{lambda(auto:1, auto:2*, auto:3*)#1}::operator()<std::__1::in_place_type_t<WasmEdge::PO::Option<unsigned short*, std::__1::in_place_type_t::Parser<unsigned short> > >, unsigned short, unsigned short const>(std::__1::in_place_type_t<WasmEdge::PO::Option<unsigned short*, std::__1::in_place_type_t::Parser<unsigned short> > >, unsigned short*, unsigned short const*) const
Unexecuted instantiation: plugin.cpp:auto WasmEdge::Plugin::(anonymous namespace)::CAPIPluginRegister::CAPIPluginRegister(WasmEdge_PluginDescriptor const*)::{lambda(auto:1, auto:2*, auto:3*)#1}::operator()<std::__1::in_place_type_t<WasmEdge::PO::Option<unsigned int*, std::__1::in_place_type_t::Parser<unsigned int> > >, unsigned int, unsigned int const>(std::__1::in_place_type_t<WasmEdge::PO::Option<unsigned int*, std::__1::in_place_type_t::Parser<unsigned int> > >, unsigned int*, unsigned int const*) const
Unexecuted instantiation: plugin.cpp:auto WasmEdge::Plugin::(anonymous namespace)::CAPIPluginRegister::CAPIPluginRegister(WasmEdge_PluginDescriptor const*)::{lambda(auto:1, auto:2*, auto:3*)#1}::operator()<std::__1::in_place_type_t<WasmEdge::PO::Option<unsigned long*, std::__1::in_place_type_t::Parser<unsigned long> > >, unsigned long, unsigned long const>(std::__1::in_place_type_t<WasmEdge::PO::Option<unsigned long*, std::__1::in_place_type_t::Parser<unsigned long> > >, unsigned long*, unsigned long const*) const
Unexecuted instantiation: plugin.cpp:auto WasmEdge::Plugin::(anonymous namespace)::CAPIPluginRegister::CAPIPluginRegister(WasmEdge_PluginDescriptor const*)::{lambda(auto:1, auto:2*, auto:3*)#1}::operator()<std::__1::in_place_type_t<WasmEdge::PO::Option<float*, std::__1::in_place_type_t::Parser<float> > >, float, float const>(std::__1::in_place_type_t<WasmEdge::PO::Option<float*, std::__1::in_place_type_t::Parser<float> > >, float*, float const*) const
Unexecuted instantiation: plugin.cpp:auto WasmEdge::Plugin::(anonymous namespace)::CAPIPluginRegister::CAPIPluginRegister(WasmEdge_PluginDescriptor const*)::{lambda(auto:1, auto:2*, auto:3*)#1}::operator()<std::__1::in_place_type_t<WasmEdge::PO::Option<double*, std::__1::in_place_type_t::Parser<double> > >, double, double const>(std::__1::in_place_type_t<WasmEdge::PO::Option<double*, std::__1::in_place_type_t::Parser<double> > >, double*, double const*) const
Unexecuted instantiation: plugin.cpp:auto WasmEdge::Plugin::(anonymous namespace)::CAPIPluginRegister::CAPIPluginRegister(WasmEdge_PluginDescriptor const*)::{lambda(auto:1, auto:2*, auto:3*)#1}::operator()<std::__1::in_place_type_t<WasmEdge::PO::Option<WasmEdge_String*, std::__1::in_place_type_t::Parser<WasmEdge::PO::Option> > >, WasmEdge::PO::Option, WasmEdge::PO::Option const>(std::__1::in_place_type_t<WasmEdge::PO::Option<WasmEdge_String*, std::__1::in_place_type_t::Parser<WasmEdge::PO::Option> > >, WasmEdge::PO::Option*, WasmEdge::PO::Option const*) const
107
0
      switch (Desc->ProgramOptions[I].Type) {
108
0
      case WasmEdge_ProgramOptionType_None:
109
0
        break;
110
0
      case WasmEdge_ProgramOptionType_Toggle:
111
0
        Emplace(std::in_place_type<PO::Option<PO::Toggle *>>,
112
0
                static_cast<bool *>(OptionDesc->Storage),
113
0
                static_cast<const bool *>(OptionDesc->DefaultValue));
114
0
        break;
115
0
      case WasmEdge_ProgramOptionType_Int8:
116
0
        Emplace(std::in_place_type<PO::Option<int8_t *>>,
117
0
                static_cast<int8_t *>(OptionDesc->Storage),
118
0
                static_cast<const int8_t *>(OptionDesc->DefaultValue));
119
0
        break;
120
0
      case WasmEdge_ProgramOptionType_Int16:
121
0
        Emplace(std::in_place_type<PO::Option<int16_t *>>,
122
0
                static_cast<int16_t *>(OptionDesc->Storage),
123
0
                static_cast<const int16_t *>(OptionDesc->DefaultValue));
124
0
        break;
125
0
      case WasmEdge_ProgramOptionType_Int32:
126
0
        Emplace(std::in_place_type<PO::Option<int32_t *>>,
127
0
                static_cast<int32_t *>(OptionDesc->Storage),
128
0
                static_cast<const int32_t *>(OptionDesc->DefaultValue));
129
0
        break;
130
0
      case WasmEdge_ProgramOptionType_Int64:
131
0
        Emplace(std::in_place_type<PO::Option<int64_t *>>,
132
0
                static_cast<int64_t *>(OptionDesc->Storage),
133
0
                static_cast<const int64_t *>(OptionDesc->DefaultValue));
134
0
        break;
135
0
      case WasmEdge_ProgramOptionType_UInt8:
136
0
        Emplace(std::in_place_type<PO::Option<uint8_t *>>,
137
0
                static_cast<uint8_t *>(OptionDesc->Storage),
138
0
                static_cast<const uint8_t *>(OptionDesc->DefaultValue));
139
0
        break;
140
0
      case WasmEdge_ProgramOptionType_UInt16:
141
0
        Emplace(std::in_place_type<PO::Option<uint16_t *>>,
142
0
                static_cast<uint16_t *>(OptionDesc->Storage),
143
0
                static_cast<const uint16_t *>(OptionDesc->DefaultValue));
144
0
        break;
145
0
      case WasmEdge_ProgramOptionType_UInt32:
146
0
        Emplace(std::in_place_type<PO::Option<uint32_t *>>,
147
0
                static_cast<uint32_t *>(OptionDesc->Storage),
148
0
                static_cast<const uint32_t *>(OptionDesc->DefaultValue));
149
0
        break;
150
0
      case WasmEdge_ProgramOptionType_UInt64:
151
0
        Emplace(std::in_place_type<PO::Option<uint64_t *>>,
152
0
                static_cast<uint64_t *>(OptionDesc->Storage),
153
0
                static_cast<const uint64_t *>(OptionDesc->DefaultValue));
154
0
        break;
155
0
      case WasmEdge_ProgramOptionType_Float:
156
0
        Emplace(std::in_place_type<PO::Option<float *>>,
157
0
                static_cast<float *>(OptionDesc->Storage),
158
0
                static_cast<const float *>(OptionDesc->DefaultValue));
159
0
        break;
160
0
      case WasmEdge_ProgramOptionType_Double:
161
0
        Emplace(std::in_place_type<PO::Option<double *>>,
162
0
                static_cast<double *>(OptionDesc->Storage),
163
0
                static_cast<const double *>(OptionDesc->DefaultValue));
164
0
        break;
165
0
      case WasmEdge_ProgramOptionType_String:
166
0
        Emplace(std::in_place_type<PO::Option<WasmEdge_String *>>,
167
0
                static_cast<WasmEdge_String *>(OptionDesc->Storage),
168
0
                static_cast<const WasmEdge_String *>(OptionDesc->DefaultValue));
169
0
        break;
170
0
      }
171
0
    }
172
173
0
    Result = Plugin::registerPlugin(&Descriptor);
174
0
  }
175
0
  bool result() const noexcept { return Result; }
176
177
private:
178
  static Runtime::Instance::ModuleInstance *
179
0
  createWrapper(const PluginModule::ModuleDescriptor *Descriptor) noexcept {
180
0
    static_assert(std::is_standard_layout_v<CAPIPluginRegister>);
181
0
    if (auto Iter = DescriptionLookup.find(Descriptor);
182
0
        unlikely(Iter == DescriptionLookup.end())) {
183
0
      return nullptr;
184
0
    } else {
185
0
      return reinterpret_cast<Runtime::Instance::ModuleInstance *>(
186
0
          Iter->second->Create(Iter->second));
187
0
    }
188
0
  }
189
  static void addOptionsWrapper(const Plugin::PluginDescriptor *Descriptor,
190
                                PO::ArgumentParser &Parser
191
0
                                [[maybe_unused]]) noexcept {
192
0
    const CAPIPluginRegister *This =
193
0
        reinterpret_cast<const CAPIPluginRegister *>(
194
0
            reinterpret_cast<uintptr_t>(Descriptor) -
195
0
            offsetof(CAPIPluginRegister, Descriptor));
196
0
    for (auto &Option : This->Options) {
197
0
      std::visit(
198
0
          [&Option, &Parser](auto &POOption) {
199
0
            Parser.add_option(Option.first->Name, POOption);
200
0
          },
Unexecuted instantiation: plugin.cpp:auto WasmEdge::Plugin::(anonymous namespace)::CAPIPluginRegister::addOptionsWrapper(WasmEdge::Plugin::Plugin::PluginDescriptor const*, WasmEdge::PO::ArgumentParser&)::{lambda(auto:1&)#1}::operator()<WasmEdge::PO::Option<WasmEdge::PO::Toggle*, WasmEdge::PO::Parser<bool> > >(WasmEdge::PO::Option<WasmEdge::PO::Toggle*, WasmEdge::PO::Parser<bool> >&) const
Unexecuted instantiation: plugin.cpp:auto WasmEdge::Plugin::(anonymous namespace)::CAPIPluginRegister::addOptionsWrapper(WasmEdge::Plugin::Plugin::PluginDescriptor const*, WasmEdge::PO::ArgumentParser&)::{lambda(auto:1&)#1}::operator()<WasmEdge::PO::Option<signed char*, WasmEdge::PO::Parser<signed char> > >(WasmEdge::PO::Option<signed char*, WasmEdge::PO::Parser<signed char> >&) const
Unexecuted instantiation: plugin.cpp:auto WasmEdge::Plugin::(anonymous namespace)::CAPIPluginRegister::addOptionsWrapper(WasmEdge::Plugin::Plugin::PluginDescriptor const*, WasmEdge::PO::ArgumentParser&)::{lambda(auto:1&)#1}::operator()<WasmEdge::PO::Option<short*, WasmEdge::PO::Parser<short> > >(WasmEdge::PO::Option<short*, WasmEdge::PO::Parser<short> >&) const
Unexecuted instantiation: plugin.cpp:auto WasmEdge::Plugin::(anonymous namespace)::CAPIPluginRegister::addOptionsWrapper(WasmEdge::Plugin::Plugin::PluginDescriptor const*, WasmEdge::PO::ArgumentParser&)::{lambda(auto:1&)#1}::operator()<WasmEdge::PO::Option<int*, WasmEdge::PO::Parser<int> > >(WasmEdge::PO::Option<int*, WasmEdge::PO::Parser<int> >&) const
Unexecuted instantiation: plugin.cpp:auto WasmEdge::Plugin::(anonymous namespace)::CAPIPluginRegister::addOptionsWrapper(WasmEdge::Plugin::Plugin::PluginDescriptor const*, WasmEdge::PO::ArgumentParser&)::{lambda(auto:1&)#1}::operator()<WasmEdge::PO::Option<long*, WasmEdge::PO::Parser<long> > >(WasmEdge::PO::Option<long*, WasmEdge::PO::Parser<long> >&) const
Unexecuted instantiation: plugin.cpp:auto WasmEdge::Plugin::(anonymous namespace)::CAPIPluginRegister::addOptionsWrapper(WasmEdge::Plugin::Plugin::PluginDescriptor const*, WasmEdge::PO::ArgumentParser&)::{lambda(auto:1&)#1}::operator()<WasmEdge::PO::Option<unsigned char*, WasmEdge::PO::Parser<unsigned char> > >(WasmEdge::PO::Option<unsigned char*, WasmEdge::PO::Parser<unsigned char> >&) const
Unexecuted instantiation: plugin.cpp:auto WasmEdge::Plugin::(anonymous namespace)::CAPIPluginRegister::addOptionsWrapper(WasmEdge::Plugin::Plugin::PluginDescriptor const*, WasmEdge::PO::ArgumentParser&)::{lambda(auto:1&)#1}::operator()<WasmEdge::PO::Option<unsigned short*, WasmEdge::PO::Parser<unsigned short> > >(WasmEdge::PO::Option<unsigned short*, WasmEdge::PO::Parser<unsigned short> >&) const
Unexecuted instantiation: plugin.cpp:auto WasmEdge::Plugin::(anonymous namespace)::CAPIPluginRegister::addOptionsWrapper(WasmEdge::Plugin::Plugin::PluginDescriptor const*, WasmEdge::PO::ArgumentParser&)::{lambda(auto:1&)#1}::operator()<WasmEdge::PO::Option<unsigned int*, WasmEdge::PO::Parser<unsigned int> > >(WasmEdge::PO::Option<unsigned int*, WasmEdge::PO::Parser<unsigned int> >&) const
Unexecuted instantiation: plugin.cpp:auto WasmEdge::Plugin::(anonymous namespace)::CAPIPluginRegister::addOptionsWrapper(WasmEdge::Plugin::Plugin::PluginDescriptor const*, WasmEdge::PO::ArgumentParser&)::{lambda(auto:1&)#1}::operator()<WasmEdge::PO::Option<unsigned long*, WasmEdge::PO::Parser<unsigned long> > >(WasmEdge::PO::Option<unsigned long*, WasmEdge::PO::Parser<unsigned long> >&) const
Unexecuted instantiation: plugin.cpp:auto WasmEdge::Plugin::(anonymous namespace)::CAPIPluginRegister::addOptionsWrapper(WasmEdge::Plugin::Plugin::PluginDescriptor const*, WasmEdge::PO::ArgumentParser&)::{lambda(auto:1&)#1}::operator()<WasmEdge::PO::Option<float*, WasmEdge::PO::Parser<float> > >(WasmEdge::PO::Option<float*, WasmEdge::PO::Parser<float> >&) const
Unexecuted instantiation: plugin.cpp:auto WasmEdge::Plugin::(anonymous namespace)::CAPIPluginRegister::addOptionsWrapper(WasmEdge::Plugin::Plugin::PluginDescriptor const*, WasmEdge::PO::ArgumentParser&)::{lambda(auto:1&)#1}::operator()<WasmEdge::PO::Option<double*, WasmEdge::PO::Parser<double> > >(WasmEdge::PO::Option<double*, WasmEdge::PO::Parser<double> >&) const
Unexecuted instantiation: plugin.cpp:auto WasmEdge::Plugin::(anonymous namespace)::CAPIPluginRegister::addOptionsWrapper(WasmEdge::Plugin::Plugin::PluginDescriptor const*, WasmEdge::PO::ArgumentParser&)::{lambda(auto:1&)#1}::operator()<WasmEdge::PO::Option<WasmEdge_String*, WasmEdge::PO::Parser<WasmEdge::PO::Option> > >(WasmEdge::PO::Option<WasmEdge_String*, WasmEdge::PO::Parser<WasmEdge::PO::Option> >&) const
201
0
          Option.second);
202
0
    }
203
0
  }
204
205
  Plugin::PluginDescriptor Descriptor;
206
  mutable std::vector<std::pair<
207
      const WasmEdge_ProgramOption *,
208
      std::variant<PO::Option<PO::Toggle *>, PO::Option<int8_t *>,
209
                   PO::Option<int16_t *>, PO::Option<int32_t *>,
210
                   PO::Option<int64_t *>, PO::Option<uint8_t *>,
211
                   PO::Option<uint16_t *>, PO::Option<uint32_t *>,
212
                   PO::Option<uint64_t *>, PO::Option<float *>,
213
                   PO::Option<double *>, PO::Option<WasmEdge_String *>>>>
214
      Options;
215
  std::vector<PluginModule::ModuleDescriptor> ModuleDescriptions;
216
  static std::unordered_map<const PluginModule::ModuleDescriptor *,
217
                            const WasmEdge_ModuleDescriptor *>
218
      DescriptionLookup;
219
220
  bool Result = false;
221
};
222
std::unordered_map<const PluginModule::ModuleDescriptor *,
223
                   const WasmEdge_ModuleDescriptor *>
224
    CAPIPluginRegister::DescriptionLookup;
225
226
std::vector<std::unique_ptr<CAPIPluginRegister>> CAPIPluginRegisters;
227
228
} // namespace
229
230
std::mutex WasmEdge::Plugin::Plugin::Mutex;
231
std::vector<Plugin> WasmEdge::Plugin::Plugin::PluginRegistry;
232
std::unordered_map<std::string_view, std::size_t, Hash::Hash>
233
    WasmEdge::Plugin::Plugin::PluginNameLookup;
234
235
0
void Plugin::loadFromDefaultPaths() noexcept {
236
0
  registerBuiltInPlugins();
237
0
  for (const auto &Path : Plugin::Plugin::getDefaultPluginPaths()) {
238
0
    Plugin::Plugin::load(Path);
239
0
  }
240
0
}
241
242
0
std::vector<std::filesystem::path> Plugin::getDefaultPluginPaths() noexcept {
243
0
  using namespace std::literals::string_view_literals;
244
0
  std::vector<std::filesystem::path> Result;
245
0
  std::error_code Error;
246
247
  // Extra directories from environ variable
248
0
  if (const auto ExtraEnv = ::getenv("WASMEDGE_PLUGIN_PATH")) {
249
0
    std::string_view ExtraEnvStr = ExtraEnv;
250
0
    for (auto Sep = ExtraEnvStr.find(':'); Sep != std::string_view::npos;
251
0
         Sep = ExtraEnvStr.find(':')) {
252
0
      Result.push_back(std::filesystem::u8path(ExtraEnvStr.substr(0, Sep)));
253
0
      const auto Next = ExtraEnvStr.find_first_not_of(':', Sep);
254
0
      ExtraEnvStr = ExtraEnvStr.substr(Next);
255
0
    }
256
0
    Result.push_back(std::filesystem::u8path(ExtraEnvStr));
257
0
  }
258
259
  // Plugin directory for the WasmEdge installation.
260
0
#if WASMEDGE_OS_LINUX || WASMEDGE_OS_MACOS
261
0
  Dl_info DLInfo;
262
0
  int Status =
263
0
      dladdr(reinterpret_cast<void *>(Plugin::getDefaultPluginPaths), &DLInfo);
264
0
  if (Status != 0) {
265
0
    if (DLInfo.dli_fname == nullptr) {
266
0
      spdlog::error(
267
0
          "Address matched to a shared object but not to any symbol "sv
268
0
          "within the object. dli_fname is null."sv);
269
0
      return std::vector<std::filesystem::path>();
270
0
    }
271
0
    auto LibPath = std::filesystem::u8path(DLInfo.dli_fname)
272
0
                       .parent_path()
273
0
                       .lexically_normal();
274
0
    const auto UsrStr = "/usr"sv;
275
0
    const auto LibStr = "/lib"sv;
276
0
    const auto &PathStr = LibPath.native();
277
0
    if ((PathStr.size() >= UsrStr.size() &&
278
0
         std::equal(UsrStr.begin(), UsrStr.end(), PathStr.begin())) ||
279
0
        (PathStr.size() >= LibStr.size() &&
280
0
         std::equal(LibStr.begin(), LibStr.end(), PathStr.begin()))) {
281
      // The installation path of the WasmEdge library is under "/usr".
282
      // Plug-in path will be in "LIB_PATH/wasmedge".
283
      // If the installation path is under "/usr/lib" or "/usr/lib64", the
284
      // traced library path will be "/lib" or "/lib64".
285
0
      Result.push_back(LibPath / std::filesystem::u8path("wasmedge"sv));
286
0
    } else {
287
      // The installation path of the WasmEdge library is not under "/usr", such
288
      // as "$HOME/.wasmedge". Plug-in path will be in "LIB_PATH/../plugin".
289
0
      Result.push_back(LibPath / std::filesystem::u8path(".."sv) /
290
0
                       std::filesystem::u8path("plugin"sv));
291
0
    }
292
0
  } else {
293
0
    spdlog::error(ErrCode::Value::NonNullRequired);
294
0
    spdlog::error("Address could not be matched to any shared object. "sv
295
0
                  "Detailed error information is not available."sv);
296
0
    return std::vector<std::filesystem::path>();
297
0
  }
298
#elif WASMEDGE_OS_WINDOWS
299
  // Global plugin directory.
300
  if (std::filesystem::path Path; GetFunctionModuleFileName(
301
          reinterpret_cast<void *>(Plugin::getDefaultPluginPaths), Path)) {
302
    Result.push_back(Path.parent_path());
303
  } else {
304
    spdlog::error("Failed to get the path of the current module."sv);
305
    return std::vector<std::filesystem::path>();
306
  }
307
308
  // Local home plugin directory.
309
  std::filesystem::path Home;
310
  if (const auto HomeEnv = ::getenv("USERPROFILE")) {
311
    Home = std::filesystem::u8path(HomeEnv);
312
  } else {
313
#if NTDDI_VERSION >= NTDDI_VISTA
314
    wchar_t *Path = nullptr;
315
    if (winapi::HRESULT_ Res = winapi::SHGetKnownFolderPath(
316
            winapi::FOLDERID_Profile, 0, nullptr, &Path);
317
        winapi::SUCCEEDED_(Res)) {
318
      Home = std::filesystem::path(Path);
319
      winapi::CoTaskMemFree(Path);
320
    }
321
#else
322
    wchar_t Path[winapi::MAX_PATH_];
323
    if (winapi::HRESULT_ Res = winapi::SHGetFolderPathW(
324
            nullptr, winapi::CSIDL_PROFILE_, nullptr, 0, Path);
325
        winapi::SUCCEEDED_(Res)) {
326
      Home = std::filesystem::path(Path);
327
    }
328
#endif
329
  }
330
  Result.push_back(Home / std::filesystem::u8path(".wasmedge"sv) /
331
                   std::filesystem::u8path("plugin"sv));
332
#endif
333
334
0
  return Result;
335
0
}
336
337
0
WASMEDGE_EXPORT bool Plugin::load(const std::filesystem::path &Path) noexcept {
338
0
  std::error_code Error;
339
0
  auto Status = std::filesystem::status(Path, Error);
340
0
  if (likely(!Error)) {
341
0
    if (std::filesystem::is_directory(Status)) {
342
0
      bool Result = false;
343
0
      for (const auto &Entry : std::filesystem::recursive_directory_iterator(
344
0
               Path, std::filesystem::directory_options::skip_permission_denied,
345
0
               Error)) {
346
0
        const auto &EntryPath = Entry.path();
347
0
        if (Entry.is_regular_file(Error) &&
348
0
            EntryPath.extension().u8string() == WASMEDGE_LIB_EXTENSION) {
349
0
          Result |= loadFile(EntryPath);
350
0
        }
351
0
      }
352
0
      return Result;
353
0
    } else if (std::filesystem::is_regular_file(Status) &&
354
0
               Path.extension().u8string() == WASMEDGE_LIB_EXTENSION) {
355
0
      return loadFile(Path);
356
0
    }
357
0
  }
358
0
  return false;
359
0
}
360
361
0
bool Plugin::registerPlugin(const PluginDescriptor *Desc) noexcept {
362
0
  if (Desc->APIVersion != CurrentAPIVersion) {
363
0
    spdlog::debug(
364
0
        "Plugin: API version {} of plugin {} is not match to current {}."sv,
365
0
        Desc->APIVersion, Desc->Name, CurrentAPIVersion);
366
0
    return false;
367
0
  }
368
0
  if (PluginNameLookup.find(Desc->Name) != PluginNameLookup.end()) {
369
0
    spdlog::debug("Plugin: {} has already loaded."sv, Desc->Name);
370
0
    return false;
371
0
  }
372
373
0
  const auto Index = PluginRegistry.size();
374
0
  PluginRegistry.emplace_back(Desc);
375
0
  PluginNameLookup.emplace(Desc->Name, Index);
376
377
0
  return true;
378
0
}
379
380
0
void Plugin::addPluginOptions(PO::ArgumentParser &Parser) noexcept {
381
0
  for (const auto &Plugin : PluginRegistry) {
382
0
    if (Plugin.Desc->AddOptions) {
383
0
      Plugin.Desc->AddOptions(Plugin.Desc, Parser);
384
0
    }
385
0
  }
386
0
}
387
388
0
WASMEDGE_EXPORT const Plugin *Plugin::find(std::string_view Name) noexcept {
389
0
  if (auto Iter = PluginNameLookup.find(Name); Iter != PluginNameLookup.end()) {
390
0
    return std::addressof(PluginRegistry[Iter->second]);
391
0
  }
392
0
  return nullptr;
393
0
}
394
395
0
Span<const Plugin> Plugin::plugins() noexcept { return PluginRegistry; }
396
397
0
bool Plugin::loadFile(const std::filesystem::path &Path) noexcept {
398
0
  std::unique_lock Lock(Mutex);
399
0
  bool Result = false;
400
0
  auto Lib = std::make_shared<Loader::SharedLibrary>();
401
0
  if (auto Res = Lib->load(Path); unlikely(!Res)) {
402
0
    return false;
403
0
  }
404
405
0
  if (auto GetDescriptor =
406
0
          Lib->get<Plugin::PluginDescriptor const *()>("GetDescriptor")) {
407
0
    Result = Plugin::registerPlugin(GetDescriptor());
408
0
  }
409
410
0
  if (!Result) {
411
    // Check C interface
412
0
    if (auto GetDescriptor = Lib->get<decltype(WasmEdge_Plugin_GetDescriptor)>(
413
0
            "WasmEdge_Plugin_GetDescriptor");
414
0
        unlikely(!GetDescriptor)) {
415
0
      return false;
416
0
    } else if (const auto *Descriptor = GetDescriptor();
417
0
               unlikely(!Descriptor)) {
418
0
      return false;
419
0
    } else {
420
0
      Result =
421
0
          CAPIPluginRegisters
422
0
              .emplace_back(std::make_unique<CAPIPluginRegister>(Descriptor))
423
0
              ->result();
424
0
    }
425
0
  }
426
427
0
  if (!Result) {
428
0
    return false;
429
0
  }
430
431
0
  auto &Plugin = PluginRegistry.back();
432
0
  Plugin.Path = Path;
433
0
  Plugin.Lib = std::move(Lib);
434
0
  return true;
435
0
}
436
437
0
void Plugin::registerBuiltInPlugins() noexcept {
438
0
  std::unique_lock Lock(Mutex);
439
  // BUILTIN-PLUGIN: Register wasi-logging here. May be refactored in 0.15.0.
440
0
  registerPlugin(&Host::WasiLoggingModule::PluginDescriptor);
441
0
}
442
443
0
Plugin::Plugin(const PluginDescriptor *D) noexcept : Desc(D) {
444
0
  for (const auto &ModuleDesc : Span<const PluginModule::ModuleDescriptor>(
445
0
           D->ModuleDescriptions, D->ModuleCount)) {
446
0
    const auto Index = ModuleRegistry.size();
447
0
    ModuleRegistry.push_back(PluginModule(&ModuleDesc));
448
0
    ModuleNameLookup.emplace(ModuleDesc.Name, Index);
449
0
  }
450
0
  for (const auto &ComponentDesc :
451
0
       Span<const PluginComponent::ComponentDescriptor>(
452
0
           D->ComponentDescriptions, D->ComponentCount)) {
453
0
    const auto Index = ComponentRegistry.size();
454
0
    ComponentRegistry.push_back(PluginComponent(&ComponentDesc));
455
0
    ComponentNameLookup.emplace(ComponentDesc.Name, Index);
456
0
  }
457
0
}
458
459
WASMEDGE_EXPORT const PluginModule *
460
0
Plugin::findModule(std::string_view Name) const noexcept {
461
0
  if (auto Iter = ModuleNameLookup.find(Name); Iter != ModuleNameLookup.end()) {
462
0
    return std::addressof(ModuleRegistry[Iter->second]);
463
0
  }
464
0
  return nullptr;
465
0
}
466
467
WASMEDGE_EXPORT const PluginComponent *
468
0
Plugin::findComponent(std::string_view Name) const noexcept {
469
0
  if (auto Iter = ComponentNameLookup.find(Name);
470
0
      Iter != ComponentNameLookup.end()) {
471
0
    return std::addressof(ComponentRegistry[Iter->second]);
472
0
  }
473
0
  return nullptr;
474
0
}
475
} // namespace Plugin
476
} // namespace WasmEdge