blob: 3f5243498b12ee4f9812b93f8e3928e14ad70152 [file] [log] [blame]
Elliott Hughes2faa5f12012-01-30 14:42:07 -08001/*
2 * Copyright (C) 2011 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 */
Brian Carlstrom78128a62011-09-15 17:21:19 -070016
17#include <stdio.h>
18#include <stdlib.h>
19
Brian Carlstrom27ec9612011-09-19 20:20:38 -070020#include <fstream>
21#include <iostream>
Igor Murashkin37743352014-11-13 14:38:00 -080022#include <map>
23#include <set>
Brian Carlstrom78128a62011-09-15 17:21:19 -070024#include <string>
Andreas Gampe54fc26c2014-09-04 21:47:42 -070025#include <unordered_map>
Andreas Gampe9fded872016-09-25 16:08:35 -070026#include <unordered_set>
Brian Carlstrom78128a62011-09-15 17:21:19 -070027#include <vector>
28
Andreas Gampe46ee31b2016-12-14 10:11:49 -080029#include "android-base/stringprintf.h"
Andreas Gampe9186ced2016-12-12 14:28:21 -080030#include "android-base/strings.h"
31
Ian Rogersd582fa42014-11-05 23:46:43 -080032#include "arch/instruction_set_features.h"
Mathieu Chartierc7853442015-03-27 14:35:38 -070033#include "art_field-inl.h"
Mathieu Chartiere401d142015-04-22 13:56:20 -070034#include "art_method-inl.h"
Vladimir Marko10c13562015-11-25 14:33:36 +000035#include "base/stl_util.h"
Elliott Hughes76160052012-12-12 16:31:20 -080036#include "base/unix_file/fd_file.h"
Brian Carlstrom78128a62011-09-15 17:21:19 -070037#include "class_linker.h"
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080038#include "class_linker-inl.h"
David Srbecky5d950762016-03-07 20:47:29 +000039#include "debug/elf_debug_writer.h"
40#include "debug/method_debug_info.h"
Ian Rogers4f6ad8a2013-03-18 15:27:28 -070041#include "dex_file-inl.h"
Christina Wadsworthbc233ac2016-06-20 15:01:32 -070042#include "dex_instruction-inl.h"
Ian Rogers3a5c1ce2012-02-29 10:06:46 -080043#include "disassembler.h"
Andreas Gampe54fc26c2014-09-04 21:47:42 -070044#include "elf_builder.h"
Ian Rogers1d54e732013-05-02 21:10:01 -070045#include "gc/space/image_space.h"
46#include "gc/space/large_object_space.h"
47#include "gc/space/space-inl.h"
Mathieu Chartier4a26f172016-01-26 14:26:18 -080048#include "image-inl.h"
Andreas Gampe9fded872016-09-25 16:08:35 -070049#include "imtable-inl.h"
Ian Rogers2bcb4a42012-11-08 10:39:18 -080050#include "indenter.h"
Andreas Gampeebfc1ac2016-09-29 19:50:27 -070051#include "interpreter/unstarted_runtime.h"
Vladimir Marko131980f2015-12-03 18:29:23 +000052#include "linker/buffered_output_stream.h"
53#include "linker/file_output_stream.h"
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080054#include "mirror/array-inl.h"
55#include "mirror/class-inl.h"
Vladimir Marko05792b92015-08-03 11:56:49 +010056#include "mirror/dex_cache-inl.h"
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080057#include "mirror/object-inl.h"
58#include "mirror/object_array-inl.h"
Brian Carlstrom700c8d32012-11-05 10:42:02 -080059#include "oat.h"
Vladimir Marko8a630572014-04-09 18:45:35 +010060#include "oat_file-inl.h"
Mathieu Chartierf9c6fc62015-10-07 11:44:05 -070061#include "oat_file_manager.h"
Elliott Hughese5448b52012-01-18 16:44:06 -080062#include "os.h"
Elliott Hughesa0e18062012-04-13 15:59:59 -070063#include "safe_map.h"
Mathieu Chartier0795f232016-09-27 18:43:30 -070064#include "scoped_thread_state_change-inl.h"
Nicolas Geoffray9c055782016-07-14 09:24:30 +000065#include "ScopedLocalRef.h"
Mathieu Chartierdc00f182016-07-14 10:10:44 -070066#include "stack_map.h"
67#include "string_reference.h"
Mathieu Chartierc22c59e2014-02-24 15:16:06 -080068#include "thread_list.h"
Andreas Gampe2ba88952016-04-29 17:52:07 -070069#include "type_lookup_table.h"
Nicolas Geoffray4acefd32016-10-24 13:14:58 +010070#include "vdex_file.h"
Ian Rogers2bcb4a42012-11-08 10:39:18 -080071#include "verifier/method_verifier.h"
Nicolas Geoffraye70dd562016-10-30 21:03:35 +000072#include "verifier/verifier_deps.h"
Andreas Gampe00b25f32014-09-17 21:49:05 -070073#include "well_known_classes.h"
Brian Carlstrom78128a62011-09-15 17:21:19 -070074
Igor Murashkin37743352014-11-13 14:38:00 -080075#include <sys/stat.h>
76#include "cmdline.h"
Brian Carlstrom78128a62011-09-15 17:21:19 -070077
Igor Murashkin37743352014-11-13 14:38:00 -080078namespace art {
Brian Carlstrom78128a62011-09-15 17:21:19 -070079
Andreas Gampe46ee31b2016-12-14 10:11:49 -080080using android::base::StringPrintf;
81
Mathieu Chartiere401d142015-04-22 13:56:20 -070082const char* image_methods_descriptions_[] = {
Ian Rogers19846512012-02-24 11:42:47 -080083 "kResolutionMethod",
Jeff Hao88474b42013-10-23 16:24:40 -070084 "kImtConflictMethod",
Mathieu Chartier2d2621a2014-10-23 16:48:06 -070085 "kImtUnimplementedMethod",
Vladimir Markofd36f1f2016-08-03 18:49:58 +010086 "kSaveAllCalleeSavesMethod",
87 "kSaveRefsOnlyMethod",
88 "kSaveRefsAndArgsMethod",
Vladimir Marko952dbb12016-07-28 12:01:51 +010089 "kSaveEverythingMethod",
Mathieu Chartiere401d142015-04-22 13:56:20 -070090};
91
92const char* image_roots_descriptions_[] = {
Brian Carlstrom58ae9412011-10-04 00:56:06 -070093 "kDexCaches",
Brian Carlstrom34f426c2011-10-04 12:58:02 -070094 "kClassRoots",
Vladimir Markoeca3eda2016-11-09 16:26:44 +000095 "kClassLoader",
Brian Carlstrom78128a62011-09-15 17:21:19 -070096};
97
Mathieu Chartierac8f4392015-08-27 13:54:20 -070098// Map is so that we don't allocate multiple dex files for the same OatDexFile.
99static std::map<const OatFile::OatDexFile*,
100 std::unique_ptr<const DexFile>> opened_dex_files;
101
102const DexFile* OpenDexFile(const OatFile::OatDexFile* oat_dex_file, std::string* error_msg) {
103 DCHECK(oat_dex_file != nullptr);
104 auto it = opened_dex_files.find(oat_dex_file);
105 if (it != opened_dex_files.end()) {
106 return it->second.get();
107 }
108 const DexFile* ret = oat_dex_file->OpenDexFile(error_msg).release();
109 opened_dex_files.emplace(oat_dex_file, std::unique_ptr<const DexFile>(ret));
110 return ret;
111}
112
Andreas Gampe2d8614b2016-03-07 16:31:34 -0800113template <typename ElfTypes>
David Srbeckybc90fd02015-04-22 19:40:27 +0100114class OatSymbolizer FINAL {
Andreas Gampe54fc26c2014-09-04 21:47:42 -0700115 public:
David Srbecky2fdd03c2016-03-10 15:32:37 +0000116 OatSymbolizer(const OatFile* oat_file, const std::string& output_name, bool no_bits) :
117 oat_file_(oat_file),
118 builder_(nullptr),
119 output_name_(output_name.empty() ? "symbolized.oat" : output_name),
120 no_bits_(no_bits) {
Andreas Gampe54fc26c2014-09-04 21:47:42 -0700121 }
122
Andreas Gampe54fc26c2014-09-04 21:47:42 -0700123 bool Symbolize() {
David Srbecky6d8c8f02015-10-26 10:57:09 +0000124 const InstructionSet isa = oat_file_->GetOatHeader().GetInstructionSet();
Andreas Gampe0415b4e2015-01-06 15:17:07 -0800125 std::unique_ptr<const InstructionSetFeatures> features = InstructionSetFeatures::FromBitmap(
David Srbecky5d811202016-03-08 13:21:22 +0000126 isa, oat_file_->GetOatHeader().GetInstructionSetFeaturesBitmap());
David Srbecky6d8c8f02015-10-26 10:57:09 +0000127
128 File* elf_file = OS::CreateEmptyFile(output_name_.c_str());
129 std::unique_ptr<BufferedOutputStream> output_stream(
Vladimir Marko10c13562015-11-25 14:33:36 +0000130 MakeUnique<BufferedOutputStream>(MakeUnique<FileOutputStream>(elf_file)));
Andreas Gampe0415b4e2015-01-06 15:17:07 -0800131 builder_.reset(new ElfBuilder<ElfTypes>(isa, features.get(), output_stream.get()));
David Srbecky6d8c8f02015-10-26 10:57:09 +0000132
133 builder_->Start();
134
135 auto* rodata = builder_->GetRoData();
136 auto* text = builder_->GetText();
137 auto* bss = builder_->GetBss();
David Srbecky6d8c8f02015-10-26 10:57:09 +0000138
David Srbecky6d8c8f02015-10-26 10:57:09 +0000139 const uint8_t* rodata_begin = oat_file_->Begin();
140 const size_t rodata_size = oat_file_->GetOatHeader().GetExecutableOffset();
David Srbecky2fdd03c2016-03-10 15:32:37 +0000141 if (no_bits_) {
142 rodata->WriteNoBitsSection(rodata_size);
143 } else {
144 rodata->Start();
145 rodata->WriteFully(rodata_begin, rodata_size);
146 rodata->End();
147 }
David Srbecky6d8c8f02015-10-26 10:57:09 +0000148
David Srbecky6d8c8f02015-10-26 10:57:09 +0000149 const uint8_t* text_begin = oat_file_->Begin() + rodata_size;
150 const size_t text_size = oat_file_->End() - text_begin;
David Srbecky2fdd03c2016-03-10 15:32:37 +0000151 if (no_bits_) {
152 text->WriteNoBitsSection(text_size);
153 } else {
154 text->Start();
155 text->WriteFully(text_begin, text_size);
156 text->End();
157 }
David Srbecky6d8c8f02015-10-26 10:57:09 +0000158
159 if (oat_file_->BssSize() != 0) {
David Srbecky5b1c2ca2016-01-25 17:32:41 +0000160 bss->WriteNoBitsSection(oat_file_->BssSize());
David Srbecky6d8c8f02015-10-26 10:57:09 +0000161 }
162
Douglas Leung316a2182015-09-17 15:26:25 -0700163 if (isa == kMips || isa == kMips64) {
164 builder_->WriteMIPSabiflagsSection();
165 }
Vladimir Markoaad75c62016-10-03 08:46:48 +0000166 builder_->PrepareDynamicSection(elf_file->GetPath(),
167 rodata_size,
168 text_size,
169 oat_file_->BssSize(),
170 oat_file_->BssRootsOffset());
Vladimir Marko944da602016-02-19 12:27:55 +0000171 builder_->WriteDynamicSection();
Andreas Gampe54fc26c2014-09-04 21:47:42 -0700172
David Srbecky5d950762016-03-07 20:47:29 +0000173 Walk();
174 for (const auto& trampoline : debug::MakeTrampolineInfos(oat_file_->GetOatHeader())) {
175 method_debug_infos_.push_back(trampoline);
176 }
Andreas Gampe54fc26c2014-09-04 21:47:42 -0700177
David Srbecky5d950762016-03-07 20:47:29 +0000178 debug::WriteDebugInfo(builder_.get(),
179 ArrayRef<const debug::MethodDebugInfo>(method_debug_infos_),
180 dwarf::DW_DEBUG_FRAME_FORMAT,
181 true /* write_oat_patches */);
Andreas Gampe54fc26c2014-09-04 21:47:42 -0700182
David Srbecky6d8c8f02015-10-26 10:57:09 +0000183 builder_->End();
Andreas Gampe54fc26c2014-09-04 21:47:42 -0700184
Vladimir Marko10c13562015-11-25 14:33:36 +0000185 return builder_->Good();
Andreas Gampe54fc26c2014-09-04 21:47:42 -0700186 }
187
David Srbecky5d950762016-03-07 20:47:29 +0000188 void Walk() {
Andreas Gampe54fc26c2014-09-04 21:47:42 -0700189 std::vector<const OatFile::OatDexFile*> oat_dex_files = oat_file_->GetOatDexFiles();
190 for (size_t i = 0; i < oat_dex_files.size(); i++) {
191 const OatFile::OatDexFile* oat_dex_file = oat_dex_files[i];
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700192 CHECK(oat_dex_file != nullptr);
David Srbecky5d950762016-03-07 20:47:29 +0000193 WalkOatDexFile(oat_dex_file);
Andreas Gampe54fc26c2014-09-04 21:47:42 -0700194 }
195 }
196
David Srbecky5d950762016-03-07 20:47:29 +0000197 void WalkOatDexFile(const OatFile::OatDexFile* oat_dex_file) {
Andreas Gampe54fc26c2014-09-04 21:47:42 -0700198 std::string error_msg;
Mathieu Chartierac8f4392015-08-27 13:54:20 -0700199 const DexFile* const dex_file = OpenDexFile(oat_dex_file, &error_msg);
200 if (dex_file == nullptr) {
Andreas Gampe54fc26c2014-09-04 21:47:42 -0700201 return;
202 }
203 for (size_t class_def_index = 0;
204 class_def_index < dex_file->NumClassDefs();
205 class_def_index++) {
Andreas Gampe54fc26c2014-09-04 21:47:42 -0700206 const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
207 OatClassType type = oat_class.GetType();
208 switch (type) {
209 case kOatClassAllCompiled:
210 case kOatClassSomeCompiled:
David Srbecky5d950762016-03-07 20:47:29 +0000211 WalkOatClass(oat_class, *dex_file, class_def_index);
Andreas Gampe54fc26c2014-09-04 21:47:42 -0700212 break;
213
214 case kOatClassNoneCompiled:
215 case kOatClassMax:
216 // Ignore.
217 break;
218 }
219 }
220 }
221
David Srbecky5d950762016-03-07 20:47:29 +0000222 void WalkOatClass(const OatFile::OatClass& oat_class,
223 const DexFile& dex_file,
224 uint32_t class_def_index) {
225 const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
Ian Rogers13735952014-10-08 12:43:28 -0700226 const uint8_t* class_data = dex_file.GetClassData(class_def);
Andreas Gampe54fc26c2014-09-04 21:47:42 -0700227 if (class_data == nullptr) { // empty class such as a marker interface?
228 return;
229 }
230 // Note: even if this is an interface or a native class, we still have to walk it, as there
231 // might be a static initializer.
232 ClassDataItemIterator it(dex_file, class_data);
Andreas Gampe54fc26c2014-09-04 21:47:42 -0700233 uint32_t class_method_idx = 0;
David Srbecky5d950762016-03-07 20:47:29 +0000234 for (; it.HasNextStaticField(); it.Next()) { /* skip */ }
235 for (; it.HasNextInstanceField(); it.Next()) { /* skip */ }
236 for (; it.HasNextDirectMethod() || it.HasNextVirtualMethod(); it.Next()) {
237 WalkOatMethod(oat_class.GetOatMethod(class_method_idx++),
238 dex_file,
239 class_def_index,
240 it.GetMemberIndex(),
241 it.GetMethodCodeItem(),
242 it.GetMethodAccessFlags());
Andreas Gampe54fc26c2014-09-04 21:47:42 -0700243 }
244 DCHECK(!it.HasNext());
245 }
246
David Srbecky5d950762016-03-07 20:47:29 +0000247 void WalkOatMethod(const OatFile::OatMethod& oat_method,
248 const DexFile& dex_file,
249 uint32_t class_def_index,
250 uint32_t dex_method_index,
251 const DexFile::CodeItem* code_item,
252 uint32_t method_access_flags) {
Andreas Gampe54fc26c2014-09-04 21:47:42 -0700253 if ((method_access_flags & kAccAbstract) != 0) {
254 // Abstract method, no code.
255 return;
256 }
David Srbecky5d950762016-03-07 20:47:29 +0000257 const OatHeader& oat_header = oat_file_->GetOatHeader();
258 const OatQuickMethodHeader* method_header = oat_method.GetOatQuickMethodHeader();
259 if (method_header == nullptr || method_header->GetCodeSize() == 0) {
Andreas Gampe54fc26c2014-09-04 21:47:42 -0700260 // No code.
261 return;
262 }
263
David Srbeckya1b4c5f2016-03-31 18:17:59 +0100264 uint32_t entry_point = oat_method.GetCodeOffset() - oat_header.GetExecutableOffset();
265 // Clear Thumb2 bit.
266 const void* code_address = EntryPointToCodePointer(reinterpret_cast<void*>(entry_point));
267
David Srbecky5d950762016-03-07 20:47:29 +0000268 debug::MethodDebugInfo info = debug::MethodDebugInfo();
269 info.trampoline_name = nullptr;
270 info.dex_file = &dex_file;
271 info.class_def_index = class_def_index;
272 info.dex_method_index = dex_method_index;
273 info.access_flags = method_access_flags;
274 info.code_item = code_item;
275 info.isa = oat_header.GetInstructionSet();
276 info.deduped = !seen_offsets_.insert(oat_method.GetCodeOffset()).second;
277 info.is_native_debuggable = oat_header.IsNativeDebuggable();
278 info.is_optimized = method_header->IsOptimized();
279 info.is_code_address_text_relative = true;
David Srbeckya1b4c5f2016-03-31 18:17:59 +0100280 info.code_address = reinterpret_cast<uintptr_t>(code_address);
David Srbecky5d950762016-03-07 20:47:29 +0000281 info.code_size = method_header->GetCodeSize();
282 info.frame_size_in_bytes = method_header->GetFrameSizeInBytes();
283 info.code_info = info.is_optimized ? method_header->GetOptimizedCodeInfoPtr() : nullptr;
284 info.cfi = ArrayRef<uint8_t>();
285 method_debug_infos_.push_back(info);
Andreas Gampe54fc26c2014-09-04 21:47:42 -0700286 }
287
Andreas Gampe54fc26c2014-09-04 21:47:42 -0700288 private:
Andreas Gampe54fc26c2014-09-04 21:47:42 -0700289 const OatFile* oat_file_;
Andreas Gampe2d8614b2016-03-07 16:31:34 -0800290 std::unique_ptr<ElfBuilder<ElfTypes> > builder_;
David Srbecky5d950762016-03-07 20:47:29 +0000291 std::vector<debug::MethodDebugInfo> method_debug_infos_;
292 std::unordered_set<uint32_t> seen_offsets_;
Ian Rogers0279ebb2014-10-08 17:27:48 -0700293 const std::string output_name_;
David Srbecky2fdd03c2016-03-10 15:32:37 +0000294 bool no_bits_;
Andreas Gampe54fc26c2014-09-04 21:47:42 -0700295};
296
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -0700297class OatDumperOptions {
298 public:
Vladimir Marko9d07e3d2016-03-31 12:02:28 +0100299 OatDumperOptions(bool dump_vmap,
Roland Levillainf2650d12015-05-28 14:53:28 +0100300 bool dump_code_info_stack_maps,
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -0700301 bool disassemble_code,
Andreas Gampe00b25f32014-09-17 21:49:05 -0700302 bool absolute_addresses,
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -0800303 const char* class_filter,
304 const char* method_filter,
305 bool list_classes,
306 bool list_methods,
David Brazdilc03d7b62016-03-02 12:18:03 +0000307 bool dump_header_only,
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -0800308 const char* export_dex_location,
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -0800309 const char* app_image,
310 const char* app_oat,
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -0800311 uint32_t addr2instr)
Vladimir Marko9d07e3d2016-03-31 12:02:28 +0100312 : dump_vmap_(dump_vmap),
Roland Levillainf2650d12015-05-28 14:53:28 +0100313 dump_code_info_stack_maps_(dump_code_info_stack_maps),
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -0700314 disassemble_code_(disassemble_code),
Andreas Gampe00b25f32014-09-17 21:49:05 -0700315 absolute_addresses_(absolute_addresses),
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -0800316 class_filter_(class_filter),
Nicolas Geoffray3fcd2202014-11-12 18:02:36 +0000317 method_filter_(method_filter),
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -0800318 list_classes_(list_classes),
319 list_methods_(list_methods),
David Brazdilc03d7b62016-03-02 12:18:03 +0000320 dump_header_only_(dump_header_only),
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -0800321 export_dex_location_(export_dex_location),
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -0800322 app_image_(app_image),
323 app_oat_(app_oat),
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -0800324 addr2instr_(addr2instr),
Igor Murashkin37743352014-11-13 14:38:00 -0800325 class_loader_(nullptr) {}
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -0700326
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -0700327 const bool dump_vmap_;
Roland Levillainf2650d12015-05-28 14:53:28 +0100328 const bool dump_code_info_stack_maps_;
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -0700329 const bool disassemble_code_;
330 const bool absolute_addresses_;
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -0800331 const char* const class_filter_;
Nicolas Geoffray3fcd2202014-11-12 18:02:36 +0000332 const char* const method_filter_;
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -0800333 const bool list_classes_;
334 const bool list_methods_;
David Brazdilc03d7b62016-03-02 12:18:03 +0000335 const bool dump_header_only_;
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -0800336 const char* const export_dex_location_;
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -0800337 const char* const app_image_;
338 const char* const app_oat_;
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -0800339 uint32_t addr2instr_;
Andreas Gampe00b25f32014-09-17 21:49:05 -0700340 Handle<mirror::ClassLoader>* class_loader_;
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -0700341};
342
Elliott Hughese3c845c2012-02-28 17:23:01 -0800343class OatDumper {
Brian Carlstromaded5f72011-10-07 17:15:04 -0700344 public:
Roland Levillain3887c462015-08-12 18:15:42 +0100345 OatDumper(const OatFile& oat_file, const OatDumperOptions& options)
Nicolas Geoffray9583fbc2014-02-28 15:21:07 +0000346 : oat_file_(oat_file),
Elliott Hughesa72ec822012-03-05 17:12:22 -0800347 oat_dex_files_(oat_file.GetOatDexFiles()),
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -0700348 options_(options),
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -0800349 resolved_addr2instr_(0),
Mathieu Chartiera7dd0382014-11-20 17:08:58 -0800350 instruction_set_(oat_file_.GetOatHeader().GetInstructionSet()),
351 disassembler_(Disassembler::Create(instruction_set_,
Andreas Gampe372f3a32016-08-19 10:49:06 -0700352 new DisassemblerOptions(
353 options_.absolute_addresses_,
354 oat_file.Begin(),
355 oat_file.End(),
356 true /* can_read_literals_ */,
357 Is64BitInstructionSet(instruction_set_)
358 ? &Thread::DumpThreadOffset<PointerSize::k64>
359 : &Thread::DumpThreadOffset<PointerSize::k32>))) {
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -0800360 CHECK(options_.class_loader_ != nullptr);
361 CHECK(options_.class_filter_ != nullptr);
362 CHECK(options_.method_filter_ != nullptr);
Ian Rogers3a5c1ce2012-02-29 10:06:46 -0800363 AddAllOffsets();
364 }
365
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -0700366 ~OatDumper() {
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -0700367 delete disassembler_;
368 }
369
Mathieu Chartiera7dd0382014-11-20 17:08:58 -0800370 InstructionSet GetInstructionSet() {
371 return instruction_set_;
372 }
373
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -0700374 bool Dump(std::ostream& os) {
375 bool success = true;
Ian Rogers3a5c1ce2012-02-29 10:06:46 -0800376 const OatHeader& oat_header = oat_file_.GetOatHeader();
Brian Carlstromaded5f72011-10-07 17:15:04 -0700377
378 os << "MAGIC:\n";
379 os << oat_header.GetMagic() << "\n\n";
380
Jeff Hao4b07a6e2016-01-15 12:50:44 -0800381 os << "LOCATION:\n";
382 os << oat_file_.GetLocation() << "\n\n";
383
Brian Carlstromaded5f72011-10-07 17:15:04 -0700384 os << "CHECKSUM:\n";
Elliott Hughesed2adb62012-02-29 14:41:01 -0800385 os << StringPrintf("0x%08x\n\n", oat_header.GetChecksum());
Brian Carlstromaded5f72011-10-07 17:15:04 -0700386
Elliott Hughesa72ec822012-03-05 17:12:22 -0800387 os << "INSTRUCTION SET:\n";
388 os << oat_header.GetInstructionSet() << "\n\n";
389
Ian Rogers6f3dbba2014-10-14 17:41:57 -0700390 {
391 std::unique_ptr<const InstructionSetFeatures> features(
392 InstructionSetFeatures::FromBitmap(oat_header.GetInstructionSet(),
393 oat_header.GetInstructionSetFeaturesBitmap()));
394 os << "INSTRUCTION SET FEATURES:\n";
395 os << features->GetFeatureString() << "\n\n";
396 }
Dave Allison70202782013-10-22 17:52:19 -0700397
Brian Carlstromaded5f72011-10-07 17:15:04 -0700398 os << "DEX FILE COUNT:\n";
399 os << oat_header.GetDexFileCount() << "\n\n";
400
Brian Carlstrom2ec65202014-03-03 15:16:37 -0800401#define DUMP_OAT_HEADER_OFFSET(label, offset) \
402 os << label " OFFSET:\n"; \
403 os << StringPrintf("0x%08x", oat_header.offset()); \
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -0800404 if (oat_header.offset() != 0 && options_.absolute_addresses_) { \
Brian Carlstrom2ec65202014-03-03 15:16:37 -0800405 os << StringPrintf(" (%p)", oat_file_.Begin() + oat_header.offset()); \
406 } \
407 os << StringPrintf("\n\n");
408
409 DUMP_OAT_HEADER_OFFSET("EXECUTABLE", GetExecutableOffset);
410 DUMP_OAT_HEADER_OFFSET("INTERPRETER TO INTERPRETER BRIDGE",
411 GetInterpreterToInterpreterBridgeOffset);
412 DUMP_OAT_HEADER_OFFSET("INTERPRETER TO COMPILED CODE BRIDGE",
413 GetInterpreterToCompiledCodeBridgeOffset);
414 DUMP_OAT_HEADER_OFFSET("JNI DLSYM LOOKUP",
415 GetJniDlsymLookupOffset);
Brian Carlstrom2ec65202014-03-03 15:16:37 -0800416 DUMP_OAT_HEADER_OFFSET("QUICK GENERIC JNI TRAMPOLINE",
417 GetQuickGenericJniTrampolineOffset);
418 DUMP_OAT_HEADER_OFFSET("QUICK IMT CONFLICT TRAMPOLINE",
419 GetQuickImtConflictTrampolineOffset);
420 DUMP_OAT_HEADER_OFFSET("QUICK RESOLUTION TRAMPOLINE",
421 GetQuickResolutionTrampolineOffset);
422 DUMP_OAT_HEADER_OFFSET("QUICK TO INTERPRETER BRIDGE",
423 GetQuickToInterpreterBridgeOffset);
424#undef DUMP_OAT_HEADER_OFFSET
Brian Carlstromaded5f72011-10-07 17:15:04 -0700425
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -0700426 os << "IMAGE PATCH DELTA:\n";
427 os << StringPrintf("%d (0x%08x)\n\n",
428 oat_header.GetImagePatchDelta(),
429 oat_header.GetImagePatchDelta());
Alex Lighta59dd802014-07-02 16:28:08 -0700430
Brian Carlstrom28db0122012-10-18 16:20:41 -0700431 os << "IMAGE FILE LOCATION OAT CHECKSUM:\n";
432 os << StringPrintf("0x%08x\n\n", oat_header.GetImageFileLocationOatChecksum());
433
434 os << "IMAGE FILE LOCATION OAT BEGIN:\n";
Brian Carlstrom700c8d32012-11-05 10:42:02 -0800435 os << StringPrintf("0x%08x\n\n", oat_header.GetImageFileLocationOatDataBegin());
Brian Carlstrom81f3ca12012-03-17 00:27:35 -0700436
Andreas Gampe22f8e5c2014-07-09 11:38:21 -0700437 // Print the key-value store.
438 {
439 os << "KEY VALUE STORE:\n";
440 size_t index = 0;
441 const char* key;
442 const char* value;
443 while (oat_header.GetStoreKeyValuePairByIndex(index, &key, &value)) {
444 os << key << " = " << value << "\n";
445 index++;
446 }
447 os << "\n";
448 }
Brian Carlstrom81f3ca12012-03-17 00:27:35 -0700449
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -0800450 if (options_.absolute_addresses_) {
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -0700451 os << "BEGIN:\n";
452 os << reinterpret_cast<const void*>(oat_file_.Begin()) << "\n\n";
Brian Carlstromaded5f72011-10-07 17:15:04 -0700453
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -0700454 os << "END:\n";
455 os << reinterpret_cast<const void*>(oat_file_.End()) << "\n\n";
456 }
457
458 os << "SIZE:\n";
459 os << oat_file_.Size() << "\n\n";
Brian Carlstromaded5f72011-10-07 17:15:04 -0700460
461 os << std::flush;
462
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -0800463 // If set, adjust relative address to be searched
464 if (options_.addr2instr_ != 0) {
465 resolved_addr2instr_ = options_.addr2instr_ + oat_header.GetExecutableOffset();
466 os << "SEARCH ADDRESS (executable offset + input):\n";
467 os << StringPrintf("0x%08x\n\n", resolved_addr2instr_);
468 }
469
Mathieu Chartierdc00f182016-07-14 10:10:44 -0700470 // Dumping the dex file overview is compact enough to do even if header only.
471 DexFileData cumulative;
472 for (size_t i = 0; i < oat_dex_files_.size(); i++) {
473 const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
474 CHECK(oat_dex_file != nullptr);
475 std::string error_msg;
476 const DexFile* const dex_file = OpenDexFile(oat_dex_file, &error_msg);
477 if (dex_file == nullptr) {
478 os << "Failed to open dex file '" << oat_dex_file->GetDexFileLocation() << "': "
479 << error_msg;
480 continue;
481 }
482 DexFileData data(*dex_file);
483 os << "Dex file data for " << dex_file->GetLocation() << "\n";
484 data.Dump(os);
485 os << "\n";
486 cumulative.Add(data);
487 }
488 os << "Cumulative dex file data\n";
489 cumulative.Dump(os);
490 os << "\n";
491
David Brazdilc03d7b62016-03-02 12:18:03 +0000492 if (!options_.dump_header_only_) {
Nicolas Geoffraye70dd562016-10-30 21:03:35 +0000493 VariableIndentationOutputStream vios(&os);
494 VdexFile::Header vdex_header = oat_file_.GetVdexFile()->GetHeader();
495 if (vdex_header.IsValid()) {
496 std::string error_msg;
497 std::vector<const DexFile*> dex_files;
498 for (size_t i = 0; i < oat_dex_files_.size(); i++) {
499 const DexFile* dex_file = OpenDexFile(oat_dex_files_[i], &error_msg);
500 if (dex_file == nullptr) {
501 os << "Error opening dex file: " << error_msg << std::endl;
502 return false;
503 }
504 dex_files.push_back(dex_file);
505 }
506 verifier::VerifierDeps deps(dex_files, oat_file_.GetVdexFile()->GetVerifierDepsData());
507 deps.Dump(&vios);
508 } else {
509 os << "UNRECOGNIZED vdex file, magic "
510 << vdex_header.GetMagic()
511 << ", version "
512 << vdex_header.GetVersion()
513 << "\n";
514 }
David Brazdilc03d7b62016-03-02 12:18:03 +0000515 for (size_t i = 0; i < oat_dex_files_.size(); i++) {
516 const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
517 CHECK(oat_dex_file != nullptr);
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -0800518
David Brazdilc03d7b62016-03-02 12:18:03 +0000519 // If file export selected skip file analysis
520 if (options_.export_dex_location_) {
521 if (!ExportDexFile(os, *oat_dex_file)) {
522 success = false;
523 }
524 } else {
525 if (!DumpOatDexFile(os, *oat_dex_file)) {
526 success = false;
527 }
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -0800528 }
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -0700529 }
Brian Carlstromaded5f72011-10-07 17:15:04 -0700530 }
David Brazdilc03d7b62016-03-02 12:18:03 +0000531
Mathieu Chartier5e7c6a92017-01-17 16:38:30 -0800532 {
533 os << "OAT FILE STATS:\n";
534 VariableIndentationOutputStream vios(&os);
535 stats_.Dump(vios);
536 }
537
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -0700538 os << std::flush;
539 return success;
Brian Carlstromaded5f72011-10-07 17:15:04 -0700540 }
541
Ian Rogers3a5c1ce2012-02-29 10:06:46 -0800542 size_t ComputeSize(const void* oat_data) {
Ian Rogers13735952014-10-08 12:43:28 -0700543 if (reinterpret_cast<const uint8_t*>(oat_data) < oat_file_.Begin() ||
544 reinterpret_cast<const uint8_t*>(oat_data) > oat_file_.End()) {
Ian Rogers3a5c1ce2012-02-29 10:06:46 -0800545 return 0; // Address not in oat file
546 }
Ian Rogersef7d42f2014-01-06 12:55:46 -0800547 uintptr_t begin_offset = reinterpret_cast<uintptr_t>(oat_data) -
548 reinterpret_cast<uintptr_t>(oat_file_.Begin());
549 auto it = offsets_.upper_bound(begin_offset);
Ian Rogers3a5c1ce2012-02-29 10:06:46 -0800550 CHECK(it != offsets_.end());
Ian Rogersef7d42f2014-01-06 12:55:46 -0800551 uintptr_t end_offset = *it;
Ian Rogers3a5c1ce2012-02-29 10:06:46 -0800552 return end_offset - begin_offset;
553 }
554
Mathieu Chartiera7dd0382014-11-20 17:08:58 -0800555 InstructionSet GetOatInstructionSet() {
Brian Carlstromf8bbb842012-03-14 03:01:42 -0700556 return oat_file_.GetOatHeader().GetInstructionSet();
557 }
558
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700559 const void* GetQuickOatCode(ArtMethod* m) REQUIRES_SHARED(Locks::mutator_lock_) {
Ian Rogers3a5c1ce2012-02-29 10:06:46 -0800560 for (size_t i = 0; i < oat_dex_files_.size(); i++) {
561 const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
Ian Rogers8d31bbd2013-10-13 10:44:14 -0700562 CHECK(oat_dex_file != nullptr);
563 std::string error_msg;
Mathieu Chartierac8f4392015-08-27 13:54:20 -0700564 const DexFile* const dex_file = OpenDexFile(oat_dex_file, &error_msg);
565 if (dex_file == nullptr) {
Ian Rogers8d31bbd2013-10-13 10:44:14 -0700566 LOG(WARNING) << "Failed to open dex file '" << oat_dex_file->GetDexFileLocation()
567 << "': " << error_msg;
568 } else {
Mathieu Chartiere7c9a8c2014-11-06 16:35:45 -0800569 const char* descriptor = m->GetDeclaringClassDescriptor();
Ian Rogers8b2c0b92013-09-19 02:56:49 -0700570 const DexFile::ClassDef* class_def =
David Sehr9aa352e2016-09-15 18:13:52 -0700571 OatDexFile::FindClassDef(*dex_file, descriptor, ComputeModifiedUtf8Hash(descriptor));
Andreas Gampe2ed8def2014-08-28 14:41:02 -0700572 if (class_def != nullptr) {
Ian Rogers8b2c0b92013-09-19 02:56:49 -0700573 uint16_t class_def_index = dex_file->GetIndexForClassDef(*class_def);
Vladimir Markod3c5beb2014-04-11 16:32:51 +0100574 const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
Ian Rogers3a5c1ce2012-02-29 10:06:46 -0800575 size_t method_index = m->GetMethodIndex();
Vladimir Markod3c5beb2014-04-11 16:32:51 +0100576 return oat_class.GetOatMethod(method_index).GetQuickCode();
Ian Rogers3a5c1ce2012-02-29 10:06:46 -0800577 }
578 }
579 }
Andreas Gampe2ed8def2014-08-28 14:41:02 -0700580 return nullptr;
Ian Rogers3a5c1ce2012-02-29 10:06:46 -0800581 }
582
Mathieu Chartier5e7c6a92017-01-17 16:38:30 -0800583 struct Stats {
584 enum ByteKind {
585 kByteKindCode,
586 kByteKindQuickMethodHeader,
587 kByteKindCodeInfoLocationCatalog,
588 kByteKindCodeInfoDexRegisterMap,
589 kByteKindCodeInfoInlineInfo,
590 kByteKindCodeInfoEncoding,
591 kByteKindCodeInfoOther,
592 kByteKindStackMapNativePc,
593 kByteKindStackMapDexPc,
594 kByteKindStackMapDexRegisterMap,
595 kByteKindStackMapInlineInfo,
596 kByteKindStackMapRegisterMask,
597 kByteKindStackMapMask,
598 kByteKindStackMapOther,
599 kByteKindCount,
600 kByteKindStackMapFirst = kByteKindCodeInfoOther,
601 kByteKindStackMapLast = kByteKindStackMapOther,
602 };
603 int64_t bits[kByteKindCount] = {};
604 // Since code has deduplication, seen tracks already seen pointers to avoid double counting
605 // deduplicated code and tables.
606 std::unordered_set<const void*> seen;
607
608 // Returns true if it was newly added.
609 bool AddBitsIfUnique(ByteKind kind, int64_t count, const void* address) {
610 if (seen.insert(address).second == true) {
611 // True means the address was not already in the set.
612 AddBits(kind, count);
613 return true;
614 }
615 return false;
616 }
617
618 void AddBits(ByteKind kind, int64_t count) {
619 bits[kind] += count;
620 }
621
622 void Dump(VariableIndentationOutputStream& os) {
623 const int64_t sum = std::accumulate(bits, bits + kByteKindCount, 0u);
624 os.Stream() << "Dumping cumulative use of " << sum / kBitsPerByte << " accounted bytes\n";
625 if (sum > 0) {
626 const int64_t stack_map_bits = std::accumulate(bits + kByteKindStackMapFirst,
627 bits + kByteKindStackMapLast + 1,
628 0u);
629 Dump(os, "Code ", bits[kByteKindCode], sum);
630 Dump(os, "QuickMethodHeader ", bits[kByteKindQuickMethodHeader], sum);
631 Dump(os, "CodeInfoEncoding ", bits[kByteKindCodeInfoEncoding], sum);
632 Dump(os, "CodeInfoLocationCatalog ", bits[kByteKindCodeInfoLocationCatalog], sum);
633 Dump(os, "CodeInfoDexRegisterMap ", bits[kByteKindCodeInfoDexRegisterMap], sum);
634 Dump(os, "CodeInfoInlineInfo ", bits[kByteKindCodeInfoInlineInfo], sum);
635 Dump(os, "CodeInfoStackMap ", stack_map_bits, sum);
636 {
637 ScopedIndentation indent1(&os);
638 Dump(os,
639 "StackMapNativePc ",
640 bits[kByteKindStackMapNativePc],
641 stack_map_bits,
642 "stack map");
643 Dump(os,
644 "StackMapDexPcEncoding ",
645 bits[kByteKindStackMapDexPc],
646 stack_map_bits,
647 "stack map");
648 Dump(os,
649 "StackMapDexRegisterMap ",
650 bits[kByteKindStackMapDexRegisterMap],
651 stack_map_bits,
652 "stack map");
653 Dump(os,
654 "StackMapInlineInfo ",
655 bits[kByteKindStackMapInlineInfo],
656 stack_map_bits,
657 "stack map");
658 Dump(os,
659 "StackMapRegisterMaskEncoding ",
660 bits[kByteKindStackMapRegisterMask],
661 stack_map_bits,
662 "stack map");
663 Dump(os,
664 "StackMapMask ",
665 bits[kByteKindStackMapMask],
666 stack_map_bits,
667 "stack map");
668 Dump(os,
669 "StackMapOther ",
670 bits[kByteKindStackMapOther],
671 stack_map_bits,
672 "stack map");
673 }
674 }
675 os.Stream() << "\n" << std::flush;
676 }
677
678 private:
679 void Dump(VariableIndentationOutputStream& os,
680 const char* name,
681 int64_t size,
682 int64_t total,
683 const char* sum_of = "total") {
684 const double percent = (static_cast<double>(size) / static_cast<double>(total)) * 100;
685 os.Stream() << StringPrintf("%s = %8" PRId64 " (%2.0f%% of %s)\n",
686 name,
687 size / kBitsPerByte,
688 percent,
689 sum_of);
690 }
691 };
692
Brian Carlstromaded5f72011-10-07 17:15:04 -0700693 private:
Ian Rogers3a5c1ce2012-02-29 10:06:46 -0800694 void AddAllOffsets() {
Elliott Hughese3c845c2012-02-28 17:23:01 -0800695 // We don't know the length of the code for each method, but we need to know where to stop
696 // when disassembling. What we do know is that a region of code will be followed by some other
697 // region, so if we keep a sorted sequence of the start of each region, we can infer the length
698 // of a piece of code by using upper_bound to find the start of the next region.
Ian Rogers3a5c1ce2012-02-29 10:06:46 -0800699 for (size_t i = 0; i < oat_dex_files_.size(); i++) {
700 const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
Andreas Gampe2ed8def2014-08-28 14:41:02 -0700701 CHECK(oat_dex_file != nullptr);
Ian Rogers8d31bbd2013-10-13 10:44:14 -0700702 std::string error_msg;
Mathieu Chartierac8f4392015-08-27 13:54:20 -0700703 const DexFile* const dex_file = OpenDexFile(oat_dex_file, &error_msg);
704 if (dex_file == nullptr) {
Ian Rogers8d31bbd2013-10-13 10:44:14 -0700705 LOG(WARNING) << "Failed to open dex file '" << oat_dex_file->GetDexFileLocation()
706 << "': " << error_msg;
Ian Rogers3a5c1ce2012-02-29 10:06:46 -0800707 continue;
Elliott Hughese3c845c2012-02-28 17:23:01 -0800708 }
Ian Rogersef7d42f2014-01-06 12:55:46 -0800709 offsets_.insert(reinterpret_cast<uintptr_t>(&dex_file->GetHeader()));
Brian Carlstrom2ec65202014-03-03 15:16:37 -0800710 for (size_t class_def_index = 0;
711 class_def_index < dex_file->NumClassDefs();
712 class_def_index++) {
Elliott Hughese3c845c2012-02-28 17:23:01 -0800713 const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
Vladimir Markod3c5beb2014-04-11 16:32:51 +0100714 const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
Ian Rogers13735952014-10-08 12:43:28 -0700715 const uint8_t* class_data = dex_file->GetClassData(class_def);
Andreas Gampe2ed8def2014-08-28 14:41:02 -0700716 if (class_data != nullptr) {
Elliott Hughese3c845c2012-02-28 17:23:01 -0800717 ClassDataItemIterator it(*dex_file, class_data);
718 SkipAllFields(it);
719 uint32_t class_method_index = 0;
720 while (it.HasNextDirectMethod()) {
Vladimir Markod3c5beb2014-04-11 16:32:51 +0100721 AddOffsets(oat_class.GetOatMethod(class_method_index++));
Elliott Hughese3c845c2012-02-28 17:23:01 -0800722 it.Next();
723 }
724 while (it.HasNextVirtualMethod()) {
Vladimir Markod3c5beb2014-04-11 16:32:51 +0100725 AddOffsets(oat_class.GetOatMethod(class_method_index++));
Elliott Hughese3c845c2012-02-28 17:23:01 -0800726 it.Next();
727 }
728 }
729 }
730 }
731
732 // If the last thing in the file is code for a method, there won't be an offset for the "next"
733 // thing. Instead of having a special case in the upper_bound code, let's just add an entry
734 // for the end of the file.
Ian Rogersef7d42f2014-01-06 12:55:46 -0800735 offsets_.insert(oat_file_.Size());
Elliott Hughese3c845c2012-02-28 17:23:01 -0800736 }
737
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -0700738 static uint32_t AlignCodeOffset(uint32_t maybe_thumb_offset) {
739 return maybe_thumb_offset & ~0x1; // TODO: Make this Thumb2 specific.
740 }
741
Elliott Hughese3c845c2012-02-28 17:23:01 -0800742 void AddOffsets(const OatFile::OatMethod& oat_method) {
Brian Carlstrom95ba0dc2012-03-05 22:06:14 -0800743 uint32_t code_offset = oat_method.GetCodeOffset();
744 if (oat_file_.GetOatHeader().GetInstructionSet() == kThumb2) {
745 code_offset &= ~0x1;
746 }
747 offsets_.insert(code_offset);
Elliott Hughese3c845c2012-02-28 17:23:01 -0800748 offsets_.insert(oat_method.GetVmapTableOffset());
Elliott Hughese3c845c2012-02-28 17:23:01 -0800749 }
750
Mathieu Chartierdc00f182016-07-14 10:10:44 -0700751 // Dex file data, may be for multiple different dex files.
752 class DexFileData {
753 public:
754 DexFileData() {}
755
756 explicit DexFileData(const DexFile& dex_file)
757 : num_string_ids_(dex_file.NumStringIds()),
758 num_method_ids_(dex_file.NumMethodIds()),
759 num_field_ids_(dex_file.NumFieldIds()),
760 num_type_ids_(dex_file.NumTypeIds()),
761 num_class_defs_(dex_file.NumClassDefs()) {
762 for (size_t class_def_index = 0; class_def_index < num_class_defs_; ++class_def_index) {
763 const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
764 WalkClass(dex_file, class_def);
765 }
766 }
767
768 void Add(const DexFileData& other) {
769 AddAll(unique_string_ids_from_code_, other.unique_string_ids_from_code_);
770 num_string_ids_from_code_ += other.num_string_ids_from_code_;
771 AddAll(dex_code_item_ptrs_, other.dex_code_item_ptrs_);
772 dex_code_bytes_ += other.dex_code_bytes_;
773 num_string_ids_ += other.num_string_ids_;
774 num_method_ids_ += other.num_method_ids_;
775 num_field_ids_ += other.num_field_ids_;
776 num_type_ids_ += other.num_type_ids_;
777 num_class_defs_ += other.num_class_defs_;
778 }
779
780 void Dump(std::ostream& os) {
781 os << "Num string ids: " << num_string_ids_ << "\n";
782 os << "Num method ids: " << num_method_ids_ << "\n";
783 os << "Num field ids: " << num_field_ids_ << "\n";
784 os << "Num type ids: " << num_type_ids_ << "\n";
785 os << "Num class defs: " << num_class_defs_ << "\n";
786 os << "Unique strings loaded from dex code: " << unique_string_ids_from_code_.size() << "\n";
787 os << "Total strings loaded from dex code: " << num_string_ids_from_code_ << "\n";
788 os << "Number of unique dex code items: " << dex_code_item_ptrs_.size() << "\n";
789 os << "Total number of dex code bytes: " << dex_code_bytes_ << "\n";
790 }
791
792 private:
Andreas Gampe9186ced2016-12-12 14:28:21 -0800793 // All of the elements from one container to another.
794 template <typename Dest, typename Src>
795 static void AddAll(Dest& dest, const Src& src) {
796 dest.insert(src.begin(), src.end());
797 }
798
Mathieu Chartierdc00f182016-07-14 10:10:44 -0700799 void WalkClass(const DexFile& dex_file, const DexFile::ClassDef& class_def) {
800 const uint8_t* class_data = dex_file.GetClassData(class_def);
801 if (class_data == nullptr) { // empty class such as a marker interface?
802 return;
803 }
804 ClassDataItemIterator it(dex_file, class_data);
805 SkipAllFields(it);
806 while (it.HasNextDirectMethod()) {
807 WalkCodeItem(dex_file, it.GetMethodCodeItem());
808 it.Next();
809 }
810 while (it.HasNextVirtualMethod()) {
811 WalkCodeItem(dex_file, it.GetMethodCodeItem());
812 it.Next();
813 }
814 DCHECK(!it.HasNext());
815 }
816
817 void WalkCodeItem(const DexFile& dex_file, const DexFile::CodeItem* code_item) {
818 if (code_item == nullptr) {
819 return;
820 }
821 const size_t code_item_size = code_item->insns_size_in_code_units_;
822 const uint16_t* code_ptr = code_item->insns_;
823 const uint16_t* code_end = code_item->insns_ + code_item_size;
824
825 // If we inserted a new dex code item pointer, add to total code bytes.
826 if (dex_code_item_ptrs_.insert(code_ptr).second) {
827 dex_code_bytes_ += code_item_size * sizeof(code_ptr[0]);
828 }
829
830 while (code_ptr < code_end) {
831 const Instruction* inst = Instruction::At(code_ptr);
832 switch (inst->Opcode()) {
833 case Instruction::CONST_STRING: {
Andreas Gampe8a0128a2016-11-28 07:38:35 -0800834 const dex::StringIndex string_index(inst->VRegB_21c());
Mathieu Chartierdc00f182016-07-14 10:10:44 -0700835 unique_string_ids_from_code_.insert(StringReference(&dex_file, string_index));
836 ++num_string_ids_from_code_;
837 break;
838 }
839 case Instruction::CONST_STRING_JUMBO: {
Andreas Gampe8a0128a2016-11-28 07:38:35 -0800840 const dex::StringIndex string_index(inst->VRegB_31c());
Mathieu Chartierdc00f182016-07-14 10:10:44 -0700841 unique_string_ids_from_code_.insert(StringReference(&dex_file, string_index));
842 ++num_string_ids_from_code_;
843 break;
844 }
845 default:
846 break;
847 }
848
849 code_ptr += inst->SizeInCodeUnits();
850 }
851 }
852
853 // Unique string ids loaded from dex code.
854 std::set<StringReference, StringReferenceComparator> unique_string_ids_from_code_;
855
856 // Total string ids loaded from dex code.
857 size_t num_string_ids_from_code_ = 0;
858
859 // Unique code pointers.
860 std::set<const void*> dex_code_item_ptrs_;
861
862 // Total "unique" dex code bytes.
863 size_t dex_code_bytes_ = 0;
864
865 // Other dex ids.
866 size_t num_string_ids_ = 0;
867 size_t num_method_ids_ = 0;
868 size_t num_field_ids_ = 0;
869 size_t num_type_ids_ = 0;
870 size_t num_class_defs_ = 0;
871 };
872
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -0700873 bool DumpOatDexFile(std::ostream& os, const OatFile::OatDexFile& oat_dex_file) {
874 bool success = true;
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -0800875 bool stop_analysis = false;
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -0700876 os << "OatDexFile:\n";
Brian Carlstroma004aa92012-02-08 18:05:09 -0800877 os << StringPrintf("location: %s\n", oat_dex_file.GetDexFileLocation().c_str());
Elliott Hughesed2adb62012-02-29 14:41:01 -0800878 os << StringPrintf("checksum: 0x%08x\n", oat_dex_file.GetDexFileLocationChecksum());
Mathieu Chartier590fee92013-09-13 13:46:47 -0700879
Andreas Gampe2ba88952016-04-29 17:52:07 -0700880 const uint8_t* const oat_file_begin = oat_dex_file.GetOatFile()->Begin();
David Brazdil7b49e6c2016-09-01 11:06:18 +0100881 const uint8_t* const vdex_file_begin = oat_dex_file.GetOatFile()->DexBegin();
882
883 // Print data range of the dex file embedded inside the corresponding vdex file.
Andreas Gampe2ba88952016-04-29 17:52:07 -0700884 const uint8_t* const dex_file_pointer = oat_dex_file.GetDexFilePointer();
David Brazdil7b49e6c2016-09-01 11:06:18 +0100885 uint32_t dex_offset = dchecked_integral_cast<uint32_t>(dex_file_pointer - vdex_file_begin);
Andreas Gampe2ba88952016-04-29 17:52:07 -0700886 os << StringPrintf("dex-file: 0x%08x..0x%08x\n",
887 dex_offset,
888 dchecked_integral_cast<uint32_t>(dex_offset + oat_dex_file.FileSize() - 1));
Mathieu Chartier590fee92013-09-13 13:46:47 -0700889
Andreas Gampe2ba88952016-04-29 17:52:07 -0700890 // Create the dex file early. A lot of print-out things depend on it.
Ian Rogers8d31bbd2013-10-13 10:44:14 -0700891 std::string error_msg;
Mathieu Chartierac8f4392015-08-27 13:54:20 -0700892 const DexFile* const dex_file = OpenDexFile(&oat_dex_file, &error_msg);
893 if (dex_file == nullptr) {
Ian Rogers8d31bbd2013-10-13 10:44:14 -0700894 os << "NOT FOUND: " << error_msg << "\n\n";
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -0700895 os << std::flush;
896 return false;
Brian Carlstromaded5f72011-10-07 17:15:04 -0700897 }
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100898
Andreas Gampe2ba88952016-04-29 17:52:07 -0700899 // Print lookup table, if it exists.
900 if (oat_dex_file.GetLookupTableData() != nullptr) {
901 uint32_t table_offset = dchecked_integral_cast<uint32_t>(
902 oat_dex_file.GetLookupTableData() - oat_file_begin);
David Sehr9aa352e2016-09-15 18:13:52 -0700903 uint32_t table_size = TypeLookupTable::RawDataLength(dex_file->NumClassDefs());
Andreas Gampe2ba88952016-04-29 17:52:07 -0700904 os << StringPrintf("type-table: 0x%08x..0x%08x\n",
905 table_offset,
906 table_offset + table_size - 1);
907 }
908
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100909 VariableIndentationOutputStream vios(&os);
910 ScopedIndentation indent1(&vios);
Brian Carlstrom2ec65202014-03-03 15:16:37 -0800911 for (size_t class_def_index = 0;
912 class_def_index < dex_file->NumClassDefs();
913 class_def_index++) {
Brian Carlstromaded5f72011-10-07 17:15:04 -0700914 const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
915 const char* descriptor = dex_file->GetClassDescriptor(class_def);
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -0800916
917 // TODO: Support regex
918 if (DescriptorToDot(descriptor).find(options_.class_filter_) == std::string::npos) {
919 continue;
920 }
921
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -0700922 uint32_t oat_class_offset = oat_dex_file.GetOatClassOffset(class_def_index);
Vladimir Markod3c5beb2014-04-11 16:32:51 +0100923 const OatFile::OatClass oat_class = oat_dex_file.GetOatClass(class_def_index);
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -0700924 os << StringPrintf("%zd: %s (offset=0x%08x) (type_idx=%d)",
Andreas Gampea5b09a62016-11-17 15:21:22 -0800925 class_def_index, descriptor, oat_class_offset, class_def.class_idx_.index_)
Vladimir Markod3c5beb2014-04-11 16:32:51 +0100926 << " (" << oat_class.GetStatus() << ")"
927 << " (" << oat_class.GetType() << ")\n";
928 // TODO: include bitmap here if type is kOatClassSomeCompiled?
Mathieu Chartierdc00f182016-07-14 10:10:44 -0700929 if (options_.list_classes_) {
930 continue;
931 }
932 if (!DumpOatClass(&vios, oat_class, *dex_file, class_def, &stop_analysis)) {
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -0700933 success = false;
934 }
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -0800935 if (stop_analysis) {
936 os << std::flush;
937 return success;
938 }
Brian Carlstromaded5f72011-10-07 17:15:04 -0700939 }
Mathieu Chartierdc00f182016-07-14 10:10:44 -0700940 os << "\n";
Brian Carlstromaded5f72011-10-07 17:15:04 -0700941 os << std::flush;
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -0700942 return success;
Brian Carlstromaded5f72011-10-07 17:15:04 -0700943 }
944
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -0800945 bool ExportDexFile(std::ostream& os, const OatFile::OatDexFile& oat_dex_file) {
946 std::string error_msg;
947 std::string dex_file_location = oat_dex_file.GetDexFileLocation();
948
Mathieu Chartierac8f4392015-08-27 13:54:20 -0700949 const DexFile* const dex_file = OpenDexFile(&oat_dex_file, &error_msg);
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -0800950 if (dex_file == nullptr) {
951 os << "Failed to open dex file '" << dex_file_location << "': " << error_msg;
952 return false;
953 }
954 size_t fsize = oat_dex_file.FileSize();
955
956 // Some quick checks just in case
957 if (fsize == 0 || fsize < sizeof(DexFile::Header)) {
958 os << "Invalid dex file\n";
959 return false;
960 }
961
962 // Verify output directory exists
963 if (!OS::DirectoryExists(options_.export_dex_location_)) {
964 // TODO: Extend OS::DirectoryExists if symlink support is required
965 os << options_.export_dex_location_ << " output directory not found or symlink\n";
966 return false;
967 }
968
969 // Beautify path names
970 if (dex_file_location.size() > PATH_MAX || dex_file_location.size() <= 0) {
971 return false;
972 }
973
974 std::string dex_orig_name;
975 size_t dex_orig_pos = dex_file_location.rfind('/');
976 if (dex_orig_pos == std::string::npos)
977 dex_orig_name = dex_file_location;
978 else
979 dex_orig_name = dex_file_location.substr(dex_orig_pos + 1);
980
981 // A more elegant approach to efficiently name user installed apps is welcome
982 if (dex_orig_name.size() == 8 && !dex_orig_name.compare("base.apk")) {
983 dex_file_location.erase(dex_orig_pos, strlen("base.apk") + 1);
984 size_t apk_orig_pos = dex_file_location.rfind('/');
985 if (apk_orig_pos != std::string::npos) {
986 dex_orig_name = dex_file_location.substr(++apk_orig_pos);
987 }
988 }
989
990 std::string out_dex_path(options_.export_dex_location_);
991 if (out_dex_path.back() != '/') {
992 out_dex_path.append("/");
993 }
994 out_dex_path.append(dex_orig_name);
995 out_dex_path.append("_export.dex");
996 if (out_dex_path.length() > PATH_MAX) {
997 return false;
998 }
999
1000 std::unique_ptr<File> file(OS::CreateEmptyFile(out_dex_path.c_str()));
1001 if (file.get() == nullptr) {
1002 os << "Failed to open output dex file " << out_dex_path;
1003 return false;
1004 }
1005
1006 if (!file->WriteFully(dex_file->Begin(), fsize)) {
1007 os << "Failed to write dex file";
1008 file->Erase();
1009 return false;
1010 }
1011
1012 if (file->FlushCloseOrErase() != 0) {
1013 os << "Flush and close failed";
1014 return false;
1015 }
1016
1017 os << StringPrintf("Dex file exported at %s (%zd bytes)\n", out_dex_path.c_str(), fsize);
1018 os << std::flush;
1019
1020 return true;
1021 }
1022
Elliott Hughese3c845c2012-02-28 17:23:01 -08001023 static void SkipAllFields(ClassDataItemIterator& it) {
Ian Rogers0571d352011-11-03 19:51:38 -07001024 while (it.HasNextStaticField()) {
1025 it.Next();
Brian Carlstromaded5f72011-10-07 17:15:04 -07001026 }
Ian Rogers0571d352011-11-03 19:51:38 -07001027 while (it.HasNextInstanceField()) {
1028 it.Next();
Brian Carlstromaded5f72011-10-07 17:15:04 -07001029 }
Elliott Hughese3c845c2012-02-28 17:23:01 -08001030 }
Brian Carlstromaded5f72011-10-07 17:15:04 -07001031
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001032 bool DumpOatClass(VariableIndentationOutputStream* vios,
1033 const OatFile::OatClass& oat_class, const DexFile& dex_file,
Mathieu Chartierdc00f182016-07-14 10:10:44 -07001034 const DexFile::ClassDef& class_def, bool* stop_analysis) {
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001035 bool success = true;
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08001036 bool addr_found = false;
Ian Rogers13735952014-10-08 12:43:28 -07001037 const uint8_t* class_data = dex_file.GetClassData(class_def);
Andreas Gampe2ed8def2014-08-28 14:41:02 -07001038 if (class_data == nullptr) { // empty class such as a marker interface?
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001039 vios->Stream() << std::flush;
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001040 return success;
Elliott Hughese3c845c2012-02-28 17:23:01 -08001041 }
1042 ClassDataItemIterator it(dex_file, class_data);
1043 SkipAllFields(it);
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001044 uint32_t class_method_index = 0;
Ian Rogers0571d352011-11-03 19:51:38 -07001045 while (it.HasNextDirectMethod()) {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001046 if (!DumpOatMethod(vios, class_def, class_method_index, oat_class, dex_file,
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001047 it.GetMemberIndex(), it.GetMethodCodeItem(),
Mathieu Chartierdc00f182016-07-14 10:10:44 -07001048 it.GetRawMemberAccessFlags(), &addr_found)) {
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001049 success = false;
1050 }
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08001051 if (addr_found) {
1052 *stop_analysis = true;
1053 return success;
1054 }
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001055 class_method_index++;
Ian Rogers0571d352011-11-03 19:51:38 -07001056 it.Next();
Brian Carlstromaded5f72011-10-07 17:15:04 -07001057 }
Ian Rogers0571d352011-11-03 19:51:38 -07001058 while (it.HasNextVirtualMethod()) {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001059 if (!DumpOatMethod(vios, class_def, class_method_index, oat_class, dex_file,
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001060 it.GetMemberIndex(), it.GetMethodCodeItem(),
Mathieu Chartierdc00f182016-07-14 10:10:44 -07001061 it.GetRawMemberAccessFlags(), &addr_found)) {
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001062 success = false;
1063 }
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08001064 if (addr_found) {
1065 *stop_analysis = true;
1066 return success;
1067 }
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001068 class_method_index++;
Ian Rogers0571d352011-11-03 19:51:38 -07001069 it.Next();
Brian Carlstromaded5f72011-10-07 17:15:04 -07001070 }
Ian Rogers0571d352011-11-03 19:51:38 -07001071 DCHECK(!it.HasNext());
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001072 vios->Stream() << std::flush;
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001073 return success;
Brian Carlstromaded5f72011-10-07 17:15:04 -07001074 }
Elliott Hughese3c845c2012-02-28 17:23:01 -08001075
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001076 static constexpr uint32_t kPrologueBytes = 16;
1077
1078 // When this was picked, the largest arm method was 55,256 bytes and arm64 was 50,412 bytes.
1079 static constexpr uint32_t kMaxCodeSize = 100 * 1000;
1080
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001081 bool DumpOatMethod(VariableIndentationOutputStream* vios,
1082 const DexFile::ClassDef& class_def,
Ian Rogers8b2c0b92013-09-19 02:56:49 -07001083 uint32_t class_method_index,
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001084 const OatFile::OatClass& oat_class, const DexFile& dex_file,
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001085 uint32_t dex_method_idx, const DexFile::CodeItem* code_item,
Mathieu Chartierdc00f182016-07-14 10:10:44 -07001086 uint32_t method_access_flags, bool* addr_found) {
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001087 bool success = true;
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08001088
1089 // TODO: Support regex
1090 std::string method_name = dex_file.GetMethodName(dex_file.GetMethodId(dex_method_idx));
1091 if (method_name.find(options_.method_filter_) == std::string::npos) {
Nicolas Geoffray3fcd2202014-11-12 18:02:36 +00001092 return success;
1093 }
1094
David Sehr709b0702016-10-13 09:12:37 -07001095 std::string pretty_method = dex_file.PrettyMethod(dex_method_idx, true);
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001096 vios->Stream() << StringPrintf("%d: %s (dex_method_idx=%d)\n",
1097 class_method_index, pretty_method.c_str(),
1098 dex_method_idx);
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08001099 if (options_.list_methods_) return success;
1100
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08001101 uint32_t oat_method_offsets_offset = oat_class.GetOatMethodOffsetsOffset(class_method_index);
1102 const OatMethodOffsets* oat_method_offsets = oat_class.GetOatMethodOffsets(class_method_index);
1103 const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_index);
1104 uint32_t code_offset = oat_method.GetCodeOffset();
1105 uint32_t code_size = oat_method.GetQuickCodeSize();
1106 if (resolved_addr2instr_ != 0) {
1107 if (resolved_addr2instr_ > code_offset + code_size) {
1108 return success;
1109 } else {
1110 *addr_found = true; // stop analyzing file at next iteration
1111 }
1112 }
1113
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001114 // Everything below is indented at least once.
1115 ScopedIndentation indent1(vios);
1116
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001117 {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001118 vios->Stream() << "DEX CODE:\n";
1119 ScopedIndentation indent2(vios);
1120 DumpDexCode(vios->Stream(), dex_file, code_item);
Ian Rogersb23a7722012-10-09 16:54:26 -07001121 }
Andreas Gampe2ed8def2014-08-28 14:41:02 -07001122
Mathieu Chartier673ed3d2015-08-28 14:56:43 -07001123 std::unique_ptr<StackHandleScope<1>> hs;
Andreas Gampe2ed8def2014-08-28 14:41:02 -07001124 std::unique_ptr<verifier::MethodVerifier> verifier;
1125 if (Runtime::Current() != nullptr) {
Mathieu Chartier673ed3d2015-08-28 14:56:43 -07001126 // We need to have the handle scope stay live until after the verifier since the verifier has
1127 // a handle to the dex cache from hs.
1128 hs.reset(new StackHandleScope<1>(Thread::Current()));
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001129 vios->Stream() << "VERIFIER TYPE ANALYSIS:\n";
1130 ScopedIndentation indent2(vios);
Mathieu Chartier673ed3d2015-08-28 14:56:43 -07001131 verifier.reset(DumpVerifier(vios, hs.get(),
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001132 dex_method_idx, &dex_file, class_def, code_item,
Andreas Gampe2ed8def2014-08-28 14:41:02 -07001133 method_access_flags));
Ian Rogersb23a7722012-10-09 16:54:26 -07001134 }
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001135 {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001136 vios->Stream() << "OatMethodOffsets ";
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08001137 if (options_.absolute_addresses_) {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001138 vios->Stream() << StringPrintf("%p ", oat_method_offsets);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001139 }
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001140 vios->Stream() << StringPrintf("(offset=0x%08x)\n", oat_method_offsets_offset);
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001141 if (oat_method_offsets_offset > oat_file_.Size()) {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001142 vios->Stream() << StringPrintf(
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001143 "WARNING: oat method offsets offset 0x%08x is past end of file 0x%08zx.\n",
1144 oat_method_offsets_offset, oat_file_.Size());
1145 // If we can't read OatMethodOffsets, the rest of the data is dangerous to read.
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001146 vios->Stream() << std::flush;
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001147 return false;
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001148 }
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001149
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001150 ScopedIndentation indent2(vios);
1151 vios->Stream() << StringPrintf("code_offset: 0x%08x ", code_offset);
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001152 uint32_t aligned_code_begin = AlignCodeOffset(oat_method.GetCodeOffset());
1153 if (aligned_code_begin > oat_file_.Size()) {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001154 vios->Stream() << StringPrintf("WARNING: "
1155 "code offset 0x%08x is past end of file 0x%08zx.\n",
1156 aligned_code_begin, oat_file_.Size());
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001157 success = false;
1158 }
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001159 vios->Stream() << "\n";
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001160 }
1161 {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001162 vios->Stream() << "OatQuickMethodHeader ";
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001163 uint32_t method_header_offset = oat_method.GetOatQuickMethodHeaderOffset();
1164 const OatQuickMethodHeader* method_header = oat_method.GetOatQuickMethodHeader();
Mathieu Chartier5e7c6a92017-01-17 16:38:30 -08001165 stats_.AddBitsIfUnique(Stats::kByteKindQuickMethodHeader,
1166 sizeof(*method_header) * kBitsPerByte,
1167 method_header);
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08001168 if (options_.absolute_addresses_) {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001169 vios->Stream() << StringPrintf("%p ", method_header);
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001170 }
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001171 vios->Stream() << StringPrintf("(offset=0x%08x)\n", method_header_offset);
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001172 if (method_header_offset > oat_file_.Size()) {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001173 vios->Stream() << StringPrintf(
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001174 "WARNING: oat quick method header offset 0x%08x is past end of file 0x%08zx.\n",
1175 method_header_offset, oat_file_.Size());
1176 // If we can't read the OatQuickMethodHeader, the rest of the data is dangerous to read.
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001177 vios->Stream() << std::flush;
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001178 return false;
1179 }
1180
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001181 ScopedIndentation indent2(vios);
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001182 vios->Stream() << "vmap_table: ";
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08001183 if (options_.absolute_addresses_) {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001184 vios->Stream() << StringPrintf("%p ", oat_method.GetVmapTable());
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001185 }
Mingyao Yang063fc772016-08-02 11:02:54 -07001186 uint32_t vmap_table_offset = method_header ==
1187 nullptr ? 0 : method_header->GetVmapTableOffset();
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001188 vios->Stream() << StringPrintf("(offset=0x%08x)\n", vmap_table_offset);
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01001189
1190 size_t vmap_table_offset_limit =
1191 (kIsVdexEnabled && IsMethodGeneratedByDexToDexCompiler(oat_method, code_item))
1192 ? oat_file_.GetVdexFile()->Size()
1193 : method_header->GetCode() - oat_file_.Begin();
1194 if (vmap_table_offset >= vmap_table_offset_limit) {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001195 vios->Stream() << StringPrintf("WARNING: "
1196 "vmap table offset 0x%08x is past end of file 0x%08zx. "
1197 "vmap table offset was loaded from offset 0x%08x.\n",
Nicolas Geoffray4acefd32016-10-24 13:14:58 +01001198 vmap_table_offset,
1199 vmap_table_offset_limit,
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001200 oat_method.GetVmapTableOffsetOffset());
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001201 success = false;
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08001202 } else if (options_.dump_vmap_) {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001203 DumpVmapData(vios, oat_method, code_item);
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001204 }
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001205 }
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001206 {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001207 vios->Stream() << "QuickMethodFrameInfo\n";
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001208
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001209 ScopedIndentation indent2(vios);
1210 vios->Stream()
1211 << StringPrintf("frame_size_in_bytes: %zd\n", oat_method.GetFrameSizeInBytes());
1212 vios->Stream() << StringPrintf("core_spill_mask: 0x%08x ", oat_method.GetCoreSpillMask());
1213 DumpSpillMask(vios->Stream(), oat_method.GetCoreSpillMask(), false);
1214 vios->Stream() << "\n";
1215 vios->Stream() << StringPrintf("fp_spill_mask: 0x%08x ", oat_method.GetFpSpillMask());
1216 DumpSpillMask(vios->Stream(), oat_method.GetFpSpillMask(), true);
1217 vios->Stream() << "\n";
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001218 }
1219 {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001220 // Based on spill masks from QuickMethodFrameInfo so placed
1221 // after it is dumped, but useful for understanding quick
1222 // code, so dumped here.
1223 ScopedIndentation indent2(vios);
1224 DumpVregLocations(vios->Stream(), oat_method, code_item);
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001225 }
1226 {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001227 vios->Stream() << "CODE: ";
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001228 uint32_t code_size_offset = oat_method.GetQuickCodeSizeOffset();
1229 if (code_size_offset > oat_file_.Size()) {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001230 ScopedIndentation indent2(vios);
1231 vios->Stream() << StringPrintf("WARNING: "
1232 "code size offset 0x%08x is past end of file 0x%08zx.",
1233 code_size_offset, oat_file_.Size());
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001234 success = false;
1235 } else {
1236 const void* code = oat_method.GetQuickCode();
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001237 uint32_t aligned_code_begin = AlignCodeOffset(code_offset);
1238 uint64_t aligned_code_end = aligned_code_begin + code_size;
Mathieu Chartier5e7c6a92017-01-17 16:38:30 -08001239 stats_.AddBitsIfUnique(Stats::kByteKindCode, code_size * kBitsPerByte, code);
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001240
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08001241 if (options_.absolute_addresses_) {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001242 vios->Stream() << StringPrintf("%p ", code);
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001243 }
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001244 vios->Stream() << StringPrintf("(code_offset=0x%08x size_offset=0x%08x size=%u)%s\n",
1245 code_offset,
1246 code_size_offset,
1247 code_size,
1248 code != nullptr ? "..." : "");
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001249
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001250 ScopedIndentation indent2(vios);
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001251 if (aligned_code_begin > oat_file_.Size()) {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001252 vios->Stream() << StringPrintf("WARNING: "
1253 "start of code at 0x%08x is past end of file 0x%08zx.",
1254 aligned_code_begin, oat_file_.Size());
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001255 success = false;
1256 } else if (aligned_code_end > oat_file_.Size()) {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001257 vios->Stream() << StringPrintf(
1258 "WARNING: "
1259 "end of code at 0x%08" PRIx64 " is past end of file 0x%08zx. "
1260 "code size is 0x%08x loaded from offset 0x%08x.\n",
1261 aligned_code_end, oat_file_.Size(),
1262 code_size, code_size_offset);
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001263 success = false;
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08001264 if (options_.disassemble_code_) {
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001265 if (code_size_offset + kPrologueBytes <= oat_file_.Size()) {
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001266 DumpCode(vios, oat_method, code_item, true, kPrologueBytes);
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001267 }
1268 }
1269 } else if (code_size > kMaxCodeSize) {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001270 vios->Stream() << StringPrintf(
1271 "WARNING: "
1272 "code size %d is bigger than max expected threshold of %d. "
1273 "code size is 0x%08x loaded from offset 0x%08x.\n",
1274 code_size, kMaxCodeSize,
1275 code_size, code_size_offset);
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001276 success = false;
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08001277 if (options_.disassemble_code_) {
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001278 if (code_size_offset + kPrologueBytes <= oat_file_.Size()) {
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001279 DumpCode(vios, oat_method, code_item, true, kPrologueBytes);
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001280 }
1281 }
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08001282 } else if (options_.disassemble_code_) {
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001283 DumpCode(vios, oat_method, code_item, !success, 0);
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001284 }
1285 }
1286 }
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001287 vios->Stream() << std::flush;
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001288 return success;
Brian Carlstromaded5f72011-10-07 17:15:04 -07001289 }
Elliott Hughese3c845c2012-02-28 17:23:01 -08001290
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08001291 void DumpSpillMask(std::ostream& os, uint32_t spill_mask, bool is_float) {
1292 if (spill_mask == 0) {
1293 return;
1294 }
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001295 os << "(";
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08001296 for (size_t i = 0; i < 32; i++) {
1297 if ((spill_mask & (1 << i)) != 0) {
1298 if (is_float) {
1299 os << "fr" << i;
1300 } else {
1301 os << "r" << i;
1302 }
1303 spill_mask ^= 1 << i; // clear bit
1304 if (spill_mask != 0) {
1305 os << ", ";
1306 } else {
1307 break;
1308 }
1309 }
1310 }
1311 os << ")";
1312 }
1313
Roland Levillain442b46a2015-02-18 16:54:21 +00001314 // Display data stored at the the vmap offset of an oat method.
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001315 void DumpVmapData(VariableIndentationOutputStream* vios,
Roland Levillain442b46a2015-02-18 16:54:21 +00001316 const OatFile::OatMethod& oat_method,
1317 const DexFile::CodeItem* code_item) {
Roland Levillainf2650d12015-05-28 14:53:28 +01001318 if (IsMethodGeneratedByOptimizingCompiler(oat_method, code_item)) {
1319 // The optimizing compiler outputs its CodeInfo data in the vmap table.
Roland Levillain442b46a2015-02-18 16:54:21 +00001320 const void* raw_code_info = oat_method.GetVmapTable();
1321 if (raw_code_info != nullptr) {
1322 CodeInfo code_info(raw_code_info);
1323 DCHECK(code_item != nullptr);
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001324 ScopedIndentation indent1(vios);
1325 DumpCodeInfo(vios, code_info, oat_method, *code_item);
Roland Levillain442b46a2015-02-18 16:54:21 +00001326 }
Nicolas Geoffray0a5cd122015-07-16 14:15:05 +01001327 } else if (IsMethodGeneratedByDexToDexCompiler(oat_method, code_item)) {
1328 // We don't encode the size in the table, so just emit that we have quickened
1329 // information.
1330 ScopedIndentation indent(vios);
1331 vios->Stream() << "quickened data\n";
Roland Levillain442b46a2015-02-18 16:54:21 +00001332 } else {
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001333 // Otherwise, there is nothing to display.
Nicolas Geoffray20d3eae2014-09-17 11:27:23 +01001334 }
Roland Levillain442b46a2015-02-18 16:54:21 +00001335 }
1336
1337 // Display a CodeInfo object emitted by the optimizing compiler.
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001338 void DumpCodeInfo(VariableIndentationOutputStream* vios,
Roland Levillain442b46a2015-02-18 16:54:21 +00001339 const CodeInfo& code_info,
Roland Levillainf2650d12015-05-28 14:53:28 +01001340 const OatFile::OatMethod& oat_method,
Roland Levillain442b46a2015-02-18 16:54:21 +00001341 const DexFile::CodeItem& code_item) {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001342 code_info.Dump(vios,
Roland Levillainf2650d12015-05-28 14:53:28 +01001343 oat_method.GetCodeOffset(),
1344 code_item.registers_size_,
Mathieu Chartiera2f526f2017-01-19 14:48:48 -08001345 options_.dump_code_info_stack_maps_,
1346 instruction_set_);
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08001347 }
1348
Razvan A Lupusorufaf9f0d2014-08-29 17:56:46 -07001349 void DumpVregLocations(std::ostream& os, const OatFile::OatMethod& oat_method,
1350 const DexFile::CodeItem* code_item) {
1351 if (code_item != nullptr) {
1352 size_t num_locals_ins = code_item->registers_size_;
1353 size_t num_ins = code_item->ins_size_;
1354 size_t num_locals = num_locals_ins - num_ins;
1355 size_t num_outs = code_item->outs_size_;
1356
1357 os << "vr_stack_locations:";
1358 for (size_t reg = 0; reg <= num_locals_ins; reg++) {
1359 // For readability, delimit the different kinds of VRs.
1360 if (reg == num_locals_ins) {
1361 os << "\n\tmethod*:";
1362 } else if (reg == num_locals && num_ins > 0) {
1363 os << "\n\tins:";
1364 } else if (reg == 0 && num_locals > 0) {
1365 os << "\n\tlocals:";
1366 }
1367
Nicolas Geoffray15b9d522015-03-12 15:05:13 +00001368 uint32_t offset = StackVisitor::GetVRegOffsetFromQuickCode(
1369 code_item,
1370 oat_method.GetCoreSpillMask(),
1371 oat_method.GetFpSpillMask(),
1372 oat_method.GetFrameSizeInBytes(),
1373 reg,
1374 GetInstructionSet());
Razvan A Lupusorufaf9f0d2014-08-29 17:56:46 -07001375 os << " v" << reg << "[sp + #" << offset << "]";
1376 }
1377
1378 for (size_t out_reg = 0; out_reg < num_outs; out_reg++) {
1379 if (out_reg == 0) {
1380 os << "\n\touts:";
1381 }
1382
1383 uint32_t offset = StackVisitor::GetOutVROffset(out_reg, GetInstructionSet());
1384 os << " v" << out_reg << "[sp + #" << offset << "]";
1385 }
1386
1387 os << "\n";
1388 }
1389 }
1390
Ian Rogersb23a7722012-10-09 16:54:26 -07001391 void DumpDexCode(std::ostream& os, const DexFile& dex_file, const DexFile::CodeItem* code_item) {
Andreas Gampe2ed8def2014-08-28 14:41:02 -07001392 if (code_item != nullptr) {
Ian Rogersb23a7722012-10-09 16:54:26 -07001393 size_t i = 0;
1394 while (i < code_item->insns_size_in_code_units_) {
1395 const Instruction* instruction = Instruction::At(&code_item->insns_[i]);
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08001396 os << StringPrintf("0x%04zx: ", i) << instruction->DumpHexLE(5)
1397 << StringPrintf("\t| %s\n", instruction->DumpString(&dex_file).c_str());
Ian Rogersb23a7722012-10-09 16:54:26 -07001398 i += instruction->SizeInCodeUnits();
1399 }
1400 }
1401 }
1402
Roland Levillainf2650d12015-05-28 14:53:28 +01001403 // Has `oat_method` -- corresponding to the Dex `code_item` -- been compiled by
1404 // the optimizing compiler?
1405 static bool IsMethodGeneratedByOptimizingCompiler(const OatFile::OatMethod& oat_method,
1406 const DexFile::CodeItem* code_item) {
1407 // If the native GC map is null and the Dex `code_item` is not
1408 // null, then this method has been compiled with the optimizing
1409 // compiler.
Nicolas Geoffray0a5cd122015-07-16 14:15:05 +01001410 return oat_method.GetQuickCode() != nullptr &&
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01001411 oat_method.GetVmapTable() != nullptr &&
Nicolas Geoffray0a5cd122015-07-16 14:15:05 +01001412 code_item != nullptr;
1413 }
1414
1415 // Has `oat_method` -- corresponding to the Dex `code_item` -- been compiled by
1416 // the dextodex compiler?
1417 static bool IsMethodGeneratedByDexToDexCompiler(const OatFile::OatMethod& oat_method,
1418 const DexFile::CodeItem* code_item) {
1419 // If the quick code is null, the Dex `code_item` is not
1420 // null, and the vmap table is not null, then this method has been compiled
1421 // with the dextodex compiler.
1422 return oat_method.GetQuickCode() == nullptr &&
1423 oat_method.GetVmapTable() != nullptr &&
1424 code_item != nullptr;
Roland Levillainf2650d12015-05-28 14:53:28 +01001425 }
1426
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001427 verifier::MethodVerifier* DumpVerifier(VariableIndentationOutputStream* vios,
Mathieu Chartier673ed3d2015-08-28 14:56:43 -07001428 StackHandleScope<1>* hs,
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001429 uint32_t dex_method_idx,
Andreas Gampe2ed8def2014-08-28 14:41:02 -07001430 const DexFile* dex_file,
1431 const DexFile::ClassDef& class_def,
1432 const DexFile::CodeItem* code_item,
1433 uint32_t method_access_flags) {
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001434 if ((method_access_flags & kAccNative) == 0) {
1435 ScopedObjectAccess soa(Thread::Current());
Mathieu Chartierd57d4542015-10-14 10:55:30 -07001436 Runtime* const runtime = Runtime::Current();
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07001437 Handle<mirror::DexCache> dex_cache(
Mathieu Chartierf284d442016-06-02 11:48:30 -07001438 hs->NewHandle(runtime->GetClassLinker()->RegisterDexFile(*dex_file, nullptr)));
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08001439 DCHECK(options_.class_loader_ != nullptr);
Mathieu Chartiere401d142015-04-22 13:56:20 -07001440 return verifier::MethodVerifier::VerifyMethodAndDump(
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001441 soa.Self(), vios, dex_method_idx, dex_file, dex_cache, *options_.class_loader_,
David Brazdil15fc7292016-09-02 14:13:18 +01001442 class_def, code_item, nullptr, method_access_flags);
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001443 }
Andreas Gampe2ed8def2014-08-28 14:41:02 -07001444
1445 return nullptr;
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001446 }
1447
Vladimir Markoadbf93e2016-04-08 11:18:25 +01001448 // The StackMapsHelper provides the stack maps in the native PC order.
1449 // For identical native PCs, the order from the CodeInfo is preserved.
1450 class StackMapsHelper {
1451 public:
Mathieu Chartiera2f526f2017-01-19 14:48:48 -08001452 explicit StackMapsHelper(const uint8_t* raw_code_info, InstructionSet instruction_set)
Vladimir Markoadbf93e2016-04-08 11:18:25 +01001453 : code_info_(raw_code_info),
1454 encoding_(code_info_.ExtractEncoding()),
1455 number_of_stack_maps_(code_info_.GetNumberOfStackMaps(encoding_)),
1456 indexes_(),
Mathieu Chartiera2f526f2017-01-19 14:48:48 -08001457 offset_(static_cast<uint32_t>(-1)),
1458 stack_map_index_(0u),
1459 instruction_set_(instruction_set) {
Vladimir Markoadbf93e2016-04-08 11:18:25 +01001460 if (number_of_stack_maps_ != 0u) {
1461 // Check if native PCs are ordered.
1462 bool ordered = true;
1463 StackMap last = code_info_.GetStackMapAt(0u, encoding_);
1464 for (size_t i = 1; i != number_of_stack_maps_; ++i) {
1465 StackMap current = code_info_.GetStackMapAt(i, encoding_);
Mathieu Chartiera2f526f2017-01-19 14:48:48 -08001466 if (last.GetNativePcOffset(encoding_.stack_map_encoding, instruction_set) >
1467 current.GetNativePcOffset(encoding_.stack_map_encoding, instruction_set)) {
Vladimir Markoadbf93e2016-04-08 11:18:25 +01001468 ordered = false;
1469 break;
1470 }
1471 last = current;
1472 }
1473 if (!ordered) {
1474 // Create indirection indexes for access in native PC order. We do not optimize
1475 // for the fact that there can currently be only two separately ordered ranges,
1476 // namely normal stack maps and catch-point stack maps.
1477 indexes_.resize(number_of_stack_maps_);
1478 std::iota(indexes_.begin(), indexes_.end(), 0u);
1479 std::sort(indexes_.begin(),
1480 indexes_.end(),
1481 [this](size_t lhs, size_t rhs) {
1482 StackMap left = code_info_.GetStackMapAt(lhs, encoding_);
Mathieu Chartiera2f526f2017-01-19 14:48:48 -08001483 uint32_t left_pc = left.GetNativePcOffset(encoding_.stack_map_encoding,
1484 instruction_set_);
Vladimir Markoadbf93e2016-04-08 11:18:25 +01001485 StackMap right = code_info_.GetStackMapAt(rhs, encoding_);
Mathieu Chartiera2f526f2017-01-19 14:48:48 -08001486 uint32_t right_pc = right.GetNativePcOffset(encoding_.stack_map_encoding,
1487 instruction_set_);
Vladimir Markoadbf93e2016-04-08 11:18:25 +01001488 // If the PCs are the same, compare indexes to preserve the original order.
1489 return (left_pc < right_pc) || (left_pc == right_pc && lhs < rhs);
1490 });
1491 }
Mathieu Chartiera2f526f2017-01-19 14:48:48 -08001492 offset_ = GetStackMapAt(0).GetNativePcOffset(encoding_.stack_map_encoding,
1493 instruction_set_);
Vladimir Markoadbf93e2016-04-08 11:18:25 +01001494 }
1495 }
1496
1497 const CodeInfo& GetCodeInfo() const {
1498 return code_info_;
1499 }
1500
1501 const CodeInfoEncoding& GetEncoding() const {
1502 return encoding_;
1503 }
1504
Mathieu Chartiera2f526f2017-01-19 14:48:48 -08001505 uint32_t GetOffset() const {
Vladimir Markoadbf93e2016-04-08 11:18:25 +01001506 return offset_;
1507 }
1508
1509 StackMap GetStackMap() const {
1510 return GetStackMapAt(stack_map_index_);
1511 }
1512
1513 void Next() {
1514 ++stack_map_index_;
1515 offset_ = (stack_map_index_ == number_of_stack_maps_)
Mathieu Chartiera2f526f2017-01-19 14:48:48 -08001516 ? static_cast<uint32_t>(-1)
1517 : GetStackMapAt(stack_map_index_).GetNativePcOffset(encoding_.stack_map_encoding,
1518 instruction_set_);
Vladimir Markoadbf93e2016-04-08 11:18:25 +01001519 }
1520
1521 private:
1522 StackMap GetStackMapAt(size_t i) const {
1523 if (!indexes_.empty()) {
1524 i = indexes_[i];
1525 }
1526 DCHECK_LT(i, number_of_stack_maps_);
1527 return code_info_.GetStackMapAt(i, encoding_);
1528 }
1529
1530 const CodeInfo code_info_;
1531 const CodeInfoEncoding encoding_;
1532 const size_t number_of_stack_maps_;
1533 dchecked_vector<size_t> indexes_; // Used if stack map native PCs are not ordered.
Mathieu Chartiera2f526f2017-01-19 14:48:48 -08001534 uint32_t offset_;
Vladimir Markoadbf93e2016-04-08 11:18:25 +01001535 size_t stack_map_index_;
Mathieu Chartiera2f526f2017-01-19 14:48:48 -08001536 const InstructionSet instruction_set_;
Vladimir Markoadbf93e2016-04-08 11:18:25 +01001537 };
1538
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001539 void DumpCode(VariableIndentationOutputStream* vios,
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001540 const OatFile::OatMethod& oat_method, const DexFile::CodeItem* code_item,
1541 bool bad_input, size_t code_size) {
Ian Rogersef7d42f2014-01-06 12:55:46 -08001542 const void* quick_code = oat_method.GetQuickCode();
1543
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001544 if (code_size == 0) {
1545 code_size = oat_method.GetQuickCodeSize();
1546 }
Elliott Hughes956af0f2014-12-11 14:34:28 -08001547 if (code_size == 0 || quick_code == nullptr) {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001548 vios->Stream() << "NO CODE!\n";
Ian Rogersb23a7722012-10-09 16:54:26 -07001549 return;
Vladimir Markoadbf93e2016-04-08 11:18:25 +01001550 } else if (!bad_input && IsMethodGeneratedByOptimizingCompiler(oat_method, code_item)) {
1551 // The optimizing compiler outputs its CodeInfo data in the vmap table.
Mathieu Chartiera2f526f2017-01-19 14:48:48 -08001552 StackMapsHelper helper(oat_method.GetVmapTable(), instruction_set_);
Mathieu Chartier5e7c6a92017-01-17 16:38:30 -08001553 {
1554 CodeInfoEncoding encoding(helper.GetEncoding());
1555 StackMapEncoding stack_map_encoding(encoding.stack_map_encoding);
1556 // helper.GetCodeInfo().GetStackMapAt(0, encoding).;
1557 const size_t num_stack_maps = encoding.number_of_stack_maps;
1558 std::vector<uint8_t> size_vector;
1559 encoding.Compress(&size_vector);
1560 if (stats_.AddBitsIfUnique(Stats::kByteKindCodeInfoEncoding,
1561 size_vector.size() * kBitsPerByte,
1562 oat_method.GetVmapTable())) {
1563 stats_.AddBits(
1564 Stats::kByteKindStackMapNativePc,
1565 stack_map_encoding.GetNativePcEncoding().BitSize() * num_stack_maps);
1566 stats_.AddBits(
1567 Stats::kByteKindStackMapDexPc,
1568 stack_map_encoding.GetDexPcEncoding().BitSize() * num_stack_maps);
1569 stats_.AddBits(
1570 Stats::kByteKindStackMapDexRegisterMap,
1571 stack_map_encoding.GetDexRegisterMapEncoding().BitSize() * num_stack_maps);
1572 stats_.AddBits(
1573 Stats::kByteKindStackMapInlineInfo,
1574 stack_map_encoding.GetInlineInfoEncoding().BitSize() * num_stack_maps);
1575 stats_.AddBits(
1576 Stats::kByteKindStackMapRegisterMask,
1577 stack_map_encoding.GetRegisterMaskEncoding().BitSize() * num_stack_maps);
1578 const size_t stack_mask_bits = encoding.stack_map_size_in_bytes * kBitsPerByte -
1579 stack_map_encoding.GetStackMaskBitOffset();
1580 stats_.AddBits(
1581 Stats::kByteKindStackMapMask,
1582 stack_mask_bits * num_stack_maps);
1583 const size_t stack_map_bits =
1584 stack_map_encoding.GetStackMaskBitOffset() + stack_mask_bits;
1585 stats_.AddBits(
1586 Stats::kByteKindStackMapOther,
1587 (encoding.stack_map_size_in_bytes * kBitsPerByte - stack_map_bits) * num_stack_maps);
1588 const size_t stack_map_bytes = helper.GetCodeInfo().GetStackMapsSize(encoding);
1589 const size_t location_catalog_bytes =
1590 helper.GetCodeInfo().GetDexRegisterLocationCatalogSize(encoding);
1591 stats_.AddBits(Stats::kByteKindCodeInfoLocationCatalog,
1592 kBitsPerByte * location_catalog_bytes);
1593 const size_t dex_register_bytes =
1594 helper.GetCodeInfo().GetDexRegisterMapsSize(encoding, code_item->registers_size_);
1595 stats_.AddBits(
1596 Stats::kByteKindCodeInfoDexRegisterMap,
1597 kBitsPerByte * dex_register_bytes);
1598 const size_t inline_info_bytes =
1599 encoding.non_header_size -
1600 stack_map_bytes -
1601 location_catalog_bytes -
1602 dex_register_bytes;
1603 stats_.AddBits(Stats::kByteKindCodeInfoInlineInfo,
1604 inline_info_bytes * kBitsPerByte);
1605 }
1606 }
Vladimir Markoadbf93e2016-04-08 11:18:25 +01001607 const uint8_t* quick_native_pc = reinterpret_cast<const uint8_t*>(quick_code);
1608 size_t offset = 0;
1609 while (offset < code_size) {
1610 offset += disassembler_->Dump(vios->Stream(), quick_native_pc + offset);
1611 if (offset == helper.GetOffset()) {
1612 ScopedIndentation indent1(vios);
1613 StackMap stack_map = helper.GetStackMap();
1614 DCHECK(stack_map.IsValid());
1615 stack_map.Dump(vios,
1616 helper.GetCodeInfo(),
1617 helper.GetEncoding(),
1618 oat_method.GetCodeOffset(),
Mathieu Chartiera2f526f2017-01-19 14:48:48 -08001619 code_item->registers_size_,
1620 instruction_set_);
Vladimir Markoadbf93e2016-04-08 11:18:25 +01001621 do {
1622 helper.Next();
1623 // There may be multiple stack maps at a given PC. We display only the first one.
1624 } while (offset == helper.GetOffset());
1625 }
1626 DCHECK_LT(offset, helper.GetOffset());
1627 }
Elliott Hughes956af0f2014-12-11 14:34:28 -08001628 } else {
Ian Rogersef7d42f2014-01-06 12:55:46 -08001629 const uint8_t* quick_native_pc = reinterpret_cast<const uint8_t*>(quick_code);
1630 size_t offset = 0;
1631 while (offset < code_size) {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001632 offset += disassembler_->Dump(vios->Stream(), quick_native_pc + offset);
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001633 }
Ian Rogersb23a7722012-10-09 16:54:26 -07001634 }
1635 }
1636
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08001637 const OatFile& oat_file_;
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001638 const std::vector<const OatFile::OatDexFile*> oat_dex_files_;
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08001639 const OatDumperOptions& options_;
1640 uint32_t resolved_addr2instr_;
Andreas Gampe372f3a32016-08-19 10:49:06 -07001641 const InstructionSet instruction_set_;
Ian Rogersef7d42f2014-01-06 12:55:46 -08001642 std::set<uintptr_t> offsets_;
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001643 Disassembler* disassembler_;
Mathieu Chartier5e7c6a92017-01-17 16:38:30 -08001644 Stats stats_;
Brian Carlstromaded5f72011-10-07 17:15:04 -07001645};
1646
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08001647class ImageDumper {
Brian Carlstrom27ec9612011-09-19 20:20:38 -07001648 public:
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08001649 ImageDumper(std::ostream* os,
1650 gc::space::ImageSpace& image_space,
1651 const ImageHeader& image_header,
1652 OatDumperOptions* oat_dumper_options)
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001653 : os_(os),
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001654 vios_(os),
1655 indent1_(&vios_),
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001656 image_space_(image_space),
1657 image_header_(image_header),
1658 oat_dumper_options_(oat_dumper_options) {}
Brian Carlstrom27ec9612011-09-19 20:20:38 -07001659
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001660 bool Dump() REQUIRES_SHARED(Locks::mutator_lock_) {
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001661 std::ostream& os = *os_;
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001662 std::ostream& indent_os = vios_.Stream();
1663
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001664 os << "MAGIC: " << image_header_.GetMagic() << "\n\n";
Brian Carlstrome24fa612011-09-29 00:53:55 -07001665
Jeff Haodcdc85b2015-12-04 14:06:18 -08001666 os << "IMAGE LOCATION: " << image_space_.GetImageLocation() << "\n\n";
1667
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001668 os << "IMAGE BEGIN: " << reinterpret_cast<void*>(image_header_.GetImageBegin()) << "\n\n";
Brian Carlstromaded5f72011-10-07 17:15:04 -07001669
Mathieu Chartiere401d142015-04-22 13:56:20 -07001670 os << "IMAGE SIZE: " << image_header_.GetImageSize() << "\n\n";
1671
1672 for (size_t i = 0; i < ImageHeader::kSectionCount; ++i) {
1673 auto section = static_cast<ImageHeader::ImageSections>(i);
1674 os << "IMAGE SECTION " << section << ": " << image_header_.GetImageSection(section) << "\n\n";
1675 }
Mathieu Chartier31e89252013-08-28 11:29:12 -07001676
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001677 os << "OAT CHECKSUM: " << StringPrintf("0x%08x\n\n", image_header_.GetOatChecksum());
Brian Carlstrom916e74e2011-09-23 11:42:01 -07001678
Brian Carlstrom700c8d32012-11-05 10:42:02 -08001679 os << "OAT FILE BEGIN:" << reinterpret_cast<void*>(image_header_.GetOatFileBegin()) << "\n\n";
Brian Carlstromaded5f72011-10-07 17:15:04 -07001680
Brian Carlstrom700c8d32012-11-05 10:42:02 -08001681 os << "OAT DATA BEGIN:" << reinterpret_cast<void*>(image_header_.GetOatDataBegin()) << "\n\n";
1682
1683 os << "OAT DATA END:" << reinterpret_cast<void*>(image_header_.GetOatDataEnd()) << "\n\n";
1684
1685 os << "OAT FILE END:" << reinterpret_cast<void*>(image_header_.GetOatFileEnd()) << "\n\n";
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08001686
Alex Lighta59dd802014-07-02 16:28:08 -07001687 os << "PATCH DELTA:" << image_header_.GetPatchDelta() << "\n\n";
1688
Igor Murashkin46774762014-10-22 11:37:02 -07001689 os << "COMPILE PIC: " << (image_header_.CompilePic() ? "yes" : "no") << "\n\n";
1690
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001691 {
1692 os << "ROOTS: " << reinterpret_cast<void*>(image_header_.GetImageRoots()) << "\n";
Mathieu Chartiere401d142015-04-22 13:56:20 -07001693 static_assert(arraysize(image_roots_descriptions_) ==
1694 static_cast<size_t>(ImageHeader::kImageRootsMax), "sizes must match");
Vladimir Markoeca3eda2016-11-09 16:26:44 +00001695 DCHECK_LE(image_header_.GetImageRoots()->GetLength(), ImageHeader::kImageRootsMax);
1696 for (int32_t i = 0, size = image_header_.GetImageRoots()->GetLength(); i != size; ++i) {
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001697 ImageHeader::ImageRoot image_root = static_cast<ImageHeader::ImageRoot>(i);
1698 const char* image_root_description = image_roots_descriptions_[i];
Ian Rogers2dd0e2c2013-01-24 12:42:14 -08001699 mirror::Object* image_root_object = image_header_.GetImageRoot(image_root);
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001700 indent_os << StringPrintf("%s: %p\n", image_root_description, image_root_object);
Vladimir Markoeca3eda2016-11-09 16:26:44 +00001701 if (image_root_object != nullptr && image_root_object->IsObjectArray()) {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -08001702 mirror::ObjectArray<mirror::Object>* image_root_object_array
Ian Rogersfa824272013-11-05 16:12:57 -08001703 = image_root_object->AsObjectArray<mirror::Object>();
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001704 ScopedIndentation indent2(&vios_);
Andreas Gampe277ccbd2014-11-03 21:36:10 -08001705 for (int j = 0; j < image_root_object_array->GetLength(); j++) {
1706 mirror::Object* value = image_root_object_array->Get(j);
Ian Rogersfa824272013-11-05 16:12:57 -08001707 size_t run = 0;
Andreas Gampe277ccbd2014-11-03 21:36:10 -08001708 for (int32_t k = j + 1; k < image_root_object_array->GetLength(); k++) {
1709 if (value == image_root_object_array->Get(k)) {
Ian Rogersfa824272013-11-05 16:12:57 -08001710 run++;
1711 } else {
1712 break;
1713 }
1714 }
1715 if (run == 0) {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001716 indent_os << StringPrintf("%d: ", j);
Ian Rogersfa824272013-11-05 16:12:57 -08001717 } else {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001718 indent_os << StringPrintf("%d to %zd: ", j, j + run);
Andreas Gampe277ccbd2014-11-03 21:36:10 -08001719 j = j + run;
Ian Rogersfa824272013-11-05 16:12:57 -08001720 }
Andreas Gampe2ed8def2014-08-28 14:41:02 -07001721 if (value != nullptr) {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001722 PrettyObjectValue(indent_os, value->GetClass(), value);
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001723 } else {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001724 indent_os << j << ": null\n";
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001725 }
Ian Rogersd5b32602012-02-26 16:40:04 -08001726 }
Brian Carlstrom34f426c2011-10-04 12:58:02 -07001727 }
1728 }
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001729 }
Mathieu Chartiere401d142015-04-22 13:56:20 -07001730
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001731 {
Mathieu Chartiere401d142015-04-22 13:56:20 -07001732 os << "METHOD ROOTS\n";
1733 static_assert(arraysize(image_methods_descriptions_) ==
1734 static_cast<size_t>(ImageHeader::kImageMethodsCount), "sizes must match");
1735 for (int i = 0; i < ImageHeader::kImageMethodsCount; i++) {
1736 auto image_root = static_cast<ImageHeader::ImageMethod>(i);
1737 const char* description = image_methods_descriptions_[i];
1738 auto* image_method = image_header_.GetImageMethod(image_root);
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001739 indent_os << StringPrintf("%s: %p\n", description, image_method);
Mathieu Chartiere401d142015-04-22 13:56:20 -07001740 }
Brian Carlstrom27ec9612011-09-19 20:20:38 -07001741 }
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001742 os << "\n";
Brian Carlstrom27ec9612011-09-19 20:20:38 -07001743
Mathieu Chartierf9c6fc62015-10-07 11:44:05 -07001744 Runtime* const runtime = Runtime::Current();
1745 ClassLinker* class_linker = runtime->GetClassLinker();
Brian Carlstrom2ec65202014-03-03 15:16:37 -08001746 std::string image_filename = image_space_.GetImageFilename();
1747 std::string oat_location = ImageHeader::GetOatLocationFromImageLocation(image_filename);
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001748 os << "OAT LOCATION: " << oat_location;
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001749 os << "\n";
Ian Rogers8d31bbd2013-10-13 10:44:14 -07001750 std::string error_msg;
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08001751 const OatFile* oat_file = image_space_.GetOatFile();
Alex Lighta59dd802014-07-02 16:28:08 -07001752 if (oat_file == nullptr) {
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08001753 oat_file = runtime->GetOatFileManager().FindOpenedOatFileFromOatLocation(oat_location);
1754 }
1755 if (oat_file == nullptr) {
1756 oat_file = OatFile::Open(oat_location,
1757 oat_location,
1758 nullptr,
1759 nullptr,
1760 false,
1761 /*low_4gb*/false,
1762 nullptr,
Igor Murashkinb1d8c312015-08-04 11:18:43 -07001763 &error_msg);
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08001764 }
1765 if (oat_file == nullptr) {
1766 os << "OAT FILE NOT FOUND: " << error_msg << "\n";
1767 return EXIT_FAILURE;
Brian Carlstromaded5f72011-10-07 17:15:04 -07001768 }
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001769 os << "\n";
Brian Carlstromaded5f72011-10-07 17:15:04 -07001770
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08001771 stats_.oat_file_bytes = oat_file->Size();
1772
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08001773 oat_dumper_.reset(new OatDumper(*oat_file, *oat_dumper_options_));
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08001774
Mathieu Chartier02e25112013-08-14 16:14:24 -07001775 for (const OatFile::OatDexFile* oat_dex_file : oat_file->GetOatDexFiles()) {
Andreas Gampe2ed8def2014-08-28 14:41:02 -07001776 CHECK(oat_dex_file != nullptr);
Mathieu Chartier02e25112013-08-14 16:14:24 -07001777 stats_.oat_dex_file_sizes.push_back(std::make_pair(oat_dex_file->GetDexFileLocation(),
1778 oat_dex_file->FileSize()));
Ian Rogers05f28c62012-10-23 18:12:13 -07001779 }
1780
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001781 os << "OBJECTS:\n" << std::flush;
Mathieu Chartierb062fdd2012-07-03 09:51:48 -07001782
Jeff Haodcdc85b2015-12-04 14:06:18 -08001783 // Loop through the image space and dump its objects.
Mathieu Chartierf9c6fc62015-10-07 11:44:05 -07001784 gc::Heap* heap = runtime->GetHeap();
Ian Rogers50b35e22012-10-04 10:09:15 -07001785 Thread* self = Thread::Current();
Mathieu Chartier357e9be2012-08-01 11:00:14 -07001786 {
Mathieu Chartierc22c59e2014-02-24 15:16:06 -08001787 {
1788 WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
1789 heap->FlushAllocStack();
1790 }
Hiroshi Yamauchi90d70682014-02-20 16:17:30 -08001791 // Since FlushAllocStack() above resets the (active) allocation
1792 // stack. Need to revoke the thread-local allocation stacks that
1793 // point into it.
Mathieu Chartierf1d666e2015-09-03 16:13:34 -07001794 ScopedThreadSuspension sts(self, kNative);
Mathieu Chartier4f55e222015-09-04 13:26:21 -07001795 ScopedSuspendAll ssa(__FUNCTION__);
Mathieu Chartierf1d666e2015-09-03 16:13:34 -07001796 heap->RevokeAllThreadLocalAllocationStacks(self);
Mathieu Chartier357e9be2012-08-01 11:00:14 -07001797 }
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001798 {
Mathieu Chartiere401d142015-04-22 13:56:20 -07001799 // Mark dex caches.
Vladimir Marko05792b92015-08-03 11:56:49 +01001800 dex_caches_.clear();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001801 {
Andreas Gampecc1b5352016-12-01 16:58:38 -08001802 ReaderMutexLock mu(self, *Locks::dex_lock_);
Hiroshi Yamauchi04302db2015-11-11 23:45:34 -08001803 for (const ClassLinker::DexCacheData& data : class_linker->GetDexCachesData()) {
Mathieu Chartierc4f39252016-10-05 18:32:08 -07001804 ObjPtr<mirror::DexCache> dex_cache =
1805 ObjPtr<mirror::DexCache>::DownCast(self->DecodeJObject(data.weak_root));
Mathieu Chartier673ed3d2015-08-28 14:56:43 -07001806 if (dex_cache != nullptr) {
Mathieu Chartierc4f39252016-10-05 18:32:08 -07001807 dex_caches_.insert(dex_cache.Ptr());
Mathieu Chartier673ed3d2015-08-28 14:56:43 -07001808 }
Mathieu Chartiere401d142015-04-22 13:56:20 -07001809 }
1810 }
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001811 ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
Jeff Haodcdc85b2015-12-04 14:06:18 -08001812 // Dump the normal objects before ArtMethods.
1813 image_space_.GetLiveBitmap()->Walk(ImageDumper::Callback, this);
1814 indent_os << "\n";
1815 // TODO: Dump fields.
1816 // Dump methods after.
Jeff Haodcdc85b2015-12-04 14:06:18 -08001817 DumpArtMethodVisitor visitor(this);
Mathieu Chartiere42888f2016-04-14 10:49:19 -07001818 image_header_.VisitPackedArtMethods(&visitor,
1819 image_space_.Begin(),
1820 image_header_.GetPointerSize());
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001821 // Dump the large objects separately.
Mathieu Chartierbbd695c2014-04-16 09:48:48 -07001822 heap->GetLargeObjectsSpace()->GetLiveBitmap()->Walk(ImageDumper::Callback, this);
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001823 indent_os << "\n";
Mathieu Chartierb062fdd2012-07-03 09:51:48 -07001824 }
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001825 os << "STATS:\n" << std::flush;
Ian Rogers700a4022014-05-19 16:49:03 -07001826 std::unique_ptr<File> file(OS::OpenFileForReading(image_filename.c_str()));
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08001827 size_t data_size = image_header_.GetDataSize(); // stored size in file.
1828 if (file == nullptr) {
Brian Carlstrom2ec65202014-03-03 15:16:37 -08001829 LOG(WARNING) << "Failed to find image in " << image_filename;
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08001830 } else {
Brian Carlstrom2ec65202014-03-03 15:16:37 -08001831 stats_.file_bytes = file->GetLength();
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08001832 // If the image is compressed, adjust to decompressed size.
1833 size_t uncompressed_size = image_header_.GetImageSize() - sizeof(ImageHeader);
1834 if (image_header_.GetStorageMode() == ImageHeader::kStorageModeUncompressed) {
1835 DCHECK_EQ(uncompressed_size, data_size) << "Sizes should match for uncompressed image";
1836 }
1837 stats_.file_bytes += uncompressed_size - data_size;
Brian Carlstrom6f277752013-09-30 17:56:45 -07001838 }
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08001839 size_t header_bytes = sizeof(ImageHeader);
Andreas Gampeace0dc12016-01-20 13:33:13 -08001840 const auto& object_section = image_header_.GetImageSection(ImageHeader::kSectionObjects);
Mathieu Chartiere401d142015-04-22 13:56:20 -07001841 const auto& field_section = image_header_.GetImageSection(ImageHeader::kSectionArtFields);
1842 const auto& method_section = image_header_.GetMethodsSection();
Vladimir Marko05792b92015-08-03 11:56:49 +01001843 const auto& dex_cache_arrays_section = image_header_.GetImageSection(
1844 ImageHeader::kSectionDexCacheArrays);
Mathieu Chartierd39645e2015-06-09 17:50:29 -07001845 const auto& intern_section = image_header_.GetImageSection(
1846 ImageHeader::kSectionInternedStrings);
Mathieu Chartier208a5cb2015-12-02 15:44:07 -08001847 const auto& class_table_section = image_header_.GetImageSection(
1848 ImageHeader::kSectionClassTable);
Andreas Gampeace0dc12016-01-20 13:33:13 -08001849 const auto& bitmap_section = image_header_.GetImageSection(ImageHeader::kSectionImageBitmap);
1850
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08001851 stats_.header_bytes = header_bytes;
Andreas Gampeace0dc12016-01-20 13:33:13 -08001852
1853 // Objects are kObjectAlignment-aligned.
1854 // CHECK_EQ(RoundUp(header_bytes, kObjectAlignment), object_section.Offset());
1855 if (object_section.Offset() > header_bytes) {
1856 stats_.alignment_bytes += object_section.Offset() - header_bytes;
1857 }
1858
1859 // Field section is 4-byte aligned.
1860 constexpr size_t kFieldSectionAlignment = 4U;
1861 uint32_t end_objects = object_section.Offset() + object_section.Size();
1862 CHECK_EQ(RoundUp(end_objects, kFieldSectionAlignment), field_section.Offset());
1863 stats_.alignment_bytes += field_section.Offset() - end_objects;
1864
1865 // Method section is 4/8 byte aligned depending on target. Just check for 4-byte alignment.
1866 uint32_t end_fields = field_section.Offset() + field_section.Size();
1867 CHECK_ALIGNED(method_section.Offset(), 4);
1868 stats_.alignment_bytes += method_section.Offset() - end_fields;
1869
1870 // Dex cache arrays section is aligned depending on the target. Just check for 4-byte alignment.
1871 uint32_t end_methods = method_section.Offset() + method_section.Size();
1872 CHECK_ALIGNED(dex_cache_arrays_section.Offset(), 4);
1873 stats_.alignment_bytes += dex_cache_arrays_section.Offset() - end_methods;
1874
1875 // Intern table is 8-byte aligned.
1876 uint32_t end_caches = dex_cache_arrays_section.Offset() + dex_cache_arrays_section.Size();
1877 CHECK_EQ(RoundUp(end_caches, 8U), intern_section.Offset());
1878 stats_.alignment_bytes += intern_section.Offset() - end_caches;
1879
1880 // Add space between intern table and class table.
1881 uint32_t end_intern = intern_section.Offset() + intern_section.Size();
1882 stats_.alignment_bytes += class_table_section.Offset() - end_intern;
1883
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08001884 // Add space between end of image data and bitmap. Expect the bitmap to be page-aligned.
1885 const size_t bitmap_offset = sizeof(ImageHeader) + data_size;
Andreas Gampeace0dc12016-01-20 13:33:13 -08001886 CHECK_ALIGNED(bitmap_section.Offset(), kPageSize);
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08001887 stats_.alignment_bytes += RoundUp(bitmap_offset, kPageSize) - bitmap_offset;
Andreas Gampeace0dc12016-01-20 13:33:13 -08001888
Mathieu Chartiere401d142015-04-22 13:56:20 -07001889 stats_.bitmap_bytes += bitmap_section.Size();
1890 stats_.art_field_bytes += field_section.Size();
Vladimir Markocf36d492015-08-12 19:27:26 +01001891 stats_.art_method_bytes += method_section.Size();
Vladimir Marko05792b92015-08-03 11:56:49 +01001892 stats_.dex_cache_arrays_bytes += dex_cache_arrays_section.Size();
Mathieu Chartierd39645e2015-06-09 17:50:29 -07001893 stats_.interned_strings_bytes += intern_section.Size();
Mathieu Chartier208a5cb2015-12-02 15:44:07 -08001894 stats_.class_table_bytes += class_table_section.Size();
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001895 stats_.Dump(os, indent_os);
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001896 os << "\n";
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08001897
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001898 os << std::flush;
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08001899
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001900 return oat_dumper_->Dump(os);
Brian Carlstrom78128a62011-09-15 17:21:19 -07001901 }
1902
Brian Carlstrom27ec9612011-09-19 20:20:38 -07001903 private:
Mathieu Chartier54d220e2015-07-30 16:20:06 -07001904 class DumpArtMethodVisitor : public ArtMethodVisitor {
1905 public:
1906 explicit DumpArtMethodVisitor(ImageDumper* image_dumper) : image_dumper_(image_dumper) {}
1907
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001908 virtual void Visit(ArtMethod* method) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
Mathieu Chartier54d220e2015-07-30 16:20:06 -07001909 std::ostream& indent_os = image_dumper_->vios_.Stream();
David Sehr709b0702016-10-13 09:12:37 -07001910 indent_os << method << " " << " ArtMethod: " << ArtMethod::PrettyMethod(method) << "\n";
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08001911 image_dumper_->DumpMethod(method, indent_os);
Mathieu Chartier54d220e2015-07-30 16:20:06 -07001912 indent_os << "\n";
1913 }
1914
1915 private:
1916 ImageDumper* const image_dumper_;
1917 };
1918
Mathieu Chartier3398c782016-09-30 10:27:43 -07001919 static void PrettyObjectValue(std::ostream& os,
1920 ObjPtr<mirror::Class> type,
1921 ObjPtr<mirror::Object> value)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001922 REQUIRES_SHARED(Locks::mutator_lock_) {
Andreas Gampe2ed8def2014-08-28 14:41:02 -07001923 CHECK(type != nullptr);
1924 if (value == nullptr) {
David Sehr709b0702016-10-13 09:12:37 -07001925 os << StringPrintf("null %s\n", type->PrettyDescriptor().c_str());
Ian Rogersd5b32602012-02-26 16:40:04 -08001926 } else if (type->IsStringClass()) {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -08001927 mirror::String* string = value->AsString();
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001928 os << StringPrintf("%p String: %s\n", string,
Ian Rogers68b56852014-08-29 20:19:11 -07001929 PrintableString(string->ToModifiedUtf8().c_str()).c_str());
Ian Rogers64b6d142012-10-29 16:34:15 -07001930 } else if (type->IsClassClass()) {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -08001931 mirror::Class* klass = value->AsClass();
David Sehr709b0702016-10-13 09:12:37 -07001932 os << StringPrintf("%p Class: %s\n", klass, mirror::Class::PrettyDescriptor(klass).c_str());
Ian Rogersd5b32602012-02-26 16:40:04 -08001933 } else {
David Sehr709b0702016-10-13 09:12:37 -07001934 os << StringPrintf("%p %s\n", value.Ptr(), type->PrettyDescriptor().c_str());
Ian Rogersd5b32602012-02-26 16:40:04 -08001935 }
1936 }
1937
Mathieu Chartier3398c782016-09-30 10:27:43 -07001938 static void PrintField(std::ostream& os, ArtField* field, ObjPtr<mirror::Object> obj)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001939 REQUIRES_SHARED(Locks::mutator_lock_) {
Mathieu Chartier61c5ebc2014-06-05 17:42:53 -07001940 os << StringPrintf("%s: ", field->GetName());
Ian Rogers08f1f502014-12-02 15:04:37 -08001941 switch (field->GetTypeAsPrimitiveType()) {
1942 case Primitive::kPrimLong:
Ian Rogersef7d42f2014-01-06 12:55:46 -08001943 os << StringPrintf("%" PRId64 " (0x%" PRIx64 ")\n", field->Get64(obj), field->Get64(obj));
Ian Rogers08f1f502014-12-02 15:04:37 -08001944 break;
1945 case Primitive::kPrimDouble:
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001946 os << StringPrintf("%f (%a)\n", field->GetDouble(obj), field->GetDouble(obj));
Ian Rogers08f1f502014-12-02 15:04:37 -08001947 break;
1948 case Primitive::kPrimFloat:
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001949 os << StringPrintf("%f (%a)\n", field->GetFloat(obj), field->GetFloat(obj));
Ian Rogers08f1f502014-12-02 15:04:37 -08001950 break;
1951 case Primitive::kPrimInt:
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001952 os << StringPrintf("%d (0x%x)\n", field->Get32(obj), field->Get32(obj));
Ian Rogers08f1f502014-12-02 15:04:37 -08001953 break;
1954 case Primitive::kPrimChar:
Fred Shih37f05ef2014-07-16 18:38:08 -07001955 os << StringPrintf("%u (0x%x)\n", field->GetChar(obj), field->GetChar(obj));
Ian Rogers08f1f502014-12-02 15:04:37 -08001956 break;
1957 case Primitive::kPrimShort:
Fred Shih37f05ef2014-07-16 18:38:08 -07001958 os << StringPrintf("%d (0x%x)\n", field->GetShort(obj), field->GetShort(obj));
Ian Rogers08f1f502014-12-02 15:04:37 -08001959 break;
1960 case Primitive::kPrimBoolean:
Fred Shih37f05ef2014-07-16 18:38:08 -07001961 os << StringPrintf("%s (0x%x)\n", field->GetBoolean(obj)? "true" : "false",
1962 field->GetBoolean(obj));
Ian Rogers08f1f502014-12-02 15:04:37 -08001963 break;
1964 case Primitive::kPrimByte:
Fred Shih37f05ef2014-07-16 18:38:08 -07001965 os << StringPrintf("%d (0x%x)\n", field->GetByte(obj), field->GetByte(obj));
Ian Rogers08f1f502014-12-02 15:04:37 -08001966 break;
1967 case Primitive::kPrimNot: {
1968 // Get the value, don't compute the type unless it is non-null as we don't want
1969 // to cause class loading.
Mathieu Chartier3398c782016-09-30 10:27:43 -07001970 ObjPtr<mirror::Object> value = field->GetObj(obj);
Ian Rogers08f1f502014-12-02 15:04:37 -08001971 if (value == nullptr) {
1972 os << StringPrintf("null %s\n", PrettyDescriptor(field->GetTypeDescriptor()).c_str());
Ian Rogers50239c72013-06-17 14:53:22 -07001973 } else {
Ian Rogers08f1f502014-12-02 15:04:37 -08001974 // Grab the field type without causing resolution.
Mathieu Chartier3398c782016-09-30 10:27:43 -07001975 ObjPtr<mirror::Class> field_type = field->GetType<false>();
Ian Rogers08f1f502014-12-02 15:04:37 -08001976 if (field_type != nullptr) {
1977 PrettyObjectValue(os, field_type, value);
1978 } else {
Mathieu Chartier3398c782016-09-30 10:27:43 -07001979 os << StringPrintf("%p %s\n",
Mathieu Chartier1cc62e42016-10-03 18:01:28 -07001980 value.Ptr(),
Ian Rogers08f1f502014-12-02 15:04:37 -08001981 PrettyDescriptor(field->GetTypeDescriptor()).c_str());
1982 }
Ian Rogers50239c72013-06-17 14:53:22 -07001983 }
Ian Rogers08f1f502014-12-02 15:04:37 -08001984 break;
Ian Rogers48efc2b2012-08-27 17:20:31 -07001985 }
Ian Rogers08f1f502014-12-02 15:04:37 -08001986 default:
1987 os << "unexpected field type: " << field->GetTypeDescriptor() << "\n";
1988 break;
Ian Rogersd5b32602012-02-26 16:40:04 -08001989 }
1990 }
1991
Ian Rogers2dd0e2c2013-01-24 12:42:14 -08001992 static void DumpFields(std::ostream& os, mirror::Object* obj, mirror::Class* klass)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07001993 REQUIRES_SHARED(Locks::mutator_lock_) {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -08001994 mirror::Class* super = klass->GetSuperClass();
Andreas Gampe2ed8def2014-08-28 14:41:02 -07001995 if (super != nullptr) {
Ian Rogers2bcb4a42012-11-08 10:39:18 -08001996 DumpFields(os, obj, super);
Ian Rogersd5b32602012-02-26 16:40:04 -08001997 }
Mathieu Chartier54d220e2015-07-30 16:20:06 -07001998 for (ArtField& field : klass->GetIFields()) {
1999 PrintField(os, &field, obj);
Ian Rogersd5b32602012-02-26 16:40:04 -08002000 }
2001 }
2002
Ian Rogers2dd0e2c2013-01-24 12:42:14 -08002003 bool InDumpSpace(const mirror::Object* object) {
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002004 return image_space_.Contains(object);
Brian Carlstromf8bbb842012-03-14 03:01:42 -07002005 }
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002006
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07002007 const void* GetQuickOatCodeBegin(ArtMethod* m) REQUIRES_SHARED(Locks::mutator_lock_) {
Mathieu Chartiera7dd0382014-11-20 17:08:58 -08002008 const void* quick_code = m->GetEntryPointFromQuickCompiledCodePtrSize(
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08002009 image_header_.GetPointerSize());
Ian Rogers6f3dbba2014-10-14 17:41:57 -07002010 if (Runtime::Current()->GetClassLinker()->IsQuickResolutionStub(quick_code)) {
Ian Rogersef7d42f2014-01-06 12:55:46 -08002011 quick_code = oat_dumper_->GetQuickOatCode(m);
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002012 }
Brian Carlstromf8bbb842012-03-14 03:01:42 -07002013 if (oat_dumper_->GetInstructionSet() == kThumb2) {
Ian Rogersef7d42f2014-01-06 12:55:46 -08002014 quick_code = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(quick_code) & ~0x1);
Brian Carlstromf8bbb842012-03-14 03:01:42 -07002015 }
Ian Rogersef7d42f2014-01-06 12:55:46 -08002016 return quick_code;
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002017 }
2018
Mathieu Chartiere401d142015-04-22 13:56:20 -07002019 uint32_t GetQuickOatCodeSize(ArtMethod* m)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07002020 REQUIRES_SHARED(Locks::mutator_lock_) {
Ian Rogersef7d42f2014-01-06 12:55:46 -08002021 const uint32_t* oat_code_begin = reinterpret_cast<const uint32_t*>(GetQuickOatCodeBegin(m));
2022 if (oat_code_begin == nullptr) {
Brian Carlstromf8bbb842012-03-14 03:01:42 -07002023 return 0;
2024 }
2025 return oat_code_begin[-1];
2026 }
2027
Mathieu Chartiere401d142015-04-22 13:56:20 -07002028 const void* GetQuickOatCodeEnd(ArtMethod* m)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07002029 REQUIRES_SHARED(Locks::mutator_lock_) {
Ian Rogersef7d42f2014-01-06 12:55:46 -08002030 const uint8_t* oat_code_begin = reinterpret_cast<const uint8_t*>(GetQuickOatCodeBegin(m));
Andreas Gampe2ed8def2014-08-28 14:41:02 -07002031 if (oat_code_begin == nullptr) {
2032 return nullptr;
Brian Carlstromf8bbb842012-03-14 03:01:42 -07002033 }
Ian Rogersef7d42f2014-01-06 12:55:46 -08002034 return oat_code_begin + GetQuickOatCodeSize(m);
Brian Carlstromf8bbb842012-03-14 03:01:42 -07002035 }
2036
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07002037 static void Callback(mirror::Object* obj, void* arg) REQUIRES_SHARED(Locks::mutator_lock_) {
Andreas Gampe2ed8def2014-08-28 14:41:02 -07002038 DCHECK(obj != nullptr);
2039 DCHECK(arg != nullptr);
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002040 ImageDumper* state = reinterpret_cast<ImageDumper*>(arg);
Brian Carlstrom78128a62011-09-15 17:21:19 -07002041 if (!state->InDumpSpace(obj)) {
2042 return;
2043 }
Brian Carlstrom916e74e2011-09-23 11:42:01 -07002044
2045 size_t object_bytes = obj->SizeOf();
2046 size_t alignment_bytes = RoundUp(object_bytes, kObjectAlignment) - object_bytes;
2047 state->stats_.object_bytes += object_bytes;
2048 state->stats_.alignment_bytes += alignment_bytes;
2049
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01002050 std::ostream& os = state->vios_.Stream();
2051
Ian Rogers2dd0e2c2013-01-24 12:42:14 -08002052 mirror::Class* obj_class = obj->GetClass();
Ian Rogersd5b32602012-02-26 16:40:04 -08002053 if (obj_class->IsArrayClass()) {
David Sehr709b0702016-10-13 09:12:37 -07002054 os << StringPrintf("%p: %s length:%d\n", obj, obj_class->PrettyDescriptor().c_str(),
Ian Rogers2bcb4a42012-11-08 10:39:18 -08002055 obj->AsArray()->GetLength());
Ian Rogersd5b32602012-02-26 16:40:04 -08002056 } else if (obj->IsClass()) {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -08002057 mirror::Class* klass = obj->AsClass();
David Sehr709b0702016-10-13 09:12:37 -07002058 os << StringPrintf("%p: java.lang.Class \"%s\" (", obj,
2059 mirror::Class::PrettyDescriptor(klass).c_str())
Ian Rogers2bcb4a42012-11-08 10:39:18 -08002060 << klass->GetStatus() << ")\n";
Ian Rogersd5b32602012-02-26 16:40:04 -08002061 } else if (obj_class->IsStringClass()) {
Ian Rogers2bcb4a42012-11-08 10:39:18 -08002062 os << StringPrintf("%p: java.lang.String %s\n", obj,
Ian Rogers68b56852014-08-29 20:19:11 -07002063 PrintableString(obj->AsString()->ToModifiedUtf8().c_str()).c_str());
Ian Rogersd5b32602012-02-26 16:40:04 -08002064 } else {
David Sehr709b0702016-10-13 09:12:37 -07002065 os << StringPrintf("%p: %s\n", obj, obj_class->PrettyDescriptor().c_str());
Ian Rogersd5b32602012-02-26 16:40:04 -08002066 }
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01002067 ScopedIndentation indent1(&state->vios_);
2068 DumpFields(os, obj, obj_class);
Andreas Gampe542451c2016-07-26 09:02:02 -07002069 const PointerSize image_pointer_size = state->image_header_.GetPointerSize();
Ian Rogersd5b32602012-02-26 16:40:04 -08002070 if (obj->IsObjectArray()) {
Mathieu Chartiere401d142015-04-22 13:56:20 -07002071 auto* obj_array = obj->AsObjectArray<mirror::Object>();
2072 for (int32_t i = 0, length = obj_array->GetLength(); i < length; i++) {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -08002073 mirror::Object* value = obj_array->Get(i);
Ian Rogersd5b32602012-02-26 16:40:04 -08002074 size_t run = 0;
2075 for (int32_t j = i + 1; j < length; j++) {
2076 if (value == obj_array->Get(j)) {
2077 run++;
2078 } else {
2079 break;
2080 }
2081 }
2082 if (run == 0) {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01002083 os << StringPrintf("%d: ", i);
Ian Rogersd5b32602012-02-26 16:40:04 -08002084 } else {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01002085 os << StringPrintf("%d to %zd: ", i, i + run);
Ian Rogersd5b32602012-02-26 16:40:04 -08002086 i = i + run;
2087 }
Brian Carlstrom2ec65202014-03-03 15:16:37 -08002088 mirror::Class* value_class =
Andreas Gampe2ed8def2014-08-28 14:41:02 -07002089 (value == nullptr) ? obj_class->GetComponentType() : value->GetClass();
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01002090 PrettyObjectValue(os, value_class, value);
Ian Rogersd5b32602012-02-26 16:40:04 -08002091 }
2092 } else if (obj->IsClass()) {
Mathieu Chartierc7853442015-03-27 14:35:38 -07002093 mirror::Class* klass = obj->AsClass();
Mathieu Chartier54d220e2015-07-30 16:20:06 -07002094 if (klass->NumStaticFields() != 0) {
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01002095 os << "STATICS:\n";
2096 ScopedIndentation indent2(&state->vios_);
Mathieu Chartier54d220e2015-07-30 16:20:06 -07002097 for (ArtField& field : klass->GetSFields()) {
2098 PrintField(os, &field, field.GetDeclaringClass());
Ian Rogersd5b32602012-02-26 16:40:04 -08002099 }
2100 }
Mathieu Chartiere401d142015-04-22 13:56:20 -07002101 } else {
Vladimir Marko05792b92015-08-03 11:56:49 +01002102 auto it = state->dex_caches_.find(obj);
2103 if (it != state->dex_caches_.end()) {
2104 auto* dex_cache = down_cast<mirror::DexCache*>(obj);
Mathieu Chartiere401d142015-04-22 13:56:20 -07002105 const auto& field_section = state->image_header_.GetImageSection(
2106 ImageHeader::kSectionArtFields);
2107 const auto& method_section = state->image_header_.GetMethodsSection();
Vladimir Marko05792b92015-08-03 11:56:49 +01002108 size_t num_methods = dex_cache->NumResolvedMethods();
2109 if (num_methods != 0u) {
Nicolas Geoffrayc6df1e32016-07-04 10:15:47 +01002110 os << "Methods (size=" << num_methods << "):\n";
Vladimir Marko05792b92015-08-03 11:56:49 +01002111 ScopedIndentation indent2(&state->vios_);
2112 auto* resolved_methods = dex_cache->GetResolvedMethods();
2113 for (size_t i = 0, length = dex_cache->NumResolvedMethods(); i < length; ++i) {
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08002114 auto* elem = mirror::DexCache::GetElementPtrSize(resolved_methods,
2115 i,
2116 image_pointer_size);
Vladimir Marko05792b92015-08-03 11:56:49 +01002117 size_t run = 0;
2118 for (size_t j = i + 1;
Nicolas Geoffrayc6df1e32016-07-04 10:15:47 +01002119 j != length && elem == mirror::DexCache::GetElementPtrSize(resolved_methods,
2120 j,
2121 image_pointer_size);
2122 ++j) {
2123 ++run;
2124 }
Vladimir Marko05792b92015-08-03 11:56:49 +01002125 if (run == 0) {
2126 os << StringPrintf("%zd: ", i);
2127 } else {
2128 os << StringPrintf("%zd to %zd: ", i, i + run);
2129 i = i + run;
2130 }
2131 std::string msg;
2132 if (elem == nullptr) {
2133 msg = "null";
2134 } else if (method_section.Contains(
2135 reinterpret_cast<uint8_t*>(elem) - state->image_space_.Begin())) {
David Sehr709b0702016-10-13 09:12:37 -07002136 msg = reinterpret_cast<ArtMethod*>(elem)->PrettyMethod();
Vladimir Marko05792b92015-08-03 11:56:49 +01002137 } else {
2138 msg = "<not in method section>";
2139 }
2140 os << StringPrintf("%p %s\n", elem, msg.c_str());
Ian Rogers0d2d3782012-04-10 11:09:18 -07002141 }
Vladimir Marko05792b92015-08-03 11:56:49 +01002142 }
2143 size_t num_fields = dex_cache->NumResolvedFields();
2144 if (num_fields != 0u) {
Nicolas Geoffrayc6df1e32016-07-04 10:15:47 +01002145 os << "Fields (size=" << num_fields << "):\n";
Vladimir Marko05792b92015-08-03 11:56:49 +01002146 ScopedIndentation indent2(&state->vios_);
2147 auto* resolved_fields = dex_cache->GetResolvedFields();
2148 for (size_t i = 0, length = dex_cache->NumResolvedFields(); i < length; ++i) {
Nicolas Geoffrayc6df1e32016-07-04 10:15:47 +01002149 auto* elem = mirror::DexCache::GetElementPtrSize(
2150 resolved_fields, i, image_pointer_size);
Vladimir Marko05792b92015-08-03 11:56:49 +01002151 size_t run = 0;
2152 for (size_t j = i + 1;
Nicolas Geoffrayc6df1e32016-07-04 10:15:47 +01002153 j != length && elem == mirror::DexCache::GetElementPtrSize(resolved_fields,
2154 j,
2155 image_pointer_size);
2156 ++j) {
2157 ++run;
2158 }
Vladimir Marko05792b92015-08-03 11:56:49 +01002159 if (run == 0) {
2160 os << StringPrintf("%zd: ", i);
2161 } else {
2162 os << StringPrintf("%zd to %zd: ", i, i + run);
2163 i = i + run;
2164 }
2165 std::string msg;
2166 if (elem == nullptr) {
2167 msg = "null";
2168 } else if (field_section.Contains(
2169 reinterpret_cast<uint8_t*>(elem) - state->image_space_.Begin())) {
David Sehr709b0702016-10-13 09:12:37 -07002170 msg = reinterpret_cast<ArtField*>(elem)->PrettyField();
Vladimir Marko05792b92015-08-03 11:56:49 +01002171 } else {
2172 msg = "<not in field section>";
2173 }
2174 os << StringPrintf("%p %s\n", elem, msg.c_str());
Mathieu Chartiere401d142015-04-22 13:56:20 -07002175 }
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002176 }
Nicolas Geoffrayc6df1e32016-07-04 10:15:47 +01002177 size_t num_types = dex_cache->NumResolvedTypes();
2178 if (num_types != 0u) {
2179 os << "Types (size=" << num_types << "):\n";
2180 ScopedIndentation indent2(&state->vios_);
2181 auto* resolved_types = dex_cache->GetResolvedTypes();
2182 for (size_t i = 0; i < num_types; ++i) {
2183 auto* elem = resolved_types[i].Read();
2184 size_t run = 0;
2185 for (size_t j = i + 1; j != num_types && elem == resolved_types[j].Read(); ++j) {
2186 ++run;
2187 }
2188 if (run == 0) {
2189 os << StringPrintf("%zd: ", i);
2190 } else {
2191 os << StringPrintf("%zd to %zd: ", i, i + run);
2192 i = i + run;
2193 }
2194 std::string msg;
2195 if (elem == nullptr) {
2196 msg = "null";
2197 } else {
David Sehr709b0702016-10-13 09:12:37 -07002198 msg = elem->PrettyClass();
Nicolas Geoffrayc6df1e32016-07-04 10:15:47 +01002199 }
2200 os << StringPrintf("%p %s\n", elem, msg.c_str());
2201 }
2202 }
Brian Carlstrom78128a62011-09-15 17:21:19 -07002203 }
2204 }
Ian Rogers1ff3c982014-08-12 02:30:58 -07002205 std::string temp;
2206 state->stats_.Update(obj_class->GetDescriptor(&temp), object_bytes);
Brian Carlstrom78128a62011-09-15 17:21:19 -07002207 }
Brian Carlstrom27ec9612011-09-19 20:20:38 -07002208
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08002209 void DumpMethod(ArtMethod* method, std::ostream& indent_os)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07002210 REQUIRES_SHARED(Locks::mutator_lock_) {
Mathieu Chartiere401d142015-04-22 13:56:20 -07002211 DCHECK(method != nullptr);
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08002212 const void* quick_oat_code_begin = GetQuickOatCodeBegin(method);
2213 const void* quick_oat_code_end = GetQuickOatCodeEnd(method);
Andreas Gampe542451c2016-07-26 09:02:02 -07002214 const PointerSize pointer_size = image_header_.GetPointerSize();
Nicolas Geoffray524e7ea2015-10-16 17:13:34 +01002215 OatQuickMethodHeader* method_header = reinterpret_cast<OatQuickMethodHeader*>(
2216 reinterpret_cast<uintptr_t>(quick_oat_code_begin) - sizeof(OatQuickMethodHeader));
Mathieu Chartiere401d142015-04-22 13:56:20 -07002217 if (method->IsNative()) {
Mathieu Chartiere401d142015-04-22 13:56:20 -07002218 bool first_occurrence;
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08002219 uint32_t quick_oat_code_size = GetQuickOatCodeSize(method);
2220 ComputeOatSize(quick_oat_code_begin, &first_occurrence);
Mathieu Chartiere401d142015-04-22 13:56:20 -07002221 if (first_occurrence) {
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08002222 stats_.native_to_managed_code_bytes += quick_oat_code_size;
Mathieu Chartiere401d142015-04-22 13:56:20 -07002223 }
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08002224 if (quick_oat_code_begin != method->GetEntryPointFromQuickCompiledCodePtrSize(
2225 image_header_.GetPointerSize())) {
Nicolas Geoffray6bc43742015-10-12 18:11:10 +01002226 indent_os << StringPrintf("OAT CODE: %p\n", quick_oat_code_begin);
Mathieu Chartiere401d142015-04-22 13:56:20 -07002227 }
Mathieu Chartiere42888f2016-04-14 10:49:19 -07002228 } else if (method->IsAbstract() || method->IsClassInitializer()) {
Nicolas Geoffray796d6302016-03-13 22:22:31 +00002229 // Don't print information for these.
Mathieu Chartiere42888f2016-04-14 10:49:19 -07002230 } else if (method->IsRuntimeMethod()) {
2231 ImtConflictTable* table = method->GetImtConflictTable(image_header_.GetPointerSize());
2232 if (table != nullptr) {
2233 indent_os << "IMT conflict table " << table << " method: ";
2234 for (size_t i = 0, count = table->NumEntries(pointer_size); i < count; ++i) {
David Sehr709b0702016-10-13 09:12:37 -07002235 indent_os << ArtMethod::PrettyMethod(table->GetImplementationMethod(i, pointer_size))
2236 << " ";
Mathieu Chartiere42888f2016-04-14 10:49:19 -07002237 }
2238 }
Mathieu Chartiere401d142015-04-22 13:56:20 -07002239 } else {
2240 const DexFile::CodeItem* code_item = method->GetCodeItem();
2241 size_t dex_instruction_bytes = code_item->insns_size_in_code_units_ * 2;
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08002242 stats_.dex_instruction_bytes += dex_instruction_bytes;
Mathieu Chartiere401d142015-04-22 13:56:20 -07002243
2244 bool first_occurrence;
Roland Levillain6d7f1792015-07-02 10:59:15 +01002245 size_t vmap_table_bytes = 0u;
Nicolas Geoffray524e7ea2015-10-16 17:13:34 +01002246 if (!method_header->IsOptimized()) {
Roland Levillain6d7f1792015-07-02 10:59:15 +01002247 // Method compiled with the optimizing compiler have no vmap table.
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08002248 vmap_table_bytes = ComputeOatSize(method_header->GetVmapTable(), &first_occurrence);
Roland Levillain6d7f1792015-07-02 10:59:15 +01002249 if (first_occurrence) {
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08002250 stats_.vmap_table_bytes += vmap_table_bytes;
Roland Levillain6d7f1792015-07-02 10:59:15 +01002251 }
Mathieu Chartiere401d142015-04-22 13:56:20 -07002252 }
2253
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08002254 uint32_t quick_oat_code_size = GetQuickOatCodeSize(method);
2255 ComputeOatSize(quick_oat_code_begin, &first_occurrence);
Mathieu Chartiere401d142015-04-22 13:56:20 -07002256 if (first_occurrence) {
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08002257 stats_.managed_code_bytes += quick_oat_code_size;
Mathieu Chartiere401d142015-04-22 13:56:20 -07002258 if (method->IsConstructor()) {
2259 if (method->IsStatic()) {
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08002260 stats_.class_initializer_code_bytes += quick_oat_code_size;
Mathieu Chartiere401d142015-04-22 13:56:20 -07002261 } else if (dex_instruction_bytes > kLargeConstructorDexBytes) {
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08002262 stats_.large_initializer_code_bytes += quick_oat_code_size;
Mathieu Chartiere401d142015-04-22 13:56:20 -07002263 }
2264 } else if (dex_instruction_bytes > kLargeMethodDexBytes) {
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08002265 stats_.large_method_code_bytes += quick_oat_code_size;
Mathieu Chartiere401d142015-04-22 13:56:20 -07002266 }
2267 }
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08002268 stats_.managed_code_bytes_ignoring_deduplication += quick_oat_code_size;
Mathieu Chartiere401d142015-04-22 13:56:20 -07002269
Igor Murashkin7617abd2015-07-10 18:27:47 -07002270 uint32_t method_access_flags = method->GetAccessFlags();
2271
Mathieu Chartiere401d142015-04-22 13:56:20 -07002272 indent_os << StringPrintf("OAT CODE: %p-%p\n", quick_oat_code_begin, quick_oat_code_end);
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01002273 indent_os << StringPrintf("SIZE: Dex Instructions=%zd StackMaps=%zd AccessFlags=0x%x\n",
2274 dex_instruction_bytes,
2275 vmap_table_bytes,
Igor Murashkin7617abd2015-07-10 18:27:47 -07002276 method_access_flags);
Mathieu Chartiere401d142015-04-22 13:56:20 -07002277
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01002278 size_t total_size = dex_instruction_bytes +
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08002279 vmap_table_bytes + quick_oat_code_size + ArtMethod::Size(image_header_.GetPointerSize());
Mathieu Chartiere401d142015-04-22 13:56:20 -07002280
2281 double expansion =
2282 static_cast<double>(quick_oat_code_size) / static_cast<double>(dex_instruction_bytes);
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08002283 stats_.ComputeOutliers(total_size, expansion, method);
Mathieu Chartiere401d142015-04-22 13:56:20 -07002284 }
2285 }
2286
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002287 std::set<const void*> already_seen_;
2288 // Compute the size of the given data within the oat file and whether this is the first time
2289 // this data has been requested
Elliott Hughesa0e18062012-04-13 15:59:59 -07002290 size_t ComputeOatSize(const void* oat_data, bool* first_occurrence) {
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002291 if (already_seen_.count(oat_data) == 0) {
Elliott Hughesa0e18062012-04-13 15:59:59 -07002292 *first_occurrence = true;
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002293 already_seen_.insert(oat_data);
2294 } else {
Elliott Hughesa0e18062012-04-13 15:59:59 -07002295 *first_occurrence = false;
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002296 }
2297 return oat_dumper_->ComputeSize(oat_data);
Brian Carlstrom27ec9612011-09-19 20:20:38 -07002298 }
Brian Carlstrom916e74e2011-09-23 11:42:01 -07002299
2300 public:
2301 struct Stats {
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002302 size_t oat_file_bytes;
Brian Carlstrom916e74e2011-09-23 11:42:01 -07002303 size_t file_bytes;
2304
2305 size_t header_bytes;
2306 size_t object_bytes;
Mathieu Chartiere401d142015-04-22 13:56:20 -07002307 size_t art_field_bytes;
2308 size_t art_method_bytes;
Vladimir Marko05792b92015-08-03 11:56:49 +01002309 size_t dex_cache_arrays_bytes;
Mathieu Chartierd39645e2015-06-09 17:50:29 -07002310 size_t interned_strings_bytes;
Mathieu Chartier208a5cb2015-12-02 15:44:07 -08002311 size_t class_table_bytes;
Mathieu Chartier32327092013-08-30 14:04:08 -07002312 size_t bitmap_bytes;
Brian Carlstrom916e74e2011-09-23 11:42:01 -07002313 size_t alignment_bytes;
2314
2315 size_t managed_code_bytes;
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002316 size_t managed_code_bytes_ignoring_deduplication;
Brian Carlstrom916e74e2011-09-23 11:42:01 -07002317 size_t native_to_managed_code_bytes;
Ian Rogers0d2d3782012-04-10 11:09:18 -07002318 size_t class_initializer_code_bytes;
2319 size_t large_initializer_code_bytes;
2320 size_t large_method_code_bytes;
Brian Carlstrom916e74e2011-09-23 11:42:01 -07002321
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002322 size_t vmap_table_bytes;
Brian Carlstrom916e74e2011-09-23 11:42:01 -07002323
2324 size_t dex_instruction_bytes;
2325
Mathieu Chartiere401d142015-04-22 13:56:20 -07002326 std::vector<ArtMethod*> method_outlier;
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002327 std::vector<size_t> method_outlier_size;
2328 std::vector<double> method_outlier_expansion;
Ian Rogers700a4022014-05-19 16:49:03 -07002329 std::vector<std::pair<std::string, size_t>> oat_dex_file_sizes;
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002330
Roland Levillain3887c462015-08-12 18:15:42 +01002331 Stats()
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002332 : oat_file_bytes(0),
2333 file_bytes(0),
Brian Carlstrom916e74e2011-09-23 11:42:01 -07002334 header_bytes(0),
2335 object_bytes(0),
Mathieu Chartiere401d142015-04-22 13:56:20 -07002336 art_field_bytes(0),
2337 art_method_bytes(0),
Vladimir Marko05792b92015-08-03 11:56:49 +01002338 dex_cache_arrays_bytes(0),
Mathieu Chartierd39645e2015-06-09 17:50:29 -07002339 interned_strings_bytes(0),
Mathieu Chartier208a5cb2015-12-02 15:44:07 -08002340 class_table_bytes(0),
Mathieu Chartier32327092013-08-30 14:04:08 -07002341 bitmap_bytes(0),
Brian Carlstrom916e74e2011-09-23 11:42:01 -07002342 alignment_bytes(0),
2343 managed_code_bytes(0),
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002344 managed_code_bytes_ignoring_deduplication(0),
Brian Carlstrom916e74e2011-09-23 11:42:01 -07002345 native_to_managed_code_bytes(0),
Ian Rogers0d2d3782012-04-10 11:09:18 -07002346 class_initializer_code_bytes(0),
2347 large_initializer_code_bytes(0),
2348 large_method_code_bytes(0),
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002349 vmap_table_bytes(0),
Brian Carlstrom916e74e2011-09-23 11:42:01 -07002350 dex_instruction_bytes(0) {}
2351
Elliott Hughesa0e18062012-04-13 15:59:59 -07002352 struct SizeAndCount {
Andreas Gampe277ccbd2014-11-03 21:36:10 -08002353 SizeAndCount(size_t bytes_in, size_t count_in) : bytes(bytes_in), count(count_in) {}
Elliott Hughesa0e18062012-04-13 15:59:59 -07002354 size_t bytes;
2355 size_t count;
2356 };
2357 typedef SafeMap<std::string, SizeAndCount> SizeAndCountTable;
2358 SizeAndCountTable sizes_and_counts;
Brian Carlstrom916e74e2011-09-23 11:42:01 -07002359
Andreas Gampe277ccbd2014-11-03 21:36:10 -08002360 void Update(const char* descriptor, size_t object_bytes_in) {
Elliott Hughesa0e18062012-04-13 15:59:59 -07002361 SizeAndCountTable::iterator it = sizes_and_counts.find(descriptor);
2362 if (it != sizes_and_counts.end()) {
Andreas Gampe277ccbd2014-11-03 21:36:10 -08002363 it->second.bytes += object_bytes_in;
Elliott Hughesa0e18062012-04-13 15:59:59 -07002364 it->second.count += 1;
2365 } else {
Andreas Gampe277ccbd2014-11-03 21:36:10 -08002366 sizes_and_counts.Put(descriptor, SizeAndCount(object_bytes_in, 1));
Elliott Hughesa0e18062012-04-13 15:59:59 -07002367 }
2368 }
Brian Carlstrom916e74e2011-09-23 11:42:01 -07002369
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002370 double PercentOfOatBytes(size_t size) {
2371 return (static_cast<double>(size) / static_cast<double>(oat_file_bytes)) * 100;
2372 }
2373
Brian Carlstrom916e74e2011-09-23 11:42:01 -07002374 double PercentOfFileBytes(size_t size) {
2375 return (static_cast<double>(size) / static_cast<double>(file_bytes)) * 100;
2376 }
2377
2378 double PercentOfObjectBytes(size_t size) {
2379 return (static_cast<double>(size) / static_cast<double>(object_bytes)) * 100;
2380 }
2381
Mathieu Chartiere401d142015-04-22 13:56:20 -07002382 void ComputeOutliers(size_t total_size, double expansion, ArtMethod* method) {
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002383 method_outlier_size.push_back(total_size);
2384 method_outlier_expansion.push_back(expansion);
2385 method_outlier.push_back(method);
2386 }
Brian Carlstrom916e74e2011-09-23 11:42:01 -07002387
Ian Rogers00f7d0e2012-07-19 15:28:27 -07002388 void DumpOutliers(std::ostream& os)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07002389 REQUIRES_SHARED(Locks::mutator_lock_) {
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002390 size_t sum_of_sizes = 0;
2391 size_t sum_of_sizes_squared = 0;
2392 size_t sum_of_expansion = 0;
2393 size_t sum_of_expansion_squared = 0;
2394 size_t n = method_outlier_size.size();
Mathieu Chartier1ebf8d32016-06-09 11:51:27 -07002395 if (n <= 1) {
Jeff Haodcdc85b2015-12-04 14:06:18 -08002396 return;
2397 }
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002398 for (size_t i = 0; i < n; i++) {
2399 size_t cur_size = method_outlier_size[i];
2400 sum_of_sizes += cur_size;
2401 sum_of_sizes_squared += cur_size * cur_size;
2402 double cur_expansion = method_outlier_expansion[i];
2403 sum_of_expansion += cur_expansion;
2404 sum_of_expansion_squared += cur_expansion * cur_expansion;
2405 }
2406 size_t size_mean = sum_of_sizes / n;
2407 size_t size_variance = (sum_of_sizes_squared - sum_of_sizes * size_mean) / (n - 1);
2408 double expansion_mean = sum_of_expansion / n;
2409 double expansion_variance =
2410 (sum_of_expansion_squared - sum_of_expansion * expansion_mean) / (n - 1);
2411
2412 // Dump methods whose size is a certain number of standard deviations from the mean
2413 size_t dumped_values = 0;
2414 size_t skipped_values = 0;
2415 for (size_t i = 100; i > 0; i--) { // i is the current number of standard deviations
2416 size_t cur_size_variance = i * i * size_variance;
2417 bool first = true;
2418 for (size_t j = 0; j < n; j++) {
2419 size_t cur_size = method_outlier_size[j];
2420 if (cur_size > size_mean) {
2421 size_t cur_var = cur_size - size_mean;
2422 cur_var = cur_var * cur_var;
2423 if (cur_var > cur_size_variance) {
2424 if (dumped_values > 20) {
2425 if (i == 1) {
2426 skipped_values++;
2427 } else {
2428 i = 2; // jump to counting for 1 standard deviation
2429 break;
2430 }
2431 } else {
2432 if (first) {
Elliott Hughesc073b072012-05-24 19:29:17 -07002433 os << "\nBig methods (size > " << i << " standard deviations the norm):\n";
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002434 first = false;
2435 }
David Sehr709b0702016-10-13 09:12:37 -07002436 os << ArtMethod::PrettyMethod(method_outlier[j]) << " requires storage of "
Elliott Hughesc073b072012-05-24 19:29:17 -07002437 << PrettySize(cur_size) << "\n";
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002438 method_outlier_size[j] = 0; // don't consider this method again
2439 dumped_values++;
2440 }
2441 }
2442 }
2443 }
2444 }
2445 if (skipped_values > 0) {
Ian Rogers2bcb4a42012-11-08 10:39:18 -08002446 os << "... skipped " << skipped_values
Elliott Hughesc073b072012-05-24 19:29:17 -07002447 << " methods with size > 1 standard deviation from the norm\n";
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002448 }
Elliott Hughesc073b072012-05-24 19:29:17 -07002449 os << std::flush;
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002450
2451 // Dump methods whose expansion is a certain number of standard deviations from the mean
2452 dumped_values = 0;
2453 skipped_values = 0;
2454 for (size_t i = 10; i > 0; i--) { // i is the current number of standard deviations
2455 double cur_expansion_variance = i * i * expansion_variance;
2456 bool first = true;
2457 for (size_t j = 0; j < n; j++) {
2458 double cur_expansion = method_outlier_expansion[j];
2459 if (cur_expansion > expansion_mean) {
2460 size_t cur_var = cur_expansion - expansion_mean;
2461 cur_var = cur_var * cur_var;
2462 if (cur_var > cur_expansion_variance) {
2463 if (dumped_values > 20) {
2464 if (i == 1) {
2465 skipped_values++;
2466 } else {
2467 i = 2; // jump to counting for 1 standard deviation
2468 break;
2469 }
2470 } else {
2471 if (first) {
2472 os << "\nLarge expansion methods (size > " << i
Elliott Hughesc073b072012-05-24 19:29:17 -07002473 << " standard deviations the norm):\n";
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002474 first = false;
2475 }
David Sehr709b0702016-10-13 09:12:37 -07002476 os << ArtMethod::PrettyMethod(method_outlier[j]) << " expanded code by "
Elliott Hughesc073b072012-05-24 19:29:17 -07002477 << cur_expansion << "\n";
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002478 method_outlier_expansion[j] = 0.0; // don't consider this method again
2479 dumped_values++;
2480 }
2481 }
2482 }
2483 }
2484 }
2485 if (skipped_values > 0) {
Ian Rogers2bcb4a42012-11-08 10:39:18 -08002486 os << "... skipped " << skipped_values
Elliott Hughesc073b072012-05-24 19:29:17 -07002487 << " methods with expansion > 1 standard deviation from the norm\n";
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002488 }
Elliott Hughesc073b072012-05-24 19:29:17 -07002489 os << "\n" << std::flush;
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002490 }
2491
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01002492 void Dump(std::ostream& os, std::ostream& indent_os)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07002493 REQUIRES_SHARED(Locks::mutator_lock_) {
Ian Rogers2bcb4a42012-11-08 10:39:18 -08002494 {
2495 os << "art_file_bytes = " << PrettySize(file_bytes) << "\n\n"
2496 << "art_file_bytes = header_bytes + object_bytes + alignment_bytes\n";
Vladimir Marko05792b92015-08-03 11:56:49 +01002497 indent_os << StringPrintf("header_bytes = %8zd (%2.0f%% of art file bytes)\n"
2498 "object_bytes = %8zd (%2.0f%% of art file bytes)\n"
2499 "art_field_bytes = %8zd (%2.0f%% of art file bytes)\n"
2500 "art_method_bytes = %8zd (%2.0f%% of art file bytes)\n"
2501 "dex_cache_arrays_bytes = %8zd (%2.0f%% of art file bytes)\n"
2502 "interned_string_bytes = %8zd (%2.0f%% of art file bytes)\n"
Mathieu Chartier208a5cb2015-12-02 15:44:07 -08002503 "class_table_bytes = %8zd (%2.0f%% of art file bytes)\n"
Vladimir Marko05792b92015-08-03 11:56:49 +01002504 "bitmap_bytes = %8zd (%2.0f%% of art file bytes)\n"
2505 "alignment_bytes = %8zd (%2.0f%% of art file bytes)\n\n",
Ian Rogers2bcb4a42012-11-08 10:39:18 -08002506 header_bytes, PercentOfFileBytes(header_bytes),
2507 object_bytes, PercentOfFileBytes(object_bytes),
Mathieu Chartiere401d142015-04-22 13:56:20 -07002508 art_field_bytes, PercentOfFileBytes(art_field_bytes),
2509 art_method_bytes, PercentOfFileBytes(art_method_bytes),
Vladimir Marko05792b92015-08-03 11:56:49 +01002510 dex_cache_arrays_bytes,
2511 PercentOfFileBytes(dex_cache_arrays_bytes),
Mathieu Chartierd39645e2015-06-09 17:50:29 -07002512 interned_strings_bytes,
2513 PercentOfFileBytes(interned_strings_bytes),
Mathieu Chartier208a5cb2015-12-02 15:44:07 -08002514 class_table_bytes, PercentOfFileBytes(class_table_bytes),
Mathieu Chartier32327092013-08-30 14:04:08 -07002515 bitmap_bytes, PercentOfFileBytes(bitmap_bytes),
Ian Rogers2bcb4a42012-11-08 10:39:18 -08002516 alignment_bytes, PercentOfFileBytes(alignment_bytes))
2517 << std::flush;
Mathieu Chartier208a5cb2015-12-02 15:44:07 -08002518 CHECK_EQ(file_bytes,
2519 header_bytes + object_bytes + art_field_bytes + art_method_bytes +
2520 dex_cache_arrays_bytes + interned_strings_bytes + class_table_bytes +
2521 bitmap_bytes + alignment_bytes);
Ian Rogers2bcb4a42012-11-08 10:39:18 -08002522 }
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002523
Ian Rogers2bcb4a42012-11-08 10:39:18 -08002524 os << "object_bytes breakdown:\n";
Brian Carlstrom916e74e2011-09-23 11:42:01 -07002525 size_t object_bytes_total = 0;
Mathieu Chartier02e25112013-08-14 16:14:24 -07002526 for (const auto& sizes_and_count : sizes_and_counts) {
2527 const std::string& descriptor(sizes_and_count.first);
2528 double average = static_cast<double>(sizes_and_count.second.bytes) /
2529 static_cast<double>(sizes_and_count.second.count);
2530 double percent = PercentOfObjectBytes(sizes_and_count.second.bytes);
Ian Rogers2bcb4a42012-11-08 10:39:18 -08002531 os << StringPrintf("%32s %8zd bytes %6zd instances "
Elliott Hughesa0e18062012-04-13 15:59:59 -07002532 "(%4.0f bytes/instance) %2.0f%% of object_bytes\n",
Mathieu Chartier02e25112013-08-14 16:14:24 -07002533 descriptor.c_str(), sizes_and_count.second.bytes,
2534 sizes_and_count.second.count, average, percent);
2535 object_bytes_total += sizes_and_count.second.bytes;
Brian Carlstrom916e74e2011-09-23 11:42:01 -07002536 }
Elliott Hughesc073b072012-05-24 19:29:17 -07002537 os << "\n" << std::flush;
Brian Carlstrom916e74e2011-09-23 11:42:01 -07002538 CHECK_EQ(object_bytes, object_bytes_total);
2539
Ian Rogers2bcb4a42012-11-08 10:39:18 -08002540 os << StringPrintf("oat_file_bytes = %8zd\n"
2541 "managed_code_bytes = %8zd (%2.0f%% of oat file bytes)\n"
Ian Rogers2bcb4a42012-11-08 10:39:18 -08002542 "native_to_managed_code_bytes = %8zd (%2.0f%% of oat file bytes)\n\n"
2543 "class_initializer_code_bytes = %8zd (%2.0f%% of oat file bytes)\n"
2544 "large_initializer_code_bytes = %8zd (%2.0f%% of oat file bytes)\n"
2545 "large_method_code_bytes = %8zd (%2.0f%% of oat file bytes)\n\n",
Ian Rogers05f28c62012-10-23 18:12:13 -07002546 oat_file_bytes,
Brian Carlstrom2ec65202014-03-03 15:16:37 -08002547 managed_code_bytes,
2548 PercentOfOatBytes(managed_code_bytes),
Brian Carlstrom2ec65202014-03-03 15:16:37 -08002549 native_to_managed_code_bytes,
2550 PercentOfOatBytes(native_to_managed_code_bytes),
2551 class_initializer_code_bytes,
2552 PercentOfOatBytes(class_initializer_code_bytes),
2553 large_initializer_code_bytes,
2554 PercentOfOatBytes(large_initializer_code_bytes),
2555 large_method_code_bytes,
2556 PercentOfOatBytes(large_method_code_bytes))
Ian Rogers2bcb4a42012-11-08 10:39:18 -08002557 << "DexFile sizes:\n";
Mathieu Chartier02e25112013-08-14 16:14:24 -07002558 for (const std::pair<std::string, size_t>& oat_dex_file_size : oat_dex_file_sizes) {
Ian Rogers2bcb4a42012-11-08 10:39:18 -08002559 os << StringPrintf("%s = %zd (%2.0f%% of oat file bytes)\n",
Mathieu Chartier02e25112013-08-14 16:14:24 -07002560 oat_dex_file_size.first.c_str(), oat_dex_file_size.second,
2561 PercentOfOatBytes(oat_dex_file_size.second));
Ian Rogers05f28c62012-10-23 18:12:13 -07002562 }
2563
Vladimir Marko9d07e3d2016-03-31 12:02:28 +01002564 os << "\n" << StringPrintf("vmap_table_bytes = %7zd (%2.0f%% of oat file bytes)\n\n",
Ian Rogers05f28c62012-10-23 18:12:13 -07002565 vmap_table_bytes, PercentOfOatBytes(vmap_table_bytes))
Elliott Hughesc073b072012-05-24 19:29:17 -07002566 << std::flush;
Brian Carlstrom916e74e2011-09-23 11:42:01 -07002567
Ian Rogers2bcb4a42012-11-08 10:39:18 -08002568 os << StringPrintf("dex_instruction_bytes = %zd\n", dex_instruction_bytes)
2569 << StringPrintf("managed_code_bytes expansion = %.2f (ignoring deduplication %.2f)\n\n",
Brian Carlstrom2ec65202014-03-03 15:16:37 -08002570 static_cast<double>(managed_code_bytes) /
2571 static_cast<double>(dex_instruction_bytes),
Elliott Hughesc073b072012-05-24 19:29:17 -07002572 static_cast<double>(managed_code_bytes_ignoring_deduplication) /
Elliott Hughescf44e6f2012-05-24 19:42:18 -07002573 static_cast<double>(dex_instruction_bytes))
Elliott Hughesc073b072012-05-24 19:29:17 -07002574 << std::flush;
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002575
2576 DumpOutliers(os);
Brian Carlstrom916e74e2011-09-23 11:42:01 -07002577 }
2578 } stats_;
2579
2580 private:
Ian Rogers0d2d3782012-04-10 11:09:18 -07002581 enum {
2582 // Number of bytes for a constructor to be considered large. Based on the 1000 basic block
2583 // threshold, we assume 2 bytes per instruction and 2 instructions per block.
2584 kLargeConstructorDexBytes = 4000,
2585 // Number of bytes for a method to be considered large. Based on the 4000 basic block
2586 // threshold, we assume 2 bytes per instruction and 2 instructions per block.
2587 kLargeMethodDexBytes = 16000
2588 };
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01002589
2590 // For performance, use the *os_ directly for anything that doesn't need indentation
2591 // and prepare an indentation stream with default indentation 1.
Ian Rogers2bcb4a42012-11-08 10:39:18 -08002592 std::ostream* os_;
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01002593 VariableIndentationOutputStream vios_;
2594 ScopedIndentation indent1_;
2595
Ian Rogers1d54e732013-05-02 21:10:01 -07002596 gc::space::ImageSpace& image_space_;
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002597 const ImageHeader& image_header_;
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07002598 std::unique_ptr<OatDumper> oat_dumper_;
Andreas Gampedf2bb1f2015-05-04 18:25:23 -07002599 OatDumperOptions* oat_dumper_options_;
Vladimir Marko05792b92015-08-03 11:56:49 +01002600 std::set<mirror::Object*> dex_caches_;
Elliott Hughesd1bb4f62011-09-23 14:09:45 -07002601
Ian Rogers3a5c1ce2012-02-29 10:06:46 -08002602 DISALLOW_COPY_AND_ASSIGN(ImageDumper);
Brian Carlstrom78128a62011-09-15 17:21:19 -07002603};
2604
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08002605static int DumpImage(gc::space::ImageSpace* image_space,
2606 OatDumperOptions* options,
Andreas Gampebdf7f1c2016-08-30 16:38:47 -07002607 std::ostream* os) REQUIRES_SHARED(Locks::mutator_lock_) {
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08002608 const ImageHeader& image_header = image_space->GetImageHeader();
2609 if (!image_header.IsValid()) {
2610 fprintf(stderr, "Invalid image header %s\n", image_space->GetImageLocation().c_str());
2611 return EXIT_FAILURE;
2612 }
2613 ImageDumper image_dumper(os, *image_space, image_header, options);
2614 if (!image_dumper.Dump()) {
2615 return EXIT_FAILURE;
2616 }
2617 return EXIT_SUCCESS;
2618}
2619
2620static int DumpImages(Runtime* runtime, OatDumperOptions* options, std::ostream* os) {
Andreas Gampe00b25f32014-09-17 21:49:05 -07002621 // Dumping the image, no explicit class loader.
Mathieu Chartier9865bde2015-12-21 09:58:16 -08002622 ScopedNullHandle<mirror::ClassLoader> null_class_loader;
Andreas Gampe00b25f32014-09-17 21:49:05 -07002623 options->class_loader_ = &null_class_loader;
2624
Ian Rogers00f7d0e2012-07-19 15:28:27 -07002625 ScopedObjectAccess soa(Thread::Current());
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08002626 if (options->app_image_ != nullptr) {
2627 if (options->app_oat_ == nullptr) {
2628 LOG(ERROR) << "Can not dump app image without app oat file";
Jeff Haodcdc85b2015-12-04 14:06:18 -08002629 return EXIT_FAILURE;
2630 }
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08002631 // We can't know if the app image is 32 bits yet, but it contains pointers into the oat file.
2632 // We need to map the oat file in the low 4gb or else the fixup wont be able to fit oat file
2633 // pointers into 32 bit pointer sized ArtMethods.
2634 std::string error_msg;
2635 std::unique_ptr<OatFile> oat_file(OatFile::Open(options->app_oat_,
2636 options->app_oat_,
2637 nullptr,
2638 nullptr,
2639 false,
2640 /*low_4gb*/true,
2641 nullptr,
2642 &error_msg));
2643 if (oat_file == nullptr) {
2644 LOG(ERROR) << "Failed to open oat file " << options->app_oat_ << " with error " << error_msg;
Jeff Haodcdc85b2015-12-04 14:06:18 -08002645 return EXIT_FAILURE;
2646 }
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08002647 std::unique_ptr<gc::space::ImageSpace> space(
2648 gc::space::ImageSpace::CreateFromAppImage(options->app_image_, oat_file.get(), &error_msg));
2649 if (space == nullptr) {
2650 LOG(ERROR) << "Failed to open app image " << options->app_image_ << " with error "
2651 << error_msg;
2652 }
2653 // Open dex files for the image.
2654 std::vector<std::unique_ptr<const DexFile>> dex_files;
2655 if (!runtime->GetClassLinker()->OpenImageDexFiles(space.get(), &dex_files, &error_msg)) {
2656 LOG(ERROR) << "Failed to open app image dex files " << options->app_image_ << " with error "
2657 << error_msg;
2658 }
2659 // Dump the actual image.
2660 int result = DumpImage(space.get(), options, os);
2661 if (result != EXIT_SUCCESS) {
2662 return result;
2663 }
2664 // Fall through to dump the boot images.
2665 }
2666
2667 gc::Heap* heap = runtime->GetHeap();
2668 CHECK(heap->HasBootImageSpace()) << "No image spaces";
2669 for (gc::space::ImageSpace* image_space : heap->GetBootImageSpaces()) {
2670 int result = DumpImage(image_space, options, os);
2671 if (result != EXIT_SUCCESS) {
2672 return result;
2673 }
Brian Carlstrom78128a62011-09-15 17:21:19 -07002674 }
Jeff Haodcdc85b2015-12-04 14:06:18 -08002675 return EXIT_SUCCESS;
Brian Carlstrom78128a62011-09-15 17:21:19 -07002676}
2677
Andreas Gampeebfc1ac2016-09-29 19:50:27 -07002678static jobject InstallOatFile(Runtime* runtime,
2679 std::unique_ptr<OatFile> oat_file,
2680 std::vector<const DexFile*>* class_path)
2681 REQUIRES_SHARED(Locks::mutator_lock_) {
Andreas Gampe00b25f32014-09-17 21:49:05 -07002682 Thread* self = Thread::Current();
2683 CHECK(self != nullptr);
2684 // Need well-known-classes.
2685 WellKnownClasses::Init(self->GetJniEnv());
2686
2687 // Need to register dex files to get a working dex cache.
Andreas Gampeebfc1ac2016-09-29 19:50:27 -07002688 OatFile* oat_file_ptr = oat_file.get();
Andreas Gampe00b25f32014-09-17 21:49:05 -07002689 ClassLinker* class_linker = runtime->GetClassLinker();
Andreas Gampeebfc1ac2016-09-29 19:50:27 -07002690 runtime->GetOatFileManager().RegisterOatFile(std::move(oat_file));
2691 for (const OatFile::OatDexFile* odf : oat_file_ptr->GetOatDexFiles()) {
Andreas Gampe00b25f32014-09-17 21:49:05 -07002692 std::string error_msg;
Mathieu Chartierac8f4392015-08-27 13:54:20 -07002693 const DexFile* const dex_file = OpenDexFile(odf, &error_msg);
Andreas Gampe00b25f32014-09-17 21:49:05 -07002694 CHECK(dex_file != nullptr) << error_msg;
Mathieu Chartierf284d442016-06-02 11:48:30 -07002695 class_linker->RegisterDexFile(*dex_file, nullptr);
Andreas Gampeebfc1ac2016-09-29 19:50:27 -07002696 class_path->push_back(dex_file);
Andreas Gampe00b25f32014-09-17 21:49:05 -07002697 }
2698
Andreas Gampeebfc1ac2016-09-29 19:50:27 -07002699 // Need a class loader. Fake that we're a compiler.
2700 // Note: this will run initializers through the unstarted runtime, so make sure it's
2701 // initialized.
2702 interpreter::UnstartedRuntime::Initialize();
2703
2704 jobject class_loader = class_linker->CreatePathClassLoader(self, *class_path);
2705
2706 return class_loader;
2707}
2708
2709static int DumpOatWithRuntime(Runtime* runtime,
2710 std::unique_ptr<OatFile> oat_file,
2711 OatDumperOptions* options,
2712 std::ostream* os) {
2713 CHECK(runtime != nullptr && oat_file != nullptr && options != nullptr);
2714 ScopedObjectAccess soa(Thread::Current());
2715
2716 OatFile* oat_file_ptr = oat_file.get();
2717 std::vector<const DexFile*> class_path;
2718 jobject class_loader = InstallOatFile(runtime, std::move(oat_file), &class_path);
Andreas Gampe00b25f32014-09-17 21:49:05 -07002719
2720 // Use the class loader while dumping.
Andreas Gampeebfc1ac2016-09-29 19:50:27 -07002721 StackHandleScope<1> scope(soa.Self());
Andreas Gampe00b25f32014-09-17 21:49:05 -07002722 Handle<mirror::ClassLoader> loader_handle = scope.NewHandle(
Mathieu Chartier0795f232016-09-27 18:43:30 -07002723 soa.Decode<mirror::ClassLoader>(class_loader));
Andreas Gampe00b25f32014-09-17 21:49:05 -07002724 options->class_loader_ = &loader_handle;
2725
Andreas Gampeebfc1ac2016-09-29 19:50:27 -07002726 OatDumper oat_dumper(*oat_file_ptr, *options);
Andreas Gampe00b25f32014-09-17 21:49:05 -07002727 bool success = oat_dumper.Dump(*os);
2728 return (success) ? EXIT_SUCCESS : EXIT_FAILURE;
2729}
2730
2731static int DumpOatWithoutRuntime(OatFile* oat_file, OatDumperOptions* options, std::ostream* os) {
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08002732 CHECK(oat_file != nullptr && options != nullptr);
Andreas Gampe00b25f32014-09-17 21:49:05 -07002733 // No image = no class loader.
Mathieu Chartier9865bde2015-12-21 09:58:16 -08002734 ScopedNullHandle<mirror::ClassLoader> null_class_loader;
Andreas Gampe00b25f32014-09-17 21:49:05 -07002735 options->class_loader_ = &null_class_loader;
2736
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08002737 OatDumper oat_dumper(*oat_file, *options);
Andreas Gampe00b25f32014-09-17 21:49:05 -07002738 bool success = oat_dumper.Dump(*os);
2739 return (success) ? EXIT_SUCCESS : EXIT_FAILURE;
2740}
2741
2742static int DumpOat(Runtime* runtime, const char* oat_filename, OatDumperOptions* options,
2743 std::ostream* os) {
2744 std::string error_msg;
Andreas Gampeebfc1ac2016-09-29 19:50:27 -07002745 std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_filename,
2746 oat_filename,
2747 nullptr,
2748 nullptr,
2749 false,
2750 /*low_4gb*/false,
2751 nullptr,
2752 &error_msg));
Andreas Gampe00b25f32014-09-17 21:49:05 -07002753 if (oat_file == nullptr) {
2754 fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str());
2755 return EXIT_FAILURE;
2756 }
2757
2758 if (runtime != nullptr) {
Andreas Gampeebfc1ac2016-09-29 19:50:27 -07002759 return DumpOatWithRuntime(runtime, std::move(oat_file), options, os);
Andreas Gampe00b25f32014-09-17 21:49:05 -07002760 } else {
Andreas Gampeebfc1ac2016-09-29 19:50:27 -07002761 return DumpOatWithoutRuntime(oat_file.get(), options, os);
Andreas Gampe00b25f32014-09-17 21:49:05 -07002762 }
2763}
2764
David Srbecky2fdd03c2016-03-10 15:32:37 +00002765static int SymbolizeOat(const char* oat_filename, std::string& output_name, bool no_bits) {
Andreas Gampe00b25f32014-09-17 21:49:05 -07002766 std::string error_msg;
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08002767 OatFile* oat_file = OatFile::Open(oat_filename,
2768 oat_filename,
2769 nullptr,
2770 nullptr,
2771 false,
2772 /*low_4gb*/false,
2773 nullptr,
2774 &error_msg);
Andreas Gampe00b25f32014-09-17 21:49:05 -07002775 if (oat_file == nullptr) {
2776 fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str());
2777 return EXIT_FAILURE;
2778 }
2779
Andreas Gampe2d8614b2016-03-07 16:31:34 -08002780 bool result;
2781 // Try to produce an ELF file of the same type. This is finicky, as we have used 32-bit ELF
2782 // files for 64-bit code in the past.
2783 if (Is64BitInstructionSet(oat_file->GetOatHeader().GetInstructionSet())) {
David Srbecky2fdd03c2016-03-10 15:32:37 +00002784 OatSymbolizer<ElfTypes64> oat_symbolizer(oat_file, output_name, no_bits);
Andreas Gampe2d8614b2016-03-07 16:31:34 -08002785 result = oat_symbolizer.Symbolize();
2786 } else {
David Srbecky2fdd03c2016-03-10 15:32:37 +00002787 OatSymbolizer<ElfTypes32> oat_symbolizer(oat_file, output_name, no_bits);
Andreas Gampe2d8614b2016-03-07 16:31:34 -08002788 result = oat_symbolizer.Symbolize();
2789 }
2790 if (!result) {
Andreas Gampe00b25f32014-09-17 21:49:05 -07002791 fprintf(stderr, "Failed to symbolize\n");
2792 return EXIT_FAILURE;
2793 }
2794
2795 return EXIT_SUCCESS;
2796}
2797
Andreas Gampe9fded872016-09-25 16:08:35 -07002798class IMTDumper {
2799 public:
Andreas Gampeebfc1ac2016-09-29 19:50:27 -07002800 static bool Dump(Runtime* runtime,
2801 const std::string& imt_file,
2802 bool dump_imt_stats,
2803 const char* oat_filename) {
2804 Thread* self = Thread::Current();
2805
2806 ScopedObjectAccess soa(self);
2807 StackHandleScope<1> scope(self);
2808 MutableHandle<mirror::ClassLoader> class_loader = scope.NewHandle<mirror::ClassLoader>(nullptr);
2809 std::vector<const DexFile*> class_path;
2810
2811 if (oat_filename != nullptr) {
2812 std::string error_msg;
2813 std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_filename,
2814 oat_filename,
2815 nullptr,
2816 nullptr,
2817 false,
2818 /*low_4gb*/false,
2819 nullptr,
2820 &error_msg));
2821 if (oat_file == nullptr) {
2822 fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str());
2823 return false;
2824 }
2825
2826 class_loader.Assign(soa.Decode<mirror::ClassLoader>(
2827 InstallOatFile(runtime, std::move(oat_file), &class_path)));
2828 } else {
2829 class_loader.Assign(nullptr); // Boot classloader. Just here for explicit documentation.
2830 class_path = runtime->GetClassLinker()->GetBootClassPath();
2831 }
2832
2833 if (!imt_file.empty()) {
2834 return DumpImt(runtime, imt_file, class_loader);
2835 }
2836
2837 if (dump_imt_stats) {
2838 return DumpImtStats(runtime, class_path, class_loader);
2839 }
2840
2841 LOG(FATAL) << "Should not reach here";
2842 UNREACHABLE();
2843 }
2844
2845 private:
2846 static bool DumpImt(Runtime* runtime,
2847 const std::string& imt_file,
2848 Handle<mirror::ClassLoader> h_class_loader)
2849 REQUIRES_SHARED(Locks::mutator_lock_) {
Andreas Gampe9fded872016-09-25 16:08:35 -07002850 std::vector<std::string> lines = ReadCommentedInputFromFile(imt_file);
2851 std::unordered_set<std::string> prepared;
2852
2853 for (const std::string& line : lines) {
2854 // A line should be either a class descriptor, in which case we will dump the complete IMT,
2855 // or a class descriptor and an interface method, in which case we will lookup the method,
2856 // determine its IMT slot, and check the class' IMT.
2857 size_t first_space = line.find(' ');
2858 if (first_space == std::string::npos) {
Andreas Gampeebfc1ac2016-09-29 19:50:27 -07002859 DumpIMTForClass(runtime, line, h_class_loader, &prepared);
Andreas Gampe9fded872016-09-25 16:08:35 -07002860 } else {
2861 DumpIMTForMethod(runtime,
2862 line.substr(0, first_space),
2863 line.substr(first_space + 1, std::string::npos),
Andreas Gampeebfc1ac2016-09-29 19:50:27 -07002864 h_class_loader,
Andreas Gampe9fded872016-09-25 16:08:35 -07002865 &prepared);
2866 }
2867 std::cerr << std::endl;
2868 }
2869
2870 return true;
2871 }
2872
Andreas Gampeebfc1ac2016-09-29 19:50:27 -07002873 static bool DumpImtStats(Runtime* runtime,
2874 const std::vector<const DexFile*>& dex_files,
2875 Handle<mirror::ClassLoader> h_class_loader)
2876 REQUIRES_SHARED(Locks::mutator_lock_) {
2877 size_t without_imt = 0;
2878 size_t with_imt = 0;
Andreas Gampe9fded872016-09-25 16:08:35 -07002879 std::map<size_t, size_t> histogram;
2880
2881 ClassLinker* class_linker = runtime->GetClassLinker();
2882 const PointerSize pointer_size = class_linker->GetImagePointerSize();
2883 std::unordered_set<std::string> prepared;
2884
2885 Thread* self = Thread::Current();
Andreas Gampe9fded872016-09-25 16:08:35 -07002886 StackHandleScope<1> scope(self);
2887 MutableHandle<mirror::Class> h_klass(scope.NewHandle<mirror::Class>(nullptr));
2888
2889 for (const DexFile* dex_file : dex_files) {
2890 for (uint32_t class_def_index = 0;
Andreas Gampeebfc1ac2016-09-29 19:50:27 -07002891 class_def_index != dex_file->NumClassDefs();
2892 ++class_def_index) {
Andreas Gampe9fded872016-09-25 16:08:35 -07002893 const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
2894 const char* descriptor = dex_file->GetClassDescriptor(class_def);
Andreas Gampeebfc1ac2016-09-29 19:50:27 -07002895 h_klass.Assign(class_linker->FindClass(self, descriptor, h_class_loader));
Andreas Gampe9fded872016-09-25 16:08:35 -07002896 if (h_klass.Get() == nullptr) {
2897 std::cerr << "Warning: could not load " << descriptor << std::endl;
2898 continue;
2899 }
2900
2901 if (HasNoIMT(runtime, h_klass, pointer_size, &prepared)) {
Andreas Gampeebfc1ac2016-09-29 19:50:27 -07002902 without_imt++;
Andreas Gampe9fded872016-09-25 16:08:35 -07002903 continue;
2904 }
2905
2906 ImTable* im_table = PrepareAndGetImTable(runtime, h_klass, pointer_size, &prepared);
2907 if (im_table == nullptr) {
2908 // Should not happen, but accept.
Andreas Gampeebfc1ac2016-09-29 19:50:27 -07002909 without_imt++;
Andreas Gampe9fded872016-09-25 16:08:35 -07002910 continue;
2911 }
2912
Andreas Gampeebfc1ac2016-09-29 19:50:27 -07002913 with_imt++;
Andreas Gampe9fded872016-09-25 16:08:35 -07002914 for (size_t imt_index = 0; imt_index != ImTable::kSize; ++imt_index) {
2915 ArtMethod* ptr = im_table->Get(imt_index, pointer_size);
2916 if (ptr->IsRuntimeMethod()) {
2917 if (ptr->IsImtUnimplementedMethod()) {
2918 histogram[0]++;
2919 } else {
2920 ImtConflictTable* current_table = ptr->GetImtConflictTable(pointer_size);
2921 histogram[current_table->NumEntries(pointer_size)]++;
2922 }
2923 } else {
2924 histogram[1]++;
2925 }
2926 }
2927 }
2928 }
2929
2930 std::cerr << "IMT stats:"
2931 << std::endl << std::endl;
2932
Andreas Gampeebfc1ac2016-09-29 19:50:27 -07002933 std::cerr << " " << with_imt << " classes with IMT."
Andreas Gampe9fded872016-09-25 16:08:35 -07002934 << std::endl << std::endl;
Andreas Gampeebfc1ac2016-09-29 19:50:27 -07002935 std::cerr << " " << without_imt << " classes without IMT (or copy from Object)."
Andreas Gampe9fded872016-09-25 16:08:35 -07002936 << std::endl << std::endl;
2937
2938 double sum_one = 0;
2939 size_t count_one = 0;
2940
2941 std::cerr << " " << "IMT histogram" << std::endl;
2942 for (auto& bucket : histogram) {
2943 std::cerr << " " << bucket.first << " " << bucket.second << std::endl;
2944 if (bucket.first > 0) {
2945 sum_one += bucket.second * bucket.first;
2946 count_one += bucket.second;
2947 }
2948 }
2949
2950 double count_zero = count_one + histogram[0];
2951 std::cerr << " Stats:" << std::endl;
2952 std::cerr << " Average depth (including empty): " << (sum_one / count_zero) << std::endl;
2953 std::cerr << " Average depth (excluding empty): " << (sum_one / count_one) << std::endl;
2954
2955 return true;
2956 }
2957
Andreas Gampeebfc1ac2016-09-29 19:50:27 -07002958 // Return whether the given class has no IMT (or the one shared with java.lang.Object).
Andreas Gampe9fded872016-09-25 16:08:35 -07002959 static bool HasNoIMT(Runtime* runtime,
2960 Handle<mirror::Class> klass,
2961 const PointerSize pointer_size,
2962 std::unordered_set<std::string>* prepared)
2963 REQUIRES_SHARED(Locks::mutator_lock_) {
2964 if (klass->IsObjectClass() || !klass->ShouldHaveImt()) {
2965 return true;
2966 }
2967
2968 if (klass->GetImt(pointer_size) == nullptr) {
2969 PrepareClass(runtime, klass, prepared);
2970 }
2971
2972 mirror::Class* object_class = mirror::Class::GetJavaLangClass()->GetSuperClass();
2973 DCHECK(object_class->IsObjectClass());
2974
2975 bool result = klass->GetImt(pointer_size) == object_class->GetImt(pointer_size);
2976
Mathieu Chartier6beced42016-11-15 15:51:31 -08002977 if (klass->GetIfTable()->Count() == 0) {
Andreas Gampe9fded872016-09-25 16:08:35 -07002978 DCHECK(result);
2979 }
2980
2981 return result;
2982 }
2983
2984 static void PrintTable(ImtConflictTable* table, PointerSize pointer_size)
2985 REQUIRES_SHARED(Locks::mutator_lock_) {
2986 if (table == nullptr) {
2987 std::cerr << " <No IMT?>" << std::endl;
2988 return;
2989 }
2990 size_t table_index = 0;
2991 for (;;) {
2992 ArtMethod* ptr = table->GetInterfaceMethod(table_index, pointer_size);
2993 if (ptr == nullptr) {
2994 return;
2995 }
2996 table_index++;
David Sehr709b0702016-10-13 09:12:37 -07002997 std::cerr << " " << ptr->PrettyMethod(true) << std::endl;
Andreas Gampe9fded872016-09-25 16:08:35 -07002998 }
2999 }
3000
3001 static ImTable* PrepareAndGetImTable(Runtime* runtime,
3002 Thread* self,
Andreas Gampeebfc1ac2016-09-29 19:50:27 -07003003 Handle<mirror::ClassLoader> h_loader,
Andreas Gampe9fded872016-09-25 16:08:35 -07003004 const std::string& class_name,
3005 const PointerSize pointer_size,
3006 mirror::Class** klass_out,
3007 std::unordered_set<std::string>* prepared)
3008 REQUIRES_SHARED(Locks::mutator_lock_) {
3009 if (class_name.empty()) {
3010 return nullptr;
3011 }
3012
3013 std::string descriptor;
3014 if (class_name[0] == 'L') {
3015 descriptor = class_name;
3016 } else {
3017 descriptor = DotToDescriptor(class_name.c_str());
3018 }
3019
Andreas Gampeebfc1ac2016-09-29 19:50:27 -07003020 mirror::Class* klass = runtime->GetClassLinker()->FindClass(self, descriptor.c_str(), h_loader);
Andreas Gampe9fded872016-09-25 16:08:35 -07003021
3022 if (klass == nullptr) {
3023 self->ClearException();
3024 std::cerr << "Did not find " << class_name << std::endl;
3025 *klass_out = nullptr;
3026 return nullptr;
3027 }
3028
3029 StackHandleScope<1> scope(Thread::Current());
3030 Handle<mirror::Class> h_klass = scope.NewHandle<mirror::Class>(klass);
3031
3032 ImTable* ret = PrepareAndGetImTable(runtime, h_klass, pointer_size, prepared);
3033 *klass_out = h_klass.Get();
3034 return ret;
3035 }
3036
3037 static ImTable* PrepareAndGetImTable(Runtime* runtime,
3038 Handle<mirror::Class> h_klass,
3039 const PointerSize pointer_size,
3040 std::unordered_set<std::string>* prepared)
3041 REQUIRES_SHARED(Locks::mutator_lock_) {
3042 PrepareClass(runtime, h_klass, prepared);
3043 return h_klass->GetImt(pointer_size);
3044 }
3045
3046 static void DumpIMTForClass(Runtime* runtime,
3047 const std::string& class_name,
Andreas Gampeebfc1ac2016-09-29 19:50:27 -07003048 Handle<mirror::ClassLoader> h_loader,
3049 std::unordered_set<std::string>* prepared)
3050 REQUIRES_SHARED(Locks::mutator_lock_) {
Andreas Gampe9fded872016-09-25 16:08:35 -07003051 const PointerSize pointer_size = runtime->GetClassLinker()->GetImagePointerSize();
3052 mirror::Class* klass;
Andreas Gampeebfc1ac2016-09-29 19:50:27 -07003053 ImTable* imt = PrepareAndGetImTable(runtime,
3054 Thread::Current(),
3055 h_loader,
3056 class_name,
3057 pointer_size,
3058 &klass,
3059 prepared);
Andreas Gampe9fded872016-09-25 16:08:35 -07003060 if (imt == nullptr) {
3061 return;
3062 }
3063
3064 std::cerr << class_name << std::endl << " IMT:" << std::endl;
3065 for (size_t index = 0; index < ImTable::kSize; ++index) {
3066 std::cerr << " " << index << ":" << std::endl;
3067 ArtMethod* ptr = imt->Get(index, pointer_size);
3068 if (ptr->IsRuntimeMethod()) {
3069 if (ptr->IsImtUnimplementedMethod()) {
3070 std::cerr << " <empty>" << std::endl;
3071 } else {
3072 ImtConflictTable* current_table = ptr->GetImtConflictTable(pointer_size);
3073 PrintTable(current_table, pointer_size);
3074 }
3075 } else {
David Sehr709b0702016-10-13 09:12:37 -07003076 std::cerr << " " << ptr->PrettyMethod(true) << std::endl;
Andreas Gampe9fded872016-09-25 16:08:35 -07003077 }
3078 }
3079
3080 std::cerr << " Interfaces:" << std::endl;
3081 // Run through iftable, find methods that slot here, see if they fit.
3082 mirror::IfTable* if_table = klass->GetIfTable();
Mathieu Chartier6beced42016-11-15 15:51:31 -08003083 for (size_t i = 0, num_interfaces = klass->GetIfTableCount(); i < num_interfaces; ++i) {
3084 mirror::Class* iface = if_table->GetInterface(i);
3085 std::string iface_name;
3086 std::cerr << " " << iface->GetDescriptor(&iface_name) << std::endl;
Andreas Gampe9fded872016-09-25 16:08:35 -07003087
Mathieu Chartier6beced42016-11-15 15:51:31 -08003088 for (ArtMethod& iface_method : iface->GetVirtualMethods(pointer_size)) {
3089 uint32_t class_hash, name_hash, signature_hash;
3090 ImTable::GetImtHashComponents(&iface_method, &class_hash, &name_hash, &signature_hash);
3091 uint32_t imt_slot = ImTable::GetImtIndex(&iface_method);
3092 std::cerr << " " << iface_method.PrettyMethod(true)
3093 << " slot=" << imt_slot
3094 << std::hex
3095 << " class_hash=0x" << class_hash
3096 << " name_hash=0x" << name_hash
3097 << " signature_hash=0x" << signature_hash
3098 << std::dec
3099 << std::endl;
Andreas Gampe9fded872016-09-25 16:08:35 -07003100 }
3101 }
3102 }
3103
3104 static void DumpIMTForMethod(Runtime* runtime,
3105 const std::string& class_name,
3106 const std::string& method,
Andreas Gampeebfc1ac2016-09-29 19:50:27 -07003107 Handle<mirror::ClassLoader> h_loader,
3108 std::unordered_set<std::string>* prepared)
3109 REQUIRES_SHARED(Locks::mutator_lock_) {
Andreas Gampe9fded872016-09-25 16:08:35 -07003110 const PointerSize pointer_size = runtime->GetClassLinker()->GetImagePointerSize();
3111 mirror::Class* klass;
3112 ImTable* imt = PrepareAndGetImTable(runtime,
Andreas Gampeebfc1ac2016-09-29 19:50:27 -07003113 Thread::Current(),
3114 h_loader,
Andreas Gampe9fded872016-09-25 16:08:35 -07003115 class_name,
3116 pointer_size,
3117 &klass,
3118 prepared);
3119 if (imt == nullptr) {
3120 return;
3121 }
3122
3123 std::cerr << class_name << " <" << method << ">" << std::endl;
3124 for (size_t index = 0; index < ImTable::kSize; ++index) {
3125 ArtMethod* ptr = imt->Get(index, pointer_size);
3126 if (ptr->IsRuntimeMethod()) {
3127 if (ptr->IsImtUnimplementedMethod()) {
3128 continue;
3129 }
3130
3131 ImtConflictTable* current_table = ptr->GetImtConflictTable(pointer_size);
3132 if (current_table == nullptr) {
3133 continue;
3134 }
3135
3136 size_t table_index = 0;
3137 for (;;) {
3138 ArtMethod* ptr2 = current_table->GetInterfaceMethod(table_index, pointer_size);
3139 if (ptr2 == nullptr) {
3140 break;
3141 }
3142 table_index++;
3143
David Sehr709b0702016-10-13 09:12:37 -07003144 std::string p_name = ptr2->PrettyMethod(true);
Andreas Gampe9186ced2016-12-12 14:28:21 -08003145 if (android::base::StartsWith(p_name, method.c_str())) {
Andreas Gampe9fded872016-09-25 16:08:35 -07003146 std::cerr << " Slot "
3147 << index
3148 << " ("
3149 << current_table->NumEntries(pointer_size)
3150 << ")"
3151 << std::endl;
3152 PrintTable(current_table, pointer_size);
3153 return;
3154 }
3155 }
3156 } else {
David Sehr709b0702016-10-13 09:12:37 -07003157 std::string p_name = ptr->PrettyMethod(true);
Andreas Gampe9186ced2016-12-12 14:28:21 -08003158 if (android::base::StartsWith(p_name, method.c_str())) {
Andreas Gampe9fded872016-09-25 16:08:35 -07003159 std::cerr << " Slot " << index << " (1)" << std::endl;
3160 std::cerr << " " << p_name << std::endl;
3161 } else {
3162 // Run through iftable, find methods that slot here, see if they fit.
3163 mirror::IfTable* if_table = klass->GetIfTable();
Mathieu Chartier6beced42016-11-15 15:51:31 -08003164 for (size_t i = 0, num_interfaces = klass->GetIfTableCount(); i < num_interfaces; ++i) {
3165 mirror::Class* iface = if_table->GetInterface(i);
3166 size_t num_methods = iface->NumDeclaredVirtualMethods();
3167 if (num_methods > 0) {
3168 for (ArtMethod& iface_method : iface->GetMethods(pointer_size)) {
3169 if (ImTable::GetImtIndex(&iface_method) == index) {
3170 std::string i_name = iface_method.PrettyMethod(true);
Andreas Gampe9186ced2016-12-12 14:28:21 -08003171 if (android::base::StartsWith(i_name, method.c_str())) {
Mathieu Chartier6beced42016-11-15 15:51:31 -08003172 std::cerr << " Slot " << index << " (1)" << std::endl;
3173 std::cerr << " " << p_name << " (" << i_name << ")" << std::endl;
Andreas Gampe9fded872016-09-25 16:08:35 -07003174 }
3175 }
3176 }
3177 }
3178 }
3179 }
3180 }
3181 }
3182 }
3183
3184 // Read lines from the given stream, dropping comments and empty lines
3185 static std::vector<std::string> ReadCommentedInputStream(std::istream& in_stream) {
3186 std::vector<std::string> output;
3187 while (in_stream.good()) {
3188 std::string dot;
3189 std::getline(in_stream, dot);
Andreas Gampe9186ced2016-12-12 14:28:21 -08003190 if (android::base::StartsWith(dot, "#") || dot.empty()) {
Andreas Gampe9fded872016-09-25 16:08:35 -07003191 continue;
3192 }
3193 output.push_back(dot);
3194 }
3195 return output;
3196 }
3197
3198 // Read lines from the given file, dropping comments and empty lines.
3199 static std::vector<std::string> ReadCommentedInputFromFile(const std::string& input_filename) {
3200 std::unique_ptr<std::ifstream> input_file(new std::ifstream(input_filename, std::ifstream::in));
3201 if (input_file.get() == nullptr) {
3202 LOG(ERROR) << "Failed to open input file " << input_filename;
3203 return std::vector<std::string>();
3204 }
3205 std::vector<std::string> result = ReadCommentedInputStream(*input_file);
3206 input_file->close();
3207 return result;
3208 }
3209
3210 // Prepare a class, i.e., ensure it has a filled IMT. Will do so recursively for superclasses,
3211 // and note in the given set that the work was done.
3212 static void PrepareClass(Runtime* runtime,
3213 Handle<mirror::Class> h_klass,
3214 std::unordered_set<std::string>* done)
3215 REQUIRES_SHARED(Locks::mutator_lock_) {
3216 if (!h_klass->ShouldHaveImt()) {
3217 return;
3218 }
3219
3220 std::string name;
3221 name = h_klass->GetDescriptor(&name);
3222
3223 if (done->find(name) != done->end()) {
3224 return;
3225 }
3226 done->insert(name);
3227
3228 if (h_klass->HasSuperClass()) {
3229 StackHandleScope<1> h(Thread::Current());
3230 PrepareClass(runtime, h.NewHandle<mirror::Class>(h_klass->GetSuperClass()), done);
3231 }
3232
3233 if (!h_klass->IsTemp()) {
3234 runtime->GetClassLinker()->FillIMTAndConflictTables(h_klass.Get());
3235 }
3236 }
3237};
3238
Igor Murashkin37743352014-11-13 14:38:00 -08003239struct OatdumpArgs : public CmdlineArgs {
3240 protected:
3241 using Base = CmdlineArgs;
Andreas Gampe00b25f32014-09-17 21:49:05 -07003242
Igor Murashkin37743352014-11-13 14:38:00 -08003243 virtual ParseStatus ParseCustom(const StringPiece& option,
3244 std::string* error_msg) OVERRIDE {
3245 {
3246 ParseStatus base_parse = Base::ParseCustom(option, error_msg);
3247 if (base_parse != kParseUnknownArgument) {
3248 return base_parse;
Andreas Gampe00b25f32014-09-17 21:49:05 -07003249 }
3250 }
3251
Igor Murashkin37743352014-11-13 14:38:00 -08003252 if (option.starts_with("--oat-file=")) {
3253 oat_filename_ = option.substr(strlen("--oat-file=")).data();
3254 } else if (option.starts_with("--image=")) {
3255 image_location_ = option.substr(strlen("--image=")).data();
Igor Murashkin37743352014-11-13 14:38:00 -08003256 } else if (option == "--no-dump:vmap") {
3257 dump_vmap_ = false;
Roland Levillainf2650d12015-05-28 14:53:28 +01003258 } else if (option =="--dump:code_info_stack_maps") {
3259 dump_code_info_stack_maps_ = true;
Igor Murashkin37743352014-11-13 14:38:00 -08003260 } else if (option == "--no-disassemble") {
3261 disassemble_code_ = false;
David Brazdilc03d7b62016-03-02 12:18:03 +00003262 } else if (option =="--header-only") {
3263 dump_header_only_ = true;
Igor Murashkin37743352014-11-13 14:38:00 -08003264 } else if (option.starts_with("--symbolize=")) {
3265 oat_filename_ = option.substr(strlen("--symbolize=")).data();
3266 symbolize_ = true;
David Srbecky2fdd03c2016-03-10 15:32:37 +00003267 } else if (option.starts_with("--only-keep-debug")) {
3268 only_keep_debug_ = true;
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08003269 } else if (option.starts_with("--class-filter=")) {
3270 class_filter_ = option.substr(strlen("--class-filter=")).data();
Igor Murashkin37743352014-11-13 14:38:00 -08003271 } else if (option.starts_with("--method-filter=")) {
3272 method_filter_ = option.substr(strlen("--method-filter=")).data();
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08003273 } else if (option.starts_with("--list-classes")) {
3274 list_classes_ = true;
3275 } else if (option.starts_with("--list-methods")) {
3276 list_methods_ = true;
3277 } else if (option.starts_with("--export-dex-to=")) {
3278 export_dex_location_ = option.substr(strlen("--export-dex-to=")).data();
3279 } else if (option.starts_with("--addr2instr=")) {
3280 if (!ParseUint(option.substr(strlen("--addr2instr=")).data(), &addr2instr_)) {
3281 *error_msg = "Address conversion failed";
3282 return kParseError;
3283 }
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08003284 } else if (option.starts_with("--app-image=")) {
3285 app_image_ = option.substr(strlen("--app-image=")).data();
3286 } else if (option.starts_with("--app-oat=")) {
3287 app_oat_ = option.substr(strlen("--app-oat=")).data();
Andreas Gampe9fded872016-09-25 16:08:35 -07003288 } else if (option.starts_with("--dump-imt=")) {
3289 imt_dump_ = option.substr(strlen("--dump-imt=")).data();
3290 } else if (option == "--dump-imt-stats") {
3291 imt_stat_dump_ = true;
Igor Murashkin37743352014-11-13 14:38:00 -08003292 } else {
3293 return kParseUnknownArgument;
Andreas Gampe00b25f32014-09-17 21:49:05 -07003294 }
3295
Igor Murashkin37743352014-11-13 14:38:00 -08003296 return kParseOk;
Andreas Gampe00b25f32014-09-17 21:49:05 -07003297 }
3298
Igor Murashkin37743352014-11-13 14:38:00 -08003299 virtual ParseStatus ParseChecks(std::string* error_msg) OVERRIDE {
3300 // Infer boot image location from the image location if possible.
3301 if (boot_image_location_ == nullptr) {
3302 boot_image_location_ = image_location_;
3303 }
3304
3305 // Perform the parent checks.
3306 ParseStatus parent_checks = Base::ParseChecks(error_msg);
3307 if (parent_checks != kParseOk) {
3308 return parent_checks;
3309 }
3310
3311 // Perform our own checks.
3312 if (image_location_ == nullptr && oat_filename_ == nullptr) {
3313 *error_msg = "Either --image or --oat-file must be specified";
3314 return kParseError;
3315 } else if (image_location_ != nullptr && oat_filename_ != nullptr) {
3316 *error_msg = "Either --image or --oat-file must be specified but not both";
3317 return kParseError;
3318 }
3319
3320 return kParseOk;
3321 }
3322
3323 virtual std::string GetUsage() const {
3324 std::string usage;
3325
3326 usage +=
3327 "Usage: oatdump [options] ...\n"
3328 " Example: oatdump --image=$ANDROID_PRODUCT_OUT/system/framework/boot.art\n"
3329 " Example: adb shell oatdump --image=/system/framework/boot.art\n"
3330 "\n"
3331 // Either oat-file or image is required.
3332 " --oat-file=<file.oat>: specifies an input oat filename.\n"
3333 " Example: --oat-file=/system/framework/boot.oat\n"
3334 "\n"
3335 " --image=<file.art>: specifies an input image location.\n"
3336 " Example: --image=/system/framework/boot.art\n"
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08003337 "\n"
3338 " --app-image=<file.art>: specifies an input app image. Must also have a specified\n"
3339 " boot image and app oat file.\n"
3340 " Example: --app-image=app.art\n"
3341 "\n"
3342 " --app-oat=<file.odex>: specifies an input app oat.\n"
3343 " Example: --app-oat=app.odex\n"
Igor Murashkin37743352014-11-13 14:38:00 -08003344 "\n";
3345
3346 usage += Base::GetUsage();
3347
3348 usage += // Optional.
Igor Murashkin37743352014-11-13 14:38:00 -08003349 " --no-dump:vmap may be used to disable vmap dumping.\n"
3350 " Example: --no-dump:vmap\n"
3351 "\n"
Roland Levillainf2650d12015-05-28 14:53:28 +01003352 " --dump:code_info_stack_maps enables dumping of stack maps in CodeInfo sections.\n"
3353 " Example: --dump:code_info_stack_maps\n"
3354 "\n"
Igor Murashkin37743352014-11-13 14:38:00 -08003355 " --no-disassemble may be used to disable disassembly.\n"
3356 " Example: --no-disassemble\n"
3357 "\n"
David Brazdilc03d7b62016-03-02 12:18:03 +00003358 " --header-only may be used to print only the oat header.\n"
3359 " Example: --header-only\n"
3360 "\n"
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08003361 " --list-classes may be used to list target file classes (can be used with filters).\n"
3362 " Example: --list-classes\n"
3363 " Example: --list-classes --class-filter=com.example.foo\n"
3364 "\n"
3365 " --list-methods may be used to list target file methods (can be used with filters).\n"
3366 " Example: --list-methods\n"
3367 " Example: --list-methods --class-filter=com.example --method-filter=foo\n"
3368 "\n"
3369 " --symbolize=<file.oat>: output a copy of file.oat with elf symbols included.\n"
3370 " Example: --symbolize=/system/framework/boot.oat\n"
3371 "\n"
David Srbecky2fdd03c2016-03-10 15:32:37 +00003372 " --only-keep-debug<file.oat>: Modifies the behaviour of --symbolize so that\n"
3373 " .rodata and .text sections are omitted in the output file to save space.\n"
3374 " Example: --symbolize=/system/framework/boot.oat --only-keep-debug\n"
3375 "\n"
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08003376 " --class-filter=<class name>: only dumps classes that contain the filter.\n"
3377 " Example: --class-filter=com.example.foo\n"
3378 "\n"
Igor Murashkin37743352014-11-13 14:38:00 -08003379 " --method-filter=<method name>: only dumps methods that contain the filter.\n"
3380 " Example: --method-filter=foo\n"
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08003381 "\n"
3382 " --export-dex-to=<directory>: may be used to export oat embedded dex files.\n"
3383 " Example: --export-dex-to=/data/local/tmp\n"
3384 "\n"
3385 " --addr2instr=<address>: output matching method disassembled code from relative\n"
3386 " address (e.g. PC from crash dump)\n"
3387 " Example: --addr2instr=0x00001a3b\n"
Andreas Gampe9fded872016-09-25 16:08:35 -07003388 "\n"
3389 " --dump-imt=<file.txt>: output IMT collisions (if any) for the given receiver\n"
3390 " types and interface methods in the given file. The file\n"
Andreas Gampeebfc1ac2016-09-29 19:50:27 -07003391 " is read line-wise, where each line should either be a class\n"
Andreas Gampe9fded872016-09-25 16:08:35 -07003392 " name or descriptor, or a class name/descriptor and a prefix\n"
Andreas Gampeebfc1ac2016-09-29 19:50:27 -07003393 " of a complete method name (separated by a whitespace).\n"
Andreas Gampe9fded872016-09-25 16:08:35 -07003394 " Example: --dump-imt=imt.txt\n"
3395 "\n"
3396 " --dump-imt-stats: output IMT statistics for the given boot image\n"
3397 " Example: --dump-imt-stats"
Igor Murashkin37743352014-11-13 14:38:00 -08003398 "\n";
3399
3400 return usage;
3401 }
3402
3403 public:
Andreas Gampe00b25f32014-09-17 21:49:05 -07003404 const char* oat_filename_ = nullptr;
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08003405 const char* class_filter_ = "";
Nicolas Geoffray3fcd2202014-11-12 18:02:36 +00003406 const char* method_filter_ = "";
Andreas Gampe00b25f32014-09-17 21:49:05 -07003407 const char* image_location_ = nullptr;
Andreas Gampe00b25f32014-09-17 21:49:05 -07003408 std::string elf_filename_prefix_;
Andreas Gampe9fded872016-09-25 16:08:35 -07003409 std::string imt_dump_;
Andreas Gampe00b25f32014-09-17 21:49:05 -07003410 bool dump_vmap_ = true;
Roland Levillainf2650d12015-05-28 14:53:28 +01003411 bool dump_code_info_stack_maps_ = false;
Andreas Gampe00b25f32014-09-17 21:49:05 -07003412 bool disassemble_code_ = true;
3413 bool symbolize_ = false;
David Srbecky2fdd03c2016-03-10 15:32:37 +00003414 bool only_keep_debug_ = false;
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08003415 bool list_classes_ = false;
3416 bool list_methods_ = false;
David Brazdilc03d7b62016-03-02 12:18:03 +00003417 bool dump_header_only_ = false;
Andreas Gampe9fded872016-09-25 16:08:35 -07003418 bool imt_stat_dump_ = false;
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08003419 uint32_t addr2instr_ = 0;
3420 const char* export_dex_location_ = nullptr;
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08003421 const char* app_image_ = nullptr;
3422 const char* app_oat_ = nullptr;
Andreas Gampe00b25f32014-09-17 21:49:05 -07003423};
3424
Igor Murashkin37743352014-11-13 14:38:00 -08003425struct OatdumpMain : public CmdlineMain<OatdumpArgs> {
3426 virtual bool NeedsRuntime() OVERRIDE {
3427 CHECK(args_ != nullptr);
Andreas Gampe00b25f32014-09-17 21:49:05 -07003428
Igor Murashkin37743352014-11-13 14:38:00 -08003429 // If we are only doing the oat file, disable absolute_addresses. Keep them for image dumping.
3430 bool absolute_addresses = (args_->oat_filename_ == nullptr);
3431
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08003432 oat_dumper_options_.reset(new OatDumperOptions(
Igor Murashkin37743352014-11-13 14:38:00 -08003433 args_->dump_vmap_,
Roland Levillainf2650d12015-05-28 14:53:28 +01003434 args_->dump_code_info_stack_maps_,
Igor Murashkin37743352014-11-13 14:38:00 -08003435 args_->disassemble_code_,
3436 absolute_addresses,
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08003437 args_->class_filter_,
3438 args_->method_filter_,
3439 args_->list_classes_,
3440 args_->list_methods_,
David Brazdilc03d7b62016-03-02 12:18:03 +00003441 args_->dump_header_only_,
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08003442 args_->export_dex_location_,
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08003443 args_->app_image_,
3444 args_->app_oat_,
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08003445 args_->addr2instr_));
Igor Murashkin37743352014-11-13 14:38:00 -08003446
Andreas Gampe9fded872016-09-25 16:08:35 -07003447 return (args_->boot_image_location_ != nullptr ||
3448 args_->image_location_ != nullptr ||
3449 !args_->imt_dump_.empty()) &&
Igor Murashkin37743352014-11-13 14:38:00 -08003450 !args_->symbolize_;
Andreas Gampe00b25f32014-09-17 21:49:05 -07003451 }
3452
Igor Murashkin37743352014-11-13 14:38:00 -08003453 virtual bool ExecuteWithoutRuntime() OVERRIDE {
3454 CHECK(args_ != nullptr);
Andreas Gampec24f3992014-12-17 20:40:11 -08003455 CHECK(args_->oat_filename_ != nullptr);
Andreas Gampe00b25f32014-09-17 21:49:05 -07003456
Mathieu Chartierd424d082014-10-15 10:31:46 -07003457 MemMap::Init();
Igor Murashkin37743352014-11-13 14:38:00 -08003458
Andreas Gampec24f3992014-12-17 20:40:11 -08003459 if (args_->symbolize_) {
David Srbecky2fdd03c2016-03-10 15:32:37 +00003460 // ELF has special kind of section called SHT_NOBITS which allows us to create
3461 // sections which exist but their data is omitted from the ELF file to save space.
3462 // This is what "strip --only-keep-debug" does when it creates separate ELF file
3463 // with only debug data. We use it in similar way to exclude .rodata and .text.
3464 bool no_bits = args_->only_keep_debug_;
3465 return SymbolizeOat(args_->oat_filename_, args_->output_name_, no_bits) == EXIT_SUCCESS;
Andreas Gampec24f3992014-12-17 20:40:11 -08003466 } else {
3467 return DumpOat(nullptr,
3468 args_->oat_filename_,
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08003469 oat_dumper_options_.get(),
Andreas Gampec24f3992014-12-17 20:40:11 -08003470 args_->os_) == EXIT_SUCCESS;
3471 }
Andreas Gampe00b25f32014-09-17 21:49:05 -07003472 }
3473
Igor Murashkin37743352014-11-13 14:38:00 -08003474 virtual bool ExecuteWithRuntime(Runtime* runtime) {
3475 CHECK(args_ != nullptr);
3476
Andreas Gampeebfc1ac2016-09-29 19:50:27 -07003477 if (!args_->imt_dump_.empty() || args_->imt_stat_dump_) {
3478 return IMTDumper::Dump(runtime,
3479 args_->imt_dump_,
3480 args_->imt_stat_dump_,
3481 args_->oat_filename_);
Andreas Gampe9fded872016-09-25 16:08:35 -07003482 }
3483
Igor Murashkin37743352014-11-13 14:38:00 -08003484 if (args_->oat_filename_ != nullptr) {
3485 return DumpOat(runtime,
3486 args_->oat_filename_,
Anestis Bechtsoudis32f500d2015-02-22 22:32:57 -08003487 oat_dumper_options_.get(),
Igor Murashkin37743352014-11-13 14:38:00 -08003488 args_->os_) == EXIT_SUCCESS;
Andreas Gampe00b25f32014-09-17 21:49:05 -07003489 }
Igor Murashkin37743352014-11-13 14:38:00 -08003490
Mathieu Chartier0b4cbd02016-03-08 16:49:58 -08003491 return DumpImages(runtime, oat_dumper_options_.get(), args_->os_) == EXIT_SUCCESS;
Andreas Gampe00b25f32014-09-17 21:49:05 -07003492 }
3493
Igor Murashkin37743352014-11-13 14:38:00 -08003494 std::unique_ptr<OatDumperOptions> oat_dumper_options_;
3495};
Andreas Gampe00b25f32014-09-17 21:49:05 -07003496
Brian Carlstrom7934ac22013-07-26 10:54:15 -07003497} // namespace art
Brian Carlstrom78128a62011-09-15 17:21:19 -07003498
3499int main(int argc, char** argv) {
Igor Murashkin37743352014-11-13 14:38:00 -08003500 art::OatdumpMain main;
3501 return main.Main(argc, argv);
Brian Carlstrom78128a62011-09-15 17:21:19 -07003502}