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 §ion) {
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 §ion) {
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