1 /*
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 <android-base/file.h>
18
19 #include <cstdint>
20 #include <iostream>
21 #include <set>
22 #include <sstream>
23
24 #include "base/mem_map.h"
25 #include "dex/code_item_accessors-inl.h"
26 #include "dex/dex_file.h"
27 #include "dex/dex_file_loader.h"
28 #include "dex/dex_instruction-inl.h"
29 #include "dexanalyze_bytecode.h"
30 #include "dexanalyze_experiments.h"
31 #include "dexanalyze_strings.h"
32
33 namespace art {
34 namespace dexanalyze {
35
36 class DexAnalyze {
37 static constexpr int kExitCodeUsageError = 1;
38 static constexpr int kExitCodeFailedToOpenFile = 2;
39 static constexpr int kExitCodeFailedToOpenDex = 3;
40 static constexpr int kExitCodeFailedToProcessDex = 4;
41
StdoutLogger(android::base::LogId,android::base::LogSeverity,const char *,const char *,unsigned int,const char * message)42 static void StdoutLogger(android::base::LogId,
43 android::base::LogSeverity,
44 const char*,
45 const char*,
46 unsigned int,
47 const char* message) {
48 std::cout << message << std::endl;
49 }
50
Usage(char ** argv)51 static int Usage(char** argv) {
52 LOG(ERROR)
53 << "Usage " << argv[0] << " [options] <dex files>\n"
54 << " [options] is a combination of the following\n"
55 << " -count-indices (Count dex indices accessed from code items)\n"
56 << " -analyze-strings (Analyze string data)\n"
57 << " -analyze-debug-info (Analyze debug info)\n"
58 << " -new-bytecode (Bytecode optimizations)\n"
59 << " -i (Ignore Dex checksum and verification failures)\n"
60 << " -a (Run all experiments)\n"
61 << " -n <int> (run experiment with 1 .. n as argument)\n"
62 << " -d (Dump on per Dex basis)\n"
63 << " -v (quiet(0) to everything(2))\n";
64 return kExitCodeUsageError;
65 }
66
67 struct Options {
Parseart::dexanalyze::DexAnalyze::Options68 int Parse(int argc, char** argv) {
69 int i;
70 for (i = 1; i < argc; ++i) {
71 const std::string arg = argv[i];
72 if (arg == "-i") {
73 verify_checksum_ = false;
74 run_dex_file_verifier_ = false;
75 } else if (arg == "-v") {
76 if (i + 1 >= argc) {
77 return Usage(argv);
78 }
79 std::istringstream iss(argv[i + 1]);
80 size_t verbose_level = 0u;
81 iss >> verbose_level;
82 if (verbose_level > static_cast<size_t>(VerboseLevel::kEverything)) {
83 return Usage(argv);
84 }
85 ++i;
86 verbose_level_ = static_cast<VerboseLevel>(verbose_level);
87 } else if (arg == "-a") {
88 run_all_experiments_ = true;
89 } else if (arg == "-n") {
90 if (i + 1 >= argc) {
91 return Usage(argv);
92 }
93 std::istringstream iss(argv[i + 1]);
94 iss >> experiment_max_;
95 ++i;
96 } else if (arg == "-count-indices") {
97 exp_count_indices_ = true;
98 } else if (arg == "-analyze-strings") {
99 exp_analyze_strings_ = true;
100 } else if (arg == "-analyze-debug-info") {
101 exp_debug_info_ = true;
102 } else if (arg == "-new-bytecode") {
103 exp_bytecode_ = true;
104 } else if (arg == "-d") {
105 dump_per_input_dex_ = true;
106 } else if (!arg.empty() && arg[0] == '-') {
107 return Usage(argv);
108 } else {
109 break;
110 }
111 }
112 filenames_.insert(filenames_.end(), argv + i, argv + argc);
113 if (filenames_.empty()) {
114 return Usage(argv);
115 }
116 return 0;
117 }
118
119 VerboseLevel verbose_level_ = VerboseLevel::kNormal;
120 bool verify_checksum_ = true;
121 bool run_dex_file_verifier_ = true;
122 bool dump_per_input_dex_ = false;
123 bool exp_count_indices_ = false;
124 bool exp_code_metrics_ = false;
125 bool exp_analyze_strings_ = false;
126 bool exp_debug_info_ = false;
127 bool exp_bytecode_ = false;
128 bool run_all_experiments_ = false;
129 uint64_t experiment_max_ = 1u;
130 std::vector<std::string> filenames_;
131 };
132
133 class Analysis {
134 public:
Analysis(const Options * options)135 explicit Analysis(const Options* options) : options_(options) {
136 if (options->run_all_experiments_ || options->exp_count_indices_) {
137 experiments_.emplace_back(new CountDexIndices);
138 }
139 if (options->run_all_experiments_ || options->exp_analyze_strings_) {
140 experiments_.emplace_back(new AnalyzeStrings);
141 }
142 if (options->run_all_experiments_ || options->exp_code_metrics_) {
143 experiments_.emplace_back(new CodeMetrics);
144 }
145 if (options->run_all_experiments_ || options->exp_debug_info_) {
146 experiments_.emplace_back(new AnalyzeDebugInfo);
147 }
148 if (options->run_all_experiments_ || options->exp_bytecode_) {
149 for (size_t i = 0; i < options->experiment_max_; ++i) {
150 uint64_t exp_value = 0u;
151 if (i == 0) {
152 exp_value = std::numeric_limits<uint64_t>::max();
153 } else if (i == 1) {
154 exp_value = 0u;
155 } else {
156 exp_value = 1u << (i - 2);
157 }
158 experiments_.emplace_back(new NewRegisterInstructions(exp_value));
159 }
160 }
161 for (const std::unique_ptr<Experiment>& experiment : experiments_) {
162 experiment->verbose_level_ = options->verbose_level_;
163 }
164 }
165
ProcessDexFiles(const std::vector<std::unique_ptr<const DexFile>> & dex_files)166 bool ProcessDexFiles(const std::vector<std::unique_ptr<const DexFile>>& dex_files) {
167 for (std::unique_ptr<Experiment>& experiment : experiments_) {
168 experiment->ProcessDexFiles(dex_files);
169 }
170 for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
171 total_size_ += dex_file->Size();
172 }
173 dex_count_ += dex_files.size();
174 return true;
175 }
176
Dump(std::ostream & os)177 void Dump(std::ostream& os) {
178 for (std::unique_ptr<Experiment>& experiment : experiments_) {
179 experiment->Dump(os, total_size_);
180 os << "\n";
181 }
182 }
183
184 const Options* const options_;
185 std::vector<std::unique_ptr<Experiment>> experiments_;
186 size_t dex_count_ = 0;
187 uint64_t total_size_ = 0u;
188 };
189
190 public:
Run(int argc,char ** argv)191 static int Run(int argc, char** argv) {
192 android::base::SetLogger(StdoutLogger);
193
194 Options options;
195 int result = options.Parse(argc, argv);
196 if (result != 0) {
197 return result;
198 }
199
200 DexFileLoaderErrorCode error_code;
201 std::string error_msg;
202 Analysis cumulative(&options);
203 for (const std::string& filename : options.filenames_) {
204 std::string content;
205 // TODO: once added, use an API to android::base to read a std::vector<uint8_t>.
206 if (!android::base::ReadFileToString(filename, &content)) {
207 LOG(ERROR) << "ReadFileToString failed for " + filename << std::endl;
208 return kExitCodeFailedToOpenFile;
209 }
210 std::vector<std::unique_ptr<const DexFile>> dex_files;
211 DexFileLoader dex_file_loader(
212 reinterpret_cast<const uint8_t*>(content.data()), content.size(), filename);
213 if (!dex_file_loader.Open(options.run_dex_file_verifier_,
214 options.verify_checksum_,
215 &error_code,
216 &error_msg,
217 &dex_files)) {
218 LOG(ERROR) << "OpenAll failed for " + filename << " with " << error_msg << std::endl;
219 return kExitCodeFailedToOpenDex;
220 }
221 if (options.dump_per_input_dex_) {
222 Analysis current(&options);
223 if (!current.ProcessDexFiles(dex_files)) {
224 LOG(ERROR) << "Failed to process " << filename << " with error " << error_msg;
225 return kExitCodeFailedToProcessDex;
226 }
227 LOG(INFO) << "Analysis for " << filename << std::endl;
228 current.Dump(LOG_STREAM(INFO));
229 }
230 cumulative.ProcessDexFiles(dex_files);
231 }
232 LOG(INFO) << "Cumulative analysis for " << cumulative.dex_count_ << " DEX files" << std::endl;
233 cumulative.Dump(LOG_STREAM(INFO));
234 return 0;
235 }
236 };
237
238 } // namespace dexanalyze
239 } // namespace art
240
main(int argc,char ** argv)241 int main(int argc, char** argv) {
242 art::MemMap::Init();
243 return art::dexanalyze::DexAnalyze::Run(argc, argv);
244 }
245
246