• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 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/config/config.h"
17 #include "verification/config/default/default_config.h"
18 #include "verification/config/process/config_process.h"
19 #include "verification/config/parse/config_parse.h"
20 #include "verification/config/options/msg_set_parser.h"
21 
22 #include "verifier_messages.h"
23 
24 #include "literal_parser.h"
25 
26 #include "runtime/include/method.h"
27 #include "runtime/include/runtime.h"
28 #include "runtime/include/mem/panda_string.h"
29 #include "runtime/include/mem/panda_containers.h"
30 
31 #include "utils/logger.h"
32 
33 namespace panda::verifier::debug {
34 
35 using panda::verifier::config::Section;
36 
37 namespace {
38 
39 using Literals = PandaVector<PandaString>;
40 
ProcessSectionMsg(MethodOption::MsgClass msg_class,const PandaString & items,MethodOptions * options)41 bool ProcessSectionMsg(MethodOption::MsgClass msg_class, const PandaString &items, MethodOptions *options)
42 {
43     MessageSetContext c;
44 
45     const char *start = items.c_str();
46     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
47     if (!MessageSetParser()(c, start, items.c_str() + items.length())) {
48         LOG(ERROR, VERIFIER) << "Unexpected set of messages: '" << items << "'";
49         return false;
50     }
51 
52     for (const auto msg_num : c.nums) {
53         options->SetMsgClass(VerifierMessageIsValid, msg_num, msg_class);
54     }
55 
56     return true;
57 }
58 
ProcessSectionShow(const Literals & literals,MethodOptions * options)59 bool ProcessSectionShow(const Literals &literals, MethodOptions *options)
60 {
61     for (const auto &option : literals) {
62         if (option == "context") {
63             options->SetShow(MethodOption::InfoType::CONTEXT);
64         } else if (option == "reg-changes") {
65             options->SetShow(MethodOption::InfoType::REG_CHANGES);
66         } else if (option == "cflow") {
67             options->SetShow(MethodOption::InfoType::CFLOW);
68         } else if (option == "jobfill") {
69             options->SetShow(MethodOption::InfoType::JOBFILL);
70         } else {
71             LOG(ERROR, VERIFIER) << "Unexpected show option: '" << option << "'";
72             return false;
73         }
74     }
75 
76     return true;
77 }
78 
ProcessSectionUplevel(const Literals & uplevel_options,const MethodOptionsConfig & all_method_options,MethodOptions * options)79 bool ProcessSectionUplevel(const Literals &uplevel_options, const MethodOptionsConfig &all_method_options,
80                            MethodOptions *options)
81 {
82     for (const auto &uplevel : uplevel_options) {
83         if (!all_method_options.IsOptionsPresent(uplevel)) {
84             LOG(ERROR, VERIFIER) << "Cannot find uplevel options: '" << uplevel << "'";
85             return false;
86         }
87         options->AddUpLevel(all_method_options.GetOptions(uplevel));
88     }
89 
90     return true;
91 }
92 
ProcessSectionCheck(const Literals & checks,MethodOptions * options)93 bool ProcessSectionCheck(const Literals &checks, MethodOptions *options)
94 {
95     auto &options_check = options->Check();
96     for (const auto &c : checks) {
97         if (c == "cflow") {
98             options_check |= MethodOption::CheckType::CFLOW;
99         } else if (c == "reg-usage") {
100             options_check |= MethodOption::CheckType::REG_USAGE;
101         } else if (c == "resolve-id") {
102             options_check |= MethodOption::CheckType::RESOLVE_ID;
103         } else if (c == "typing") {
104             options_check |= MethodOption::CheckType::TYPING;
105         } else if (c == "absint") {
106             options_check |= MethodOption::CheckType::ABSINT;
107         } else {
108             LOG(ERROR, VERIFIER) << "Unexpected check type: '" << c << "'";
109             return false;
110         }
111     }
112 
113     return true;
114 }
115 
116 }  // namespace
117 
MethodOptionsProcessor()118 const auto &MethodOptionsProcessor()
119 {
120     static const auto PROCESS_METHOD_OPTIONS = [](const Section &section) {
121         MethodOptionsConfig &all_options = Runtime::GetCurrent()->GetVerificationOptions().Debug.GetMethodOptions();
122         MethodOptions &options = all_options.NewOptions(section.name);
123 
124         for (const auto &s : section.sections) {
125             const PandaString &name = s.name;
126             PandaString items;
127             for (const auto &item : s.items) {
128                 items += item;
129                 items += " ";
130             }
131 
132             if (name == "error") {
133                 if (!ProcessSectionMsg(MethodOption::MsgClass::ERROR, items, &options)) {
134                     return false;
135                 }
136             } else if (name == "warning") {
137                 if (!ProcessSectionMsg(MethodOption::MsgClass::WARNING, items, &options)) {
138                     return false;
139                 }
140             } else if (name == "hidden") {
141                 if (!ProcessSectionMsg(MethodOption::MsgClass::HIDDEN, items, &options)) {
142                     return false;
143                 }
144             } else {
145                 Literals literals;
146                 const char *start = items.c_str();
147                 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
148                 if (!LiteralsParser()(literals, start, start + items.length())) {
149                     LOG(ERROR, VERIFIER) << "Failed to parse '" << name << "' under '" << section.name << "'";
150                     return false;
151                 }
152 
153                 if (name == "show") {
154                     if (!ProcessSectionShow(literals, &options)) {
155                         return false;
156                     }
157                 } else if (name == "uplevel") {
158                     if (!ProcessSectionUplevel(literals, all_options, &options)) {
159                         return false;
160                     }
161                 } else if (name == "check") {
162                     if (!ProcessSectionCheck(literals, &options)) {
163                         return false;
164                     }
165                 } else {
166                     LOG(ERROR, VERIFIER) << "Unexpected section name: '" << name << "' under '" << section.name << "'";
167                     return false;
168                 }
169             }
170         }
171 
172         LOG(DEBUG, VERIFIER) << options.Image();
173 
174         return true;
175     };
176 
177     return PROCESS_METHOD_OPTIONS;
178 }
179 
RegisterConfigHandlerMethodOptions()180 void RegisterConfigHandlerMethodOptions()
181 {
182     static const auto CONFIG_DEBUG_METHOD_OPTIONS_VERIFIER = [](const Section &section) {
183         bool default_present = false;
184         for (const auto &s : section.sections) {
185             if (s.name == "default") {
186                 default_present = true;
187                 break;
188             }
189         }
190         if (!default_present) {
191             // take default section from inlined config
192             Section cfg;
193             if (!ParseConfig(panda::verifier::config::VerifierDebugDefaultConfig, cfg)) {
194                 LOG(ERROR, VERIFIER) << "Cannot parse default verifier config";
195                 return false;
196             }
197             if (!MethodOptionsProcessor()(cfg["debug"]["method_options"]["verifier"]["default"])) {
198                 LOG(ERROR, VERIFIER) << "Cannot parse default method options";
199                 return false;
200             }
201         }
202         for (const auto &s : section.sections) {
203             if (!MethodOptionsProcessor()(s)) {
204                 LOG(ERROR, VERIFIER) << "Cannot parse section '" << s.name << "'";
205                 return false;
206             }
207         }
208         return true;
209     };
210 
211     config::RegisterConfigHandler("config.debug.method_options.verifier", CONFIG_DEBUG_METHOD_OPTIONS_VERIFIER);
212 }
213 
SetDefaultMethodOptions()214 void SetDefaultMethodOptions()
215 {
216     auto &runtime = *Runtime::GetCurrent();
217     auto &verif_options = runtime.GetVerificationOptions();
218     auto &options = verif_options.Debug.GetMethodOptions();
219     if (!options.IsOptionsPresent("default")) {
220         // take default section from inlined config
221         Section cfg;
222         if (!ParseConfig(panda::verifier::config::VerifierDebugDefaultConfig, cfg)) {
223             LOG(FATAL, VERIFIER) << "Cannot parse default internal config. Internal error.";
224         }
225         if (!MethodOptionsProcessor()(cfg["debug"]["method_options"]["verifier"]["default"])) {
226             LOG(FATAL, VERIFIER) << "Cannot parse default section";
227         }
228     }
229 }
230 
231 }  // namespace panda::verifier::debug
232