• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &section,
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 &section) {
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 &section) {
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