• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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