1 /*
2 * Copyright (c) 2021 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 <chrono>
17 #include <ctime>
18 #include <iostream>
19 #include <limits>
20 #include <signal.h> // NOLINTNEXTLINE(modernize-deprecated-headers)
21 #include <vector>
22
23 #include "include/runtime.h"
24 #include "include/thread.h"
25 #include "include/thread_scopes.h"
26
27 #include "libpandabase/os/mutex.h"
28 #include "libpandabase/os/native_stack.h"
29 #include "generated/base_options.h"
30
31 #include "mem/mem_stats.h"
32
33 #include "runtime/include/locks.h"
34 #include "runtime/include/method-inl.h"
35 #include "runtime/include/class.h"
36
37 #include "utils/logger.h"
38 #include "utils/pandargs.h"
39 #include "utils/span.h"
40
41 #include "verification/job_queue/job_queue.h"
42 #include "verification/job_queue/cache.h"
43
44 namespace panda {
GetPandaFile(const ClassLinker & class_linker,std::string_view file_name)45 const panda_file::File *GetPandaFile(const ClassLinker &class_linker, std::string_view file_name)
46 {
47 const panda_file::File *res = nullptr;
48 class_linker.EnumerateBootPandaFiles([&res, file_name](const panda_file::File &pf) {
49 if (pf.GetFilename() == file_name) {
50 res = &pf;
51 return false;
52 }
53 return true;
54 });
55 return res;
56 }
57
VerifierProcessFile(const panda::verifier::VerificationOptions & opts,const std::string & file_name,const std::string & entrypoint)58 bool VerifierProcessFile(const panda::verifier::VerificationOptions &opts, const std::string &file_name,
59 const std::string &entrypoint)
60 {
61 if (!opts.Mode.OnlyVerify) {
62 return true;
63 }
64
65 auto &runtime = *Runtime::GetCurrent();
66 auto &class_linker = *runtime.GetClassLinker();
67
68 bool result = true;
69 if (opts.Mode.VerifyAllRuntimeLibraryMethods) {
70 // We need AccessToManagedObjectsScope for verification since it can allocate objects
71 ScopedManagedCodeThread managed_obj_thread(MTManagedThread::GetCurrent());
72 class_linker.EnumerateClasses([&result](const Class *klass) {
73 for (auto &method : klass->GetMethods()) {
74 result = method.Verify();
75 if (!result) {
76 return false;
77 }
78 }
79 return true;
80 });
81 }
82 if (!result) {
83 return false;
84 }
85
86 if (opts.Mode.VerifyOnlyEntryPoint) {
87 auto resolved = runtime.ResolveEntryPoint(entrypoint);
88
89 result = static_cast<bool>(resolved);
90
91 if (!result) {
92 LOG(ERROR, VERIFIER) << "Error: Cannot resolve method '" << entrypoint << "'";
93 } else {
94 // We need AccessToManagedObjectsScope for verification since it can allocate objects
95 ScopedManagedCodeThread managed_obj_thread(MTManagedThread::GetCurrent());
96 Method &method = *resolved.Value();
97 result = method.Verify();
98 }
99 } else {
100 auto file = GetPandaFile(*runtime.GetClassLinker(), file_name);
101 ASSERT(file != nullptr);
102
103 auto &klass_linker = *runtime.GetClassLinker();
104
105 auto extracted = Runtime::GetCurrent()->ExtractLanguageContext(file, entrypoint);
106 result = static_cast<bool>(extracted);
107 if (!result) {
108 LOG(ERROR, VERIFIER) << "Error: Cannot extract language context for entry point: " << entrypoint;
109 return false;
110 }
111
112 LanguageContext ctx = extracted.Value();
113 bool is_default_context = true;
114
115 for (auto id : file->GetClasses()) {
116 Class *klass = nullptr;
117 {
118 // We need AccessToManagedObjectsScope for GetClass since it can allocate objects
119 ScopedManagedCodeThread managed_obj_thread(MTManagedThread::GetCurrent());
120 klass = klass_linker.GetExtension(ctx)->GetClass(*file, panda_file::File::EntityId {id});
121 }
122
123 if (klass != nullptr) {
124 if (is_default_context) {
125 ctx = Runtime::GetCurrent()->GetLanguageContext(*klass);
126 is_default_context = true;
127 }
128 for (auto &method : klass->GetMethods()) {
129 // We need AccessToManagedObjectsScope for verify since it can allocate objects
130 ScopedManagedCodeThread managed_obj_thread(MTManagedThread::GetCurrent());
131 result = method.Verify();
132 if (!result) {
133 break;
134 }
135 }
136 }
137 if (!result) {
138 break;
139 }
140 }
141 }
142
143 return result;
144 }
145
BlockSignals()146 void BlockSignals()
147 {
148 #if defined(PANDA_TARGET_UNIX)
149 sigset_t set;
150 if (sigemptyset(&set) == -1) {
151 LOG(ERROR, RUNTIME) << "sigemptyset failed";
152 return;
153 }
154 #ifdef PANDA_TARGET_MOBILE
155 int rc = 0;
156 rc += sigaddset(&set, SIGPIPE);
157 rc += sigaddset(&set, SIGQUIT);
158 rc += sigaddset(&set, SIGUSR1);
159 rc += sigaddset(&set, SIGUSR2);
160 if (rc < 0) {
161 LOG(ERROR, RUNTIME) << "sigaddset failed";
162 return;
163 }
164 #endif // PANDA_TARGET_MOBILE
165 if (os::native_stack::g_PandaThreadSigmask(SIG_BLOCK, &set, nullptr) != 0) {
166 LOG(ERROR, RUNTIME) << "PandaThreadSigmask failed";
167 }
168 #endif // PANDA_TARGET_UNIX
169 }
170
Main(const int argc,const char ** argv)171 int Main(const int argc, const char **argv)
172 {
173 auto start_time =
174 std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch())
175 .count();
176
177 BlockSignals();
178 Span<const char *> sp(argv, argc);
179 RuntimeOptions runtime_options(sp[0]);
180 base_options::Options base_options(sp[0]);
181
182 panda::PandArg<bool> help("help", false, "Print this message and exit");
183 panda::PandArg<bool> options("options", false, "Print compiler and runtime options");
184 // Tail arguments
185 panda::PandArg<std::string> file("file", "", "path to pandafile");
186 panda::PandArg<std::string> entrypoint("entrypoint", "", "full name of entrypoint function or method");
187 panda::PandArgParser pa_parser;
188
189 runtime_options.AddOptions(&pa_parser);
190 base_options.AddOptions(&pa_parser);
191
192 pa_parser.Add(&help);
193 pa_parser.Add(&options);
194 pa_parser.PushBackTail(&file);
195 pa_parser.PushBackTail(&entrypoint);
196 pa_parser.EnableTail();
197 pa_parser.EnableRemainder();
198
199 if (!pa_parser.Parse(argc, argv) || file.GetValue().empty() || entrypoint.GetValue().empty() || help.GetValue()) {
200 std::cerr << pa_parser.GetErrorString() << std::endl;
201 std::cerr << "Usage: "
202 << "panda"
203 << " [OPTIONS] [file] [entrypoint] -- [arguments]" << std::endl;
204 std::cerr << std::endl;
205 std::cerr << "optional arguments:" << std::endl;
206 std::cerr << pa_parser.GetHelpString() << std::endl;
207 return 1;
208 }
209
210 Logger::Initialize(base_options);
211
212 arg_list_t arguments = pa_parser.GetRemainder();
213
214 if (runtime_options.IsStartupTime()) {
215 std::cout << "\n"
216 << "Startup start time: " << start_time << std::endl;
217 }
218
219 auto runtime_options_err = runtime_options.Validate();
220 if (runtime_options_err) {
221 std::cerr << "Error: " << runtime_options_err.value().GetMessage() << std::endl;
222 return 1;
223 }
224
225 auto boot_panda_files = runtime_options.GetBootPandaFiles();
226
227 if (runtime_options.GetPandaFiles().empty()) {
228 boot_panda_files.push_back(file.GetValue());
229 } else {
230 auto panda_files = runtime_options.GetPandaFiles();
231 auto found_iter = std::find_if(panda_files.begin(), panda_files.end(),
232 [&](auto &file_name) { return file_name == file.GetValue(); });
233 if (found_iter == panda_files.end()) {
234 panda_files.push_back(file.GetValue());
235 runtime_options.SetPandaFiles(panda_files);
236 }
237 }
238
239 runtime_options.SetBootPandaFiles(boot_panda_files);
240
241 if (!Runtime::Create(runtime_options)) {
242 std::cerr << "Error: cannot create runtime" << std::endl;
243 return -1;
244 }
245
246 if (options.GetValue()) {
247 std::cout << pa_parser.GetRegularArgs() << std::endl;
248 }
249
250 std::string file_name = file.GetValue();
251 std::string entry = entrypoint.GetValue();
252
253 auto &runtime = *Runtime::GetCurrent();
254 auto &verif_opts = runtime.GetVerificationOptions();
255
256 int ret = 0;
257
258 if (verif_opts.Enable) {
259 runtime.GetClassLinker()->EnumerateBootPandaFiles([](const panda_file::File &pf) {
260 verifier::JobQueue::GetCache().FastAPI().ProcessFile(&pf);
261 return true;
262 });
263 bool result = VerifierProcessFile(verif_opts, file_name, entry);
264 if (!result && !verif_opts.Mode.VerifierDoesNotFail) {
265 ret = -1;
266 }
267 }
268
269 if (ret == 0 && (!verif_opts.Enable || !verif_opts.Mode.OnlyVerify)) {
270 auto res = runtime.ExecutePandaFile(file_name, entry, arguments);
271 if (!res) {
272 std::cerr << "Cannot execute panda file '" << file_name << "' with entry '" << entry << "'" << std::endl;
273 ret = -1;
274 } else {
275 ret = res.Value();
276 }
277 }
278 if (runtime_options.IsPrintMemoryStatistics()) {
279 std::cout << Runtime::GetCurrent()->GetMemoryStatistics();
280 }
281 if (runtime_options.IsPrintGcStatistics()) {
282 std::cout << Runtime::GetCurrent()->GetFinalStatistics();
283 }
284 if (!Runtime::Destroy()) {
285 std::cerr << "Error: cannot destroy runtime" << std::endl;
286 return -1;
287 }
288 pa_parser.DisableTail();
289 return ret;
290 }
291 } // namespace panda
292
main(int argc,const char ** argv)293 int main(int argc, const char **argv)
294 {
295 return panda::Main(argc, argv);
296 }
297