1 /**
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "verification/public_internal.h"
17 #include "verification/config/config.h"
18 #include "verification/config/default/default_config.h"
19 #include "verification/config/options/method_options.h"
20 #include "verification/config/options/method_options_config.h"
21 #include "verification/config/process/config_process.h"
22 #include "verification/config/parse/config_parse.h"
23 #include "verification/config/options/msg_set_parser.h"
24
25 #include "verifier_messages.h"
26
27 #include "literal_parser.h"
28
29 #include "runtime/include/mem/panda_string.h"
30 #include "runtime/include/mem/panda_containers.h"
31
32 #include "utils/logger.h"
33
34 namespace ark::verifier::debug {
35
36 using ark::verifier::config::Section;
37
38 namespace {
39
40 using Literals = PandaVector<PandaString>;
41
GetNameHandler()42 auto GetNameHandler()
43 {
44 using ark::parser::Action;
45
46 return [](Action a, MessageSetContext &c, auto from, auto to) {
47 if (a == Action::PARSED) {
48 std::string_view name {from, static_cast<size_t>(to - from)};
49 auto num = static_cast<size_t>(ark::verifier::StringToVerifierMessage(name));
50 c.stack.push_back(std::make_pair(num, num));
51 }
52 return true;
53 };
54 }
55
GetNumHandler()56 auto GetNumHandler()
57 {
58 using ark::parser::Action;
59
60 return [](Action a, MessageSetContext &c, auto from) {
61 if (a == Action::PARSED) {
62 auto num = static_cast<size_t>(std::strtol(from, nullptr, 0));
63 c.stack.push_back(std::make_pair(num, num));
64 }
65 return true;
66 };
67 }
68
GetRangeHandler()69 auto GetRangeHandler()
70 {
71 using ark::parser::Action;
72
73 return [](Action a, MessageSetContext &c) {
74 if (a == Action::PARSED) {
75 auto numEnd = c.stack.back();
76 c.stack.pop_back();
77 auto numStart = c.stack.back();
78 c.stack.pop_back();
79
80 c.stack.push_back(std::make_pair(numStart.first, numEnd.first));
81 }
82 return true;
83 };
84 }
85
GetItemHandler()86 auto GetItemHandler()
87 {
88 using ark::parser::Action;
89
90 return [](Action a, MessageSetContext &c) {
91 if (a == Action::START) {
92 c.stack.clear();
93 }
94 if (a == Action::PARSED) {
95 auto range = c.stack.back();
96 c.stack.pop_back();
97
98 for (auto i = range.first; i <= range.second; ++i) {
99 c.nums.insert(i);
100 }
101 }
102 return true;
103 };
104 }
105
MessageSetParser()106 const auto &MessageSetParser()
107 {
108 using ark::parser::Parser;
109
110 using P = Parser<MessageSetContext, const char, const char *>;
111 using P1 = typename P::P;
112 using P2 = typename P1::P;
113 using P3 = typename P2::P;
114 using P4 = typename P3::P;
115
116 static const auto WS = P::OfCharset(" \t\r\n");
117 static const auto COMMA = P1::OfCharset(",");
118 static const auto DEC = P2::OfCharset("0123456789");
119
120 static const auto NAME_HANDLER = GetNameHandler();
121 static const auto NUM_HANDLER = GetNumHandler();
122
123 static const auto RANGE_HANDLER = GetRangeHandler();
124
125 static const auto ITEM_HANDLER = GetItemHandler();
126
127 static const auto NAME = P3::OfCharset("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789") |=
128 NAME_HANDLER;
129
130 static const auto NUM = DEC |= NUM_HANDLER;
131
132 static const auto MSG = NUM | NAME;
133
134 static const auto MSG_RANGE = MSG >> ~WS >> P4::OfString("-") >> ~WS >> MSG |= RANGE_HANDLER;
135
136 static const auto ITEM = ~WS >> ((MSG_RANGE | MSG) |= ITEM_HANDLER) >> ~WS >> ~COMMA;
137
138 // clang-tidy bug, use lambda instead of ITEMS = *ITEM
139 static const auto ITEMS = [](MessageSetContext &c, const char *&start, const char *end) {
140 while (true) {
141 auto saved = start;
142 if (!ITEM(c, start, end)) {
143 start = saved;
144 break;
145 }
146 }
147 return true;
148 };
149
150 return ITEMS;
151 }
152
ProcessSectionMsg(MethodOption::MsgClass msgClass,const PandaString & items,MethodOptions * options)153 bool ProcessSectionMsg(MethodOption::MsgClass msgClass, const PandaString &items, MethodOptions *options)
154 {
155 MessageSetContext c;
156
157 const char *start = items.c_str();
158 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
159 if (!MessageSetParser()(c, start, items.c_str() + items.length())) {
160 LOG(ERROR, VERIFIER) << "Unexpected set of messages: '" << items << "'";
161 return false;
162 }
163
164 for (const auto msgNum : c.nums) {
165 options->SetMsgClass(VerifierMessageIsValid, msgNum, msgClass);
166 }
167
168 return true;
169 }
170
ProcessSectionShow(const Literals & literals,MethodOptions * options)171 bool ProcessSectionShow(const Literals &literals, MethodOptions *options)
172 {
173 for (const auto &option : literals) {
174 if (option == "context") {
175 options->SetShow(MethodOption::InfoType::CONTEXT);
176 } else if (option == "reg-changes") {
177 options->SetShow(MethodOption::InfoType::REG_CHANGES);
178 } else if (option == "cflow") {
179 options->SetShow(MethodOption::InfoType::CFLOW);
180 } else if (option == "jobfill") {
181 options->SetShow(MethodOption::InfoType::JOBFILL);
182 } else {
183 LOG(ERROR, VERIFIER) << "Unexpected show option: '" << option << "'";
184 return false;
185 }
186 }
187
188 return true;
189 }
190
ProcessSectionUplevel(const Literals & uplevelOptions,const MethodOptionsConfig & allMethodOptions,MethodOptions * options)191 bool ProcessSectionUplevel(const Literals &uplevelOptions, const MethodOptionsConfig &allMethodOptions,
192 MethodOptions *options)
193 {
194 for (const auto &uplevel : uplevelOptions) {
195 if (!allMethodOptions.IsOptionsPresent(uplevel)) {
196 LOG(ERROR, VERIFIER) << "Cannot find uplevel options: '" << uplevel << "'";
197 return false;
198 }
199 options->AddUpLevel(allMethodOptions.GetOptions(uplevel));
200 }
201
202 return true;
203 }
204
ProcessSectionCheck(const Literals & checks,MethodOptions * options)205 bool ProcessSectionCheck(const Literals &checks, MethodOptions *options)
206 {
207 auto &optionsCheck = options->Check();
208 for (const auto &c : checks) {
209 if (c == "cflow") {
210 optionsCheck |= MethodOption::CheckType::CFLOW;
211 } else if (c == "reg-usage") {
212 optionsCheck |= MethodOption::CheckType::REG_USAGE;
213 } else if (c == "resolve-id") {
214 optionsCheck |= MethodOption::CheckType::RESOLVE_ID;
215 } else if (c == "typing") {
216 optionsCheck |= MethodOption::CheckType::TYPING;
217 } else if (c == "absint") {
218 optionsCheck |= MethodOption::CheckType::ABSINT;
219 } else {
220 LOG(ERROR, VERIFIER) << "Unexpected check type: '" << c << "'";
221 return false;
222 }
223 }
224
225 return true;
226 }
227
228 } // namespace
229
MethodOptionsProcessorProcessSection(const struct Section & s,const Section & section,MethodOptionsConfig & allOptions,MethodOptions & options)230 static bool MethodOptionsProcessorProcessSection(const struct Section &s, const Section §ion,
231 MethodOptionsConfig &allOptions, MethodOptions &options)
232 {
233 const PandaString &name = s.name;
234 PandaString items;
235 for (const auto &item : s.items) {
236 items += item;
237 items += " ";
238 }
239
240 if (name == "error") {
241 if (!ProcessSectionMsg(MethodOption::MsgClass::ERROR, items, &options)) {
242 return false;
243 }
244 } else if (name == "warning") {
245 if (!ProcessSectionMsg(MethodOption::MsgClass::WARNING, items, &options)) {
246 return false;
247 }
248 } else if (name == "hidden") {
249 if (!ProcessSectionMsg(MethodOption::MsgClass::HIDDEN, items, &options)) {
250 return false;
251 }
252 } else {
253 Literals literals;
254 const char *start = items.c_str();
255 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
256 if (!LiteralsParser()(literals, start, start + items.length())) {
257 LOG(ERROR, VERIFIER) << "Failed to parse '" << name << "' under '" << section.name << "'";
258 return false;
259 }
260
261 if (name == "show") {
262 if (!ProcessSectionShow(literals, &options)) {
263 return false;
264 }
265 } else if (name == "uplevel") {
266 if (!ProcessSectionUplevel(literals, allOptions, &options)) {
267 return false;
268 }
269 } else if (name == "check") {
270 if (!ProcessSectionCheck(literals, &options)) {
271 return false;
272 }
273 } else {
274 LOG(ERROR, VERIFIER) << "Unexpected section name: '" << name << "' under '" << section.name << "'";
275 return false;
276 }
277 }
278 return true;
279 }
280
MethodOptionsProcessor()281 const auto &MethodOptionsProcessor()
282 {
283 static const auto PROCESS_METHOD_OPTIONS = [](Config *cfg, const Section §ion) {
284 MethodOptionsConfig &allOptions = cfg->opts.debug.GetMethodOptions();
285 MethodOptions &options = allOptions.NewOptions(section.name);
286
287 for (const auto &s : section.sections) {
288 if (!MethodOptionsProcessorProcessSection(s, section, allOptions, options)) {
289 return false;
290 }
291 }
292
293 LOG(DEBUG, VERIFIER) << options.Image();
294
295 return true;
296 };
297
298 return PROCESS_METHOD_OPTIONS;
299 }
300
RegisterConfigHandlerMethodOptions(Config * dcfg)301 void RegisterConfigHandlerMethodOptions(Config *dcfg)
302 {
303 static const auto CONFIG_DEBUG_METHOD_OPTIONS_VERIFIER = [](Config *ddcfg, const Section §ion) {
304 bool defaultPresent = false;
305 for (const auto &s : section.sections) {
306 if (s.name == "default") {
307 defaultPresent = true;
308 break;
309 }
310 }
311 if (!defaultPresent) {
312 // take default section from inlined config
313 Section cfg;
314 if (!ParseConfig(ark::verifier::config::VERIFIER_DEBUG_DEFAULT_CONFIG, cfg)) {
315 LOG(ERROR, VERIFIER) << "Cannot parse default verifier config";
316 return false;
317 }
318 if (!MethodOptionsProcessor()(ddcfg, cfg["debug"]["method_options"]["verifier"]["default"])) {
319 LOG(ERROR, VERIFIER) << "Cannot parse default method options";
320 return false;
321 }
322 }
323 for (const auto &s : section.sections) {
324 if (!MethodOptionsProcessor()(ddcfg, s)) {
325 LOG(ERROR, VERIFIER) << "Cannot parse section '" << s.name << "'";
326 return false;
327 }
328 }
329 return true;
330 };
331
332 config::RegisterConfigHandler(dcfg, "config.debug.method_options.verifier", CONFIG_DEBUG_METHOD_OPTIONS_VERIFIER);
333 }
334
SetDefaultMethodOptions(Config * dcfg)335 void SetDefaultMethodOptions(Config *dcfg)
336 {
337 auto &verifOptions = dcfg->opts;
338 auto &options = verifOptions.debug.GetMethodOptions();
339 if (!options.IsOptionsPresent("default")) {
340 // take default section from inlined config
341 Section cfg;
342 if (!ParseConfig(ark::verifier::config::VERIFIER_DEBUG_DEFAULT_CONFIG, cfg)) {
343 LOG(FATAL, VERIFIER) << "Cannot parse default internal config. Internal error.";
344 }
345 if (!MethodOptionsProcessor()(dcfg, cfg["debug"]["method_options"]["verifier"]["default"])) {
346 LOG(FATAL, VERIFIER) << "Cannot parse default section";
347 }
348 }
349 }
350
351 } // namespace ark::verifier::debug
352