Coverage Report

Created: 2026-11-12 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/lib/driver/toolConfig.cpp
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright The WasmEdge Authors
3
4
#include "common/configure.h"
5
#include "common/filesystem.h"
6
#include "common/spdlog.h"
7
#include "driver/options.h"
8
#include "driver/tool.h"
9
#include "vm/vm.h"
10
11
#include <filesystem>
12
#include <optional>
13
#include <string>
14
#include <string_view>
15
#include <system_error>
16
17
using namespace std::literals;
18
19
namespace WasmEdge {
20
namespace Driver {
21
22
Configure
23
0
createProposalConfigure(const struct DriverProposalOptions &Opt) noexcept {
24
0
  Configure Conf;
25
  // WASM standard configuration has the highest priority.
26
0
  if (Opt.PropWASM1.value()) {
27
0
    Conf.setWASMStandard(Standard::WASM_1);
28
0
  }
29
0
  if (Opt.PropWASM2.value()) {
30
0
    Conf.setWASMStandard(Standard::WASM_2);
31
0
  }
32
0
  if (Opt.PropWASM3.value()) {
33
0
    Conf.setWASMStandard(Standard::WASM_3);
34
0
  }
35
36
  // Proposals adjustment.
37
0
  if (Opt.PropMutGlobals.value()) {
38
0
    Conf.removeProposal(Proposal::ImportExportMutGlobals);
39
0
  }
40
0
  if (Opt.PropNonTrapF2IConvs.value()) {
41
0
    Conf.removeProposal(Proposal::NonTrapFloatToIntConversions);
42
0
  }
43
0
  if (Opt.PropSignExtendOps.value()) {
44
0
    Conf.removeProposal(Proposal::SignExtensionOperators);
45
0
  }
46
0
  if (Opt.PropMultiValue.value()) {
47
0
    Conf.removeProposal(Proposal::MultiValue);
48
0
  }
49
0
  if (Opt.PropBulkMemOps.value()) {
50
0
    Conf.removeProposal(Proposal::BulkMemoryOperations);
51
0
  }
52
0
  if (Opt.PropSIMD.value()) {
53
0
    Conf.removeProposal(Proposal::SIMD);
54
0
  }
55
0
  if (Opt.PropTailCall.value()) {
56
0
    Conf.removeProposal(Proposal::TailCall);
57
0
  }
58
0
  if (Opt.PropExtendConst.value()) {
59
0
    Conf.removeProposal(Proposal::ExtendedConst);
60
0
  }
61
0
  if (Opt.PropMultiMem.value()) {
62
0
    Conf.removeProposal(Proposal::MultiMemories);
63
0
  }
64
0
  if (Opt.PropRelaxedSIMD.value()) {
65
0
    Conf.removeProposal(Proposal::RelaxSIMD);
66
0
  }
67
0
  if (Opt.PropExceptionHandling.value()) {
68
0
    Conf.removeProposal(Proposal::ExceptionHandling);
69
0
  }
70
0
  if (Opt.PropMemory64.value()) {
71
0
    Conf.removeProposal(Proposal::Memory64);
72
0
  }
73
74
  // Handle the proposal removal which has dependency.
75
  // The GC proposal depends on the func-ref proposal, and the func-ref proposal
76
  // depends on the ref-types proposal.
77
0
  if (Opt.PropGC.value()) {
78
0
    Conf.removeProposal(Proposal::GC);
79
0
  }
80
0
  if (Opt.PropFunctionReference.value()) {
81
    // This will automatically not work if the GC proposal not disabled.
82
0
    Conf.removeProposal(Proposal::FunctionReferences);
83
0
  }
84
0
  if (Opt.PropRefTypes.value()) {
85
    // This will automatically not work if the GC or func-ref proposal not
86
    // disabled.
87
0
    Conf.removeProposal(Proposal::ReferenceTypes);
88
0
  }
89
90
0
  if (Opt.PropThreads.value()) {
91
0
    Conf.addProposal(Proposal::Threads);
92
0
  }
93
0
  if (Opt.PropAll.value()) {
94
0
    Conf.setWASMStandard(Standard::WASM_3);
95
0
    Conf.addProposal(Proposal::Threads);
96
0
  }
97
98
0
  return Conf;
99
0
}
100
101
void setStatisticsConfigure(const struct DriverStatisticsOptions &Opt,
102
0
                            Configure &Conf) noexcept {
103
0
  if (Opt.ConfEnableAllStatistics.value()) {
104
0
    Conf.getStatisticsConfigure().setInstructionCounting(true);
105
0
    Conf.getStatisticsConfigure().setCostMeasuring(true);
106
0
    Conf.getStatisticsConfigure().setTimeMeasuring(true);
107
0
  } else {
108
0
    if (Opt.ConfEnableInstructionCounting.value()) {
109
0
      Conf.getStatisticsConfigure().setInstructionCounting(true);
110
0
    }
111
0
    if (Opt.ConfEnableGasMeasuring.value()) {
112
0
      Conf.getStatisticsConfigure().setCostMeasuring(true);
113
0
    }
114
0
    if (Opt.ConfEnableTimeMeasuring.value()) {
115
0
      Conf.getStatisticsConfigure().setTimeMeasuring(true);
116
0
    }
117
0
  }
118
0
}
119
120
0
void setLoggingLevel(const struct DriverLoggingOptions &Opt) noexcept {
121
0
  const std::string &Level =
122
0
      Opt.LogLevel.value().empty() ? "info" : Opt.LogLevel.value();
123
0
  if (!Log::setLoggingLevelFromString(Level)) {
124
0
    spdlog::warn("Invalid log level: {}. Valid values are: off, trace, debug, "
125
0
                 "info, warning, error, fatal. Falling back to info level."sv,
126
0
                 Level);
127
0
    Log::setInfoLoggingLevel();
128
0
  }
129
0
}
130
131
0
Configure createConfigure(const struct DriverToolOptions &Opt) noexcept {
132
0
  setLoggingLevel(Opt);
133
134
0
  Configure Conf = createProposalConfigure(Opt);
135
136
0
  if (Opt.PropComponent.value()) {
137
0
    Conf.addProposal(Proposal::Component);
138
0
    spdlog::warn("component model is enabled, this is experimental."sv);
139
0
  }
140
0
  if (Opt.PropAll.value()) {
141
0
    spdlog::warn("component model is enabled, this is experimental."sv);
142
0
    Conf.addProposal(Proposal::Component);
143
0
  }
144
145
0
  for (const auto &Name : Opt.ForbiddenPlugins.value()) {
146
0
    Conf.addForbiddenPlugins(Name);
147
0
  }
148
149
0
  return Conf;
150
0
}
151
152
std::optional<std::filesystem::path>
153
0
getAbsolutePath(const std::string &Name, std::string_view Kind) noexcept {
154
  // std::filesystem::absolute throws on an empty path on some standard
155
  // libraries; reject it here and take the error code for the other failures.
156
0
  if (Name.empty()) {
157
0
    spdlog::error("No {} provided."sv, Kind);
158
0
    return std::nullopt;
159
0
  }
160
0
  std::error_code Err;
161
0
  auto Path = std::filesystem::absolute(u8path(Name), Err);
162
0
  if (Err) {
163
0
    spdlog::error("Invalid {} path \"{}\": {}"sv, Kind, Name, Err.message());
164
0
    return std::nullopt;
165
0
  }
166
0
  return Path;
167
0
}
168
169
std::optional<std::filesystem::path>
170
0
getInputPath(const struct DriverToolOptions &Opt) noexcept {
171
0
  return getAbsolutePath(Opt.SoName.value(), "input wasm file"sv);
172
0
}
173
174
void setMemoryPageLimit(const struct DriverToolOptions &Opt,
175
0
                        Configure &Conf) noexcept {
176
0
  if (Opt.MemLim.value().size() > 0) {
177
0
    Conf.getRuntimeConfigure().setMaxMemoryPage(Opt.MemLim.value().back());
178
0
  }
179
0
}
180
181
bool registerLinkedModules(const struct DriverToolOptions &Opt,
182
0
                           VM::VM &VM) noexcept {
183
0
  for (const auto &ModEntry : Opt.LinkedModules.value()) {
184
0
    const auto Pos = ModEntry.find(':');
185
0
    if (Pos == std::string::npos || Pos == 0 || Pos + 1 == ModEntry.size()) {
186
0
      spdlog::error("Invalid --module format: \"{}\". Expected name:path."sv,
187
0
                    ModEntry);
188
0
      return false;
189
0
    }
190
0
    const auto Name = ModEntry.substr(0, Pos);
191
0
    const auto Path =
192
0
        getAbsolutePath(ModEntry.substr(Pos + 1), "module file"sv);
193
0
    if (!Path) {
194
0
      return false;
195
0
    }
196
0
    if (auto Result = VM.registerModule(Name, *Path); !Result) {
197
0
      spdlog::error("Failed to register module \"{}\" from: {}"sv, Name,
198
0
                    u8string(*Path));
199
0
      return false;
200
0
    }
201
0
  }
202
0
  return true;
203
0
}
204
205
} // namespace Driver
206
} // namespace WasmEdge