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