blob: b4aa6784c8906cd49c20b29a5f922141da4d0ae1 [file] [log] [blame]
Andreas Gampe85ac3602018-08-03 03:42:08 -07001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <string>
18#include <vector>
19
20#include "android-base/logging.h"
21
22#include "base/logging.h"
23#include "base/os.h"
24#include "class_linker-inl.h"
25#include "dex/art_dex_file_loader.h"
26#include "dex/class_accessor-inl.h"
27#include "dex/dex_file-inl.h"
28#include "interpreter/unstarted_runtime.h"
29#include "mirror/class-inl.h"
30#include "mirror/dex_cache-inl.h"
31#include "runtime.h"
32#include "scoped_thread_state_change-inl.h"
33#include "verifier/method_verifier.h"
34#include "well_known_classes.h"
35
36#include <sys/stat.h>
37#include "cmdline.h"
38
39namespace art {
40
41namespace {
42
43bool LoadDexFile(const std::string& dex_filename,
44 std::vector<std::unique_ptr<const DexFile>>* dex_files) {
45 const ArtDexFileLoader dex_file_loader;
46 std::string error_msg;
47 if (!dex_file_loader.Open(dex_filename.c_str(),
48 dex_filename.c_str(),
Andreas Gampe9b031f72018-10-04 11:03:34 -070049 /* verify= */ true,
50 /* verify_checksum= */ true,
Andreas Gampe85ac3602018-08-03 03:42:08 -070051 &error_msg,
52 dex_files)) {
53 LOG(ERROR) << error_msg;
54 return false;
55 }
56 return true;
57}
58
59jobject Install(Runtime* runtime,
60 std::vector<std::unique_ptr<const DexFile>>& in,
61 std::vector<const DexFile*>* out)
62 REQUIRES_SHARED(Locks::mutator_lock_) {
63 Thread* self = Thread::Current();
64 CHECK(self != nullptr);
65
66 // Need well-known-classes.
67 WellKnownClasses::Init(self->GetJniEnv());
68 // Need a class loader. Fake that we're a compiler.
69 // Note: this will run initializers through the unstarted runtime, so make sure it's
70 // initialized.
71 interpreter::UnstartedRuntime::Initialize();
72
73 for (std::unique_ptr<const DexFile>& dex_file : in) {
74 out->push_back(dex_file.release());
75 }
76
77 ClassLinker* class_linker = runtime->GetClassLinker();
78
79 jobject class_loader = class_linker->CreatePathClassLoader(self, *out);
80
81 // Need to register dex files to get a working dex cache.
82 for (const DexFile* dex_file : *out) {
83 ObjPtr<mirror::DexCache> dex_cache = class_linker->RegisterDexFile(
84 *dex_file, self->DecodeJObject(class_loader)->AsClassLoader());
85 CHECK(dex_cache != nullptr);
86 }
87
88 return class_loader;
89}
90
91struct MethodVerifierArgs : public CmdlineArgs {
92 protected:
93 using Base = CmdlineArgs;
94
Vladimir Marko8581e2a2019-02-06 15:54:55 +000095 ParseStatus ParseCustom(const char* raw_option,
96 size_t raw_option_length,
97 std::string* error_msg) override {
98 DCHECK_EQ(strlen(raw_option), raw_option_length);
Andreas Gampe85ac3602018-08-03 03:42:08 -070099 {
Vladimir Marko8581e2a2019-02-06 15:54:55 +0000100 ParseStatus base_parse = Base::ParseCustom(raw_option, raw_option_length, error_msg);
Andreas Gampe85ac3602018-08-03 03:42:08 -0700101 if (base_parse != kParseUnknownArgument) {
102 return base_parse;
103 }
104 }
105
Vladimir Marko8581e2a2019-02-06 15:54:55 +0000106 std::string_view option(raw_option, raw_option_length);
107 if (StartsWith(option, "--dex-file=")) {
108 dex_filename_ = raw_option + strlen("--dex-file=");
Andreas Gampe85ac3602018-08-03 03:42:08 -0700109 } else if (option == "--dex-file-verifier") {
110 dex_file_verifier_ = true;
111 } else if (option == "--verbose") {
112 method_verifier_verbose_ = true;
113 } else if (option == "--verbose-debug") {
114 method_verifier_verbose_debug_ = true;
Vladimir Marko8581e2a2019-02-06 15:54:55 +0000115 } else if (StartsWith(option, "--repetitions=")) {
Andreas Gampe85ac3602018-08-03 03:42:08 -0700116 char* end;
Vladimir Marko8581e2a2019-02-06 15:54:55 +0000117 repetitions_ = strtoul(raw_option + strlen("--repetitions="), &end, 10);
118 } else if (StartsWith(option, "--api-level=")) {
Andreas Gampe6cc23ac2018-08-24 15:22:43 -0700119 char* end;
Vladimir Marko8581e2a2019-02-06 15:54:55 +0000120 api_level_ = strtoul(raw_option + strlen("--api-level="), &end, 10);
Andreas Gampe85ac3602018-08-03 03:42:08 -0700121 } else {
122 return kParseUnknownArgument;
123 }
124
125 return kParseOk;
126 }
127
Roland Levillainf73caca2018-08-24 17:19:07 +0100128 ParseStatus ParseChecks(std::string* error_msg) override {
Andreas Gampe85ac3602018-08-03 03:42:08 -0700129 // Perform the parent checks.
130 ParseStatus parent_checks = Base::ParseChecks(error_msg);
131 if (parent_checks != kParseOk) {
132 return parent_checks;
133 }
134
135 // Perform our own checks.
136 if (dex_filename_ == nullptr) {
137 *error_msg = "--dex-filename not set";
138 return kParseError;
139 }
140
141 return kParseOk;
142 }
143
Andreas Gampefa6a1b02018-09-07 08:11:55 -0700144 std::string GetUsage() const override {
Andreas Gampe85ac3602018-08-03 03:42:08 -0700145 std::string usage;
146
147 usage +=
148 "Usage: method_verifier_cmd [options] ...\n"
149 // Dex file is required.
150 " --dex-file=<file.dex>: specifies an input dex file.\n"
151 " Example: --dex-file=app.apk\n"
152 " --dex-file-verifier: only run dex file verifier.\n"
153 " --verbose: use verbose verifier mode.\n"
154 " --verbose-debug: use verbose verifier debug mode.\n"
155 " --repetitions=<count>: repeat the verification count times.\n"
Andreas Gampe6cc23ac2018-08-24 15:22:43 -0700156 " --api-level=<level>: use API level for verification.\n"
Andreas Gampe85ac3602018-08-03 03:42:08 -0700157 "\n";
158
159 usage += Base::GetUsage();
160
161 return usage;
162 }
163
164 public:
165 const char* dex_filename_ = nullptr;
166
167 bool dex_file_verifier_ = false;
168
169 bool method_verifier_verbose_ = false;
170 bool method_verifier_verbose_debug_ = false;
171
172 size_t repetitions_ = 0u;
Andreas Gampe6cc23ac2018-08-24 15:22:43 -0700173
174 uint32_t api_level_ = 0u;
Andreas Gampe85ac3602018-08-03 03:42:08 -0700175};
176
177struct MethodVerifierMain : public CmdlineMain<MethodVerifierArgs> {
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100178 bool NeedsRuntime() override {
Andreas Gampe85ac3602018-08-03 03:42:08 -0700179 return true;
180 }
181
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100182 bool ExecuteWithoutRuntime() override {
Andreas Gampe85ac3602018-08-03 03:42:08 -0700183 LOG(FATAL) << "Unreachable";
184 UNREACHABLE();
185 }
186
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100187 bool ExecuteWithRuntime(Runtime* runtime) override {
Andreas Gampe85ac3602018-08-03 03:42:08 -0700188 CHECK(args_ != nullptr);
189
190 const size_t dex_reps = args_->dex_file_verifier_
191 // If we're focused on the dex file verifier, use the
192 // repetitions parameter.
193 ? std::max(static_cast<size_t>(1u), args_->repetitions_)
194 // Otherwise just load the dex files once.
195 : 1;
196
197 std::vector<std::unique_ptr<const DexFile>> unique_dex_files;
198 for (size_t i = 0; i != dex_reps; ++i) {
199 if (args_->dex_file_verifier_ && args_->repetitions_ != 0) {
200 LOG(INFO) << "Repetition " << (i + 1);
201 }
202 unique_dex_files.clear();
203 if (!LoadDexFile(args_->dex_filename_, &unique_dex_files)) {
204 return false;
205 }
206 }
207 if (args_->dex_file_verifier_) {
208 // We're done here.
209 return true;
210 }
211
212 ScopedObjectAccess soa(Thread::Current());
213 std::vector<const DexFile*> dex_files;
214 jobject class_loader = Install(runtime, unique_dex_files, &dex_files);
215 CHECK(class_loader != nullptr);
216
217 StackHandleScope<2> scope(soa.Self());
218 Handle<mirror::ClassLoader> h_loader = scope.NewHandle(
219 soa.Decode<mirror::ClassLoader>(class_loader));
220 MutableHandle<mirror::Class> h_klass(scope.NewHandle<mirror::Class>(nullptr));
221
222 if (args_->method_verifier_verbose_) {
223 gLogVerbosity.verifier = true;
224 }
225 if (args_->method_verifier_verbose_debug_) {
226 gLogVerbosity.verifier_debug = true;
227 }
228
229 const size_t verifier_reps = std::max(static_cast<size_t>(1u), args_->repetitions_);
230
231 ClassLinker* class_linker = runtime->GetClassLinker();
232 for (size_t i = 0; i != verifier_reps; ++i) {
233 if (args_->repetitions_ != 0) {
234 LOG(INFO) << "Repetition " << (i + 1);
235 }
236 for (const DexFile* dex_file : dex_files) {
237 for (ClassAccessor accessor : dex_file->GetClasses()) {
238 const char* descriptor = accessor.GetDescriptor();
239 h_klass.Assign(class_linker->FindClass(soa.Self(), descriptor, h_loader));
240 if (h_klass == nullptr || h_klass->IsErroneous()) {
241 if (args_->repetitions_ == 0) {
242 LOG(ERROR) << "Warning: could not load " << descriptor;
243 }
244 soa.Self()->ClearException();
245 continue;
246 }
247 std::string error_msg;
248 verifier::FailureKind res =
249 verifier::MethodVerifier::VerifyClass(soa.Self(),
250 h_klass.Get(),
251 runtime->GetCompilerCallbacks(),
252 true,
253 verifier::HardFailLogMode::kLogWarning,
Andreas Gampe6cc23ac2018-08-24 15:22:43 -0700254 args_->api_level_,
Andreas Gampe85ac3602018-08-03 03:42:08 -0700255 &error_msg);
256 if (args_->repetitions_ == 0) {
257 LOG(INFO) << descriptor << ": " << res << " " << error_msg;
258 }
259 }
260 }
261 }
262
263 return true;
264 }
265};
266
267} // namespace
268
269} // namespace art
270
271int main(int argc, char** argv) {
272 // Output all logging to stderr.
273 android::base::SetLogger(android::base::StderrLogger);
274
275 art::MethodVerifierMain main;
276 return main.Main(argc, argv);
277}