blob: 12674f5a5e61ac895ab35b104ccd700ba9dd20b7 [file] [log] [blame]
Jeff Haoec7f1a92017-03-13 16:24:24 -07001 /*
David Sehr7629f602016-08-07 16:01:51 -07002 * 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
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070025#include <fcntl.h>
David Sehr7629f602016-08-07 16:01:51 -070026#include <stdio.h>
27#include <string.h>
David Sehrcdcfde72016-09-26 07:44:04 -070028#include <sys/stat.h>
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070029#include <sys/types.h>
30#include <unistd.h>
David Sehr7629f602016-08-07 16:01:51 -070031
Andreas Gampe57943812017-12-06 21:39:13 -080032#include <android-base/logging.h>
33
34#include "base/logging.h" // For InitLogging.
David Sehr79e26072018-04-06 17:58:50 -070035#include "base/mem_map.h"
David Sehr82d046e2018-04-23 08:14:19 -070036#include "profile/profile_compilation_info.h"
David Sehr7629f602016-08-07 16:01:51 -070037
38namespace art {
39
40static const char* kProgramName = "dexlayout";
41
42/*
43 * Shows usage.
44 */
Andreas Gampe6142e582018-09-18 16:49:15 -070045static void Usage() {
Andreas Gampe221d9812018-01-22 17:48:56 -080046 LOG(ERROR) << "Copyright (C) 2016 The Android Open Source Project\n";
47 LOG(ERROR) << kProgramName
48 << ": [-a] [-c] [-d] [-e] [-f] [-h] [-i] [-l layout] [-o outfile] [-p profile]"
Matthew Caryd228d912018-09-07 11:09:39 +020049 " [-s] [-t] [-u] [-v] [-w directory] dexfile...\n";
Andreas Gampe221d9812018-01-22 17:48:56 -080050 LOG(ERROR) << " -a : display annotations";
51 LOG(ERROR) << " -b : build dex_ir";
52 LOG(ERROR) << " -c : verify checksum and exit";
53 LOG(ERROR) << " -d : disassemble code sections";
54 LOG(ERROR) << " -e : display exported items only";
55 LOG(ERROR) << " -f : display summary information from file header";
56 LOG(ERROR) << " -h : display file header details";
57 LOG(ERROR) << " -i : ignore checksum failures";
58 LOG(ERROR) << " -l : output layout, either 'plain' or 'xml'";
59 LOG(ERROR) << " -o : output file name (defaults to stdout)";
60 LOG(ERROR) << " -p : profile file name (defaults to no profile)";
61 LOG(ERROR) << " -s : visualize reference pattern";
62 LOG(ERROR) << " -t : display file section sizes";
Mathieu Chartier36f7df52018-08-28 17:59:53 -070063 LOG(ERROR) << " -u : update dex checksums";
Andreas Gampe221d9812018-01-22 17:48:56 -080064 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'";
David Sehr7629f602016-08-07 16:01:51 -070067}
68
David Sehr671af6c2018-05-17 11:00:35 -070069NO_RETURN static void Abort(const char* msg) {
70 LOG(ERROR) << msg;
71 exit(1);
72}
73
David Sehr7629f602016-08-07 16:01:51 -070074/*
75 * Main driver of the dexlayout utility.
76 */
77int DexlayoutDriver(int argc, char** argv) {
78 // Art specific set up.
David Sehr671af6c2018-05-17 11:00:35 -070079 InitLogging(argv, Abort);
David Sehr7629f602016-08-07 16:01:51 -070080 MemMap::Init();
81
Jeff Haoea7c6292016-11-14 18:10:16 -080082 Options options;
83 options.dump_ = true;
84 options.verbose_ = true;
David Sehr7629f602016-08-07 16:01:51 -070085 bool want_usage = false;
David Sehr7629f602016-08-07 16:01:51 -070086
87 // Parse all arguments.
Andreas Gampe8351aac2018-09-10 12:37:49 -070088 while (true) {
Mathieu Chartier36f7df52018-08-28 17:59:53 -070089 const int ic = getopt(argc, argv, "abcdefghil:o:p:stuvw:x:");
David Sehr7629f602016-08-07 16:01:51 -070090 if (ic < 0) {
91 break; // done
92 }
93 switch (ic) {
94 case 'a': // display annotations
Jeff Haoea7c6292016-11-14 18:10:16 -080095 options.show_annotations_ = true;
David Sehr7629f602016-08-07 16:01:51 -070096 break;
97 case 'b': // build dex_ir
Jeff Haoea7c6292016-11-14 18:10:16 -080098 options.build_dex_ir_ = true;
David Sehr7629f602016-08-07 16:01:51 -070099 break;
100 case 'c': // verify the checksum then exit
Jeff Haoea7c6292016-11-14 18:10:16 -0800101 options.checksum_only_ = true;
David Sehr7629f602016-08-07 16:01:51 -0700102 break;
103 case 'd': // disassemble Dalvik instructions
Jeff Haoea7c6292016-11-14 18:10:16 -0800104 options.disassemble_ = true;
David Sehr7629f602016-08-07 16:01:51 -0700105 break;
106 case 'e': // exported items only
Jeff Haoea7c6292016-11-14 18:10:16 -0800107 options.exports_only_ = true;
David Sehr7629f602016-08-07 16:01:51 -0700108 break;
109 case 'f': // display outer file header
Jeff Haoea7c6292016-11-14 18:10:16 -0800110 options.show_file_headers_ = true;
David Sehr7629f602016-08-07 16:01:51 -0700111 break;
David Sehr7629f602016-08-07 16:01:51 -0700112 case 'h': // display section headers, i.e. all meta-data
Jeff Haoea7c6292016-11-14 18:10:16 -0800113 options.show_section_headers_ = true;
David Sehr7629f602016-08-07 16:01:51 -0700114 break;
115 case 'i': // continue even if checksum is bad
Jeff Haoea7c6292016-11-14 18:10:16 -0800116 options.ignore_bad_checksum_ = true;
David Sehr7629f602016-08-07 16:01:51 -0700117 break;
118 case 'l': // layout
119 if (strcmp(optarg, "plain") == 0) {
Jeff Haoea7c6292016-11-14 18:10:16 -0800120 options.output_format_ = kOutputPlain;
David Sehr7629f602016-08-07 16:01:51 -0700121 } else if (strcmp(optarg, "xml") == 0) {
Jeff Haoea7c6292016-11-14 18:10:16 -0800122 options.output_format_ = kOutputXml;
123 options.verbose_ = false;
David Sehr7629f602016-08-07 16:01:51 -0700124 } else {
125 want_usage = true;
126 }
127 break;
128 case 'o': // output file
Jeff Haoea7c6292016-11-14 18:10:16 -0800129 options.output_file_name_ = optarg;
David Sehr7629f602016-08-07 16:01:51 -0700130 break;
David Sehrcdcfde72016-09-26 07:44:04 -0700131 case 'p': // profile file
Jeff Haoea7c6292016-11-14 18:10:16 -0800132 options.profile_file_name_ = optarg;
David Sehrcdcfde72016-09-26 07:44:04 -0700133 break;
134 case 's': // visualize access pattern
Jeff Haoea7c6292016-11-14 18:10:16 -0800135 options.visualize_pattern_ = true;
136 options.verbose_ = false;
David Sehrcdcfde72016-09-26 07:44:04 -0700137 break;
David Sehr93357492017-03-09 08:02:44 -0800138 case 't': // display section statistics
139 options.show_section_statistics_ = true;
140 options.verbose_ = false;
141 break;
Mathieu Chartier36f7df52018-08-28 17:59:53 -0700142 case 'u': // update checksum
143 options.update_checksum_ = true;
144 break;
Jeff Haoec7f1a92017-03-13 16:24:24 -0700145 case 'v': // verify output
146 options.verify_output_ = true;
147 break;
Jeff Haoa8621002016-10-04 18:13:44 +0000148 case 'w': // output dex files directory
Jeff Haoea7c6292016-11-14 18:10:16 -0800149 options.output_dex_directory_ = optarg;
Jeff Hao3ab96b42016-09-09 18:35:01 -0700150 break;
Mathieu Chartier5c362202018-01-17 14:52:55 -0800151 case 'x': // compact dex level
152 if (strcmp(optarg, "none") == 0) {
153 options.compact_dex_level_ = CompactDexLevel::kCompactDexLevelNone;
154 } else if (strcmp(optarg, "fast") == 0) {
155 options.compact_dex_level_ = CompactDexLevel::kCompactDexLevelFast;
156 } else {
157 want_usage = true;
158 }
159 break;
David Sehr7629f602016-08-07 16:01:51 -0700160 default:
161 want_usage = true;
162 break;
163 } // switch
164 } // while
165
166 // Detect early problems.
167 if (optind == argc) {
Andreas Gampe221d9812018-01-22 17:48:56 -0800168 LOG(ERROR) << "no file specified";
David Sehr7629f602016-08-07 16:01:51 -0700169 want_usage = true;
170 }
Jeff Haoea7c6292016-11-14 18:10:16 -0800171 if (options.checksum_only_ && options.ignore_bad_checksum_) {
Andreas Gampe221d9812018-01-22 17:48:56 -0800172 LOG(ERROR) << "Can't specify both -c and -i";
David Sehr7629f602016-08-07 16:01:51 -0700173 want_usage = true;
174 }
175 if (want_usage) {
176 Usage();
177 return 2;
178 }
179
180 // Open alternative output file.
Jeff Haoea7c6292016-11-14 18:10:16 -0800181 FILE* out_file = stdout;
182 if (options.output_file_name_) {
183 out_file = fopen(options.output_file_name_, "w");
184 if (!out_file) {
Andreas Gampe221d9812018-01-22 17:48:56 -0800185 PLOG(ERROR) << "Can't open " << options.output_file_name_;
David Sehr7629f602016-08-07 16:01:51 -0700186 return 1;
187 }
188 }
189
David Sehrcdcfde72016-09-26 07:44:04 -0700190 // Open profile file.
Andreas Gampe08ae77f2017-04-26 22:02:33 -0700191 std::unique_ptr<ProfileCompilationInfo> profile_info;
Jeff Haoea7c6292016-11-14 18:10:16 -0800192 if (options.profile_file_name_) {
David Sehr9d9227a2018-12-19 12:32:50 -0800193#ifdef _WIN32
194 int flags = O_RDONLY;
195#else
196 int flags = O_RDONLY | O_CLOEXEC;
197#endif
198 int profile_fd = open(options.profile_file_name_, flags);
David Sehrcdcfde72016-09-26 07:44:04 -0700199 if (profile_fd < 0) {
Andreas Gampe221d9812018-01-22 17:48:56 -0800200 PLOG(ERROR) << "Can't open " << options.profile_file_name_;
David Sehrcdcfde72016-09-26 07:44:04 -0700201 return 1;
202 }
Andreas Gampe08ae77f2017-04-26 22:02:33 -0700203 profile_info.reset(new ProfileCompilationInfo());
Jeff Haoea7c6292016-11-14 18:10:16 -0800204 if (!profile_info->Load(profile_fd)) {
Andreas Gampe221d9812018-01-22 17:48:56 -0800205 LOG(ERROR) << "Can't read profile info from " << options.profile_file_name_;
David Sehrcdcfde72016-09-26 07:44:04 -0700206 return 1;
207 }
208 }
David Sehr9d9227a2018-12-19 12:32:50 -0800209 PLOG(INFO) << "After opening profile file";
David Sehrcdcfde72016-09-26 07:44:04 -0700210
Jeff Haoea7c6292016-11-14 18:10:16 -0800211 // Create DexLayout instance.
Andreas Gampe9b031f72018-10-04 11:03:34 -0700212 DexLayout dex_layout(options, profile_info.get(), out_file, /*header=*/ nullptr);
Jeff Haoea7c6292016-11-14 18:10:16 -0800213
David Sehr7629f602016-08-07 16:01:51 -0700214 // Process all files supplied on command line.
215 int result = 0;
216 while (optind < argc) {
Jeff Haoea7c6292016-11-14 18:10:16 -0800217 result |= dex_layout.ProcessFile(argv[optind++]);
David Sehr7629f602016-08-07 16:01:51 -0700218 } // while
Andreas Gampe08ae77f2017-04-26 22:02:33 -0700219
220 if (options.output_file_name_) {
221 CHECK(out_file != nullptr && out_file != stdout);
222 fclose(out_file);
223 }
224
Andreas Gampe7c5acbb2018-09-20 13:54:52 -0700225 return result != 0 ? 1 : 0;
David Sehr7629f602016-08-07 16:01:51 -0700226}
227
228} // namespace art
229
230int main(int argc, char** argv) {
Andreas Gampe221d9812018-01-22 17:48:56 -0800231 // Output all logging to stderr.
232 android::base::SetLogger(android::base::StderrLogger);
233
David Sehr7629f602016-08-07 16:01:51 -0700234 return art::DexlayoutDriver(argc, argv);
235}