1 /*
2 * Copyright (C) 2016 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 * Main driver of the dexlayout utility.
17 *
18 * This is a tool to read dex files into an internal representation,
19 * reorganize the representation, and emit dex files with a better
20 * file layout.
21 */
22
23 #include "dexlayout.h"
24
25 #include <fcntl.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #include <unistd.h>
31
32 #include <android-base/logging.h>
33
34 #include "base/logging.h" // For InitLogging.
35 #include "jit/profile_compilation_info.h"
36 #include "mem_map.h"
37 #include "runtime.h"
38
39 namespace art {
40
41 static const char* kProgramName = "dexlayout";
42
43 /*
44 * Shows usage.
45 */
Usage(void)46 static void Usage(void) {
47 LOG(ERROR) << "Copyright (C) 2016 The Android Open Source Project\n";
48 LOG(ERROR) << kProgramName
49 << ": [-a] [-c] [-d] [-e] [-f] [-h] [-i] [-l layout] [-o outfile] [-p profile]"
50 " [-s] [-t] [-v] [-w directory] dexfile...\n";
51 LOG(ERROR) << " -a : display annotations";
52 LOG(ERROR) << " -b : build dex_ir";
53 LOG(ERROR) << " -c : verify checksum and exit";
54 LOG(ERROR) << " -d : disassemble code sections";
55 LOG(ERROR) << " -e : display exported items only";
56 LOG(ERROR) << " -f : display summary information from file header";
57 LOG(ERROR) << " -h : display file header details";
58 LOG(ERROR) << " -i : ignore checksum failures";
59 LOG(ERROR) << " -l : output layout, either 'plain' or 'xml'";
60 LOG(ERROR) << " -o : output file name (defaults to stdout)";
61 LOG(ERROR) << " -p : profile file name (defaults to no profile)";
62 LOG(ERROR) << " -s : visualize reference pattern";
63 LOG(ERROR) << " -t : display file section sizes";
64 LOG(ERROR) << " -v : verify output file is canonical to input (IR level comparison)";
65 LOG(ERROR) << " -w : output dex directory";
66 LOG(ERROR) << " -x : compact dex generation level, either 'none' or 'fast'";
67 }
68
69 /*
70 * Main driver of the dexlayout utility.
71 */
DexlayoutDriver(int argc,char ** argv)72 int DexlayoutDriver(int argc, char** argv) {
73 // Art specific set up.
74 InitLogging(argv, Runtime::Abort);
75 MemMap::Init();
76
77 Options options;
78 options.dump_ = true;
79 options.verbose_ = true;
80 bool want_usage = false;
81
82 // Parse all arguments.
83 while (1) {
84 const int ic = getopt(argc, argv, "abcdefghil:o:p:stvw:x:");
85 if (ic < 0) {
86 break; // done
87 }
88 switch (ic) {
89 case 'a': // display annotations
90 options.show_annotations_ = true;
91 break;
92 case 'b': // build dex_ir
93 options.build_dex_ir_ = true;
94 break;
95 case 'c': // verify the checksum then exit
96 options.checksum_only_ = true;
97 break;
98 case 'd': // disassemble Dalvik instructions
99 options.disassemble_ = true;
100 break;
101 case 'e': // exported items only
102 options.exports_only_ = true;
103 break;
104 case 'f': // display outer file header
105 options.show_file_headers_ = true;
106 break;
107 case 'h': // display section headers, i.e. all meta-data
108 options.show_section_headers_ = true;
109 break;
110 case 'i': // continue even if checksum is bad
111 options.ignore_bad_checksum_ = true;
112 break;
113 case 'l': // layout
114 if (strcmp(optarg, "plain") == 0) {
115 options.output_format_ = kOutputPlain;
116 } else if (strcmp(optarg, "xml") == 0) {
117 options.output_format_ = kOutputXml;
118 options.verbose_ = false;
119 } else {
120 want_usage = true;
121 }
122 break;
123 case 'o': // output file
124 options.output_file_name_ = optarg;
125 break;
126 case 'p': // profile file
127 options.profile_file_name_ = optarg;
128 break;
129 case 's': // visualize access pattern
130 options.visualize_pattern_ = true;
131 options.verbose_ = false;
132 break;
133 case 't': // display section statistics
134 options.show_section_statistics_ = true;
135 options.verbose_ = false;
136 break;
137 case 'v': // verify output
138 options.verify_output_ = true;
139 break;
140 case 'w': // output dex files directory
141 options.output_dex_directory_ = optarg;
142 break;
143 case 'x': // compact dex level
144 if (strcmp(optarg, "none") == 0) {
145 options.compact_dex_level_ = CompactDexLevel::kCompactDexLevelNone;
146 } else if (strcmp(optarg, "fast") == 0) {
147 options.compact_dex_level_ = CompactDexLevel::kCompactDexLevelFast;
148 } else {
149 want_usage = true;
150 }
151 break;
152 default:
153 want_usage = true;
154 break;
155 } // switch
156 } // while
157
158 // Detect early problems.
159 if (optind == argc) {
160 LOG(ERROR) << "no file specified";
161 want_usage = true;
162 }
163 if (options.checksum_only_ && options.ignore_bad_checksum_) {
164 LOG(ERROR) << "Can't specify both -c and -i";
165 want_usage = true;
166 }
167 if (want_usage) {
168 Usage();
169 return 2;
170 }
171
172 // Open alternative output file.
173 FILE* out_file = stdout;
174 if (options.output_file_name_) {
175 out_file = fopen(options.output_file_name_, "w");
176 if (!out_file) {
177 PLOG(ERROR) << "Can't open " << options.output_file_name_;
178 return 1;
179 }
180 }
181
182 // Open profile file.
183 std::unique_ptr<ProfileCompilationInfo> profile_info;
184 if (options.profile_file_name_) {
185 int profile_fd = open(options.profile_file_name_, O_RDONLY);
186 if (profile_fd < 0) {
187 PLOG(ERROR) << "Can't open " << options.profile_file_name_;
188 return 1;
189 }
190 profile_info.reset(new ProfileCompilationInfo());
191 if (!profile_info->Load(profile_fd)) {
192 LOG(ERROR) << "Can't read profile info from " << options.profile_file_name_;
193 return 1;
194 }
195 }
196
197 // Create DexLayout instance.
198 DexLayout dex_layout(options, profile_info.get(), out_file, /*header*/ nullptr);
199
200 // Process all files supplied on command line.
201 int result = 0;
202 while (optind < argc) {
203 result |= dex_layout.ProcessFile(argv[optind++]);
204 } // while
205
206 if (options.output_file_name_) {
207 CHECK(out_file != nullptr && out_file != stdout);
208 fclose(out_file);
209 }
210
211 return result != 0;
212 }
213
214 } // namespace art
215
main(int argc,char ** argv)216 int main(int argc, char** argv) {
217 // Output all logging to stderr.
218 android::base::SetLogger(android::base::StderrLogger);
219
220 return art::DexlayoutDriver(argc, argv);
221 }
222