blob: 0ef6c06dffcf17bc895eaa1b0c21b956e40e56f4 [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
Roland Levillainf73caca2018-08-24 17:19:07 +010095 ParseStatus ParseCustom(const StringPiece& option, std::string* error_msg) override {
Andreas Gampe85ac3602018-08-03 03:42:08 -070096 {
97 ParseStatus base_parse = Base::ParseCustom(option, error_msg);
98 if (base_parse != kParseUnknownArgument) {
99 return base_parse;
100 }
101 }
102
103 if (option.starts_with("--dex-file=")) {
104 dex_filename_ = option.substr(strlen("--dex-file=")).data();
105 } else if (option == "--dex-file-verifier") {
106 dex_file_verifier_ = true;
107 } else if (option == "--verbose") {
108 method_verifier_verbose_ = true;
109 } else if (option == "--verbose-debug") {
110 method_verifier_verbose_debug_ = true;
111 } else if (option.starts_with("--repetitions=")) {
112 char* end;
113 repetitions_ = strtoul(option.substr(strlen("--repetitions=")).data(), &end, 10);
Andreas Gampe6cc23ac2018-08-24 15:22:43 -0700114 } else if (option.starts_with("--api-level=")) {
115 char* end;
116 api_level_ = strtoul(option.substr(strlen("--api-level=")).data(), &end, 10);
Andreas Gampe85ac3602018-08-03 03:42:08 -0700117 } else {
118 return kParseUnknownArgument;
119 }
120
121 return kParseOk;
122 }
123
Roland Levillainf73caca2018-08-24 17:19:07 +0100124 ParseStatus ParseChecks(std::string* error_msg) override {
Andreas Gampe85ac3602018-08-03 03:42:08 -0700125 // Perform the parent checks.
126 ParseStatus parent_checks = Base::ParseChecks(error_msg);
127 if (parent_checks != kParseOk) {
128 return parent_checks;
129 }
130
131 // Perform our own checks.
132 if (dex_filename_ == nullptr) {
133 *error_msg = "--dex-filename not set";
134 return kParseError;
135 }
136
137 return kParseOk;
138 }
139
Andreas Gampefa6a1b02018-09-07 08:11:55 -0700140 std::string GetUsage() const override {
Andreas Gampe85ac3602018-08-03 03:42:08 -0700141 std::string usage;
142
143 usage +=
144 "Usage: method_verifier_cmd [options] ...\n"
145 // Dex file is required.
146 " --dex-file=<file.dex>: specifies an input dex file.\n"
147 " Example: --dex-file=app.apk\n"
148 " --dex-file-verifier: only run dex file verifier.\n"
149 " --verbose: use verbose verifier mode.\n"
150 " --verbose-debug: use verbose verifier debug mode.\n"
151 " --repetitions=<count>: repeat the verification count times.\n"
Andreas Gampe6cc23ac2018-08-24 15:22:43 -0700152 " --api-level=<level>: use API level for verification.\n"
Andreas Gampe85ac3602018-08-03 03:42:08 -0700153 "\n";
154
155 usage += Base::GetUsage();
156
157 return usage;
158 }
159
160 public:
161 const char* dex_filename_ = nullptr;
162
163 bool dex_file_verifier_ = false;
164
165 bool method_verifier_verbose_ = false;
166 bool method_verifier_verbose_debug_ = false;
167
168 size_t repetitions_ = 0u;
Andreas Gampe6cc23ac2018-08-24 15:22:43 -0700169
170 uint32_t api_level_ = 0u;
Andreas Gampe85ac3602018-08-03 03:42:08 -0700171};
172
173struct MethodVerifierMain : public CmdlineMain<MethodVerifierArgs> {
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100174 bool NeedsRuntime() override {
Andreas Gampe85ac3602018-08-03 03:42:08 -0700175 return true;
176 }
177
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100178 bool ExecuteWithoutRuntime() override {
Andreas Gampe85ac3602018-08-03 03:42:08 -0700179 LOG(FATAL) << "Unreachable";
180 UNREACHABLE();
181 }
182
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100183 bool ExecuteWithRuntime(Runtime* runtime) override {
Andreas Gampe85ac3602018-08-03 03:42:08 -0700184 CHECK(args_ != nullptr);
185
186 const size_t dex_reps = args_->dex_file_verifier_
187 // If we're focused on the dex file verifier, use the
188 // repetitions parameter.
189 ? std::max(static_cast<size_t>(1u), args_->repetitions_)
190 // Otherwise just load the dex files once.
191 : 1;
192
193 std::vector<std::unique_ptr<const DexFile>> unique_dex_files;
194 for (size_t i = 0; i != dex_reps; ++i) {
195 if (args_->dex_file_verifier_ && args_->repetitions_ != 0) {
196 LOG(INFO) << "Repetition " << (i + 1);
197 }
198 unique_dex_files.clear();
199 if (!LoadDexFile(args_->dex_filename_, &unique_dex_files)) {
200 return false;
201 }
202 }
203 if (args_->dex_file_verifier_) {
204 // We're done here.
205 return true;
206 }
207
208 ScopedObjectAccess soa(Thread::Current());
209 std::vector<const DexFile*> dex_files;
210 jobject class_loader = Install(runtime, unique_dex_files, &dex_files);
211 CHECK(class_loader != nullptr);
212
213 StackHandleScope<2> scope(soa.Self());
214 Handle<mirror::ClassLoader> h_loader = scope.NewHandle(
215 soa.Decode<mirror::ClassLoader>(class_loader));
216 MutableHandle<mirror::Class> h_klass(scope.NewHandle<mirror::Class>(nullptr));
217
218 if (args_->method_verifier_verbose_) {
219 gLogVerbosity.verifier = true;
220 }
221 if (args_->method_verifier_verbose_debug_) {
222 gLogVerbosity.verifier_debug = true;
223 }
224
225 const size_t verifier_reps = std::max(static_cast<size_t>(1u), args_->repetitions_);
226
227 ClassLinker* class_linker = runtime->GetClassLinker();
228 for (size_t i = 0; i != verifier_reps; ++i) {
229 if (args_->repetitions_ != 0) {
230 LOG(INFO) << "Repetition " << (i + 1);
231 }
232 for (const DexFile* dex_file : dex_files) {
233 for (ClassAccessor accessor : dex_file->GetClasses()) {
234 const char* descriptor = accessor.GetDescriptor();
235 h_klass.Assign(class_linker->FindClass(soa.Self(), descriptor, h_loader));
236 if (h_klass == nullptr || h_klass->IsErroneous()) {
237 if (args_->repetitions_ == 0) {
238 LOG(ERROR) << "Warning: could not load " << descriptor;
239 }
240 soa.Self()->ClearException();
241 continue;
242 }
243 std::string error_msg;
244 verifier::FailureKind res =
245 verifier::MethodVerifier::VerifyClass(soa.Self(),
246 h_klass.Get(),
247 runtime->GetCompilerCallbacks(),
248 true,
249 verifier::HardFailLogMode::kLogWarning,
Andreas Gampe6cc23ac2018-08-24 15:22:43 -0700250 args_->api_level_,
Andreas Gampe85ac3602018-08-03 03:42:08 -0700251 &error_msg);
252 if (args_->repetitions_ == 0) {
253 LOG(INFO) << descriptor << ": " << res << " " << error_msg;
254 }
255 }
256 }
257 }
258
259 return true;
260 }
261};
262
263} // namespace
264
265} // namespace art
266
267int main(int argc, char** argv) {
268 // Output all logging to stderr.
269 android::base::SetLogger(android::base::StderrLogger);
270
271 art::MethodVerifierMain main;
272 return main.Main(argc, argv);
273}