1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2011 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #include <stdio.h>
18*795d594fSAndroid Build Coastguard Worker #include <stdlib.h>
19*795d594fSAndroid Build Coastguard Worker #include <sys/stat.h>
20*795d594fSAndroid Build Coastguard Worker
21*795d594fSAndroid Build Coastguard Worker #include <algorithm>
22*795d594fSAndroid Build Coastguard Worker #include <cstdlib>
23*795d594fSAndroid Build Coastguard Worker #include <fstream>
24*795d594fSAndroid Build Coastguard Worker #include <iomanip>
25*795d594fSAndroid Build Coastguard Worker #include <iostream>
26*795d594fSAndroid Build Coastguard Worker #include <map>
27*795d594fSAndroid Build Coastguard Worker #include <optional>
28*795d594fSAndroid Build Coastguard Worker #include <set>
29*795d594fSAndroid Build Coastguard Worker #include <string>
30*795d594fSAndroid Build Coastguard Worker #include <unordered_map>
31*795d594fSAndroid Build Coastguard Worker #include <unordered_set>
32*795d594fSAndroid Build Coastguard Worker #include <utility>
33*795d594fSAndroid Build Coastguard Worker #include <vector>
34*795d594fSAndroid Build Coastguard Worker
35*795d594fSAndroid Build Coastguard Worker #include "android-base/logging.h"
36*795d594fSAndroid Build Coastguard Worker #include "android-base/parseint.h"
37*795d594fSAndroid Build Coastguard Worker #include "android-base/stringprintf.h"
38*795d594fSAndroid Build Coastguard Worker #include "android-base/strings.h"
39*795d594fSAndroid Build Coastguard Worker #include "arch/instruction_set.h"
40*795d594fSAndroid Build Coastguard Worker #include "arch/instruction_set_features.h"
41*795d594fSAndroid Build Coastguard Worker #include "art_field-inl.h"
42*795d594fSAndroid Build Coastguard Worker #include "art_method-inl.h"
43*795d594fSAndroid Build Coastguard Worker #include "base/array_ref.h"
44*795d594fSAndroid Build Coastguard Worker #include "base/bit_utils_iterator.h"
45*795d594fSAndroid Build Coastguard Worker #include "base/file_utils.h"
46*795d594fSAndroid Build Coastguard Worker #include "base/indenter.h"
47*795d594fSAndroid Build Coastguard Worker #include "base/os.h"
48*795d594fSAndroid Build Coastguard Worker #include "base/safe_map.h"
49*795d594fSAndroid Build Coastguard Worker #include "base/stats-inl.h"
50*795d594fSAndroid Build Coastguard Worker #include "base/stl_util.h"
51*795d594fSAndroid Build Coastguard Worker #include "base/unix_file/fd_file.h"
52*795d594fSAndroid Build Coastguard Worker #include "class_linker-inl.h"
53*795d594fSAndroid Build Coastguard Worker #include "class_linker.h"
54*795d594fSAndroid Build Coastguard Worker #include "class_root-inl.h"
55*795d594fSAndroid Build Coastguard Worker #include "cmdline.h"
56*795d594fSAndroid Build Coastguard Worker #include "debug/debug_info.h"
57*795d594fSAndroid Build Coastguard Worker #include "debug/elf_debug_writer.h"
58*795d594fSAndroid Build Coastguard Worker #include "debug/method_debug_info.h"
59*795d594fSAndroid Build Coastguard Worker #include "dex/art_dex_file_loader.h"
60*795d594fSAndroid Build Coastguard Worker #include "dex/class_accessor-inl.h"
61*795d594fSAndroid Build Coastguard Worker #include "dex/code_item_accessors-inl.h"
62*795d594fSAndroid Build Coastguard Worker #include "dex/descriptors_names.h"
63*795d594fSAndroid Build Coastguard Worker #include "dex/dex_file-inl.h"
64*795d594fSAndroid Build Coastguard Worker #include "dex/dex_instruction-inl.h"
65*795d594fSAndroid Build Coastguard Worker #include "dex/string_reference.h"
66*795d594fSAndroid Build Coastguard Worker #include "dex/type_lookup_table.h"
67*795d594fSAndroid Build Coastguard Worker #include "disassembler.h"
68*795d594fSAndroid Build Coastguard Worker #include "elf/elf_builder.h"
69*795d594fSAndroid Build Coastguard Worker #include "gc/accounting/space_bitmap-inl.h"
70*795d594fSAndroid Build Coastguard Worker #include "gc/space/image_space.h"
71*795d594fSAndroid Build Coastguard Worker #include "gc/space/large_object_space.h"
72*795d594fSAndroid Build Coastguard Worker #include "gc/space/space-inl.h"
73*795d594fSAndroid Build Coastguard Worker #include "imtable-inl.h"
74*795d594fSAndroid Build Coastguard Worker #include "interpreter/unstarted_runtime.h"
75*795d594fSAndroid Build Coastguard Worker #include "mirror/array-inl.h"
76*795d594fSAndroid Build Coastguard Worker #include "mirror/class-inl.h"
77*795d594fSAndroid Build Coastguard Worker #include "mirror/dex_cache-inl.h"
78*795d594fSAndroid Build Coastguard Worker #include "mirror/object-inl.h"
79*795d594fSAndroid Build Coastguard Worker #include "mirror/object_array-inl.h"
80*795d594fSAndroid Build Coastguard Worker #include "oat/image-inl.h"
81*795d594fSAndroid Build Coastguard Worker #include "oat/index_bss_mapping.h"
82*795d594fSAndroid Build Coastguard Worker #include "oat/oat.h"
83*795d594fSAndroid Build Coastguard Worker #include "oat/oat_file-inl.h"
84*795d594fSAndroid Build Coastguard Worker #include "oat/oat_file_assistant.h"
85*795d594fSAndroid Build Coastguard Worker #include "oat/oat_file_assistant_context.h"
86*795d594fSAndroid Build Coastguard Worker #include "oat/oat_file_manager.h"
87*795d594fSAndroid Build Coastguard Worker #include "oat/stack_map.h"
88*795d594fSAndroid Build Coastguard Worker #include "scoped_thread_state_change-inl.h"
89*795d594fSAndroid Build Coastguard Worker #include "stack.h"
90*795d594fSAndroid Build Coastguard Worker #include "stream/buffered_output_stream.h"
91*795d594fSAndroid Build Coastguard Worker #include "stream/file_output_stream.h"
92*795d594fSAndroid Build Coastguard Worker #include "subtype_check.h"
93*795d594fSAndroid Build Coastguard Worker #include "thread_list.h"
94*795d594fSAndroid Build Coastguard Worker #include "vdex_file.h"
95*795d594fSAndroid Build Coastguard Worker #include "verifier/method_verifier.h"
96*795d594fSAndroid Build Coastguard Worker #include "verifier/verifier_deps.h"
97*795d594fSAndroid Build Coastguard Worker #include "well_known_classes.h"
98*795d594fSAndroid Build Coastguard Worker
99*795d594fSAndroid Build Coastguard Worker namespace art {
100*795d594fSAndroid Build Coastguard Worker
101*795d594fSAndroid Build Coastguard Worker using android::base::StringPrintf;
102*795d594fSAndroid Build Coastguard Worker
103*795d594fSAndroid Build Coastguard Worker const char* image_methods_descriptions_[] = {
104*795d594fSAndroid Build Coastguard Worker "kResolutionMethod",
105*795d594fSAndroid Build Coastguard Worker "kImtConflictMethod",
106*795d594fSAndroid Build Coastguard Worker "kImtUnimplementedMethod",
107*795d594fSAndroid Build Coastguard Worker "kSaveAllCalleeSavesMethod",
108*795d594fSAndroid Build Coastguard Worker "kSaveRefsOnlyMethod",
109*795d594fSAndroid Build Coastguard Worker "kSaveRefsAndArgsMethod",
110*795d594fSAndroid Build Coastguard Worker "kSaveEverythingMethod",
111*795d594fSAndroid Build Coastguard Worker "kSaveEverythingMethodForClinit",
112*795d594fSAndroid Build Coastguard Worker "kSaveEverythingMethodForSuspendCheck",
113*795d594fSAndroid Build Coastguard Worker };
114*795d594fSAndroid Build Coastguard Worker
115*795d594fSAndroid Build Coastguard Worker const char* image_roots_descriptions_[] = {
116*795d594fSAndroid Build Coastguard Worker "kDexCaches",
117*795d594fSAndroid Build Coastguard Worker "kClassRoots",
118*795d594fSAndroid Build Coastguard Worker "kSpecialRoots",
119*795d594fSAndroid Build Coastguard Worker };
120*795d594fSAndroid Build Coastguard Worker
121*795d594fSAndroid Build Coastguard Worker // Map is so that we don't allocate multiple dex files for the same OatDexFile.
122*795d594fSAndroid Build Coastguard Worker static std::map<const OatDexFile*, std::unique_ptr<const DexFile>> opened_dex_files;
123*795d594fSAndroid Build Coastguard Worker
OpenDexFile(const OatDexFile * oat_dex_file,std::string * error_msg)124*795d594fSAndroid Build Coastguard Worker const DexFile* OpenDexFile(const OatDexFile* oat_dex_file, std::string* error_msg) {
125*795d594fSAndroid Build Coastguard Worker DCHECK(oat_dex_file != nullptr);
126*795d594fSAndroid Build Coastguard Worker auto it = opened_dex_files.find(oat_dex_file);
127*795d594fSAndroid Build Coastguard Worker if (it != opened_dex_files.end()) {
128*795d594fSAndroid Build Coastguard Worker return it->second.get();
129*795d594fSAndroid Build Coastguard Worker }
130*795d594fSAndroid Build Coastguard Worker const DexFile* ret = oat_dex_file->OpenDexFile(error_msg).release();
131*795d594fSAndroid Build Coastguard Worker opened_dex_files.emplace(oat_dex_file, std::unique_ptr<const DexFile>(ret));
132*795d594fSAndroid Build Coastguard Worker return ret;
133*795d594fSAndroid Build Coastguard Worker }
134*795d594fSAndroid Build Coastguard Worker
135*795d594fSAndroid Build Coastguard Worker template <typename ElfTypes>
136*795d594fSAndroid Build Coastguard Worker class OatSymbolizer final {
137*795d594fSAndroid Build Coastguard Worker public:
OatSymbolizer(const OatFile * oat_file,const std::string & output_name,bool no_bits)138*795d594fSAndroid Build Coastguard Worker OatSymbolizer(const OatFile* oat_file, const std::string& output_name, bool no_bits) :
139*795d594fSAndroid Build Coastguard Worker oat_file_(oat_file),
140*795d594fSAndroid Build Coastguard Worker builder_(nullptr),
141*795d594fSAndroid Build Coastguard Worker output_name_(output_name.empty() ? "symbolized.oat" : output_name),
142*795d594fSAndroid Build Coastguard Worker no_bits_(no_bits) {
143*795d594fSAndroid Build Coastguard Worker }
144*795d594fSAndroid Build Coastguard Worker
Symbolize()145*795d594fSAndroid Build Coastguard Worker bool Symbolize() {
146*795d594fSAndroid Build Coastguard Worker const InstructionSet isa = oat_file_->GetOatHeader().GetInstructionSet();
147*795d594fSAndroid Build Coastguard Worker std::unique_ptr<const InstructionSetFeatures> features = InstructionSetFeatures::FromBitmap(
148*795d594fSAndroid Build Coastguard Worker isa, oat_file_->GetOatHeader().GetInstructionSetFeaturesBitmap());
149*795d594fSAndroid Build Coastguard Worker
150*795d594fSAndroid Build Coastguard Worker std::unique_ptr<File> elf_file(OS::CreateEmptyFile(output_name_.c_str()));
151*795d594fSAndroid Build Coastguard Worker if (elf_file == nullptr) {
152*795d594fSAndroid Build Coastguard Worker return false;
153*795d594fSAndroid Build Coastguard Worker }
154*795d594fSAndroid Build Coastguard Worker std::unique_ptr<BufferedOutputStream> output_stream =
155*795d594fSAndroid Build Coastguard Worker std::make_unique<BufferedOutputStream>(
156*795d594fSAndroid Build Coastguard Worker std::make_unique<FileOutputStream>(elf_file.get()));
157*795d594fSAndroid Build Coastguard Worker builder_.reset(new ElfBuilder<ElfTypes>(isa, output_stream.get()));
158*795d594fSAndroid Build Coastguard Worker
159*795d594fSAndroid Build Coastguard Worker builder_->Start();
160*795d594fSAndroid Build Coastguard Worker
161*795d594fSAndroid Build Coastguard Worker auto* rodata = builder_->GetRoData();
162*795d594fSAndroid Build Coastguard Worker auto* text = builder_->GetText();
163*795d594fSAndroid Build Coastguard Worker
164*795d594fSAndroid Build Coastguard Worker const uint8_t* rodata_begin = oat_file_->Begin();
165*795d594fSAndroid Build Coastguard Worker const size_t rodata_size = oat_file_->GetOatHeader().GetExecutableOffset();
166*795d594fSAndroid Build Coastguard Worker if (!no_bits_) {
167*795d594fSAndroid Build Coastguard Worker rodata->Start();
168*795d594fSAndroid Build Coastguard Worker rodata->WriteFully(rodata_begin, rodata_size);
169*795d594fSAndroid Build Coastguard Worker rodata->End();
170*795d594fSAndroid Build Coastguard Worker }
171*795d594fSAndroid Build Coastguard Worker
172*795d594fSAndroid Build Coastguard Worker const uint8_t* text_begin = oat_file_->Begin() + rodata_size;
173*795d594fSAndroid Build Coastguard Worker const size_t text_size = oat_file_->End() - text_begin;
174*795d594fSAndroid Build Coastguard Worker if (!no_bits_) {
175*795d594fSAndroid Build Coastguard Worker text->Start();
176*795d594fSAndroid Build Coastguard Worker text->WriteFully(text_begin, text_size);
177*795d594fSAndroid Build Coastguard Worker text->End();
178*795d594fSAndroid Build Coastguard Worker }
179*795d594fSAndroid Build Coastguard Worker
180*795d594fSAndroid Build Coastguard Worker builder_->PrepareDynamicSection(elf_file->GetPath(),
181*795d594fSAndroid Build Coastguard Worker rodata_size,
182*795d594fSAndroid Build Coastguard Worker text_size,
183*795d594fSAndroid Build Coastguard Worker oat_file_->DataImgRelRoSize(),
184*795d594fSAndroid Build Coastguard Worker oat_file_->DataImgRelRoAppImageOffset(),
185*795d594fSAndroid Build Coastguard Worker oat_file_->BssSize(),
186*795d594fSAndroid Build Coastguard Worker oat_file_->BssMethodsOffset(),
187*795d594fSAndroid Build Coastguard Worker oat_file_->BssRootsOffset(),
188*795d594fSAndroid Build Coastguard Worker oat_file_->VdexSize());
189*795d594fSAndroid Build Coastguard Worker builder_->WriteDynamicSection();
190*795d594fSAndroid Build Coastguard Worker
191*795d594fSAndroid Build Coastguard Worker const OatHeader& oat_header = oat_file_->GetOatHeader();
192*795d594fSAndroid Build Coastguard Worker #define DO_TRAMPOLINE(fn_name) \
193*795d594fSAndroid Build Coastguard Worker if (oat_header.Get ## fn_name ## Offset() != 0) { \
194*795d594fSAndroid Build Coastguard Worker debug::MethodDebugInfo info = {}; \
195*795d594fSAndroid Build Coastguard Worker info.custom_name = #fn_name; \
196*795d594fSAndroid Build Coastguard Worker info.isa = oat_header.GetInstructionSet(); \
197*795d594fSAndroid Build Coastguard Worker info.is_code_address_text_relative = true; \
198*795d594fSAndroid Build Coastguard Worker size_t code_offset = oat_header.Get ## fn_name ## Offset(); \
199*795d594fSAndroid Build Coastguard Worker code_offset -= GetInstructionSetEntryPointAdjustment(oat_header.GetInstructionSet()); \
200*795d594fSAndroid Build Coastguard Worker info.code_address = code_offset - oat_header.GetExecutableOffset(); \
201*795d594fSAndroid Build Coastguard Worker info.code_size = 0; /* The symbol lasts until the next symbol. */ \
202*795d594fSAndroid Build Coastguard Worker method_debug_infos_.push_back(std::move(info)); \
203*795d594fSAndroid Build Coastguard Worker }
204*795d594fSAndroid Build Coastguard Worker DO_TRAMPOLINE(JniDlsymLookupTrampoline);
205*795d594fSAndroid Build Coastguard Worker DO_TRAMPOLINE(JniDlsymLookupCriticalTrampoline);
206*795d594fSAndroid Build Coastguard Worker DO_TRAMPOLINE(QuickGenericJniTrampoline);
207*795d594fSAndroid Build Coastguard Worker DO_TRAMPOLINE(QuickImtConflictTrampoline);
208*795d594fSAndroid Build Coastguard Worker DO_TRAMPOLINE(QuickResolutionTrampoline);
209*795d594fSAndroid Build Coastguard Worker DO_TRAMPOLINE(QuickToInterpreterBridge);
210*795d594fSAndroid Build Coastguard Worker DO_TRAMPOLINE(NterpTrampoline);
211*795d594fSAndroid Build Coastguard Worker #undef DO_TRAMPOLINE
212*795d594fSAndroid Build Coastguard Worker
213*795d594fSAndroid Build Coastguard Worker Walk();
214*795d594fSAndroid Build Coastguard Worker
215*795d594fSAndroid Build Coastguard Worker // TODO: Try to symbolize link-time thunks?
216*795d594fSAndroid Build Coastguard Worker // This would require disassembling all methods to find branches outside the method code.
217*795d594fSAndroid Build Coastguard Worker
218*795d594fSAndroid Build Coastguard Worker // TODO: Add symbols for dex bytecode in the .dex section.
219*795d594fSAndroid Build Coastguard Worker
220*795d594fSAndroid Build Coastguard Worker debug::DebugInfo debug_info{};
221*795d594fSAndroid Build Coastguard Worker debug_info.compiled_methods = ArrayRef<const debug::MethodDebugInfo>(method_debug_infos_);
222*795d594fSAndroid Build Coastguard Worker
223*795d594fSAndroid Build Coastguard Worker debug::WriteDebugInfo(builder_.get(), debug_info);
224*795d594fSAndroid Build Coastguard Worker
225*795d594fSAndroid Build Coastguard Worker builder_->End();
226*795d594fSAndroid Build Coastguard Worker
227*795d594fSAndroid Build Coastguard Worker bool ret_value = builder_->Good();
228*795d594fSAndroid Build Coastguard Worker
229*795d594fSAndroid Build Coastguard Worker builder_.reset();
230*795d594fSAndroid Build Coastguard Worker output_stream.reset();
231*795d594fSAndroid Build Coastguard Worker
232*795d594fSAndroid Build Coastguard Worker if (elf_file->FlushCloseOrErase() != 0) {
233*795d594fSAndroid Build Coastguard Worker return false;
234*795d594fSAndroid Build Coastguard Worker }
235*795d594fSAndroid Build Coastguard Worker elf_file.reset();
236*795d594fSAndroid Build Coastguard Worker
237*795d594fSAndroid Build Coastguard Worker return ret_value;
238*795d594fSAndroid Build Coastguard Worker }
239*795d594fSAndroid Build Coastguard Worker
Walk()240*795d594fSAndroid Build Coastguard Worker void Walk() {
241*795d594fSAndroid Build Coastguard Worker std::vector<const OatDexFile*> oat_dex_files = oat_file_->GetOatDexFiles();
242*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < oat_dex_files.size(); i++) {
243*795d594fSAndroid Build Coastguard Worker const OatDexFile* oat_dex_file = oat_dex_files[i];
244*795d594fSAndroid Build Coastguard Worker CHECK(oat_dex_file != nullptr);
245*795d594fSAndroid Build Coastguard Worker WalkOatDexFile(oat_dex_file);
246*795d594fSAndroid Build Coastguard Worker }
247*795d594fSAndroid Build Coastguard Worker }
248*795d594fSAndroid Build Coastguard Worker
WalkOatDexFile(const OatDexFile * oat_dex_file)249*795d594fSAndroid Build Coastguard Worker void WalkOatDexFile(const OatDexFile* oat_dex_file) {
250*795d594fSAndroid Build Coastguard Worker std::string error_msg;
251*795d594fSAndroid Build Coastguard Worker const DexFile* const dex_file = OpenDexFile(oat_dex_file, &error_msg);
252*795d594fSAndroid Build Coastguard Worker if (dex_file == nullptr) {
253*795d594fSAndroid Build Coastguard Worker return;
254*795d594fSAndroid Build Coastguard Worker }
255*795d594fSAndroid Build Coastguard Worker for (size_t class_def_index = 0;
256*795d594fSAndroid Build Coastguard Worker class_def_index < dex_file->NumClassDefs();
257*795d594fSAndroid Build Coastguard Worker class_def_index++) {
258*795d594fSAndroid Build Coastguard Worker const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
259*795d594fSAndroid Build Coastguard Worker OatClassType type = oat_class.GetType();
260*795d594fSAndroid Build Coastguard Worker switch (type) {
261*795d594fSAndroid Build Coastguard Worker case OatClassType::kAllCompiled:
262*795d594fSAndroid Build Coastguard Worker case OatClassType::kSomeCompiled:
263*795d594fSAndroid Build Coastguard Worker WalkOatClass(oat_class, *dex_file, class_def_index);
264*795d594fSAndroid Build Coastguard Worker break;
265*795d594fSAndroid Build Coastguard Worker
266*795d594fSAndroid Build Coastguard Worker case OatClassType::kNoneCompiled:
267*795d594fSAndroid Build Coastguard Worker // Ignore.
268*795d594fSAndroid Build Coastguard Worker break;
269*795d594fSAndroid Build Coastguard Worker }
270*795d594fSAndroid Build Coastguard Worker }
271*795d594fSAndroid Build Coastguard Worker }
272*795d594fSAndroid Build Coastguard Worker
WalkOatClass(const OatFile::OatClass & oat_class,const DexFile & dex_file,uint32_t class_def_index)273*795d594fSAndroid Build Coastguard Worker void WalkOatClass(const OatFile::OatClass& oat_class,
274*795d594fSAndroid Build Coastguard Worker const DexFile& dex_file,
275*795d594fSAndroid Build Coastguard Worker uint32_t class_def_index) {
276*795d594fSAndroid Build Coastguard Worker ClassAccessor accessor(dex_file, class_def_index);
277*795d594fSAndroid Build Coastguard Worker // Note: even if this is an interface or a native class, we still have to walk it, as there
278*795d594fSAndroid Build Coastguard Worker // might be a static initializer.
279*795d594fSAndroid Build Coastguard Worker uint32_t class_method_idx = 0;
280*795d594fSAndroid Build Coastguard Worker for (const ClassAccessor::Method& method : accessor.GetMethods()) {
281*795d594fSAndroid Build Coastguard Worker WalkOatMethod(oat_class.GetOatMethod(class_method_idx++),
282*795d594fSAndroid Build Coastguard Worker dex_file,
283*795d594fSAndroid Build Coastguard Worker class_def_index,
284*795d594fSAndroid Build Coastguard Worker method.GetIndex(),
285*795d594fSAndroid Build Coastguard Worker method.GetCodeItem(),
286*795d594fSAndroid Build Coastguard Worker method.GetAccessFlags());
287*795d594fSAndroid Build Coastguard Worker }
288*795d594fSAndroid Build Coastguard Worker }
289*795d594fSAndroid Build Coastguard Worker
WalkOatMethod(const OatFile::OatMethod & oat_method,const DexFile & dex_file,uint32_t class_def_index,uint32_t dex_method_index,const dex::CodeItem * code_item,uint32_t method_access_flags)290*795d594fSAndroid Build Coastguard Worker void WalkOatMethod(const OatFile::OatMethod& oat_method,
291*795d594fSAndroid Build Coastguard Worker const DexFile& dex_file,
292*795d594fSAndroid Build Coastguard Worker uint32_t class_def_index,
293*795d594fSAndroid Build Coastguard Worker uint32_t dex_method_index,
294*795d594fSAndroid Build Coastguard Worker const dex::CodeItem* code_item,
295*795d594fSAndroid Build Coastguard Worker uint32_t method_access_flags) {
296*795d594fSAndroid Build Coastguard Worker if ((method_access_flags & kAccAbstract) != 0) {
297*795d594fSAndroid Build Coastguard Worker // Abstract method, no code.
298*795d594fSAndroid Build Coastguard Worker return;
299*795d594fSAndroid Build Coastguard Worker }
300*795d594fSAndroid Build Coastguard Worker const OatHeader& oat_header = oat_file_->GetOatHeader();
301*795d594fSAndroid Build Coastguard Worker const OatQuickMethodHeader* method_header = oat_method.GetOatQuickMethodHeader();
302*795d594fSAndroid Build Coastguard Worker if (method_header == nullptr || method_header->GetCodeSize() == 0) {
303*795d594fSAndroid Build Coastguard Worker // No code.
304*795d594fSAndroid Build Coastguard Worker return;
305*795d594fSAndroid Build Coastguard Worker }
306*795d594fSAndroid Build Coastguard Worker
307*795d594fSAndroid Build Coastguard Worker uint32_t entry_point = oat_method.GetCodeOffset() - oat_header.GetExecutableOffset();
308*795d594fSAndroid Build Coastguard Worker // Clear Thumb2 bit.
309*795d594fSAndroid Build Coastguard Worker const void* code_address = EntryPointToCodePointer(reinterpret_cast<void*>(entry_point));
310*795d594fSAndroid Build Coastguard Worker
311*795d594fSAndroid Build Coastguard Worker debug::MethodDebugInfo info = {};
312*795d594fSAndroid Build Coastguard Worker DCHECK(info.custom_name.empty());
313*795d594fSAndroid Build Coastguard Worker info.dex_file = &dex_file;
314*795d594fSAndroid Build Coastguard Worker info.class_def_index = class_def_index;
315*795d594fSAndroid Build Coastguard Worker info.dex_method_index = dex_method_index;
316*795d594fSAndroid Build Coastguard Worker info.access_flags = method_access_flags;
317*795d594fSAndroid Build Coastguard Worker info.code_item = code_item;
318*795d594fSAndroid Build Coastguard Worker info.isa = oat_header.GetInstructionSet();
319*795d594fSAndroid Build Coastguard Worker info.deduped = !seen_offsets_.insert(oat_method.GetCodeOffset()).second;
320*795d594fSAndroid Build Coastguard Worker info.is_native_debuggable = oat_header.IsNativeDebuggable();
321*795d594fSAndroid Build Coastguard Worker info.is_optimized = method_header->IsOptimized();
322*795d594fSAndroid Build Coastguard Worker info.is_code_address_text_relative = true;
323*795d594fSAndroid Build Coastguard Worker info.code_address = reinterpret_cast<uintptr_t>(code_address);
324*795d594fSAndroid Build Coastguard Worker info.code_size = method_header->GetCodeSize();
325*795d594fSAndroid Build Coastguard Worker info.frame_size_in_bytes = method_header->GetFrameSizeInBytes();
326*795d594fSAndroid Build Coastguard Worker info.code_info = info.is_optimized ? method_header->GetOptimizedCodeInfoPtr() : nullptr;
327*795d594fSAndroid Build Coastguard Worker info.cfi = ArrayRef<uint8_t>();
328*795d594fSAndroid Build Coastguard Worker method_debug_infos_.push_back(info);
329*795d594fSAndroid Build Coastguard Worker }
330*795d594fSAndroid Build Coastguard Worker
331*795d594fSAndroid Build Coastguard Worker private:
332*795d594fSAndroid Build Coastguard Worker const OatFile* oat_file_;
333*795d594fSAndroid Build Coastguard Worker std::unique_ptr<ElfBuilder<ElfTypes>> builder_;
334*795d594fSAndroid Build Coastguard Worker std::vector<debug::MethodDebugInfo> method_debug_infos_;
335*795d594fSAndroid Build Coastguard Worker std::unordered_set<uint32_t> seen_offsets_;
336*795d594fSAndroid Build Coastguard Worker const std::string output_name_;
337*795d594fSAndroid Build Coastguard Worker bool no_bits_;
338*795d594fSAndroid Build Coastguard Worker };
339*795d594fSAndroid Build Coastguard Worker
340*795d594fSAndroid Build Coastguard Worker class OatDumperOptions {
341*795d594fSAndroid Build Coastguard Worker public:
OatDumperOptions(bool dump_vmap,bool dump_code_info_stack_maps,bool disassemble_code,bool absolute_addresses,const char * class_filter,const char * method_filter,bool list_classes,bool list_methods,bool dump_header_only,bool dump_method_and_offset_as_json,const char * export_dex_location,const char * app_image,const char * oat_filename,const char * dex_filename,uint32_t addr2instr)342*795d594fSAndroid Build Coastguard Worker OatDumperOptions(bool dump_vmap,
343*795d594fSAndroid Build Coastguard Worker bool dump_code_info_stack_maps,
344*795d594fSAndroid Build Coastguard Worker bool disassemble_code,
345*795d594fSAndroid Build Coastguard Worker bool absolute_addresses,
346*795d594fSAndroid Build Coastguard Worker const char* class_filter,
347*795d594fSAndroid Build Coastguard Worker const char* method_filter,
348*795d594fSAndroid Build Coastguard Worker bool list_classes,
349*795d594fSAndroid Build Coastguard Worker bool list_methods,
350*795d594fSAndroid Build Coastguard Worker bool dump_header_only,
351*795d594fSAndroid Build Coastguard Worker bool dump_method_and_offset_as_json,
352*795d594fSAndroid Build Coastguard Worker const char* export_dex_location,
353*795d594fSAndroid Build Coastguard Worker const char* app_image,
354*795d594fSAndroid Build Coastguard Worker const char* oat_filename,
355*795d594fSAndroid Build Coastguard Worker const char* dex_filename,
356*795d594fSAndroid Build Coastguard Worker uint32_t addr2instr)
357*795d594fSAndroid Build Coastguard Worker : dump_vmap_(dump_vmap),
358*795d594fSAndroid Build Coastguard Worker dump_code_info_stack_maps_(dump_code_info_stack_maps),
359*795d594fSAndroid Build Coastguard Worker disassemble_code_(disassemble_code),
360*795d594fSAndroid Build Coastguard Worker absolute_addresses_(absolute_addresses),
361*795d594fSAndroid Build Coastguard Worker class_filter_(class_filter),
362*795d594fSAndroid Build Coastguard Worker method_filter_(method_filter),
363*795d594fSAndroid Build Coastguard Worker list_classes_(list_classes),
364*795d594fSAndroid Build Coastguard Worker list_methods_(list_methods),
365*795d594fSAndroid Build Coastguard Worker dump_header_only_(dump_header_only),
366*795d594fSAndroid Build Coastguard Worker dump_method_and_offset_as_json(dump_method_and_offset_as_json),
367*795d594fSAndroid Build Coastguard Worker export_dex_location_(export_dex_location),
368*795d594fSAndroid Build Coastguard Worker app_image_(app_image),
369*795d594fSAndroid Build Coastguard Worker oat_filename_(oat_filename != nullptr ? std::make_optional(oat_filename) : std::nullopt),
370*795d594fSAndroid Build Coastguard Worker dex_filename_(dex_filename != nullptr ? std::make_optional(dex_filename) : std::nullopt),
371*795d594fSAndroid Build Coastguard Worker addr2instr_(addr2instr),
372*795d594fSAndroid Build Coastguard Worker class_loader_(nullptr) {}
373*795d594fSAndroid Build Coastguard Worker
374*795d594fSAndroid Build Coastguard Worker const bool dump_vmap_;
375*795d594fSAndroid Build Coastguard Worker const bool dump_code_info_stack_maps_;
376*795d594fSAndroid Build Coastguard Worker const bool disassemble_code_;
377*795d594fSAndroid Build Coastguard Worker const bool absolute_addresses_;
378*795d594fSAndroid Build Coastguard Worker const char* const class_filter_;
379*795d594fSAndroid Build Coastguard Worker const char* const method_filter_;
380*795d594fSAndroid Build Coastguard Worker const bool list_classes_;
381*795d594fSAndroid Build Coastguard Worker const bool list_methods_;
382*795d594fSAndroid Build Coastguard Worker const bool dump_header_only_;
383*795d594fSAndroid Build Coastguard Worker const bool dump_method_and_offset_as_json;
384*795d594fSAndroid Build Coastguard Worker const char* const export_dex_location_;
385*795d594fSAndroid Build Coastguard Worker const char* const app_image_;
386*795d594fSAndroid Build Coastguard Worker const std::optional<std::string> oat_filename_;
387*795d594fSAndroid Build Coastguard Worker const std::optional<std::string> dex_filename_;
388*795d594fSAndroid Build Coastguard Worker uint32_t addr2instr_;
389*795d594fSAndroid Build Coastguard Worker Handle<mirror::ClassLoader>* class_loader_;
390*795d594fSAndroid Build Coastguard Worker };
391*795d594fSAndroid Build Coastguard Worker
392*795d594fSAndroid Build Coastguard Worker class OatDumper {
393*795d594fSAndroid Build Coastguard Worker public:
OatDumper(const OatFile & oat_file,const OatDumperOptions & options)394*795d594fSAndroid Build Coastguard Worker OatDumper(const OatFile& oat_file, const OatDumperOptions& options)
395*795d594fSAndroid Build Coastguard Worker : oat_file_(oat_file),
396*795d594fSAndroid Build Coastguard Worker oat_dex_files_(oat_file.GetOatDexFiles()),
397*795d594fSAndroid Build Coastguard Worker options_(options),
398*795d594fSAndroid Build Coastguard Worker resolved_addr2instr_(0),
399*795d594fSAndroid Build Coastguard Worker instruction_set_(oat_file_.GetOatHeader().GetInstructionSet()) {
400*795d594fSAndroid Build Coastguard Worker CHECK(options_.class_loader_ != nullptr);
401*795d594fSAndroid Build Coastguard Worker CHECK(options_.class_filter_ != nullptr);
402*795d594fSAndroid Build Coastguard Worker CHECK(options_.method_filter_ != nullptr);
403*795d594fSAndroid Build Coastguard Worker
404*795d594fSAndroid Build Coastguard Worker std::string error_msg;
405*795d594fSAndroid Build Coastguard Worker const uint8_t* elf_begin = oat_file.ComputeElfBegin(&error_msg);
406*795d594fSAndroid Build Coastguard Worker DCHECK_NE(elf_begin, nullptr) << error_msg;
407*795d594fSAndroid Build Coastguard Worker DCHECK_GE(oat_file.Begin(), elf_begin);
408*795d594fSAndroid Build Coastguard Worker oat_offset_ = reinterpret_cast<size_t>(oat_file.Begin()) - reinterpret_cast<size_t>(elf_begin);
409*795d594fSAndroid Build Coastguard Worker
410*795d594fSAndroid Build Coastguard Worker disassembler_ = Disassembler::Create(
411*795d594fSAndroid Build Coastguard Worker instruction_set_,
412*795d594fSAndroid Build Coastguard Worker new DisassemblerOptions(options_.absolute_addresses_,
413*795d594fSAndroid Build Coastguard Worker elf_begin,
414*795d594fSAndroid Build Coastguard Worker oat_file.End(),
415*795d594fSAndroid Build Coastguard Worker /* can_read_literals_= */ true,
416*795d594fSAndroid Build Coastguard Worker Is64BitInstructionSet(instruction_set_) ?
417*795d594fSAndroid Build Coastguard Worker &Thread::DumpThreadOffset<PointerSize::k64> :
418*795d594fSAndroid Build Coastguard Worker &Thread::DumpThreadOffset<PointerSize::k32>));
419*795d594fSAndroid Build Coastguard Worker
420*795d594fSAndroid Build Coastguard Worker AddAllOffsets();
421*795d594fSAndroid Build Coastguard Worker }
422*795d594fSAndroid Build Coastguard Worker
~OatDumper()423*795d594fSAndroid Build Coastguard Worker ~OatDumper() {
424*795d594fSAndroid Build Coastguard Worker delete disassembler_;
425*795d594fSAndroid Build Coastguard Worker }
426*795d594fSAndroid Build Coastguard Worker
GetInstructionSet()427*795d594fSAndroid Build Coastguard Worker InstructionSet GetInstructionSet() {
428*795d594fSAndroid Build Coastguard Worker return instruction_set_;
429*795d594fSAndroid Build Coastguard Worker }
430*795d594fSAndroid Build Coastguard Worker
431*795d594fSAndroid Build Coastguard Worker using DexFileUniqV = std::vector<std::unique_ptr<const DexFile>>;
432*795d594fSAndroid Build Coastguard Worker
Dump(std::ostream & os)433*795d594fSAndroid Build Coastguard Worker bool Dump(std::ostream& os) {
434*795d594fSAndroid Build Coastguard Worker if (options_.dump_method_and_offset_as_json) {
435*795d594fSAndroid Build Coastguard Worker return DumpMethodAndOffsetAsJson(os);
436*795d594fSAndroid Build Coastguard Worker }
437*795d594fSAndroid Build Coastguard Worker
438*795d594fSAndroid Build Coastguard Worker bool success = true;
439*795d594fSAndroid Build Coastguard Worker const OatHeader& oat_header = oat_file_.GetOatHeader();
440*795d594fSAndroid Build Coastguard Worker
441*795d594fSAndroid Build Coastguard Worker os << "MAGIC:\n";
442*795d594fSAndroid Build Coastguard Worker os << oat_header.GetMagic() << "\n\n";
443*795d594fSAndroid Build Coastguard Worker
444*795d594fSAndroid Build Coastguard Worker os << "LOCATION:\n";
445*795d594fSAndroid Build Coastguard Worker os << oat_file_.GetLocation() << "\n\n";
446*795d594fSAndroid Build Coastguard Worker
447*795d594fSAndroid Build Coastguard Worker os << "CHECKSUM:\n";
448*795d594fSAndroid Build Coastguard Worker os << StringPrintf("0x%08x\n\n", oat_header.GetChecksum());
449*795d594fSAndroid Build Coastguard Worker
450*795d594fSAndroid Build Coastguard Worker os << "INSTRUCTION SET:\n";
451*795d594fSAndroid Build Coastguard Worker os << oat_header.GetInstructionSet() << "\n\n";
452*795d594fSAndroid Build Coastguard Worker
453*795d594fSAndroid Build Coastguard Worker {
454*795d594fSAndroid Build Coastguard Worker std::unique_ptr<const InstructionSetFeatures> features(
455*795d594fSAndroid Build Coastguard Worker InstructionSetFeatures::FromBitmap(oat_header.GetInstructionSet(),
456*795d594fSAndroid Build Coastguard Worker oat_header.GetInstructionSetFeaturesBitmap()));
457*795d594fSAndroid Build Coastguard Worker os << "INSTRUCTION SET FEATURES:\n";
458*795d594fSAndroid Build Coastguard Worker os << features->GetFeatureString() << "\n\n";
459*795d594fSAndroid Build Coastguard Worker }
460*795d594fSAndroid Build Coastguard Worker
461*795d594fSAndroid Build Coastguard Worker os << "DEX FILE COUNT:\n";
462*795d594fSAndroid Build Coastguard Worker os << oat_header.GetDexFileCount() << "\n\n";
463*795d594fSAndroid Build Coastguard Worker
464*795d594fSAndroid Build Coastguard Worker #define DUMP_OAT_HEADER_OFFSET(label, offset) \
465*795d594fSAndroid Build Coastguard Worker os << label " OFFSET:\n"; \
466*795d594fSAndroid Build Coastguard Worker os << StringPrintf("0x%08zx", AdjustOffset(oat_header.offset())); \
467*795d594fSAndroid Build Coastguard Worker if (oat_header.offset() != 0 && options_.absolute_addresses_) { \
468*795d594fSAndroid Build Coastguard Worker os << StringPrintf(" (%p)", oat_file_.Begin() + oat_header.offset()); \
469*795d594fSAndroid Build Coastguard Worker } \
470*795d594fSAndroid Build Coastguard Worker os << StringPrintf("\n\n");
471*795d594fSAndroid Build Coastguard Worker
472*795d594fSAndroid Build Coastguard Worker DUMP_OAT_HEADER_OFFSET("EXECUTABLE", GetExecutableOffset);
473*795d594fSAndroid Build Coastguard Worker DUMP_OAT_HEADER_OFFSET("JNI DLSYM LOOKUP TRAMPOLINE",
474*795d594fSAndroid Build Coastguard Worker GetJniDlsymLookupTrampolineOffset);
475*795d594fSAndroid Build Coastguard Worker DUMP_OAT_HEADER_OFFSET("JNI DLSYM LOOKUP CRITICAL TRAMPOLINE",
476*795d594fSAndroid Build Coastguard Worker GetJniDlsymLookupCriticalTrampolineOffset);
477*795d594fSAndroid Build Coastguard Worker DUMP_OAT_HEADER_OFFSET("QUICK GENERIC JNI TRAMPOLINE",
478*795d594fSAndroid Build Coastguard Worker GetQuickGenericJniTrampolineOffset);
479*795d594fSAndroid Build Coastguard Worker DUMP_OAT_HEADER_OFFSET("QUICK IMT CONFLICT TRAMPOLINE",
480*795d594fSAndroid Build Coastguard Worker GetQuickImtConflictTrampolineOffset);
481*795d594fSAndroid Build Coastguard Worker DUMP_OAT_HEADER_OFFSET("QUICK RESOLUTION TRAMPOLINE",
482*795d594fSAndroid Build Coastguard Worker GetQuickResolutionTrampolineOffset);
483*795d594fSAndroid Build Coastguard Worker DUMP_OAT_HEADER_OFFSET("QUICK TO INTERPRETER BRIDGE",
484*795d594fSAndroid Build Coastguard Worker GetQuickToInterpreterBridgeOffset);
485*795d594fSAndroid Build Coastguard Worker DUMP_OAT_HEADER_OFFSET("NTERP_TRAMPOLINE",
486*795d594fSAndroid Build Coastguard Worker GetNterpTrampolineOffset);
487*795d594fSAndroid Build Coastguard Worker #undef DUMP_OAT_HEADER_OFFSET
488*795d594fSAndroid Build Coastguard Worker
489*795d594fSAndroid Build Coastguard Worker // Print the key-value store.
490*795d594fSAndroid Build Coastguard Worker {
491*795d594fSAndroid Build Coastguard Worker os << "KEY VALUE STORE:\n";
492*795d594fSAndroid Build Coastguard Worker size_t index = 0;
493*795d594fSAndroid Build Coastguard Worker const char* key;
494*795d594fSAndroid Build Coastguard Worker const char* value;
495*795d594fSAndroid Build Coastguard Worker while (oat_header.GetStoreKeyValuePairByIndex(index, &key, &value)) {
496*795d594fSAndroid Build Coastguard Worker os << key << " = " << value << "\n";
497*795d594fSAndroid Build Coastguard Worker index++;
498*795d594fSAndroid Build Coastguard Worker }
499*795d594fSAndroid Build Coastguard Worker os << "\n";
500*795d594fSAndroid Build Coastguard Worker }
501*795d594fSAndroid Build Coastguard Worker
502*795d594fSAndroid Build Coastguard Worker if (options_.absolute_addresses_) {
503*795d594fSAndroid Build Coastguard Worker os << "BEGIN:\n";
504*795d594fSAndroid Build Coastguard Worker os << reinterpret_cast<const void*>(oat_file_.Begin()) << "\n\n";
505*795d594fSAndroid Build Coastguard Worker
506*795d594fSAndroid Build Coastguard Worker os << "END:\n";
507*795d594fSAndroid Build Coastguard Worker os << reinterpret_cast<const void*>(oat_file_.End()) << "\n\n";
508*795d594fSAndroid Build Coastguard Worker }
509*795d594fSAndroid Build Coastguard Worker
510*795d594fSAndroid Build Coastguard Worker os << "SIZE:\n";
511*795d594fSAndroid Build Coastguard Worker os << oat_file_.Size() << "\n\n";
512*795d594fSAndroid Build Coastguard Worker
513*795d594fSAndroid Build Coastguard Worker os << std::flush;
514*795d594fSAndroid Build Coastguard Worker
515*795d594fSAndroid Build Coastguard Worker // If set, adjust relative address to be searched
516*795d594fSAndroid Build Coastguard Worker if (options_.addr2instr_ != 0) {
517*795d594fSAndroid Build Coastguard Worker resolved_addr2instr_ = options_.addr2instr_ + oat_header.GetExecutableOffset();
518*795d594fSAndroid Build Coastguard Worker os << "SEARCH ADDRESS (executable offset + input):\n";
519*795d594fSAndroid Build Coastguard Worker os << StringPrintf("0x%08zx\n\n", AdjustOffset(resolved_addr2instr_));
520*795d594fSAndroid Build Coastguard Worker }
521*795d594fSAndroid Build Coastguard Worker
522*795d594fSAndroid Build Coastguard Worker // Dump .data.img.rel.ro entries.
523*795d594fSAndroid Build Coastguard Worker DumpDataImgRelRoEntries(os);
524*795d594fSAndroid Build Coastguard Worker
525*795d594fSAndroid Build Coastguard Worker // Dump .bss summary, individual entries are dumped per dex file.
526*795d594fSAndroid Build Coastguard Worker os << ".bss: ";
527*795d594fSAndroid Build Coastguard Worker if (oat_file_.GetBssMethods().empty() && oat_file_.GetBssGcRoots().empty()) {
528*795d594fSAndroid Build Coastguard Worker os << "empty.\n\n";
529*795d594fSAndroid Build Coastguard Worker } else {
530*795d594fSAndroid Build Coastguard Worker os << oat_file_.GetBssMethods().size() << " methods, ";
531*795d594fSAndroid Build Coastguard Worker os << oat_file_.GetBssGcRoots().size() << " GC roots.\n\n";
532*795d594fSAndroid Build Coastguard Worker }
533*795d594fSAndroid Build Coastguard Worker
534*795d594fSAndroid Build Coastguard Worker // Dumping the dex file overview is compact enough to do even if header only.
535*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < oat_dex_files_.size(); i++) {
536*795d594fSAndroid Build Coastguard Worker const OatDexFile* oat_dex_file = oat_dex_files_[i];
537*795d594fSAndroid Build Coastguard Worker CHECK(oat_dex_file != nullptr);
538*795d594fSAndroid Build Coastguard Worker std::string error_msg;
539*795d594fSAndroid Build Coastguard Worker const DexFile* const dex_file = OpenDexFile(oat_dex_file, &error_msg);
540*795d594fSAndroid Build Coastguard Worker if (dex_file == nullptr) {
541*795d594fSAndroid Build Coastguard Worker os << "Failed to open dex file '" << oat_dex_file->GetDexFileLocation() << "': "
542*795d594fSAndroid Build Coastguard Worker << error_msg;
543*795d594fSAndroid Build Coastguard Worker continue;
544*795d594fSAndroid Build Coastguard Worker }
545*795d594fSAndroid Build Coastguard Worker
546*795d594fSAndroid Build Coastguard Worker const DexLayoutSections* const layout_sections = oat_dex_file->GetDexLayoutSections();
547*795d594fSAndroid Build Coastguard Worker if (layout_sections != nullptr) {
548*795d594fSAndroid Build Coastguard Worker os << "Layout data\n";
549*795d594fSAndroid Build Coastguard Worker os << *layout_sections;
550*795d594fSAndroid Build Coastguard Worker os << "\n";
551*795d594fSAndroid Build Coastguard Worker }
552*795d594fSAndroid Build Coastguard Worker
553*795d594fSAndroid Build Coastguard Worker if (!options_.dump_header_only_) {
554*795d594fSAndroid Build Coastguard Worker DumpBssMappings(os,
555*795d594fSAndroid Build Coastguard Worker dex_file,
556*795d594fSAndroid Build Coastguard Worker oat_dex_file->GetMethodBssMapping(),
557*795d594fSAndroid Build Coastguard Worker oat_dex_file->GetTypeBssMapping(),
558*795d594fSAndroid Build Coastguard Worker oat_dex_file->GetPublicTypeBssMapping(),
559*795d594fSAndroid Build Coastguard Worker oat_dex_file->GetPackageTypeBssMapping(),
560*795d594fSAndroid Build Coastguard Worker oat_dex_file->GetStringBssMapping(),
561*795d594fSAndroid Build Coastguard Worker oat_dex_file->GetMethodTypeBssMapping());
562*795d594fSAndroid Build Coastguard Worker }
563*795d594fSAndroid Build Coastguard Worker }
564*795d594fSAndroid Build Coastguard Worker
565*795d594fSAndroid Build Coastguard Worker if (!options_.dump_header_only_) {
566*795d594fSAndroid Build Coastguard Worker Runtime* const runtime = Runtime::Current();
567*795d594fSAndroid Build Coastguard Worker ClassLinker* const linker = runtime != nullptr ? runtime->GetClassLinker() : nullptr;
568*795d594fSAndroid Build Coastguard Worker
569*795d594fSAndroid Build Coastguard Worker if (linker != nullptr) {
570*795d594fSAndroid Build Coastguard Worker ArrayRef<const DexFile* const> bcp_dex_files(linker->GetBootClassPath());
571*795d594fSAndroid Build Coastguard Worker // The guarantee that we have is that we can safely take a look the BCP DexFiles in
572*795d594fSAndroid Build Coastguard Worker // [0..number_of_compiled_bcp_dexfiles) since the runtime may add more DexFiles after that.
573*795d594fSAndroid Build Coastguard Worker // As a note, in the case of not having mappings or in the case of multi image we
574*795d594fSAndroid Build Coastguard Worker // purposively leave `oat_file_.bcp_bss_info` empty.
575*795d594fSAndroid Build Coastguard Worker CHECK_LE(oat_file_.bcp_bss_info_.size(), bcp_dex_files.size());
576*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < oat_file_.bcp_bss_info_.size(); i++) {
577*795d594fSAndroid Build Coastguard Worker const DexFile* const dex_file = bcp_dex_files[i];
578*795d594fSAndroid Build Coastguard Worker os << "Entries for BCP DexFile: " << dex_file->GetLocation() << "\n";
579*795d594fSAndroid Build Coastguard Worker DumpBssMappings(os,
580*795d594fSAndroid Build Coastguard Worker dex_file,
581*795d594fSAndroid Build Coastguard Worker oat_file_.bcp_bss_info_[i].method_bss_mapping,
582*795d594fSAndroid Build Coastguard Worker oat_file_.bcp_bss_info_[i].type_bss_mapping,
583*795d594fSAndroid Build Coastguard Worker oat_file_.bcp_bss_info_[i].public_type_bss_mapping,
584*795d594fSAndroid Build Coastguard Worker oat_file_.bcp_bss_info_[i].package_type_bss_mapping,
585*795d594fSAndroid Build Coastguard Worker oat_file_.bcp_bss_info_[i].string_bss_mapping,
586*795d594fSAndroid Build Coastguard Worker oat_file_.bcp_bss_info_[i].method_type_bss_mapping);
587*795d594fSAndroid Build Coastguard Worker }
588*795d594fSAndroid Build Coastguard Worker } else {
589*795d594fSAndroid Build Coastguard Worker // We don't have a runtime, just dump the offsets
590*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < oat_file_.bcp_bss_info_.size(); i++) {
591*795d594fSAndroid Build Coastguard Worker os << "Offsets for BCP DexFile at index " << i << "\n";
592*795d594fSAndroid Build Coastguard Worker DumpBssOffsets(os, "ArtMethod", oat_file_.bcp_bss_info_[i].method_bss_mapping);
593*795d594fSAndroid Build Coastguard Worker DumpBssOffsets(os, "Class", oat_file_.bcp_bss_info_[i].type_bss_mapping);
594*795d594fSAndroid Build Coastguard Worker DumpBssOffsets(os, "Public Class", oat_file_.bcp_bss_info_[i].public_type_bss_mapping);
595*795d594fSAndroid Build Coastguard Worker DumpBssOffsets(os, "Package Class", oat_file_.bcp_bss_info_[i].package_type_bss_mapping);
596*795d594fSAndroid Build Coastguard Worker DumpBssOffsets(os, "String", oat_file_.bcp_bss_info_[i].string_bss_mapping);
597*795d594fSAndroid Build Coastguard Worker DumpBssOffsets(os, "MethodType", oat_file_.bcp_bss_info_[i].method_type_bss_mapping);
598*795d594fSAndroid Build Coastguard Worker }
599*795d594fSAndroid Build Coastguard Worker }
600*795d594fSAndroid Build Coastguard Worker }
601*795d594fSAndroid Build Coastguard Worker
602*795d594fSAndroid Build Coastguard Worker if (!options_.dump_header_only_) {
603*795d594fSAndroid Build Coastguard Worker VariableIndentationOutputStream vios(&os);
604*795d594fSAndroid Build Coastguard Worker VdexFile::VdexFileHeader vdex_header = oat_file_.GetVdexFile()->GetVdexFileHeader();
605*795d594fSAndroid Build Coastguard Worker if (vdex_header.IsValid()) {
606*795d594fSAndroid Build Coastguard Worker std::string error_msg;
607*795d594fSAndroid Build Coastguard Worker std::vector<const DexFile*> dex_files;
608*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < oat_dex_files_.size(); i++) {
609*795d594fSAndroid Build Coastguard Worker const DexFile* dex_file = OpenDexFile(oat_dex_files_[i], &error_msg);
610*795d594fSAndroid Build Coastguard Worker if (dex_file == nullptr) {
611*795d594fSAndroid Build Coastguard Worker os << "Error opening dex file: " << error_msg << std::endl;
612*795d594fSAndroid Build Coastguard Worker return false;
613*795d594fSAndroid Build Coastguard Worker }
614*795d594fSAndroid Build Coastguard Worker dex_files.push_back(dex_file);
615*795d594fSAndroid Build Coastguard Worker }
616*795d594fSAndroid Build Coastguard Worker verifier::VerifierDeps deps(dex_files, /*output_only=*/ false);
617*795d594fSAndroid Build Coastguard Worker if (!deps.ParseStoredData(dex_files, oat_file_.GetVdexFile()->GetVerifierDepsData())) {
618*795d594fSAndroid Build Coastguard Worker os << "Error parsing verifier dependencies." << std::endl;
619*795d594fSAndroid Build Coastguard Worker return false;
620*795d594fSAndroid Build Coastguard Worker }
621*795d594fSAndroid Build Coastguard Worker deps.Dump(&vios);
622*795d594fSAndroid Build Coastguard Worker } else {
623*795d594fSAndroid Build Coastguard Worker os << "UNRECOGNIZED vdex file, magic "
624*795d594fSAndroid Build Coastguard Worker << vdex_header.GetMagic()
625*795d594fSAndroid Build Coastguard Worker << ", version "
626*795d594fSAndroid Build Coastguard Worker << vdex_header.GetVdexVersion()
627*795d594fSAndroid Build Coastguard Worker << "\n";
628*795d594fSAndroid Build Coastguard Worker }
629*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < oat_dex_files_.size(); i++) {
630*795d594fSAndroid Build Coastguard Worker const OatDexFile* oat_dex_file = oat_dex_files_[i];
631*795d594fSAndroid Build Coastguard Worker CHECK(oat_dex_file != nullptr);
632*795d594fSAndroid Build Coastguard Worker if (!DumpOatDexFile(os, *oat_dex_file)) {
633*795d594fSAndroid Build Coastguard Worker success = false;
634*795d594fSAndroid Build Coastguard Worker }
635*795d594fSAndroid Build Coastguard Worker }
636*795d594fSAndroid Build Coastguard Worker }
637*795d594fSAndroid Build Coastguard Worker
638*795d594fSAndroid Build Coastguard Worker if (options_.export_dex_location_) {
639*795d594fSAndroid Build Coastguard Worker std::string error_msg;
640*795d594fSAndroid Build Coastguard Worker std::string vdex_filename = GetVdexFilename(oat_file_.GetLocation());
641*795d594fSAndroid Build Coastguard Worker if (!OS::FileExists(vdex_filename.c_str())) {
642*795d594fSAndroid Build Coastguard Worker os << "File " << vdex_filename.c_str() << " does not exist\n";
643*795d594fSAndroid Build Coastguard Worker return false;
644*795d594fSAndroid Build Coastguard Worker }
645*795d594fSAndroid Build Coastguard Worker
646*795d594fSAndroid Build Coastguard Worker DexFileUniqV vdex_dex_files;
647*795d594fSAndroid Build Coastguard Worker std::unique_ptr<const VdexFile> vdex_file = OpenVdex(vdex_filename,
648*795d594fSAndroid Build Coastguard Worker &vdex_dex_files,
649*795d594fSAndroid Build Coastguard Worker &error_msg);
650*795d594fSAndroid Build Coastguard Worker if (vdex_file.get() == nullptr) {
651*795d594fSAndroid Build Coastguard Worker os << "Failed to open vdex file: " << error_msg << "\n";
652*795d594fSAndroid Build Coastguard Worker return false;
653*795d594fSAndroid Build Coastguard Worker }
654*795d594fSAndroid Build Coastguard Worker if (oat_dex_files_.size() != vdex_dex_files.size()) {
655*795d594fSAndroid Build Coastguard Worker os << "Dex files number in Vdex file does not match Dex files number in Oat file: "
656*795d594fSAndroid Build Coastguard Worker << vdex_dex_files.size() << " vs " << oat_dex_files_.size() << '\n';
657*795d594fSAndroid Build Coastguard Worker return false;
658*795d594fSAndroid Build Coastguard Worker }
659*795d594fSAndroid Build Coastguard Worker
660*795d594fSAndroid Build Coastguard Worker size_t i = 0;
661*795d594fSAndroid Build Coastguard Worker for (const auto& vdex_dex_file : vdex_dex_files) {
662*795d594fSAndroid Build Coastguard Worker const OatDexFile* oat_dex_file = oat_dex_files_[i];
663*795d594fSAndroid Build Coastguard Worker CHECK(oat_dex_file != nullptr);
664*795d594fSAndroid Build Coastguard Worker CHECK(vdex_dex_file != nullptr);
665*795d594fSAndroid Build Coastguard Worker
666*795d594fSAndroid Build Coastguard Worker if (!vdex_dex_file->IsDexContainerFirstEntry()) {
667*795d594fSAndroid Build Coastguard Worker // All the data was already exported together with the primary dex file.
668*795d594fSAndroid Build Coastguard Worker continue;
669*795d594fSAndroid Build Coastguard Worker }
670*795d594fSAndroid Build Coastguard Worker
671*795d594fSAndroid Build Coastguard Worker if (!ExportDexFile(os, *oat_dex_file, vdex_dex_file.get(), /*used_dexlayout=*/ false)) {
672*795d594fSAndroid Build Coastguard Worker success = false;
673*795d594fSAndroid Build Coastguard Worker break;
674*795d594fSAndroid Build Coastguard Worker }
675*795d594fSAndroid Build Coastguard Worker i++;
676*795d594fSAndroid Build Coastguard Worker }
677*795d594fSAndroid Build Coastguard Worker }
678*795d594fSAndroid Build Coastguard Worker
679*795d594fSAndroid Build Coastguard Worker {
680*795d594fSAndroid Build Coastguard Worker os << "OAT FILE STATS:\n";
681*795d594fSAndroid Build Coastguard Worker VariableIndentationOutputStream vios(&os);
682*795d594fSAndroid Build Coastguard Worker stats_.AddBytes(oat_file_.Size());
683*795d594fSAndroid Build Coastguard Worker stats_.DumpSizes(vios, "OatFile");
684*795d594fSAndroid Build Coastguard Worker }
685*795d594fSAndroid Build Coastguard Worker
686*795d594fSAndroid Build Coastguard Worker os << std::flush;
687*795d594fSAndroid Build Coastguard Worker return success;
688*795d594fSAndroid Build Coastguard Worker }
689*795d594fSAndroid Build Coastguard Worker
DumpMethodAndOffsetAsJson(std::ostream & os)690*795d594fSAndroid Build Coastguard Worker bool DumpMethodAndOffsetAsJson(std::ostream& os) {
691*795d594fSAndroid Build Coastguard Worker for (const OatDexFile* oat_dex_file : oat_dex_files_) {
692*795d594fSAndroid Build Coastguard Worker CHECK(oat_dex_file != nullptr);
693*795d594fSAndroid Build Coastguard Worker // Create the dex file early. A lot of print-out things depend on it.
694*795d594fSAndroid Build Coastguard Worker std::string error_msg;
695*795d594fSAndroid Build Coastguard Worker const DexFile* const dex_file = art::OpenDexFile(oat_dex_file, &error_msg);
696*795d594fSAndroid Build Coastguard Worker if (dex_file == nullptr) {
697*795d594fSAndroid Build Coastguard Worker LOG(WARNING) << "Failed to open dex file '" << oat_dex_file->GetDexFileLocation()
698*795d594fSAndroid Build Coastguard Worker << "': " << error_msg;
699*795d594fSAndroid Build Coastguard Worker return false;
700*795d594fSAndroid Build Coastguard Worker }
701*795d594fSAndroid Build Coastguard Worker for (ClassAccessor accessor : dex_file->GetClasses()) {
702*795d594fSAndroid Build Coastguard Worker const char* descriptor = accessor.GetDescriptor();
703*795d594fSAndroid Build Coastguard Worker if (DescriptorToDot(descriptor).find(options_.class_filter_) == std::string::npos) {
704*795d594fSAndroid Build Coastguard Worker continue;
705*795d594fSAndroid Build Coastguard Worker }
706*795d594fSAndroid Build Coastguard Worker
707*795d594fSAndroid Build Coastguard Worker const uint16_t class_def_index = accessor.GetClassDefIndex();
708*795d594fSAndroid Build Coastguard Worker const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
709*795d594fSAndroid Build Coastguard Worker uint32_t class_method_index = 0;
710*795d594fSAndroid Build Coastguard Worker
711*795d594fSAndroid Build Coastguard Worker // inspired by DumpOatMethod
712*795d594fSAndroid Build Coastguard Worker for (const ClassAccessor::Method& method : accessor.GetMethods()) {
713*795d594fSAndroid Build Coastguard Worker uint32_t code_offset = oat_class.GetOatMethod(class_method_index).GetCodeOffset();
714*795d594fSAndroid Build Coastguard Worker class_method_index++;
715*795d594fSAndroid Build Coastguard Worker
716*795d594fSAndroid Build Coastguard Worker uint32_t dex_method_idx = method.GetIndex();
717*795d594fSAndroid Build Coastguard Worker std::string method_name = dex_file->GetMethodName(dex_file->GetMethodId(dex_method_idx));
718*795d594fSAndroid Build Coastguard Worker if (method_name.find(options_.method_filter_) == std::string::npos) {
719*795d594fSAndroid Build Coastguard Worker continue;
720*795d594fSAndroid Build Coastguard Worker }
721*795d594fSAndroid Build Coastguard Worker
722*795d594fSAndroid Build Coastguard Worker std::string pretty_method = dex_file->PrettyMethod(dex_method_idx, true);
723*795d594fSAndroid Build Coastguard Worker
724*795d594fSAndroid Build Coastguard Worker os << StringPrintf("{\"method\":\"%s\",\"offset\":\"0x%08zx\"}\n",
725*795d594fSAndroid Build Coastguard Worker pretty_method.c_str(),
726*795d594fSAndroid Build Coastguard Worker AdjustOffset(code_offset));
727*795d594fSAndroid Build Coastguard Worker }
728*795d594fSAndroid Build Coastguard Worker }
729*795d594fSAndroid Build Coastguard Worker }
730*795d594fSAndroid Build Coastguard Worker return true;
731*795d594fSAndroid Build Coastguard Worker }
732*795d594fSAndroid Build Coastguard Worker
ComputeSize(const void * oat_data)733*795d594fSAndroid Build Coastguard Worker size_t ComputeSize(const void* oat_data) {
734*795d594fSAndroid Build Coastguard Worker if (reinterpret_cast<const uint8_t*>(oat_data) < oat_file_.Begin() ||
735*795d594fSAndroid Build Coastguard Worker reinterpret_cast<const uint8_t*>(oat_data) > oat_file_.End()) {
736*795d594fSAndroid Build Coastguard Worker return 0; // Address not in oat file
737*795d594fSAndroid Build Coastguard Worker }
738*795d594fSAndroid Build Coastguard Worker uintptr_t begin_offset = reinterpret_cast<uintptr_t>(oat_data) -
739*795d594fSAndroid Build Coastguard Worker reinterpret_cast<uintptr_t>(oat_file_.Begin());
740*795d594fSAndroid Build Coastguard Worker auto it = offsets_.upper_bound(begin_offset);
741*795d594fSAndroid Build Coastguard Worker CHECK(it != offsets_.end());
742*795d594fSAndroid Build Coastguard Worker uintptr_t end_offset = *it;
743*795d594fSAndroid Build Coastguard Worker return end_offset - begin_offset;
744*795d594fSAndroid Build Coastguard Worker }
745*795d594fSAndroid Build Coastguard Worker
GetOatInstructionSet()746*795d594fSAndroid Build Coastguard Worker InstructionSet GetOatInstructionSet() {
747*795d594fSAndroid Build Coastguard Worker return oat_file_.GetOatHeader().GetInstructionSet();
748*795d594fSAndroid Build Coastguard Worker }
749*795d594fSAndroid Build Coastguard Worker
GetQuickOatCode(ArtMethod * m)750*795d594fSAndroid Build Coastguard Worker const void* GetQuickOatCode(ArtMethod* m) REQUIRES_SHARED(Locks::mutator_lock_) {
751*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < oat_dex_files_.size(); i++) {
752*795d594fSAndroid Build Coastguard Worker const OatDexFile* oat_dex_file = oat_dex_files_[i];
753*795d594fSAndroid Build Coastguard Worker CHECK(oat_dex_file != nullptr);
754*795d594fSAndroid Build Coastguard Worker std::string error_msg;
755*795d594fSAndroid Build Coastguard Worker const DexFile* const dex_file = OpenDexFile(oat_dex_file, &error_msg);
756*795d594fSAndroid Build Coastguard Worker if (dex_file == nullptr) {
757*795d594fSAndroid Build Coastguard Worker LOG(WARNING) << "Failed to open dex file '" << oat_dex_file->GetDexFileLocation()
758*795d594fSAndroid Build Coastguard Worker << "': " << error_msg;
759*795d594fSAndroid Build Coastguard Worker } else {
760*795d594fSAndroid Build Coastguard Worker const char* descriptor = m->GetDeclaringClassDescriptor();
761*795d594fSAndroid Build Coastguard Worker const dex::ClassDef* class_def =
762*795d594fSAndroid Build Coastguard Worker OatDexFile::FindClassDef(*dex_file, descriptor, ComputeModifiedUtf8Hash(descriptor));
763*795d594fSAndroid Build Coastguard Worker if (class_def != nullptr) {
764*795d594fSAndroid Build Coastguard Worker uint16_t class_def_index = dex_file->GetIndexForClassDef(*class_def);
765*795d594fSAndroid Build Coastguard Worker const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
766*795d594fSAndroid Build Coastguard Worker uint32_t oat_method_index;
767*795d594fSAndroid Build Coastguard Worker if (m->IsStatic() || m->IsDirect()) {
768*795d594fSAndroid Build Coastguard Worker // Simple case where the oat method index was stashed at load time.
769*795d594fSAndroid Build Coastguard Worker oat_method_index = m->GetMethodIndex();
770*795d594fSAndroid Build Coastguard Worker } else {
771*795d594fSAndroid Build Coastguard Worker // Compute the oat_method_index by search for its position in the class def.
772*795d594fSAndroid Build Coastguard Worker ClassAccessor accessor(*dex_file, *class_def);
773*795d594fSAndroid Build Coastguard Worker oat_method_index = accessor.NumDirectMethods();
774*795d594fSAndroid Build Coastguard Worker bool found_virtual = false;
775*795d594fSAndroid Build Coastguard Worker for (ClassAccessor::Method dex_method : accessor.GetVirtualMethods()) {
776*795d594fSAndroid Build Coastguard Worker // Check method index instead of identity in case of duplicate method definitions.
777*795d594fSAndroid Build Coastguard Worker if (dex_method.GetIndex() == m->GetDexMethodIndex()) {
778*795d594fSAndroid Build Coastguard Worker found_virtual = true;
779*795d594fSAndroid Build Coastguard Worker break;
780*795d594fSAndroid Build Coastguard Worker }
781*795d594fSAndroid Build Coastguard Worker ++oat_method_index;
782*795d594fSAndroid Build Coastguard Worker }
783*795d594fSAndroid Build Coastguard Worker CHECK(found_virtual) << "Didn't find oat method index for virtual method: "
784*795d594fSAndroid Build Coastguard Worker << dex_file->PrettyMethod(m->GetDexMethodIndex());
785*795d594fSAndroid Build Coastguard Worker }
786*795d594fSAndroid Build Coastguard Worker return oat_class.GetOatMethod(oat_method_index).GetQuickCode();
787*795d594fSAndroid Build Coastguard Worker }
788*795d594fSAndroid Build Coastguard Worker }
789*795d594fSAndroid Build Coastguard Worker }
790*795d594fSAndroid Build Coastguard Worker return nullptr;
791*795d594fSAndroid Build Coastguard Worker }
792*795d594fSAndroid Build Coastguard Worker
793*795d594fSAndroid Build Coastguard Worker // Returns nullptr and updates error_msg if the Vdex file cannot be opened, otherwise all Dex
794*795d594fSAndroid Build Coastguard Worker // files are stored in dex_files.
OpenVdex(const std::string & vdex_filename,DexFileUniqV * dex_files,std::string * error_msg)795*795d594fSAndroid Build Coastguard Worker std::unique_ptr<const VdexFile> OpenVdex(const std::string& vdex_filename,
796*795d594fSAndroid Build Coastguard Worker /* out */ DexFileUniqV* dex_files,
797*795d594fSAndroid Build Coastguard Worker /* out */ std::string* error_msg) {
798*795d594fSAndroid Build Coastguard Worker std::unique_ptr<const File> file(OS::OpenFileForReading(vdex_filename.c_str()));
799*795d594fSAndroid Build Coastguard Worker if (file == nullptr) {
800*795d594fSAndroid Build Coastguard Worker *error_msg = "Could not open file " + vdex_filename + " for reading.";
801*795d594fSAndroid Build Coastguard Worker return nullptr;
802*795d594fSAndroid Build Coastguard Worker }
803*795d594fSAndroid Build Coastguard Worker
804*795d594fSAndroid Build Coastguard Worker int64_t vdex_length = file->GetLength();
805*795d594fSAndroid Build Coastguard Worker if (vdex_length == -1) {
806*795d594fSAndroid Build Coastguard Worker *error_msg = "Could not read the length of file " + vdex_filename;
807*795d594fSAndroid Build Coastguard Worker return nullptr;
808*795d594fSAndroid Build Coastguard Worker }
809*795d594fSAndroid Build Coastguard Worker
810*795d594fSAndroid Build Coastguard Worker MemMap mmap = MemMap::MapFile(
811*795d594fSAndroid Build Coastguard Worker file->GetLength(),
812*795d594fSAndroid Build Coastguard Worker PROT_READ | PROT_WRITE,
813*795d594fSAndroid Build Coastguard Worker MAP_PRIVATE,
814*795d594fSAndroid Build Coastguard Worker file->Fd(),
815*795d594fSAndroid Build Coastguard Worker /* start offset= */ 0,
816*795d594fSAndroid Build Coastguard Worker /* low_4gb= */ false,
817*795d594fSAndroid Build Coastguard Worker vdex_filename.c_str(),
818*795d594fSAndroid Build Coastguard Worker error_msg);
819*795d594fSAndroid Build Coastguard Worker if (!mmap.IsValid()) {
820*795d594fSAndroid Build Coastguard Worker *error_msg = "Failed to mmap file " + vdex_filename + ": " + *error_msg;
821*795d594fSAndroid Build Coastguard Worker return nullptr;
822*795d594fSAndroid Build Coastguard Worker }
823*795d594fSAndroid Build Coastguard Worker
824*795d594fSAndroid Build Coastguard Worker std::unique_ptr<VdexFile> vdex_file(new VdexFile(std::move(mmap)));
825*795d594fSAndroid Build Coastguard Worker if (!vdex_file->IsValid()) {
826*795d594fSAndroid Build Coastguard Worker *error_msg = "Vdex file is not valid";
827*795d594fSAndroid Build Coastguard Worker return nullptr;
828*795d594fSAndroid Build Coastguard Worker }
829*795d594fSAndroid Build Coastguard Worker
830*795d594fSAndroid Build Coastguard Worker DexFileUniqV tmp_dex_files;
831*795d594fSAndroid Build Coastguard Worker if (!vdex_file->OpenAllDexFiles(&tmp_dex_files, error_msg)) {
832*795d594fSAndroid Build Coastguard Worker *error_msg = "Failed to open Dex files from Vdex: " + *error_msg;
833*795d594fSAndroid Build Coastguard Worker return nullptr;
834*795d594fSAndroid Build Coastguard Worker }
835*795d594fSAndroid Build Coastguard Worker
836*795d594fSAndroid Build Coastguard Worker *dex_files = std::move(tmp_dex_files);
837*795d594fSAndroid Build Coastguard Worker return vdex_file;
838*795d594fSAndroid Build Coastguard Worker }
839*795d594fSAndroid Build Coastguard Worker
AddStatsObject(const void * address)840*795d594fSAndroid Build Coastguard Worker bool AddStatsObject(const void* address) {
841*795d594fSAndroid Build Coastguard Worker return seen_stats_objects_.insert(address).second; // Inserted new entry.
842*795d594fSAndroid Build Coastguard Worker }
843*795d594fSAndroid Build Coastguard Worker
844*795d594fSAndroid Build Coastguard Worker private:
AddAllOffsets()845*795d594fSAndroid Build Coastguard Worker void AddAllOffsets() {
846*795d594fSAndroid Build Coastguard Worker // We don't know the length of the code for each method, but we need to know where to stop
847*795d594fSAndroid Build Coastguard Worker // when disassembling. What we do know is that a region of code will be followed by some other
848*795d594fSAndroid Build Coastguard Worker // region, so if we keep a sorted sequence of the start of each region, we can infer the length
849*795d594fSAndroid Build Coastguard Worker // of a piece of code by using upper_bound to find the start of the next region.
850*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < oat_dex_files_.size(); i++) {
851*795d594fSAndroid Build Coastguard Worker const OatDexFile* oat_dex_file = oat_dex_files_[i];
852*795d594fSAndroid Build Coastguard Worker CHECK(oat_dex_file != nullptr);
853*795d594fSAndroid Build Coastguard Worker std::string error_msg;
854*795d594fSAndroid Build Coastguard Worker const DexFile* const dex_file = OpenDexFile(oat_dex_file, &error_msg);
855*795d594fSAndroid Build Coastguard Worker if (dex_file == nullptr) {
856*795d594fSAndroid Build Coastguard Worker LOG(WARNING) << "Failed to open dex file '" << oat_dex_file->GetDexFileLocation()
857*795d594fSAndroid Build Coastguard Worker << "': " << error_msg;
858*795d594fSAndroid Build Coastguard Worker continue;
859*795d594fSAndroid Build Coastguard Worker }
860*795d594fSAndroid Build Coastguard Worker offsets_.insert(reinterpret_cast<uintptr_t>(&dex_file->GetHeader()));
861*795d594fSAndroid Build Coastguard Worker for (ClassAccessor accessor : dex_file->GetClasses()) {
862*795d594fSAndroid Build Coastguard Worker const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(accessor.GetClassDefIndex());
863*795d594fSAndroid Build Coastguard Worker for (uint32_t class_method_index = 0;
864*795d594fSAndroid Build Coastguard Worker class_method_index < accessor.NumMethods();
865*795d594fSAndroid Build Coastguard Worker ++class_method_index) {
866*795d594fSAndroid Build Coastguard Worker AddOffsets(oat_class.GetOatMethod(class_method_index));
867*795d594fSAndroid Build Coastguard Worker }
868*795d594fSAndroid Build Coastguard Worker }
869*795d594fSAndroid Build Coastguard Worker }
870*795d594fSAndroid Build Coastguard Worker
871*795d594fSAndroid Build Coastguard Worker // If the last thing in the file is code for a method, there won't be an offset for the "next"
872*795d594fSAndroid Build Coastguard Worker // thing. Instead of having a special case in the upper_bound code, let's just add an entry
873*795d594fSAndroid Build Coastguard Worker // for the end of the file.
874*795d594fSAndroid Build Coastguard Worker offsets_.insert(oat_file_.Size());
875*795d594fSAndroid Build Coastguard Worker }
876*795d594fSAndroid Build Coastguard Worker
AlignCodeOffset(uint32_t maybe_thumb_offset)877*795d594fSAndroid Build Coastguard Worker static uint32_t AlignCodeOffset(uint32_t maybe_thumb_offset) {
878*795d594fSAndroid Build Coastguard Worker return maybe_thumb_offset & ~0x1; // TODO: Make this Thumb2 specific.
879*795d594fSAndroid Build Coastguard Worker }
880*795d594fSAndroid Build Coastguard Worker
AddOffsets(const OatFile::OatMethod & oat_method)881*795d594fSAndroid Build Coastguard Worker void AddOffsets(const OatFile::OatMethod& oat_method) {
882*795d594fSAndroid Build Coastguard Worker uint32_t code_offset = oat_method.GetCodeOffset();
883*795d594fSAndroid Build Coastguard Worker if (oat_file_.GetOatHeader().GetInstructionSet() == InstructionSet::kThumb2) {
884*795d594fSAndroid Build Coastguard Worker code_offset &= ~0x1;
885*795d594fSAndroid Build Coastguard Worker }
886*795d594fSAndroid Build Coastguard Worker offsets_.insert(code_offset);
887*795d594fSAndroid Build Coastguard Worker offsets_.insert(oat_method.GetVmapTableOffset());
888*795d594fSAndroid Build Coastguard Worker }
889*795d594fSAndroid Build Coastguard Worker
DumpOatDexFile(std::ostream & os,const OatDexFile & oat_dex_file)890*795d594fSAndroid Build Coastguard Worker bool DumpOatDexFile(std::ostream& os, const OatDexFile& oat_dex_file) {
891*795d594fSAndroid Build Coastguard Worker bool success = true;
892*795d594fSAndroid Build Coastguard Worker bool stop_analysis = false;
893*795d594fSAndroid Build Coastguard Worker os << "OatDexFile:\n";
894*795d594fSAndroid Build Coastguard Worker os << StringPrintf("location: %s\n", oat_dex_file.GetDexFileLocation().c_str());
895*795d594fSAndroid Build Coastguard Worker os << StringPrintf("checksum: 0x%08x\n", oat_dex_file.GetDexFileLocationChecksum());
896*795d594fSAndroid Build Coastguard Worker
897*795d594fSAndroid Build Coastguard Worker if (oat_dex_file.GetOatFile()->ContainsDexCode()) {
898*795d594fSAndroid Build Coastguard Worker const uint8_t* const vdex_file_begin = oat_dex_file.GetOatFile()->DexBegin();
899*795d594fSAndroid Build Coastguard Worker
900*795d594fSAndroid Build Coastguard Worker // Print data range of the dex file embedded inside the corresponding vdex file.
901*795d594fSAndroid Build Coastguard Worker const uint8_t* const dex_file_pointer = oat_dex_file.GetDexFilePointer();
902*795d594fSAndroid Build Coastguard Worker uint32_t dex_offset = dchecked_integral_cast<uint32_t>(dex_file_pointer - vdex_file_begin);
903*795d594fSAndroid Build Coastguard Worker os << StringPrintf(
904*795d594fSAndroid Build Coastguard Worker "dex-file: 0x%08x..0x%08x\n",
905*795d594fSAndroid Build Coastguard Worker dex_offset,
906*795d594fSAndroid Build Coastguard Worker dchecked_integral_cast<uint32_t>(dex_offset + oat_dex_file.FileSize() - 1));
907*795d594fSAndroid Build Coastguard Worker } else {
908*795d594fSAndroid Build Coastguard Worker os << StringPrintf("dex-file not in VDEX file\n");
909*795d594fSAndroid Build Coastguard Worker }
910*795d594fSAndroid Build Coastguard Worker
911*795d594fSAndroid Build Coastguard Worker // Create the dex file early. A lot of print-out things depend on it.
912*795d594fSAndroid Build Coastguard Worker std::string error_msg;
913*795d594fSAndroid Build Coastguard Worker const DexFile* const dex_file = OpenDexFile(&oat_dex_file, &error_msg);
914*795d594fSAndroid Build Coastguard Worker if (dex_file == nullptr) {
915*795d594fSAndroid Build Coastguard Worker os << "NOT FOUND: " << error_msg << "\n\n";
916*795d594fSAndroid Build Coastguard Worker os << std::flush;
917*795d594fSAndroid Build Coastguard Worker return false;
918*795d594fSAndroid Build Coastguard Worker }
919*795d594fSAndroid Build Coastguard Worker
920*795d594fSAndroid Build Coastguard Worker // Print lookup table, if it exists.
921*795d594fSAndroid Build Coastguard Worker if (oat_dex_file.GetLookupTableData() != nullptr) {
922*795d594fSAndroid Build Coastguard Worker uint32_t table_offset = dchecked_integral_cast<uint32_t>(
923*795d594fSAndroid Build Coastguard Worker oat_dex_file.GetLookupTableData() - oat_dex_file.GetOatFile()->DexBegin());
924*795d594fSAndroid Build Coastguard Worker uint32_t table_size = TypeLookupTable::RawDataLength(dex_file->NumClassDefs());
925*795d594fSAndroid Build Coastguard Worker os << StringPrintf("type-table: 0x%08x..0x%08x\n",
926*795d594fSAndroid Build Coastguard Worker table_offset,
927*795d594fSAndroid Build Coastguard Worker table_offset + table_size - 1);
928*795d594fSAndroid Build Coastguard Worker const TypeLookupTable& lookup = oat_dex_file.GetTypeLookupTable();
929*795d594fSAndroid Build Coastguard Worker lookup.Dump(os);
930*795d594fSAndroid Build Coastguard Worker }
931*795d594fSAndroid Build Coastguard Worker
932*795d594fSAndroid Build Coastguard Worker VariableIndentationOutputStream vios(&os);
933*795d594fSAndroid Build Coastguard Worker ScopedIndentation indent1(&vios);
934*795d594fSAndroid Build Coastguard Worker for (ClassAccessor accessor : dex_file->GetClasses()) {
935*795d594fSAndroid Build Coastguard Worker // TODO: Support regex
936*795d594fSAndroid Build Coastguard Worker const char* descriptor = accessor.GetDescriptor();
937*795d594fSAndroid Build Coastguard Worker if (DescriptorToDot(descriptor).find(options_.class_filter_) == std::string::npos) {
938*795d594fSAndroid Build Coastguard Worker continue;
939*795d594fSAndroid Build Coastguard Worker }
940*795d594fSAndroid Build Coastguard Worker
941*795d594fSAndroid Build Coastguard Worker const uint16_t class_def_index = accessor.GetClassDefIndex();
942*795d594fSAndroid Build Coastguard Worker uint32_t oat_class_offset = oat_dex_file.GetOatClassOffset(class_def_index);
943*795d594fSAndroid Build Coastguard Worker const OatFile::OatClass oat_class = oat_dex_file.GetOatClass(class_def_index);
944*795d594fSAndroid Build Coastguard Worker os << StringPrintf("%zd: %s (offset=0x%08zx) (type_idx=%d)",
945*795d594fSAndroid Build Coastguard Worker static_cast<ssize_t>(class_def_index),
946*795d594fSAndroid Build Coastguard Worker descriptor,
947*795d594fSAndroid Build Coastguard Worker AdjustOffset(oat_class_offset),
948*795d594fSAndroid Build Coastguard Worker accessor.GetClassIdx().index_)
949*795d594fSAndroid Build Coastguard Worker << " (" << oat_class.GetStatus() << ")" << " (" << oat_class.GetType() << ")\n";
950*795d594fSAndroid Build Coastguard Worker // TODO: include bitmap here if type is kOatClassSomeCompiled?
951*795d594fSAndroid Build Coastguard Worker if (options_.list_classes_) {
952*795d594fSAndroid Build Coastguard Worker continue;
953*795d594fSAndroid Build Coastguard Worker }
954*795d594fSAndroid Build Coastguard Worker if (!DumpOatClass(&vios, oat_class, *dex_file, accessor, &stop_analysis)) {
955*795d594fSAndroid Build Coastguard Worker success = false;
956*795d594fSAndroid Build Coastguard Worker }
957*795d594fSAndroid Build Coastguard Worker if (stop_analysis) {
958*795d594fSAndroid Build Coastguard Worker os << std::flush;
959*795d594fSAndroid Build Coastguard Worker return success;
960*795d594fSAndroid Build Coastguard Worker }
961*795d594fSAndroid Build Coastguard Worker }
962*795d594fSAndroid Build Coastguard Worker os << "\n";
963*795d594fSAndroid Build Coastguard Worker os << std::flush;
964*795d594fSAndroid Build Coastguard Worker return success;
965*795d594fSAndroid Build Coastguard Worker }
966*795d594fSAndroid Build Coastguard Worker
967*795d594fSAndroid Build Coastguard Worker // Backwards compatible Dex file export. If dex_file is nullptr (valid Vdex file not present) the
968*795d594fSAndroid Build Coastguard Worker // Dex resource is extracted from the oat_dex_file and its checksum is repaired since it's not
969*795d594fSAndroid Build Coastguard Worker // unquickened. Otherwise the dex_file has been fully unquickened and is expected to verify the
970*795d594fSAndroid Build Coastguard Worker // original checksum.
ExportDexFile(std::ostream & os,const OatDexFile & oat_dex_file,const DexFile * dex_file,bool used_dexlayout)971*795d594fSAndroid Build Coastguard Worker bool ExportDexFile(std::ostream& os,
972*795d594fSAndroid Build Coastguard Worker const OatDexFile& oat_dex_file,
973*795d594fSAndroid Build Coastguard Worker const DexFile* dex_file,
974*795d594fSAndroid Build Coastguard Worker bool used_dexlayout) {
975*795d594fSAndroid Build Coastguard Worker std::string error_msg;
976*795d594fSAndroid Build Coastguard Worker std::string dex_file_location = oat_dex_file.GetDexFileLocation();
977*795d594fSAndroid Build Coastguard Worker
978*795d594fSAndroid Build Coastguard Worker // If dex_file (from unquicken or dexlayout) is not available, the output DexFile size is the
979*795d594fSAndroid Build Coastguard Worker // same as the one extracted from the Oat container (pre-oreo)
980*795d594fSAndroid Build Coastguard Worker size_t fsize = dex_file == nullptr ? oat_dex_file.FileSize() : dex_file->Size();
981*795d594fSAndroid Build Coastguard Worker
982*795d594fSAndroid Build Coastguard Worker // Some quick checks just in case
983*795d594fSAndroid Build Coastguard Worker if (fsize == 0 || fsize < sizeof(DexFile::Header)) {
984*795d594fSAndroid Build Coastguard Worker os << "Invalid dex file\n";
985*795d594fSAndroid Build Coastguard Worker return false;
986*795d594fSAndroid Build Coastguard Worker }
987*795d594fSAndroid Build Coastguard Worker
988*795d594fSAndroid Build Coastguard Worker if (dex_file == nullptr) {
989*795d594fSAndroid Build Coastguard Worker // Exported bytecode is quickened (dex-to-dex transformations present)
990*795d594fSAndroid Build Coastguard Worker dex_file = OpenDexFile(&oat_dex_file, &error_msg);
991*795d594fSAndroid Build Coastguard Worker if (dex_file == nullptr) {
992*795d594fSAndroid Build Coastguard Worker os << "Failed to open dex file '" << dex_file_location << "': " << error_msg;
993*795d594fSAndroid Build Coastguard Worker return false;
994*795d594fSAndroid Build Coastguard Worker }
995*795d594fSAndroid Build Coastguard Worker
996*795d594fSAndroid Build Coastguard Worker // Recompute checksum
997*795d594fSAndroid Build Coastguard Worker reinterpret_cast<DexFile::Header*>(const_cast<uint8_t*>(dex_file->Begin()))->checksum_ =
998*795d594fSAndroid Build Coastguard Worker dex_file->CalculateChecksum();
999*795d594fSAndroid Build Coastguard Worker } else {
1000*795d594fSAndroid Build Coastguard Worker // If dexlayout was used to convert CompactDex back to StandardDex, checksum will be updated
1001*795d594fSAndroid Build Coastguard Worker // due to `update_checksum_` option, otherwise we expect a reproducible checksum.
1002*795d594fSAndroid Build Coastguard Worker if (!used_dexlayout) {
1003*795d594fSAndroid Build Coastguard Worker // Vdex unquicken output should match original input bytecode
1004*795d594fSAndroid Build Coastguard Worker uint32_t orig_checksum =
1005*795d594fSAndroid Build Coastguard Worker reinterpret_cast<DexFile::Header*>(const_cast<uint8_t*>(dex_file->Begin()))->checksum_;
1006*795d594fSAndroid Build Coastguard Worker if (orig_checksum != dex_file->CalculateChecksum()) {
1007*795d594fSAndroid Build Coastguard Worker os << "Unexpected checksum from unquicken dex file '" << dex_file_location << "'\n";
1008*795d594fSAndroid Build Coastguard Worker return false;
1009*795d594fSAndroid Build Coastguard Worker }
1010*795d594fSAndroid Build Coastguard Worker }
1011*795d594fSAndroid Build Coastguard Worker // Extend the data range to export all the dex files in the container.
1012*795d594fSAndroid Build Coastguard Worker CHECK(dex_file->IsDexContainerFirstEntry()) << dex_file_location;
1013*795d594fSAndroid Build Coastguard Worker fsize = dex_file->GetHeader().ContainerSize();
1014*795d594fSAndroid Build Coastguard Worker }
1015*795d594fSAndroid Build Coastguard Worker
1016*795d594fSAndroid Build Coastguard Worker // Verify output directory exists
1017*795d594fSAndroid Build Coastguard Worker if (!OS::DirectoryExists(options_.export_dex_location_)) {
1018*795d594fSAndroid Build Coastguard Worker // TODO: Extend OS::DirectoryExists if symlink support is required
1019*795d594fSAndroid Build Coastguard Worker os << options_.export_dex_location_ << " output directory not found or symlink\n";
1020*795d594fSAndroid Build Coastguard Worker return false;
1021*795d594fSAndroid Build Coastguard Worker }
1022*795d594fSAndroid Build Coastguard Worker
1023*795d594fSAndroid Build Coastguard Worker // Beautify path names
1024*795d594fSAndroid Build Coastguard Worker if (dex_file_location.size() > PATH_MAX || dex_file_location.size() <= 0) {
1025*795d594fSAndroid Build Coastguard Worker return false;
1026*795d594fSAndroid Build Coastguard Worker }
1027*795d594fSAndroid Build Coastguard Worker
1028*795d594fSAndroid Build Coastguard Worker std::string dex_orig_name;
1029*795d594fSAndroid Build Coastguard Worker size_t dex_orig_pos = dex_file_location.rfind('/');
1030*795d594fSAndroid Build Coastguard Worker if (dex_orig_pos == std::string::npos)
1031*795d594fSAndroid Build Coastguard Worker dex_orig_name = dex_file_location;
1032*795d594fSAndroid Build Coastguard Worker else
1033*795d594fSAndroid Build Coastguard Worker dex_orig_name = dex_file_location.substr(dex_orig_pos + 1);
1034*795d594fSAndroid Build Coastguard Worker
1035*795d594fSAndroid Build Coastguard Worker // A more elegant approach to efficiently name user installed apps is welcome
1036*795d594fSAndroid Build Coastguard Worker if (dex_orig_name.size() == 8 &&
1037*795d594fSAndroid Build Coastguard Worker dex_orig_name.compare("base.apk") == 0 &&
1038*795d594fSAndroid Build Coastguard Worker dex_orig_pos != std::string::npos) {
1039*795d594fSAndroid Build Coastguard Worker dex_file_location.erase(dex_orig_pos, strlen("base.apk") + 1);
1040*795d594fSAndroid Build Coastguard Worker size_t apk_orig_pos = dex_file_location.rfind('/');
1041*795d594fSAndroid Build Coastguard Worker if (apk_orig_pos != std::string::npos) {
1042*795d594fSAndroid Build Coastguard Worker dex_orig_name = dex_file_location.substr(++apk_orig_pos);
1043*795d594fSAndroid Build Coastguard Worker }
1044*795d594fSAndroid Build Coastguard Worker }
1045*795d594fSAndroid Build Coastguard Worker
1046*795d594fSAndroid Build Coastguard Worker std::string out_dex_path(options_.export_dex_location_);
1047*795d594fSAndroid Build Coastguard Worker if (out_dex_path.back() != '/') {
1048*795d594fSAndroid Build Coastguard Worker out_dex_path.append("/");
1049*795d594fSAndroid Build Coastguard Worker }
1050*795d594fSAndroid Build Coastguard Worker out_dex_path.append(dex_orig_name);
1051*795d594fSAndroid Build Coastguard Worker out_dex_path.append("_export.dex");
1052*795d594fSAndroid Build Coastguard Worker if (out_dex_path.length() > PATH_MAX) {
1053*795d594fSAndroid Build Coastguard Worker return false;
1054*795d594fSAndroid Build Coastguard Worker }
1055*795d594fSAndroid Build Coastguard Worker
1056*795d594fSAndroid Build Coastguard Worker std::unique_ptr<File> file(OS::CreateEmptyFile(out_dex_path.c_str()));
1057*795d594fSAndroid Build Coastguard Worker if (file.get() == nullptr) {
1058*795d594fSAndroid Build Coastguard Worker os << "Failed to open output dex file " << out_dex_path;
1059*795d594fSAndroid Build Coastguard Worker return false;
1060*795d594fSAndroid Build Coastguard Worker }
1061*795d594fSAndroid Build Coastguard Worker
1062*795d594fSAndroid Build Coastguard Worker bool success = file->WriteFully(dex_file->Begin(), fsize);
1063*795d594fSAndroid Build Coastguard Worker if (!success) {
1064*795d594fSAndroid Build Coastguard Worker os << "Failed to write dex file";
1065*795d594fSAndroid Build Coastguard Worker file->Erase();
1066*795d594fSAndroid Build Coastguard Worker return false;
1067*795d594fSAndroid Build Coastguard Worker }
1068*795d594fSAndroid Build Coastguard Worker
1069*795d594fSAndroid Build Coastguard Worker if (file->FlushCloseOrErase() != 0) {
1070*795d594fSAndroid Build Coastguard Worker os << "Flush and close failed";
1071*795d594fSAndroid Build Coastguard Worker return false;
1072*795d594fSAndroid Build Coastguard Worker }
1073*795d594fSAndroid Build Coastguard Worker
1074*795d594fSAndroid Build Coastguard Worker os << StringPrintf("Dex file exported at %s (%zd bytes)\n", out_dex_path.c_str(), fsize);
1075*795d594fSAndroid Build Coastguard Worker os << std::flush;
1076*795d594fSAndroid Build Coastguard Worker
1077*795d594fSAndroid Build Coastguard Worker return true;
1078*795d594fSAndroid Build Coastguard Worker }
1079*795d594fSAndroid Build Coastguard Worker
DumpOatClass(VariableIndentationOutputStream * vios,const OatFile::OatClass & oat_class,const DexFile & dex_file,const ClassAccessor & class_accessor,bool * stop_analysis)1080*795d594fSAndroid Build Coastguard Worker bool DumpOatClass(VariableIndentationOutputStream* vios,
1081*795d594fSAndroid Build Coastguard Worker const OatFile::OatClass& oat_class,
1082*795d594fSAndroid Build Coastguard Worker const DexFile& dex_file,
1083*795d594fSAndroid Build Coastguard Worker const ClassAccessor& class_accessor,
1084*795d594fSAndroid Build Coastguard Worker bool* stop_analysis) {
1085*795d594fSAndroid Build Coastguard Worker bool success = true;
1086*795d594fSAndroid Build Coastguard Worker bool addr_found = false;
1087*795d594fSAndroid Build Coastguard Worker uint32_t class_method_index = 0;
1088*795d594fSAndroid Build Coastguard Worker for (const ClassAccessor::Method& method : class_accessor.GetMethods()) {
1089*795d594fSAndroid Build Coastguard Worker if (!DumpOatMethod(vios,
1090*795d594fSAndroid Build Coastguard Worker dex_file.GetClassDef(class_accessor.GetClassDefIndex()),
1091*795d594fSAndroid Build Coastguard Worker class_method_index,
1092*795d594fSAndroid Build Coastguard Worker oat_class,
1093*795d594fSAndroid Build Coastguard Worker dex_file,
1094*795d594fSAndroid Build Coastguard Worker method.GetIndex(),
1095*795d594fSAndroid Build Coastguard Worker method.GetCodeItem(),
1096*795d594fSAndroid Build Coastguard Worker method.GetAccessFlags(),
1097*795d594fSAndroid Build Coastguard Worker &addr_found)) {
1098*795d594fSAndroid Build Coastguard Worker success = false;
1099*795d594fSAndroid Build Coastguard Worker }
1100*795d594fSAndroid Build Coastguard Worker if (addr_found) {
1101*795d594fSAndroid Build Coastguard Worker *stop_analysis = true;
1102*795d594fSAndroid Build Coastguard Worker return success;
1103*795d594fSAndroid Build Coastguard Worker }
1104*795d594fSAndroid Build Coastguard Worker class_method_index++;
1105*795d594fSAndroid Build Coastguard Worker }
1106*795d594fSAndroid Build Coastguard Worker vios->Stream() << std::flush;
1107*795d594fSAndroid Build Coastguard Worker return success;
1108*795d594fSAndroid Build Coastguard Worker }
1109*795d594fSAndroid Build Coastguard Worker
1110*795d594fSAndroid Build Coastguard Worker static constexpr uint32_t kPrologueBytes = 16;
1111*795d594fSAndroid Build Coastguard Worker
1112*795d594fSAndroid Build Coastguard Worker // When this was picked, the largest arm method was 55,256 bytes and arm64 was 50,412 bytes.
1113*795d594fSAndroid Build Coastguard Worker static constexpr uint32_t kMaxCodeSize = 100 * 1000;
1114*795d594fSAndroid Build Coastguard Worker
DumpOatMethod(VariableIndentationOutputStream * vios,const dex::ClassDef & class_def,uint32_t class_method_index,const OatFile::OatClass & oat_class,const DexFile & dex_file,uint32_t dex_method_idx,const dex::CodeItem * code_item,uint32_t method_access_flags,bool * addr_found)1115*795d594fSAndroid Build Coastguard Worker bool DumpOatMethod(VariableIndentationOutputStream* vios,
1116*795d594fSAndroid Build Coastguard Worker const dex::ClassDef& class_def,
1117*795d594fSAndroid Build Coastguard Worker uint32_t class_method_index,
1118*795d594fSAndroid Build Coastguard Worker const OatFile::OatClass& oat_class,
1119*795d594fSAndroid Build Coastguard Worker const DexFile& dex_file,
1120*795d594fSAndroid Build Coastguard Worker uint32_t dex_method_idx,
1121*795d594fSAndroid Build Coastguard Worker const dex::CodeItem* code_item,
1122*795d594fSAndroid Build Coastguard Worker uint32_t method_access_flags,
1123*795d594fSAndroid Build Coastguard Worker bool* addr_found) {
1124*795d594fSAndroid Build Coastguard Worker bool success = true;
1125*795d594fSAndroid Build Coastguard Worker
1126*795d594fSAndroid Build Coastguard Worker CodeItemDataAccessor code_item_accessor(dex_file, code_item);
1127*795d594fSAndroid Build Coastguard Worker
1128*795d594fSAndroid Build Coastguard Worker // TODO: Support regex
1129*795d594fSAndroid Build Coastguard Worker std::string method_name = dex_file.GetMethodName(dex_file.GetMethodId(dex_method_idx));
1130*795d594fSAndroid Build Coastguard Worker if (method_name.find(options_.method_filter_) == std::string::npos) {
1131*795d594fSAndroid Build Coastguard Worker return success;
1132*795d594fSAndroid Build Coastguard Worker }
1133*795d594fSAndroid Build Coastguard Worker
1134*795d594fSAndroid Build Coastguard Worker std::string pretty_method = dex_file.PrettyMethod(dex_method_idx, true);
1135*795d594fSAndroid Build Coastguard Worker vios->Stream() << StringPrintf("%d: %s (dex_method_idx=%d)\n",
1136*795d594fSAndroid Build Coastguard Worker class_method_index, pretty_method.c_str(),
1137*795d594fSAndroid Build Coastguard Worker dex_method_idx);
1138*795d594fSAndroid Build Coastguard Worker if (options_.list_methods_) {
1139*795d594fSAndroid Build Coastguard Worker return success;
1140*795d594fSAndroid Build Coastguard Worker }
1141*795d594fSAndroid Build Coastguard Worker
1142*795d594fSAndroid Build Coastguard Worker uint32_t oat_method_offsets_offset = oat_class.GetOatMethodOffsetsOffset(class_method_index);
1143*795d594fSAndroid Build Coastguard Worker const OatMethodOffsets* oat_method_offsets = oat_class.GetOatMethodOffsets(class_method_index);
1144*795d594fSAndroid Build Coastguard Worker const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_index);
1145*795d594fSAndroid Build Coastguard Worker uint32_t code_offset = oat_method.GetCodeOffset();
1146*795d594fSAndroid Build Coastguard Worker uint32_t code_size = oat_method.GetQuickCodeSize();
1147*795d594fSAndroid Build Coastguard Worker if (resolved_addr2instr_ != 0) {
1148*795d594fSAndroid Build Coastguard Worker if (resolved_addr2instr_ > code_offset + code_size) {
1149*795d594fSAndroid Build Coastguard Worker return success;
1150*795d594fSAndroid Build Coastguard Worker } else {
1151*795d594fSAndroid Build Coastguard Worker *addr_found = true; // stop analyzing file at next iteration
1152*795d594fSAndroid Build Coastguard Worker }
1153*795d594fSAndroid Build Coastguard Worker }
1154*795d594fSAndroid Build Coastguard Worker
1155*795d594fSAndroid Build Coastguard Worker // Everything below is indented at least once.
1156*795d594fSAndroid Build Coastguard Worker ScopedIndentation indent1(vios);
1157*795d594fSAndroid Build Coastguard Worker
1158*795d594fSAndroid Build Coastguard Worker {
1159*795d594fSAndroid Build Coastguard Worker vios->Stream() << "DEX CODE:\n";
1160*795d594fSAndroid Build Coastguard Worker ScopedIndentation indent2(vios);
1161*795d594fSAndroid Build Coastguard Worker if (code_item_accessor.HasCodeItem()) {
1162*795d594fSAndroid Build Coastguard Worker uint32_t max_pc = code_item_accessor.InsnsSizeInCodeUnits();
1163*795d594fSAndroid Build Coastguard Worker for (const DexInstructionPcPair& inst : code_item_accessor) {
1164*795d594fSAndroid Build Coastguard Worker if (inst.DexPc() + inst->SizeInCodeUnits() > max_pc) {
1165*795d594fSAndroid Build Coastguard Worker LOG(WARNING) << "GLITCH: run-away instruction at idx=0x" << std::hex << inst.DexPc();
1166*795d594fSAndroid Build Coastguard Worker break;
1167*795d594fSAndroid Build Coastguard Worker }
1168*795d594fSAndroid Build Coastguard Worker vios->Stream() << StringPrintf("0x%04x: ", inst.DexPc()) << inst->DumpHexLE(5)
1169*795d594fSAndroid Build Coastguard Worker << StringPrintf("\t| %s\n", inst->DumpString(&dex_file).c_str());
1170*795d594fSAndroid Build Coastguard Worker }
1171*795d594fSAndroid Build Coastguard Worker }
1172*795d594fSAndroid Build Coastguard Worker }
1173*795d594fSAndroid Build Coastguard Worker
1174*795d594fSAndroid Build Coastguard Worker std::unique_ptr<StackHandleScope<1>> hs;
1175*795d594fSAndroid Build Coastguard Worker std::unique_ptr<verifier::MethodVerifier> verifier;
1176*795d594fSAndroid Build Coastguard Worker if (Runtime::Current() != nullptr) {
1177*795d594fSAndroid Build Coastguard Worker // We need to have the handle scope stay live until after the verifier since the verifier has
1178*795d594fSAndroid Build Coastguard Worker // a handle to the dex cache from hs.
1179*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(Thread::Current());
1180*795d594fSAndroid Build Coastguard Worker hs.reset(new StackHandleScope<1>(Thread::Current()));
1181*795d594fSAndroid Build Coastguard Worker vios->Stream() << "VERIFIER TYPE ANALYSIS:\n";
1182*795d594fSAndroid Build Coastguard Worker ScopedIndentation indent2(vios);
1183*795d594fSAndroid Build Coastguard Worker DumpVerifier(vios,
1184*795d594fSAndroid Build Coastguard Worker soa,
1185*795d594fSAndroid Build Coastguard Worker hs.get(),
1186*795d594fSAndroid Build Coastguard Worker dex_method_idx,
1187*795d594fSAndroid Build Coastguard Worker &dex_file,
1188*795d594fSAndroid Build Coastguard Worker class_def,
1189*795d594fSAndroid Build Coastguard Worker code_item,
1190*795d594fSAndroid Build Coastguard Worker method_access_flags);
1191*795d594fSAndroid Build Coastguard Worker }
1192*795d594fSAndroid Build Coastguard Worker {
1193*795d594fSAndroid Build Coastguard Worker vios->Stream() << "OatMethodOffsets ";
1194*795d594fSAndroid Build Coastguard Worker if (options_.absolute_addresses_) {
1195*795d594fSAndroid Build Coastguard Worker vios->Stream() << StringPrintf("%p ", oat_method_offsets);
1196*795d594fSAndroid Build Coastguard Worker }
1197*795d594fSAndroid Build Coastguard Worker vios->Stream() << StringPrintf("(offset=0x%08zx)\n", AdjustOffset(oat_method_offsets_offset));
1198*795d594fSAndroid Build Coastguard Worker if (oat_method_offsets_offset > oat_file_.Size()) {
1199*795d594fSAndroid Build Coastguard Worker vios->Stream() << StringPrintf(
1200*795d594fSAndroid Build Coastguard Worker "WARNING: oat method offsets offset 0x%08zx is past end of file 0x%08zx.\n",
1201*795d594fSAndroid Build Coastguard Worker AdjustOffset(oat_method_offsets_offset),
1202*795d594fSAndroid Build Coastguard Worker AdjustOffset(oat_file_.Size()));
1203*795d594fSAndroid Build Coastguard Worker // If we can't read OatMethodOffsets, the rest of the data is dangerous to read.
1204*795d594fSAndroid Build Coastguard Worker vios->Stream() << std::flush;
1205*795d594fSAndroid Build Coastguard Worker return false;
1206*795d594fSAndroid Build Coastguard Worker }
1207*795d594fSAndroid Build Coastguard Worker
1208*795d594fSAndroid Build Coastguard Worker ScopedIndentation indent2(vios);
1209*795d594fSAndroid Build Coastguard Worker vios->Stream() << StringPrintf("code_offset: 0x%08zx ", AdjustOffset(code_offset));
1210*795d594fSAndroid Build Coastguard Worker uint32_t aligned_code_begin = AlignCodeOffset(oat_method.GetCodeOffset());
1211*795d594fSAndroid Build Coastguard Worker if (aligned_code_begin > oat_file_.Size()) {
1212*795d594fSAndroid Build Coastguard Worker vios->Stream() << StringPrintf(
1213*795d594fSAndroid Build Coastguard Worker "WARNING: code offset 0x%08zx is past end of file 0x%08zx.\n",
1214*795d594fSAndroid Build Coastguard Worker AdjustOffset(aligned_code_begin),
1215*795d594fSAndroid Build Coastguard Worker AdjustOffset(oat_file_.Size()));
1216*795d594fSAndroid Build Coastguard Worker success = false;
1217*795d594fSAndroid Build Coastguard Worker }
1218*795d594fSAndroid Build Coastguard Worker vios->Stream() << "\n";
1219*795d594fSAndroid Build Coastguard Worker }
1220*795d594fSAndroid Build Coastguard Worker {
1221*795d594fSAndroid Build Coastguard Worker vios->Stream() << "OatQuickMethodHeader ";
1222*795d594fSAndroid Build Coastguard Worker uint32_t method_header_offset = oat_method.GetOatQuickMethodHeaderOffset();
1223*795d594fSAndroid Build Coastguard Worker const OatQuickMethodHeader* method_header = oat_method.GetOatQuickMethodHeader();
1224*795d594fSAndroid Build Coastguard Worker if (method_header != nullptr && AddStatsObject(method_header)) {
1225*795d594fSAndroid Build Coastguard Worker stats_["QuickMethodHeader"].AddBytes(sizeof(*method_header));
1226*795d594fSAndroid Build Coastguard Worker }
1227*795d594fSAndroid Build Coastguard Worker if (options_.absolute_addresses_) {
1228*795d594fSAndroid Build Coastguard Worker vios->Stream() << StringPrintf("%p ", method_header);
1229*795d594fSAndroid Build Coastguard Worker }
1230*795d594fSAndroid Build Coastguard Worker vios->Stream() << StringPrintf("(offset=0x%08zx)\n", AdjustOffset(method_header_offset));
1231*795d594fSAndroid Build Coastguard Worker if (method_header_offset > oat_file_.Size() ||
1232*795d594fSAndroid Build Coastguard Worker sizeof(OatQuickMethodHeader) > oat_file_.Size() - method_header_offset) {
1233*795d594fSAndroid Build Coastguard Worker vios->Stream() << StringPrintf(
1234*795d594fSAndroid Build Coastguard Worker "WARNING: oat quick method header at offset 0x%08zx is past end of file 0x%08zx.\n",
1235*795d594fSAndroid Build Coastguard Worker AdjustOffset(method_header_offset),
1236*795d594fSAndroid Build Coastguard Worker AdjustOffset(oat_file_.Size()));
1237*795d594fSAndroid Build Coastguard Worker // If we can't read the OatQuickMethodHeader, the rest of the data is dangerous to read.
1238*795d594fSAndroid Build Coastguard Worker vios->Stream() << std::flush;
1239*795d594fSAndroid Build Coastguard Worker return false;
1240*795d594fSAndroid Build Coastguard Worker }
1241*795d594fSAndroid Build Coastguard Worker
1242*795d594fSAndroid Build Coastguard Worker ScopedIndentation indent2(vios);
1243*795d594fSAndroid Build Coastguard Worker vios->Stream() << "vmap_table: ";
1244*795d594fSAndroid Build Coastguard Worker if (options_.absolute_addresses_) {
1245*795d594fSAndroid Build Coastguard Worker vios->Stream() << StringPrintf("%p ", oat_method.GetVmapTable());
1246*795d594fSAndroid Build Coastguard Worker }
1247*795d594fSAndroid Build Coastguard Worker uint32_t vmap_table_offset =
1248*795d594fSAndroid Build Coastguard Worker (method_header == nullptr) ? 0 : method_header->GetCodeInfoOffset();
1249*795d594fSAndroid Build Coastguard Worker vios->Stream() << StringPrintf("(offset=0x%08zx)\n", AdjustOffset(vmap_table_offset));
1250*795d594fSAndroid Build Coastguard Worker
1251*795d594fSAndroid Build Coastguard Worker size_t vmap_table_offset_limit =
1252*795d594fSAndroid Build Coastguard Worker (method_header == nullptr) ? 0 : (method_header->GetCode() - oat_file_.Begin());
1253*795d594fSAndroid Build Coastguard Worker if (method_header != nullptr && vmap_table_offset >= vmap_table_offset_limit) {
1254*795d594fSAndroid Build Coastguard Worker vios->Stream() << StringPrintf(
1255*795d594fSAndroid Build Coastguard Worker "WARNING: vmap table offset 0x%08zx is past end of file 0x%08zx. ",
1256*795d594fSAndroid Build Coastguard Worker AdjustOffset(vmap_table_offset),
1257*795d594fSAndroid Build Coastguard Worker AdjustOffset(vmap_table_offset_limit));
1258*795d594fSAndroid Build Coastguard Worker success = false;
1259*795d594fSAndroid Build Coastguard Worker } else if (options_.dump_vmap_) {
1260*795d594fSAndroid Build Coastguard Worker DumpVmapData(vios, oat_method, code_item_accessor);
1261*795d594fSAndroid Build Coastguard Worker }
1262*795d594fSAndroid Build Coastguard Worker }
1263*795d594fSAndroid Build Coastguard Worker {
1264*795d594fSAndroid Build Coastguard Worker vios->Stream() << "QuickMethodFrameInfo\n";
1265*795d594fSAndroid Build Coastguard Worker
1266*795d594fSAndroid Build Coastguard Worker ScopedIndentation indent2(vios);
1267*795d594fSAndroid Build Coastguard Worker vios->Stream()
1268*795d594fSAndroid Build Coastguard Worker << StringPrintf("frame_size_in_bytes: %zd\n", oat_method.GetFrameSizeInBytes());
1269*795d594fSAndroid Build Coastguard Worker vios->Stream() << StringPrintf("core_spill_mask: 0x%08x ", oat_method.GetCoreSpillMask());
1270*795d594fSAndroid Build Coastguard Worker DumpSpillMask(vios->Stream(), oat_method.GetCoreSpillMask(), false);
1271*795d594fSAndroid Build Coastguard Worker vios->Stream() << "\n";
1272*795d594fSAndroid Build Coastguard Worker vios->Stream() << StringPrintf("fp_spill_mask: 0x%08x ", oat_method.GetFpSpillMask());
1273*795d594fSAndroid Build Coastguard Worker DumpSpillMask(vios->Stream(), oat_method.GetFpSpillMask(), true);
1274*795d594fSAndroid Build Coastguard Worker vios->Stream() << "\n";
1275*795d594fSAndroid Build Coastguard Worker }
1276*795d594fSAndroid Build Coastguard Worker {
1277*795d594fSAndroid Build Coastguard Worker // Based on spill masks from QuickMethodFrameInfo so placed
1278*795d594fSAndroid Build Coastguard Worker // after it is dumped, but useful for understanding quick
1279*795d594fSAndroid Build Coastguard Worker // code, so dumped here.
1280*795d594fSAndroid Build Coastguard Worker ScopedIndentation indent2(vios);
1281*795d594fSAndroid Build Coastguard Worker DumpVregLocations(vios->Stream(), oat_method, code_item_accessor);
1282*795d594fSAndroid Build Coastguard Worker }
1283*795d594fSAndroid Build Coastguard Worker {
1284*795d594fSAndroid Build Coastguard Worker vios->Stream() << "CODE: ";
1285*795d594fSAndroid Build Coastguard Worker {
1286*795d594fSAndroid Build Coastguard Worker const void* code = oat_method.GetQuickCode();
1287*795d594fSAndroid Build Coastguard Worker uint32_t aligned_code_begin = AlignCodeOffset(code_offset);
1288*795d594fSAndroid Build Coastguard Worker uint32_t aligned_code_end = aligned_code_begin + code_size;
1289*795d594fSAndroid Build Coastguard Worker if (AddStatsObject(code)) {
1290*795d594fSAndroid Build Coastguard Worker stats_["Code"].AddBytes(code_size);
1291*795d594fSAndroid Build Coastguard Worker }
1292*795d594fSAndroid Build Coastguard Worker
1293*795d594fSAndroid Build Coastguard Worker if (options_.absolute_addresses_) {
1294*795d594fSAndroid Build Coastguard Worker vios->Stream() << StringPrintf("%p ", code);
1295*795d594fSAndroid Build Coastguard Worker }
1296*795d594fSAndroid Build Coastguard Worker vios->Stream() << StringPrintf("(code_offset=0x%08zx size=%u)%s\n",
1297*795d594fSAndroid Build Coastguard Worker AdjustOffset(code_offset),
1298*795d594fSAndroid Build Coastguard Worker code_size,
1299*795d594fSAndroid Build Coastguard Worker code != nullptr ? "..." : "");
1300*795d594fSAndroid Build Coastguard Worker
1301*795d594fSAndroid Build Coastguard Worker ScopedIndentation indent2(vios);
1302*795d594fSAndroid Build Coastguard Worker if (aligned_code_begin > oat_file_.Size()) {
1303*795d594fSAndroid Build Coastguard Worker vios->Stream() << StringPrintf(
1304*795d594fSAndroid Build Coastguard Worker "WARNING: start of code at 0x%08zx is past end of file 0x%08zx.",
1305*795d594fSAndroid Build Coastguard Worker AdjustOffset(aligned_code_begin),
1306*795d594fSAndroid Build Coastguard Worker AdjustOffset(oat_file_.Size()));
1307*795d594fSAndroid Build Coastguard Worker success = false;
1308*795d594fSAndroid Build Coastguard Worker } else if (aligned_code_end > oat_file_.Size()) {
1309*795d594fSAndroid Build Coastguard Worker vios->Stream() << StringPrintf(
1310*795d594fSAndroid Build Coastguard Worker "WARNING: end of code at 0x%08zx is past end of file 0x%08zx. code size is 0x%08x.\n",
1311*795d594fSAndroid Build Coastguard Worker AdjustOffset(aligned_code_end),
1312*795d594fSAndroid Build Coastguard Worker AdjustOffset(oat_file_.Size()),
1313*795d594fSAndroid Build Coastguard Worker code_size);
1314*795d594fSAndroid Build Coastguard Worker success = false;
1315*795d594fSAndroid Build Coastguard Worker if (options_.disassemble_code_) {
1316*795d594fSAndroid Build Coastguard Worker if (aligned_code_begin + kPrologueBytes <= oat_file_.Size()) {
1317*795d594fSAndroid Build Coastguard Worker DumpCode(vios, oat_method, code_item_accessor, true, kPrologueBytes);
1318*795d594fSAndroid Build Coastguard Worker }
1319*795d594fSAndroid Build Coastguard Worker }
1320*795d594fSAndroid Build Coastguard Worker } else if (code_size > kMaxCodeSize) {
1321*795d594fSAndroid Build Coastguard Worker vios->Stream() << StringPrintf(
1322*795d594fSAndroid Build Coastguard Worker "WARNING: "
1323*795d594fSAndroid Build Coastguard Worker "code size %d is bigger than max expected threshold of %d. "
1324*795d594fSAndroid Build Coastguard Worker "code size is 0x%08x.\n",
1325*795d594fSAndroid Build Coastguard Worker code_size,
1326*795d594fSAndroid Build Coastguard Worker kMaxCodeSize,
1327*795d594fSAndroid Build Coastguard Worker code_size);
1328*795d594fSAndroid Build Coastguard Worker success = false;
1329*795d594fSAndroid Build Coastguard Worker if (options_.disassemble_code_) {
1330*795d594fSAndroid Build Coastguard Worker if (aligned_code_begin + kPrologueBytes <= oat_file_.Size()) {
1331*795d594fSAndroid Build Coastguard Worker DumpCode(vios, oat_method, code_item_accessor, true, kPrologueBytes);
1332*795d594fSAndroid Build Coastguard Worker }
1333*795d594fSAndroid Build Coastguard Worker }
1334*795d594fSAndroid Build Coastguard Worker } else if (options_.disassemble_code_) {
1335*795d594fSAndroid Build Coastguard Worker DumpCode(vios, oat_method, code_item_accessor, !success, 0);
1336*795d594fSAndroid Build Coastguard Worker }
1337*795d594fSAndroid Build Coastguard Worker }
1338*795d594fSAndroid Build Coastguard Worker }
1339*795d594fSAndroid Build Coastguard Worker vios->Stream() << std::flush;
1340*795d594fSAndroid Build Coastguard Worker return success;
1341*795d594fSAndroid Build Coastguard Worker }
1342*795d594fSAndroid Build Coastguard Worker
DumpSpillMask(std::ostream & os,uint32_t spill_mask,bool is_float)1343*795d594fSAndroid Build Coastguard Worker void DumpSpillMask(std::ostream& os, uint32_t spill_mask, bool is_float) {
1344*795d594fSAndroid Build Coastguard Worker if (spill_mask == 0) {
1345*795d594fSAndroid Build Coastguard Worker return;
1346*795d594fSAndroid Build Coastguard Worker }
1347*795d594fSAndroid Build Coastguard Worker os << "(";
1348*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < 32; i++) {
1349*795d594fSAndroid Build Coastguard Worker if ((spill_mask & (1 << i)) != 0) {
1350*795d594fSAndroid Build Coastguard Worker if (is_float) {
1351*795d594fSAndroid Build Coastguard Worker os << "fr" << i;
1352*795d594fSAndroid Build Coastguard Worker } else {
1353*795d594fSAndroid Build Coastguard Worker os << "r" << i;
1354*795d594fSAndroid Build Coastguard Worker }
1355*795d594fSAndroid Build Coastguard Worker spill_mask ^= 1 << i; // clear bit
1356*795d594fSAndroid Build Coastguard Worker if (spill_mask != 0) {
1357*795d594fSAndroid Build Coastguard Worker os << ", ";
1358*795d594fSAndroid Build Coastguard Worker } else {
1359*795d594fSAndroid Build Coastguard Worker break;
1360*795d594fSAndroid Build Coastguard Worker }
1361*795d594fSAndroid Build Coastguard Worker }
1362*795d594fSAndroid Build Coastguard Worker }
1363*795d594fSAndroid Build Coastguard Worker os << ")";
1364*795d594fSAndroid Build Coastguard Worker }
1365*795d594fSAndroid Build Coastguard Worker
1366*795d594fSAndroid Build Coastguard Worker // Display data stored at the the vmap offset of an oat method.
DumpVmapData(VariableIndentationOutputStream * vios,const OatFile::OatMethod & oat_method,const CodeItemDataAccessor & code_item_accessor)1367*795d594fSAndroid Build Coastguard Worker void DumpVmapData(VariableIndentationOutputStream* vios,
1368*795d594fSAndroid Build Coastguard Worker const OatFile::OatMethod& oat_method,
1369*795d594fSAndroid Build Coastguard Worker const CodeItemDataAccessor& code_item_accessor) {
1370*795d594fSAndroid Build Coastguard Worker if (IsMethodGeneratedByOptimizingCompiler(oat_method, code_item_accessor)) {
1371*795d594fSAndroid Build Coastguard Worker // The optimizing compiler outputs its CodeInfo data in the vmap table.
1372*795d594fSAndroid Build Coastguard Worker const uint8_t* raw_code_info = oat_method.GetVmapTable();
1373*795d594fSAndroid Build Coastguard Worker if (raw_code_info != nullptr) {
1374*795d594fSAndroid Build Coastguard Worker CodeInfo code_info(raw_code_info);
1375*795d594fSAndroid Build Coastguard Worker DCHECK(code_item_accessor.HasCodeItem());
1376*795d594fSAndroid Build Coastguard Worker ScopedIndentation indent1(vios);
1377*795d594fSAndroid Build Coastguard Worker DumpCodeInfo(vios, code_info, oat_method);
1378*795d594fSAndroid Build Coastguard Worker }
1379*795d594fSAndroid Build Coastguard Worker } else {
1380*795d594fSAndroid Build Coastguard Worker // Otherwise, there is nothing to display.
1381*795d594fSAndroid Build Coastguard Worker }
1382*795d594fSAndroid Build Coastguard Worker }
1383*795d594fSAndroid Build Coastguard Worker
1384*795d594fSAndroid Build Coastguard Worker // Display a CodeInfo object emitted by the optimizing compiler.
DumpCodeInfo(VariableIndentationOutputStream * vios,const CodeInfo & code_info,const OatFile::OatMethod & oat_method)1385*795d594fSAndroid Build Coastguard Worker void DumpCodeInfo(VariableIndentationOutputStream* vios,
1386*795d594fSAndroid Build Coastguard Worker const CodeInfo& code_info,
1387*795d594fSAndroid Build Coastguard Worker const OatFile::OatMethod& oat_method) {
1388*795d594fSAndroid Build Coastguard Worker code_info.Dump(vios,
1389*795d594fSAndroid Build Coastguard Worker oat_method.GetCodeOffset(),
1390*795d594fSAndroid Build Coastguard Worker options_.dump_code_info_stack_maps_,
1391*795d594fSAndroid Build Coastguard Worker instruction_set_);
1392*795d594fSAndroid Build Coastguard Worker }
1393*795d594fSAndroid Build Coastguard Worker
GetOutVROffset(uint16_t out_num,InstructionSet isa)1394*795d594fSAndroid Build Coastguard Worker static int GetOutVROffset(uint16_t out_num, InstructionSet isa) {
1395*795d594fSAndroid Build Coastguard Worker // According to stack model, the first out is above the Method referernce.
1396*795d594fSAndroid Build Coastguard Worker return static_cast<size_t>(InstructionSetPointerSize(isa)) + out_num * sizeof(uint32_t);
1397*795d594fSAndroid Build Coastguard Worker }
1398*795d594fSAndroid Build Coastguard Worker
GetVRegOffsetFromQuickCode(const CodeItemDataAccessor & code_item_accessor,uint32_t core_spills,uint32_t fp_spills,size_t frame_size,int reg,InstructionSet isa)1399*795d594fSAndroid Build Coastguard Worker static uint32_t GetVRegOffsetFromQuickCode(const CodeItemDataAccessor& code_item_accessor,
1400*795d594fSAndroid Build Coastguard Worker uint32_t core_spills,
1401*795d594fSAndroid Build Coastguard Worker uint32_t fp_spills,
1402*795d594fSAndroid Build Coastguard Worker size_t frame_size,
1403*795d594fSAndroid Build Coastguard Worker int reg,
1404*795d594fSAndroid Build Coastguard Worker InstructionSet isa) {
1405*795d594fSAndroid Build Coastguard Worker PointerSize pointer_size = InstructionSetPointerSize(isa);
1406*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
1407*795d594fSAndroid Build Coastguard Worker auto* runtime = Runtime::Current();
1408*795d594fSAndroid Build Coastguard Worker if (runtime != nullptr) {
1409*795d594fSAndroid Build Coastguard Worker CHECK_EQ(runtime->GetClassLinker()->GetImagePointerSize(), pointer_size);
1410*795d594fSAndroid Build Coastguard Worker }
1411*795d594fSAndroid Build Coastguard Worker }
1412*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED(frame_size, kStackAlignment);
1413*795d594fSAndroid Build Coastguard Worker DCHECK_NE(reg, -1);
1414*795d594fSAndroid Build Coastguard Worker int spill_size = POPCOUNT(core_spills) * GetBytesPerGprSpillLocation(isa)
1415*795d594fSAndroid Build Coastguard Worker + POPCOUNT(fp_spills) * GetBytesPerFprSpillLocation(isa)
1416*795d594fSAndroid Build Coastguard Worker + sizeof(uint32_t); // Filler.
1417*795d594fSAndroid Build Coastguard Worker int num_regs = code_item_accessor.RegistersSize() - code_item_accessor.InsSize();
1418*795d594fSAndroid Build Coastguard Worker int temp_threshold = code_item_accessor.RegistersSize();
1419*795d594fSAndroid Build Coastguard Worker const int max_num_special_temps = 1;
1420*795d594fSAndroid Build Coastguard Worker if (reg == temp_threshold) {
1421*795d594fSAndroid Build Coastguard Worker // The current method pointer corresponds to special location on stack.
1422*795d594fSAndroid Build Coastguard Worker return 0;
1423*795d594fSAndroid Build Coastguard Worker } else if (reg >= temp_threshold + max_num_special_temps) {
1424*795d594fSAndroid Build Coastguard Worker /*
1425*795d594fSAndroid Build Coastguard Worker * Special temporaries may have custom locations and the logic above deals with that.
1426*795d594fSAndroid Build Coastguard Worker * However, non-special temporaries are placed relative to the outs.
1427*795d594fSAndroid Build Coastguard Worker */
1428*795d594fSAndroid Build Coastguard Worker int temps_start = code_item_accessor.OutsSize() * sizeof(uint32_t)
1429*795d594fSAndroid Build Coastguard Worker + static_cast<size_t>(pointer_size) /* art method */;
1430*795d594fSAndroid Build Coastguard Worker int relative_offset = (reg - (temp_threshold + max_num_special_temps)) * sizeof(uint32_t);
1431*795d594fSAndroid Build Coastguard Worker return temps_start + relative_offset;
1432*795d594fSAndroid Build Coastguard Worker } else if (reg < num_regs) {
1433*795d594fSAndroid Build Coastguard Worker int locals_start = frame_size - spill_size - num_regs * sizeof(uint32_t);
1434*795d594fSAndroid Build Coastguard Worker return locals_start + (reg * sizeof(uint32_t));
1435*795d594fSAndroid Build Coastguard Worker } else {
1436*795d594fSAndroid Build Coastguard Worker // Handle ins.
1437*795d594fSAndroid Build Coastguard Worker return frame_size + ((reg - num_regs) * sizeof(uint32_t))
1438*795d594fSAndroid Build Coastguard Worker + static_cast<size_t>(pointer_size) /* art method */;
1439*795d594fSAndroid Build Coastguard Worker }
1440*795d594fSAndroid Build Coastguard Worker }
1441*795d594fSAndroid Build Coastguard Worker
DumpVregLocations(std::ostream & os,const OatFile::OatMethod & oat_method,const CodeItemDataAccessor & code_item_accessor)1442*795d594fSAndroid Build Coastguard Worker void DumpVregLocations(std::ostream& os, const OatFile::OatMethod& oat_method,
1443*795d594fSAndroid Build Coastguard Worker const CodeItemDataAccessor& code_item_accessor) {
1444*795d594fSAndroid Build Coastguard Worker if (code_item_accessor.HasCodeItem()) {
1445*795d594fSAndroid Build Coastguard Worker size_t num_locals_ins = code_item_accessor.RegistersSize();
1446*795d594fSAndroid Build Coastguard Worker size_t num_ins = code_item_accessor.InsSize();
1447*795d594fSAndroid Build Coastguard Worker size_t num_locals = num_locals_ins - num_ins;
1448*795d594fSAndroid Build Coastguard Worker size_t num_outs = code_item_accessor.OutsSize();
1449*795d594fSAndroid Build Coastguard Worker
1450*795d594fSAndroid Build Coastguard Worker os << "vr_stack_locations:";
1451*795d594fSAndroid Build Coastguard Worker for (size_t reg = 0; reg <= num_locals_ins; reg++) {
1452*795d594fSAndroid Build Coastguard Worker // For readability, delimit the different kinds of VRs.
1453*795d594fSAndroid Build Coastguard Worker if (reg == num_locals_ins) {
1454*795d594fSAndroid Build Coastguard Worker os << "\n\tmethod*:";
1455*795d594fSAndroid Build Coastguard Worker } else if (reg == num_locals && num_ins > 0) {
1456*795d594fSAndroid Build Coastguard Worker os << "\n\tins:";
1457*795d594fSAndroid Build Coastguard Worker } else if (reg == 0 && num_locals > 0) {
1458*795d594fSAndroid Build Coastguard Worker os << "\n\tlocals:";
1459*795d594fSAndroid Build Coastguard Worker }
1460*795d594fSAndroid Build Coastguard Worker
1461*795d594fSAndroid Build Coastguard Worker uint32_t offset = GetVRegOffsetFromQuickCode(code_item_accessor,
1462*795d594fSAndroid Build Coastguard Worker oat_method.GetCoreSpillMask(),
1463*795d594fSAndroid Build Coastguard Worker oat_method.GetFpSpillMask(),
1464*795d594fSAndroid Build Coastguard Worker oat_method.GetFrameSizeInBytes(),
1465*795d594fSAndroid Build Coastguard Worker reg,
1466*795d594fSAndroid Build Coastguard Worker GetInstructionSet());
1467*795d594fSAndroid Build Coastguard Worker os << " v" << reg << "[sp + #" << offset << "]";
1468*795d594fSAndroid Build Coastguard Worker }
1469*795d594fSAndroid Build Coastguard Worker
1470*795d594fSAndroid Build Coastguard Worker for (size_t out_reg = 0; out_reg < num_outs; out_reg++) {
1471*795d594fSAndroid Build Coastguard Worker if (out_reg == 0) {
1472*795d594fSAndroid Build Coastguard Worker os << "\n\touts:";
1473*795d594fSAndroid Build Coastguard Worker }
1474*795d594fSAndroid Build Coastguard Worker
1475*795d594fSAndroid Build Coastguard Worker uint32_t offset = GetOutVROffset(out_reg, GetInstructionSet());
1476*795d594fSAndroid Build Coastguard Worker os << " v" << out_reg << "[sp + #" << offset << "]";
1477*795d594fSAndroid Build Coastguard Worker }
1478*795d594fSAndroid Build Coastguard Worker
1479*795d594fSAndroid Build Coastguard Worker os << "\n";
1480*795d594fSAndroid Build Coastguard Worker }
1481*795d594fSAndroid Build Coastguard Worker }
1482*795d594fSAndroid Build Coastguard Worker
1483*795d594fSAndroid Build Coastguard Worker // Has `oat_method` -- corresponding to the Dex `code_item` -- been compiled by
1484*795d594fSAndroid Build Coastguard Worker // the optimizing compiler?
IsMethodGeneratedByOptimizingCompiler(const OatFile::OatMethod & oat_method,const CodeItemDataAccessor & code_item_accessor)1485*795d594fSAndroid Build Coastguard Worker static bool IsMethodGeneratedByOptimizingCompiler(
1486*795d594fSAndroid Build Coastguard Worker const OatFile::OatMethod& oat_method,
1487*795d594fSAndroid Build Coastguard Worker const CodeItemDataAccessor& code_item_accessor) {
1488*795d594fSAndroid Build Coastguard Worker // If the native GC map is null and the Dex `code_item` is not
1489*795d594fSAndroid Build Coastguard Worker // null, then this method has been compiled with the optimizing
1490*795d594fSAndroid Build Coastguard Worker // compiler.
1491*795d594fSAndroid Build Coastguard Worker return oat_method.GetQuickCode() != nullptr &&
1492*795d594fSAndroid Build Coastguard Worker oat_method.GetVmapTable() != nullptr &&
1493*795d594fSAndroid Build Coastguard Worker code_item_accessor.HasCodeItem();
1494*795d594fSAndroid Build Coastguard Worker }
1495*795d594fSAndroid Build Coastguard Worker
DumpVerifier(VariableIndentationOutputStream * vios,ScopedObjectAccess & soa,StackHandleScope<1> * hs,uint32_t dex_method_idx,const DexFile * dex_file,const dex::ClassDef & class_def,const dex::CodeItem * code_item,uint32_t method_access_flags)1496*795d594fSAndroid Build Coastguard Worker void DumpVerifier(VariableIndentationOutputStream* vios,
1497*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess& soa,
1498*795d594fSAndroid Build Coastguard Worker StackHandleScope<1>* hs,
1499*795d594fSAndroid Build Coastguard Worker uint32_t dex_method_idx,
1500*795d594fSAndroid Build Coastguard Worker const DexFile* dex_file,
1501*795d594fSAndroid Build Coastguard Worker const dex::ClassDef& class_def,
1502*795d594fSAndroid Build Coastguard Worker const dex::CodeItem* code_item,
1503*795d594fSAndroid Build Coastguard Worker uint32_t method_access_flags)
1504*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
1505*795d594fSAndroid Build Coastguard Worker if ((method_access_flags & kAccNative) == 0) {
1506*795d594fSAndroid Build Coastguard Worker Runtime* const runtime = Runtime::Current();
1507*795d594fSAndroid Build Coastguard Worker DCHECK(options_.class_loader_ != nullptr);
1508*795d594fSAndroid Build Coastguard Worker Handle<mirror::DexCache> dex_cache = hs->NewHandle(
1509*795d594fSAndroid Build Coastguard Worker runtime->GetClassLinker()->RegisterDexFile(*dex_file, options_.class_loader_->Get()));
1510*795d594fSAndroid Build Coastguard Worker CHECK(dex_cache != nullptr);
1511*795d594fSAndroid Build Coastguard Worker ArtMethod* method = runtime->GetClassLinker()->ResolveMethodId(
1512*795d594fSAndroid Build Coastguard Worker dex_method_idx, dex_cache, *options_.class_loader_);
1513*795d594fSAndroid Build Coastguard Worker if (method == nullptr) {
1514*795d594fSAndroid Build Coastguard Worker soa.Self()->ClearException();
1515*795d594fSAndroid Build Coastguard Worker return;
1516*795d594fSAndroid Build Coastguard Worker }
1517*795d594fSAndroid Build Coastguard Worker verifier::MethodVerifier::VerifyMethodAndDump(
1518*795d594fSAndroid Build Coastguard Worker soa.Self(),
1519*795d594fSAndroid Build Coastguard Worker vios,
1520*795d594fSAndroid Build Coastguard Worker dex_method_idx,
1521*795d594fSAndroid Build Coastguard Worker dex_file,
1522*795d594fSAndroid Build Coastguard Worker dex_cache,
1523*795d594fSAndroid Build Coastguard Worker *options_.class_loader_,
1524*795d594fSAndroid Build Coastguard Worker class_def,
1525*795d594fSAndroid Build Coastguard Worker code_item,
1526*795d594fSAndroid Build Coastguard Worker method_access_flags,
1527*795d594fSAndroid Build Coastguard Worker /* api_level= */ 0);
1528*795d594fSAndroid Build Coastguard Worker }
1529*795d594fSAndroid Build Coastguard Worker }
1530*795d594fSAndroid Build Coastguard Worker
DumpCode(VariableIndentationOutputStream * vios,const OatFile::OatMethod & oat_method,const CodeItemDataAccessor & code_item_accessor,bool bad_input,size_t code_size)1531*795d594fSAndroid Build Coastguard Worker void DumpCode(VariableIndentationOutputStream* vios,
1532*795d594fSAndroid Build Coastguard Worker const OatFile::OatMethod& oat_method,
1533*795d594fSAndroid Build Coastguard Worker const CodeItemDataAccessor& code_item_accessor,
1534*795d594fSAndroid Build Coastguard Worker bool bad_input, size_t code_size) {
1535*795d594fSAndroid Build Coastguard Worker const void* quick_code = oat_method.GetQuickCode();
1536*795d594fSAndroid Build Coastguard Worker
1537*795d594fSAndroid Build Coastguard Worker if (code_size == 0) {
1538*795d594fSAndroid Build Coastguard Worker code_size = oat_method.GetQuickCodeSize();
1539*795d594fSAndroid Build Coastguard Worker }
1540*795d594fSAndroid Build Coastguard Worker if (code_size == 0 || quick_code == nullptr) {
1541*795d594fSAndroid Build Coastguard Worker vios->Stream() << "NO CODE!\n";
1542*795d594fSAndroid Build Coastguard Worker return;
1543*795d594fSAndroid Build Coastguard Worker } else if (!bad_input && IsMethodGeneratedByOptimizingCompiler(oat_method,
1544*795d594fSAndroid Build Coastguard Worker code_item_accessor)) {
1545*795d594fSAndroid Build Coastguard Worker // The optimizing compiler outputs its CodeInfo data in the vmap table.
1546*795d594fSAndroid Build Coastguard Worker CodeInfo code_info(oat_method.GetVmapTable());
1547*795d594fSAndroid Build Coastguard Worker if (AddStatsObject(oat_method.GetVmapTable())) {
1548*795d594fSAndroid Build Coastguard Worker code_info.CollectSizeStats(oat_method.GetVmapTable(), stats_["CodeInfo"]);
1549*795d594fSAndroid Build Coastguard Worker }
1550*795d594fSAndroid Build Coastguard Worker std::unordered_map<uint32_t, std::vector<StackMap>> stack_maps;
1551*795d594fSAndroid Build Coastguard Worker for (const StackMap& it : code_info.GetStackMaps()) {
1552*795d594fSAndroid Build Coastguard Worker stack_maps[it.GetNativePcOffset(instruction_set_)].push_back(it);
1553*795d594fSAndroid Build Coastguard Worker }
1554*795d594fSAndroid Build Coastguard Worker
1555*795d594fSAndroid Build Coastguard Worker const uint8_t* quick_native_pc = reinterpret_cast<const uint8_t*>(quick_code);
1556*795d594fSAndroid Build Coastguard Worker size_t offset = 0;
1557*795d594fSAndroid Build Coastguard Worker while (offset < code_size) {
1558*795d594fSAndroid Build Coastguard Worker offset += disassembler_->Dump(vios->Stream(), quick_native_pc + offset);
1559*795d594fSAndroid Build Coastguard Worker auto it = stack_maps.find(offset);
1560*795d594fSAndroid Build Coastguard Worker if (it != stack_maps.end()) {
1561*795d594fSAndroid Build Coastguard Worker ScopedIndentation indent1(vios);
1562*795d594fSAndroid Build Coastguard Worker for (StackMap stack_map : it->second) {
1563*795d594fSAndroid Build Coastguard Worker stack_map.Dump(vios, code_info, oat_method.GetCodeOffset(), instruction_set_);
1564*795d594fSAndroid Build Coastguard Worker }
1565*795d594fSAndroid Build Coastguard Worker stack_maps.erase(it);
1566*795d594fSAndroid Build Coastguard Worker }
1567*795d594fSAndroid Build Coastguard Worker }
1568*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(stack_maps.size(), 0u); // Check that all stack maps have been printed.
1569*795d594fSAndroid Build Coastguard Worker } else {
1570*795d594fSAndroid Build Coastguard Worker const uint8_t* quick_native_pc = reinterpret_cast<const uint8_t*>(quick_code);
1571*795d594fSAndroid Build Coastguard Worker size_t offset = 0;
1572*795d594fSAndroid Build Coastguard Worker while (offset < code_size) {
1573*795d594fSAndroid Build Coastguard Worker offset += disassembler_->Dump(vios->Stream(), quick_native_pc + offset);
1574*795d594fSAndroid Build Coastguard Worker }
1575*795d594fSAndroid Build Coastguard Worker }
1576*795d594fSAndroid Build Coastguard Worker }
1577*795d594fSAndroid Build Coastguard Worker
GetBootImageLiveObjectsDataRange(gc::Heap * heap) const1578*795d594fSAndroid Build Coastguard Worker std::pair<const uint8_t*, const uint8_t*> GetBootImageLiveObjectsDataRange(gc::Heap* heap) const
1579*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
1580*795d594fSAndroid Build Coastguard Worker const std::vector<gc::space::ImageSpace*>& boot_image_spaces = heap->GetBootImageSpaces();
1581*795d594fSAndroid Build Coastguard Worker const ImageHeader& main_header = boot_image_spaces[0]->GetImageHeader();
1582*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects =
1583*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::ObjectArray<mirror::Object>>::DownCast(
1584*795d594fSAndroid Build Coastguard Worker main_header.GetImageRoot<kWithoutReadBarrier>(ImageHeader::kBootImageLiveObjects));
1585*795d594fSAndroid Build Coastguard Worker DCHECK(boot_image_live_objects != nullptr);
1586*795d594fSAndroid Build Coastguard Worker DCHECK(heap->ObjectIsInBootImageSpace(boot_image_live_objects));
1587*795d594fSAndroid Build Coastguard Worker const uint8_t* boot_image_live_objects_address =
1588*795d594fSAndroid Build Coastguard Worker reinterpret_cast<const uint8_t*>(boot_image_live_objects.Ptr());
1589*795d594fSAndroid Build Coastguard Worker uint32_t begin_offset = mirror::ObjectArray<mirror::Object>::OffsetOfElement(0).Uint32Value();
1590*795d594fSAndroid Build Coastguard Worker uint32_t end_offset = mirror::ObjectArray<mirror::Object>::OffsetOfElement(
1591*795d594fSAndroid Build Coastguard Worker boot_image_live_objects->GetLength()).Uint32Value();
1592*795d594fSAndroid Build Coastguard Worker return std::make_pair(boot_image_live_objects_address + begin_offset,
1593*795d594fSAndroid Build Coastguard Worker boot_image_live_objects_address + end_offset);
1594*795d594fSAndroid Build Coastguard Worker }
1595*795d594fSAndroid Build Coastguard Worker
DumpDataImgRelRoEntries(std::ostream & os)1596*795d594fSAndroid Build Coastguard Worker void DumpDataImgRelRoEntries(std::ostream& os) {
1597*795d594fSAndroid Build Coastguard Worker os << ".data.img.rel.ro: ";
1598*795d594fSAndroid Build Coastguard Worker if (oat_file_.GetBootImageRelocations().empty()) {
1599*795d594fSAndroid Build Coastguard Worker os << "empty.\n\n";
1600*795d594fSAndroid Build Coastguard Worker return;
1601*795d594fSAndroid Build Coastguard Worker }
1602*795d594fSAndroid Build Coastguard Worker
1603*795d594fSAndroid Build Coastguard Worker os << oat_file_.GetBootImageRelocations().size() << " entries.\n";
1604*795d594fSAndroid Build Coastguard Worker Runtime* runtime = Runtime::Current();
1605*795d594fSAndroid Build Coastguard Worker if (runtime != nullptr && !runtime->GetHeap()->GetBootImageSpaces().empty()) {
1606*795d594fSAndroid Build Coastguard Worker const std::vector<gc::space::ImageSpace*>& boot_image_spaces =
1607*795d594fSAndroid Build Coastguard Worker runtime->GetHeap()->GetBootImageSpaces();
1608*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(Thread::Current());
1609*795d594fSAndroid Build Coastguard Worker auto live_objects = GetBootImageLiveObjectsDataRange(runtime->GetHeap());
1610*795d594fSAndroid Build Coastguard Worker const uint8_t* live_objects_begin = live_objects.first;
1611*795d594fSAndroid Build Coastguard Worker const uint8_t* live_objects_end = live_objects.second;
1612*795d594fSAndroid Build Coastguard Worker for (const uint32_t& object_offset : oat_file_.GetBootImageRelocations()) {
1613*795d594fSAndroid Build Coastguard Worker uint32_t entry_index = &object_offset - oat_file_.GetBootImageRelocations().data();
1614*795d594fSAndroid Build Coastguard Worker uint32_t entry_offset = entry_index * sizeof(oat_file_.GetBootImageRelocations()[0]);
1615*795d594fSAndroid Build Coastguard Worker os << StringPrintf(" 0x%x: 0x%08x", entry_offset, object_offset);
1616*795d594fSAndroid Build Coastguard Worker uint8_t* address = boot_image_spaces[0]->Begin() + object_offset;
1617*795d594fSAndroid Build Coastguard Worker bool found = false;
1618*795d594fSAndroid Build Coastguard Worker for (gc::space::ImageSpace* space : boot_image_spaces) {
1619*795d594fSAndroid Build Coastguard Worker uint64_t local_offset = address - space->Begin();
1620*795d594fSAndroid Build Coastguard Worker if (local_offset < space->GetImageHeader().GetImageSize()) {
1621*795d594fSAndroid Build Coastguard Worker if (space->GetImageHeader().GetObjectsSection().Contains(local_offset)) {
1622*795d594fSAndroid Build Coastguard Worker if (address >= live_objects_begin && address < live_objects_end) {
1623*795d594fSAndroid Build Coastguard Worker size_t index =
1624*795d594fSAndroid Build Coastguard Worker (address - live_objects_begin) / sizeof(mirror::HeapReference<mirror::Object>);
1625*795d594fSAndroid Build Coastguard Worker os << StringPrintf(" 0x%08x BootImageLiveObject[%zu]",
1626*795d594fSAndroid Build Coastguard Worker object_offset,
1627*795d594fSAndroid Build Coastguard Worker index);
1628*795d594fSAndroid Build Coastguard Worker } else {
1629*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Object> o = reinterpret_cast<mirror::Object*>(address);
1630*795d594fSAndroid Build Coastguard Worker if (o->IsString()) {
1631*795d594fSAndroid Build Coastguard Worker os << " String: " << o->AsString()->ToModifiedUtf8();
1632*795d594fSAndroid Build Coastguard Worker } else if (o->IsClass()) {
1633*795d594fSAndroid Build Coastguard Worker os << " Class: " << o->AsClass()->PrettyDescriptor();
1634*795d594fSAndroid Build Coastguard Worker } else {
1635*795d594fSAndroid Build Coastguard Worker os << StringPrintf(" 0x%08x %s",
1636*795d594fSAndroid Build Coastguard Worker object_offset,
1637*795d594fSAndroid Build Coastguard Worker o->GetClass()->PrettyDescriptor().c_str());
1638*795d594fSAndroid Build Coastguard Worker }
1639*795d594fSAndroid Build Coastguard Worker }
1640*795d594fSAndroid Build Coastguard Worker } else if (space->GetImageHeader().GetMethodsSection().Contains(local_offset)) {
1641*795d594fSAndroid Build Coastguard Worker ArtMethod* m = reinterpret_cast<ArtMethod*>(address);
1642*795d594fSAndroid Build Coastguard Worker os << " ArtMethod: " << m->PrettyMethod();
1643*795d594fSAndroid Build Coastguard Worker } else {
1644*795d594fSAndroid Build Coastguard Worker os << StringPrintf(" 0x%08x <unexpected section in %s>",
1645*795d594fSAndroid Build Coastguard Worker object_offset,
1646*795d594fSAndroid Build Coastguard Worker space->GetImageFilename().c_str());
1647*795d594fSAndroid Build Coastguard Worker }
1648*795d594fSAndroid Build Coastguard Worker found = true;
1649*795d594fSAndroid Build Coastguard Worker break;
1650*795d594fSAndroid Build Coastguard Worker }
1651*795d594fSAndroid Build Coastguard Worker }
1652*795d594fSAndroid Build Coastguard Worker if (!found) {
1653*795d594fSAndroid Build Coastguard Worker os << StringPrintf(" 0x%08x <outside boot image spaces>", object_offset);
1654*795d594fSAndroid Build Coastguard Worker }
1655*795d594fSAndroid Build Coastguard Worker os << "\n";
1656*795d594fSAndroid Build Coastguard Worker }
1657*795d594fSAndroid Build Coastguard Worker } else {
1658*795d594fSAndroid Build Coastguard Worker for (const uint32_t& object_offset : oat_file_.GetBootImageRelocations()) {
1659*795d594fSAndroid Build Coastguard Worker uint32_t entry_index = &object_offset - oat_file_.GetBootImageRelocations().data();
1660*795d594fSAndroid Build Coastguard Worker uint32_t entry_offset = entry_index * sizeof(oat_file_.GetBootImageRelocations()[0]);
1661*795d594fSAndroid Build Coastguard Worker os << StringPrintf(" 0x%x: 0x%08x\n", entry_offset, object_offset);
1662*795d594fSAndroid Build Coastguard Worker }
1663*795d594fSAndroid Build Coastguard Worker }
1664*795d594fSAndroid Build Coastguard Worker os << "\n";
1665*795d594fSAndroid Build Coastguard Worker }
1666*795d594fSAndroid Build Coastguard Worker
1667*795d594fSAndroid Build Coastguard Worker template <typename NameGetter>
DumpBssEntries(std::ostream & os,const char * slot_type,const IndexBssMapping * mapping,uint32_t number_of_indexes,size_t slot_size,NameGetter name)1668*795d594fSAndroid Build Coastguard Worker void DumpBssEntries(std::ostream& os,
1669*795d594fSAndroid Build Coastguard Worker const char* slot_type,
1670*795d594fSAndroid Build Coastguard Worker const IndexBssMapping* mapping,
1671*795d594fSAndroid Build Coastguard Worker uint32_t number_of_indexes,
1672*795d594fSAndroid Build Coastguard Worker size_t slot_size,
1673*795d594fSAndroid Build Coastguard Worker NameGetter name) {
1674*795d594fSAndroid Build Coastguard Worker os << ".bss mapping for " << slot_type << ": ";
1675*795d594fSAndroid Build Coastguard Worker if (mapping == nullptr) {
1676*795d594fSAndroid Build Coastguard Worker os << "empty.\n";
1677*795d594fSAndroid Build Coastguard Worker return;
1678*795d594fSAndroid Build Coastguard Worker }
1679*795d594fSAndroid Build Coastguard Worker size_t index_bits = IndexBssMappingEntry::IndexBits(number_of_indexes);
1680*795d594fSAndroid Build Coastguard Worker size_t num_valid_indexes = 0u;
1681*795d594fSAndroid Build Coastguard Worker for (const IndexBssMappingEntry& entry : *mapping) {
1682*795d594fSAndroid Build Coastguard Worker num_valid_indexes += 1u + POPCOUNT(entry.GetMask(index_bits));
1683*795d594fSAndroid Build Coastguard Worker }
1684*795d594fSAndroid Build Coastguard Worker os << mapping->size() << " entries for " << num_valid_indexes << " valid indexes.\n";
1685*795d594fSAndroid Build Coastguard Worker os << std::hex;
1686*795d594fSAndroid Build Coastguard Worker for (const IndexBssMappingEntry& entry : *mapping) {
1687*795d594fSAndroid Build Coastguard Worker uint32_t index = entry.GetIndex(index_bits);
1688*795d594fSAndroid Build Coastguard Worker uint32_t mask = entry.GetMask(index_bits);
1689*795d594fSAndroid Build Coastguard Worker size_t bss_offset = entry.bss_offset - POPCOUNT(mask) * slot_size;
1690*795d594fSAndroid Build Coastguard Worker for (uint32_t n : LowToHighBits(mask)) {
1691*795d594fSAndroid Build Coastguard Worker size_t current_index = index - (32u - index_bits) + n;
1692*795d594fSAndroid Build Coastguard Worker os << " 0x" << bss_offset << ": " << slot_type << ": " << name(current_index) << "\n";
1693*795d594fSAndroid Build Coastguard Worker bss_offset += slot_size;
1694*795d594fSAndroid Build Coastguard Worker }
1695*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(bss_offset, entry.bss_offset);
1696*795d594fSAndroid Build Coastguard Worker os << " 0x" << bss_offset << ": " << slot_type << ": " << name(index) << "\n";
1697*795d594fSAndroid Build Coastguard Worker }
1698*795d594fSAndroid Build Coastguard Worker os << std::dec;
1699*795d594fSAndroid Build Coastguard Worker }
1700*795d594fSAndroid Build Coastguard Worker
DumpBssMappings(std::ostream & os,const DexFile * dex_file,const IndexBssMapping * method_bss_mapping,const IndexBssMapping * type_bss_mapping,const IndexBssMapping * public_type_bss_mapping,const IndexBssMapping * package_type_bss_mapping,const IndexBssMapping * string_bss_mapping,const IndexBssMapping * method_type_bss_mapping)1701*795d594fSAndroid Build Coastguard Worker void DumpBssMappings(std::ostream& os,
1702*795d594fSAndroid Build Coastguard Worker const DexFile* dex_file,
1703*795d594fSAndroid Build Coastguard Worker const IndexBssMapping* method_bss_mapping,
1704*795d594fSAndroid Build Coastguard Worker const IndexBssMapping* type_bss_mapping,
1705*795d594fSAndroid Build Coastguard Worker const IndexBssMapping* public_type_bss_mapping,
1706*795d594fSAndroid Build Coastguard Worker const IndexBssMapping* package_type_bss_mapping,
1707*795d594fSAndroid Build Coastguard Worker const IndexBssMapping* string_bss_mapping,
1708*795d594fSAndroid Build Coastguard Worker const IndexBssMapping* method_type_bss_mapping) {
1709*795d594fSAndroid Build Coastguard Worker DumpBssEntries(os,
1710*795d594fSAndroid Build Coastguard Worker "ArtMethod",
1711*795d594fSAndroid Build Coastguard Worker method_bss_mapping,
1712*795d594fSAndroid Build Coastguard Worker dex_file->NumMethodIds(),
1713*795d594fSAndroid Build Coastguard Worker static_cast<size_t>(GetInstructionSetPointerSize(instruction_set_)),
1714*795d594fSAndroid Build Coastguard Worker [=](uint32_t index) { return dex_file->PrettyMethod(index); });
1715*795d594fSAndroid Build Coastguard Worker DumpBssEntries(os,
1716*795d594fSAndroid Build Coastguard Worker "Class",
1717*795d594fSAndroid Build Coastguard Worker type_bss_mapping,
1718*795d594fSAndroid Build Coastguard Worker dex_file->NumTypeIds(),
1719*795d594fSAndroid Build Coastguard Worker sizeof(GcRoot<mirror::Class>),
1720*795d594fSAndroid Build Coastguard Worker [=](uint32_t index) { return dex_file->PrettyType(dex::TypeIndex(index)); });
1721*795d594fSAndroid Build Coastguard Worker DumpBssEntries(os,
1722*795d594fSAndroid Build Coastguard Worker "Public Class",
1723*795d594fSAndroid Build Coastguard Worker public_type_bss_mapping,
1724*795d594fSAndroid Build Coastguard Worker dex_file->NumTypeIds(),
1725*795d594fSAndroid Build Coastguard Worker sizeof(GcRoot<mirror::Class>),
1726*795d594fSAndroid Build Coastguard Worker [=](uint32_t index) { return dex_file->PrettyType(dex::TypeIndex(index)); });
1727*795d594fSAndroid Build Coastguard Worker DumpBssEntries(os,
1728*795d594fSAndroid Build Coastguard Worker "Package Class",
1729*795d594fSAndroid Build Coastguard Worker package_type_bss_mapping,
1730*795d594fSAndroid Build Coastguard Worker dex_file->NumTypeIds(),
1731*795d594fSAndroid Build Coastguard Worker sizeof(GcRoot<mirror::Class>),
1732*795d594fSAndroid Build Coastguard Worker [=](uint32_t index) { return dex_file->PrettyType(dex::TypeIndex(index)); });
1733*795d594fSAndroid Build Coastguard Worker DumpBssEntries(
1734*795d594fSAndroid Build Coastguard Worker os,
1735*795d594fSAndroid Build Coastguard Worker "String",
1736*795d594fSAndroid Build Coastguard Worker string_bss_mapping,
1737*795d594fSAndroid Build Coastguard Worker dex_file->NumStringIds(),
1738*795d594fSAndroid Build Coastguard Worker sizeof(GcRoot<mirror::Class>),
1739*795d594fSAndroid Build Coastguard Worker [=](uint32_t index) { return dex_file->GetStringData(dex::StringIndex(index)); });
1740*795d594fSAndroid Build Coastguard Worker DumpBssEntries(os,
1741*795d594fSAndroid Build Coastguard Worker "MethodType",
1742*795d594fSAndroid Build Coastguard Worker method_type_bss_mapping,
1743*795d594fSAndroid Build Coastguard Worker dex_file->NumProtoIds(),
1744*795d594fSAndroid Build Coastguard Worker sizeof(GcRoot<mirror::MethodType>),
1745*795d594fSAndroid Build Coastguard Worker [=](uint32_t index) {
1746*795d594fSAndroid Build Coastguard Worker const dex::ProtoId& proto_id = dex_file->GetProtoId(dex::ProtoIndex(index));
1747*795d594fSAndroid Build Coastguard Worker return dex_file->GetProtoSignature(proto_id).ToString();
1748*795d594fSAndroid Build Coastguard Worker });
1749*795d594fSAndroid Build Coastguard Worker }
1750*795d594fSAndroid Build Coastguard Worker
DumpBssOffsets(std::ostream & os,const char * slot_type,const IndexBssMapping * mapping)1751*795d594fSAndroid Build Coastguard Worker void DumpBssOffsets(std::ostream& os, const char* slot_type, const IndexBssMapping* mapping) {
1752*795d594fSAndroid Build Coastguard Worker os << ".bss offset for " << slot_type << ": ";
1753*795d594fSAndroid Build Coastguard Worker if (mapping == nullptr) {
1754*795d594fSAndroid Build Coastguard Worker os << "empty.\n";
1755*795d594fSAndroid Build Coastguard Worker return;
1756*795d594fSAndroid Build Coastguard Worker }
1757*795d594fSAndroid Build Coastguard Worker
1758*795d594fSAndroid Build Coastguard Worker os << "Mapping size: " << mapping->size() << "\n";
1759*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < mapping->size(); ++i) {
1760*795d594fSAndroid Build Coastguard Worker os << "Entry[" << i << "]: index_and_mask: "
1761*795d594fSAndroid Build Coastguard Worker << mapping->At(i).index_and_mask
1762*795d594fSAndroid Build Coastguard Worker << ", bss_offset: "
1763*795d594fSAndroid Build Coastguard Worker << mapping->At(i).bss_offset << "\n";
1764*795d594fSAndroid Build Coastguard Worker }
1765*795d594fSAndroid Build Coastguard Worker
1766*795d594fSAndroid Build Coastguard Worker // TODO(solanes, 154012332): We are dumping the raw values but we could make assumptions about
1767*795d594fSAndroid Build Coastguard Worker // ordering of the entries and deconstruct even the `index_and_mask`. This would allow us to use
1768*795d594fSAndroid Build Coastguard Worker // DumpBssEntries and dump more information. The size and alignment of the entry (ArtMethod*
1769*795d594fSAndroid Build Coastguard Worker // depends on instruction set but Class and String references are 32-bit) and the difference
1770*795d594fSAndroid Build Coastguard Worker // from the previous `bss_offset` (or from the "oatbss" symbol for the first item) tell us how
1771*795d594fSAndroid Build Coastguard Worker // many .bss entries a single `IndexBssMappingEntry` should describe. So we know how many most
1772*795d594fSAndroid Build Coastguard Worker // significant set bits represent the mask and the rest is the actual index. And the position of
1773*795d594fSAndroid Build Coastguard Worker // the mask bits would allow reconstructing the other indexes.
1774*795d594fSAndroid Build Coastguard Worker }
1775*795d594fSAndroid Build Coastguard Worker
1776*795d594fSAndroid Build Coastguard Worker // Adjusts an offset relative to the OAT file begin to an offset relative to the ELF file begin.
AdjustOffset(size_t offset) const1777*795d594fSAndroid Build Coastguard Worker size_t AdjustOffset(size_t offset) const { return (offset > 0) ? (oat_offset_ + offset) : 0; }
1778*795d594fSAndroid Build Coastguard Worker
1779*795d594fSAndroid Build Coastguard Worker const OatFile& oat_file_;
1780*795d594fSAndroid Build Coastguard Worker size_t oat_offset_;
1781*795d594fSAndroid Build Coastguard Worker const std::vector<const OatDexFile*> oat_dex_files_;
1782*795d594fSAndroid Build Coastguard Worker const OatDumperOptions& options_;
1783*795d594fSAndroid Build Coastguard Worker uint32_t resolved_addr2instr_;
1784*795d594fSAndroid Build Coastguard Worker const InstructionSet instruction_set_;
1785*795d594fSAndroid Build Coastguard Worker std::set<uintptr_t> offsets_;
1786*795d594fSAndroid Build Coastguard Worker Disassembler* disassembler_;
1787*795d594fSAndroid Build Coastguard Worker Stats stats_;
1788*795d594fSAndroid Build Coastguard Worker std::unordered_set<const void*> seen_stats_objects_;
1789*795d594fSAndroid Build Coastguard Worker };
1790*795d594fSAndroid Build Coastguard Worker
1791*795d594fSAndroid Build Coastguard Worker class ImageDumper {
1792*795d594fSAndroid Build Coastguard Worker public:
ImageDumper(std::ostream * os,gc::space::ImageSpace & image_space,const ImageHeader & image_header,OatDumperOptions * oat_dumper_options)1793*795d594fSAndroid Build Coastguard Worker ImageDumper(std::ostream* os,
1794*795d594fSAndroid Build Coastguard Worker gc::space::ImageSpace& image_space,
1795*795d594fSAndroid Build Coastguard Worker const ImageHeader& image_header,
1796*795d594fSAndroid Build Coastguard Worker OatDumperOptions* oat_dumper_options)
1797*795d594fSAndroid Build Coastguard Worker : os_(os),
1798*795d594fSAndroid Build Coastguard Worker vios_(os),
1799*795d594fSAndroid Build Coastguard Worker indent1_(&vios_),
1800*795d594fSAndroid Build Coastguard Worker image_space_(image_space),
1801*795d594fSAndroid Build Coastguard Worker image_header_(image_header),
1802*795d594fSAndroid Build Coastguard Worker oat_dumper_options_(oat_dumper_options) {}
1803*795d594fSAndroid Build Coastguard Worker
Dump()1804*795d594fSAndroid Build Coastguard Worker bool Dump() REQUIRES_SHARED(Locks::mutator_lock_) {
1805*795d594fSAndroid Build Coastguard Worker std::ostream& os = *os_;
1806*795d594fSAndroid Build Coastguard Worker std::ostream& indent_os = vios_.Stream();
1807*795d594fSAndroid Build Coastguard Worker
1808*795d594fSAndroid Build Coastguard Worker os << "MAGIC: " << image_header_.GetMagic() << "\n\n";
1809*795d594fSAndroid Build Coastguard Worker
1810*795d594fSAndroid Build Coastguard Worker os << "IMAGE LOCATION: " << image_space_.GetImageLocation() << "\n\n";
1811*795d594fSAndroid Build Coastguard Worker
1812*795d594fSAndroid Build Coastguard Worker os << "IMAGE BEGIN: " << reinterpret_cast<void*>(image_header_.GetImageBegin()) << "\n";
1813*795d594fSAndroid Build Coastguard Worker os << "IMAGE SIZE: " << image_header_.GetImageSize() << "\n";
1814*795d594fSAndroid Build Coastguard Worker os << "IMAGE CHECKSUM: " << std::hex << image_header_.GetImageChecksum() << std::dec << "\n\n";
1815*795d594fSAndroid Build Coastguard Worker
1816*795d594fSAndroid Build Coastguard Worker os << "OAT CHECKSUM: " << StringPrintf("0x%08x\n\n", image_header_.GetOatChecksum()) << "\n";
1817*795d594fSAndroid Build Coastguard Worker os << "OAT FILE BEGIN:" << reinterpret_cast<void*>(image_header_.GetOatFileBegin()) << "\n";
1818*795d594fSAndroid Build Coastguard Worker os << "OAT DATA BEGIN:" << reinterpret_cast<void*>(image_header_.GetOatDataBegin()) << "\n";
1819*795d594fSAndroid Build Coastguard Worker os << "OAT DATA END:" << reinterpret_cast<void*>(image_header_.GetOatDataEnd()) << "\n";
1820*795d594fSAndroid Build Coastguard Worker os << "OAT FILE END:" << reinterpret_cast<void*>(image_header_.GetOatFileEnd()) << "\n\n";
1821*795d594fSAndroid Build Coastguard Worker
1822*795d594fSAndroid Build Coastguard Worker os << "BOOT IMAGE BEGIN: " << reinterpret_cast<void*>(image_header_.GetBootImageBegin())
1823*795d594fSAndroid Build Coastguard Worker << "\n";
1824*795d594fSAndroid Build Coastguard Worker os << "BOOT IMAGE SIZE: " << image_header_.GetBootImageSize() << "\n\n";
1825*795d594fSAndroid Build Coastguard Worker
1826*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < ImageHeader::kSectionCount; ++i) {
1827*795d594fSAndroid Build Coastguard Worker auto section = static_cast<ImageHeader::ImageSections>(i);
1828*795d594fSAndroid Build Coastguard Worker os << "IMAGE SECTION " << section << ": " << image_header_.GetImageSection(section) << "\n\n";
1829*795d594fSAndroid Build Coastguard Worker }
1830*795d594fSAndroid Build Coastguard Worker
1831*795d594fSAndroid Build Coastguard Worker {
1832*795d594fSAndroid Build Coastguard Worker os << "ROOTS: " << reinterpret_cast<void*>(image_header_.GetImageRoots().Ptr()) << "\n";
1833*795d594fSAndroid Build Coastguard Worker static_assert(arraysize(image_roots_descriptions_) ==
1834*795d594fSAndroid Build Coastguard Worker static_cast<size_t>(ImageHeader::kImageRootsMax), "sizes must match");
1835*795d594fSAndroid Build Coastguard Worker DCHECK_LE(image_header_.GetImageRoots()->GetLength(), ImageHeader::kImageRootsMax);
1836*795d594fSAndroid Build Coastguard Worker for (int32_t i = 0, size = image_header_.GetImageRoots()->GetLength(); i != size; ++i) {
1837*795d594fSAndroid Build Coastguard Worker ImageHeader::ImageRoot image_root = static_cast<ImageHeader::ImageRoot>(i);
1838*795d594fSAndroid Build Coastguard Worker const char* image_root_description = image_roots_descriptions_[i];
1839*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Object> image_root_object = image_header_.GetImageRoot(image_root);
1840*795d594fSAndroid Build Coastguard Worker indent_os << StringPrintf("%s: %p\n", image_root_description, image_root_object.Ptr());
1841*795d594fSAndroid Build Coastguard Worker if (image_root_object != nullptr && image_root_object->IsObjectArray()) {
1842*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::ObjectArray<mirror::Object>> image_root_object_array
1843*795d594fSAndroid Build Coastguard Worker = image_root_object->AsObjectArray<mirror::Object>();
1844*795d594fSAndroid Build Coastguard Worker ScopedIndentation indent2(&vios_);
1845*795d594fSAndroid Build Coastguard Worker for (int j = 0; j < image_root_object_array->GetLength(); j++) {
1846*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Object> value = image_root_object_array->Get(j);
1847*795d594fSAndroid Build Coastguard Worker size_t run = 0;
1848*795d594fSAndroid Build Coastguard Worker for (int32_t k = j + 1; k < image_root_object_array->GetLength(); k++) {
1849*795d594fSAndroid Build Coastguard Worker if (value == image_root_object_array->Get(k)) {
1850*795d594fSAndroid Build Coastguard Worker run++;
1851*795d594fSAndroid Build Coastguard Worker } else {
1852*795d594fSAndroid Build Coastguard Worker break;
1853*795d594fSAndroid Build Coastguard Worker }
1854*795d594fSAndroid Build Coastguard Worker }
1855*795d594fSAndroid Build Coastguard Worker if (run == 0) {
1856*795d594fSAndroid Build Coastguard Worker indent_os << StringPrintf("%d: ", j);
1857*795d594fSAndroid Build Coastguard Worker } else {
1858*795d594fSAndroid Build Coastguard Worker indent_os << StringPrintf("%d to %zd: ", j, j + run);
1859*795d594fSAndroid Build Coastguard Worker j = j + run;
1860*795d594fSAndroid Build Coastguard Worker }
1861*795d594fSAndroid Build Coastguard Worker if (value != nullptr) {
1862*795d594fSAndroid Build Coastguard Worker PrettyObjectValue(indent_os, value->GetClass(), value);
1863*795d594fSAndroid Build Coastguard Worker } else {
1864*795d594fSAndroid Build Coastguard Worker indent_os << j << ": null\n";
1865*795d594fSAndroid Build Coastguard Worker }
1866*795d594fSAndroid Build Coastguard Worker }
1867*795d594fSAndroid Build Coastguard Worker }
1868*795d594fSAndroid Build Coastguard Worker }
1869*795d594fSAndroid Build Coastguard Worker }
1870*795d594fSAndroid Build Coastguard Worker
1871*795d594fSAndroid Build Coastguard Worker {
1872*795d594fSAndroid Build Coastguard Worker os << "METHOD ROOTS\n";
1873*795d594fSAndroid Build Coastguard Worker static_assert(arraysize(image_methods_descriptions_) ==
1874*795d594fSAndroid Build Coastguard Worker static_cast<size_t>(ImageHeader::kImageMethodsCount), "sizes must match");
1875*795d594fSAndroid Build Coastguard Worker for (int i = 0; i < ImageHeader::kImageMethodsCount; i++) {
1876*795d594fSAndroid Build Coastguard Worker auto image_root = static_cast<ImageHeader::ImageMethod>(i);
1877*795d594fSAndroid Build Coastguard Worker const char* description = image_methods_descriptions_[i];
1878*795d594fSAndroid Build Coastguard Worker auto* image_method = image_header_.GetImageMethod(image_root);
1879*795d594fSAndroid Build Coastguard Worker indent_os << StringPrintf("%s: %p\n", description, image_method);
1880*795d594fSAndroid Build Coastguard Worker }
1881*795d594fSAndroid Build Coastguard Worker }
1882*795d594fSAndroid Build Coastguard Worker os << "\n";
1883*795d594fSAndroid Build Coastguard Worker
1884*795d594fSAndroid Build Coastguard Worker Runtime* const runtime = Runtime::Current();
1885*795d594fSAndroid Build Coastguard Worker std::string image_filename = image_space_.GetImageFilename();
1886*795d594fSAndroid Build Coastguard Worker std::string oat_location = ImageHeader::GetOatLocationFromImageLocation(image_filename);
1887*795d594fSAndroid Build Coastguard Worker os << "OAT LOCATION: " << oat_location;
1888*795d594fSAndroid Build Coastguard Worker os << "\n";
1889*795d594fSAndroid Build Coastguard Worker std::string error_msg;
1890*795d594fSAndroid Build Coastguard Worker const OatFile* oat_file = image_space_.GetOatFile();
1891*795d594fSAndroid Build Coastguard Worker if (oat_file == nullptr) {
1892*795d594fSAndroid Build Coastguard Worker oat_file = runtime->GetOatFileManager().FindOpenedOatFileFromOatLocation(oat_location);
1893*795d594fSAndroid Build Coastguard Worker }
1894*795d594fSAndroid Build Coastguard Worker if (oat_file == nullptr) {
1895*795d594fSAndroid Build Coastguard Worker oat_file = OatFile::Open(/*zip_fd=*/ -1,
1896*795d594fSAndroid Build Coastguard Worker oat_location,
1897*795d594fSAndroid Build Coastguard Worker oat_location,
1898*795d594fSAndroid Build Coastguard Worker /*executable=*/ false,
1899*795d594fSAndroid Build Coastguard Worker /*low_4gb=*/ false,
1900*795d594fSAndroid Build Coastguard Worker &error_msg);
1901*795d594fSAndroid Build Coastguard Worker }
1902*795d594fSAndroid Build Coastguard Worker if (oat_file == nullptr) {
1903*795d594fSAndroid Build Coastguard Worker os << "OAT FILE NOT FOUND: " << error_msg << "\n";
1904*795d594fSAndroid Build Coastguard Worker return EXIT_FAILURE;
1905*795d594fSAndroid Build Coastguard Worker }
1906*795d594fSAndroid Build Coastguard Worker os << "\n";
1907*795d594fSAndroid Build Coastguard Worker
1908*795d594fSAndroid Build Coastguard Worker stats_.oat_file_bytes = oat_file->Size();
1909*795d594fSAndroid Build Coastguard Worker stats_.oat_file_stats.AddBytes(oat_file->Size());
1910*795d594fSAndroid Build Coastguard Worker
1911*795d594fSAndroid Build Coastguard Worker oat_dumper_.reset(new OatDumper(*oat_file, *oat_dumper_options_));
1912*795d594fSAndroid Build Coastguard Worker
1913*795d594fSAndroid Build Coastguard Worker for (const OatDexFile* oat_dex_file : oat_file->GetOatDexFiles()) {
1914*795d594fSAndroid Build Coastguard Worker CHECK(oat_dex_file != nullptr);
1915*795d594fSAndroid Build Coastguard Worker stats_.oat_dex_file_sizes.push_back(std::make_pair(oat_dex_file->GetDexFileLocation(),
1916*795d594fSAndroid Build Coastguard Worker oat_dex_file->FileSize()));
1917*795d594fSAndroid Build Coastguard Worker }
1918*795d594fSAndroid Build Coastguard Worker
1919*795d594fSAndroid Build Coastguard Worker os << "OBJECTS:\n" << std::flush;
1920*795d594fSAndroid Build Coastguard Worker
1921*795d594fSAndroid Build Coastguard Worker // Loop through the image space and dump its objects.
1922*795d594fSAndroid Build Coastguard Worker gc::Heap* heap = runtime->GetHeap();
1923*795d594fSAndroid Build Coastguard Worker Thread* self = Thread::Current();
1924*795d594fSAndroid Build Coastguard Worker {
1925*795d594fSAndroid Build Coastguard Worker {
1926*795d594fSAndroid Build Coastguard Worker WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
1927*795d594fSAndroid Build Coastguard Worker heap->FlushAllocStack();
1928*795d594fSAndroid Build Coastguard Worker }
1929*795d594fSAndroid Build Coastguard Worker // Since FlushAllocStack() above resets the (active) allocation
1930*795d594fSAndroid Build Coastguard Worker // stack. Need to revoke the thread-local allocation stacks that
1931*795d594fSAndroid Build Coastguard Worker // point into it.
1932*795d594fSAndroid Build Coastguard Worker ScopedThreadSuspension sts(self, ThreadState::kNative);
1933*795d594fSAndroid Build Coastguard Worker ScopedSuspendAll ssa(__FUNCTION__);
1934*795d594fSAndroid Build Coastguard Worker heap->RevokeAllThreadLocalAllocationStacks(self);
1935*795d594fSAndroid Build Coastguard Worker }
1936*795d594fSAndroid Build Coastguard Worker {
1937*795d594fSAndroid Build Coastguard Worker auto dump_visitor = [&](mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_) {
1938*795d594fSAndroid Build Coastguard Worker DumpObject(obj);
1939*795d594fSAndroid Build Coastguard Worker };
1940*795d594fSAndroid Build Coastguard Worker ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
1941*795d594fSAndroid Build Coastguard Worker // Dump the normal objects before ArtMethods.
1942*795d594fSAndroid Build Coastguard Worker image_space_.GetLiveBitmap()->Walk(dump_visitor);
1943*795d594fSAndroid Build Coastguard Worker indent_os << "\n";
1944*795d594fSAndroid Build Coastguard Worker // TODO: Dump fields.
1945*795d594fSAndroid Build Coastguard Worker // Dump methods after.
1946*795d594fSAndroid Build Coastguard Worker image_header_.VisitPackedArtMethods([&](ArtMethod& method)
1947*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
1948*795d594fSAndroid Build Coastguard Worker std::ostream& indent_os = vios_.Stream();
1949*795d594fSAndroid Build Coastguard Worker indent_os << &method << " " << " ArtMethod: " << method.PrettyMethod() << "\n";
1950*795d594fSAndroid Build Coastguard Worker DumpMethod(&method, indent_os);
1951*795d594fSAndroid Build Coastguard Worker indent_os << "\n";
1952*795d594fSAndroid Build Coastguard Worker }, image_space_.Begin(), image_header_.GetPointerSize());
1953*795d594fSAndroid Build Coastguard Worker // Dump the large objects separately.
1954*795d594fSAndroid Build Coastguard Worker heap->GetLargeObjectsSpace()->GetLiveBitmap()->Walk(dump_visitor);
1955*795d594fSAndroid Build Coastguard Worker indent_os << "\n";
1956*795d594fSAndroid Build Coastguard Worker }
1957*795d594fSAndroid Build Coastguard Worker os << "STATS:\n" << std::flush;
1958*795d594fSAndroid Build Coastguard Worker std::unique_ptr<File> file(OS::OpenFileForReading(image_filename.c_str()));
1959*795d594fSAndroid Build Coastguard Worker size_t data_size = image_header_.GetDataSize(); // stored size in file.
1960*795d594fSAndroid Build Coastguard Worker if (file == nullptr) {
1961*795d594fSAndroid Build Coastguard Worker LOG(WARNING) << "Failed to find image in " << image_filename;
1962*795d594fSAndroid Build Coastguard Worker } else {
1963*795d594fSAndroid Build Coastguard Worker size_t file_bytes = file->GetLength();
1964*795d594fSAndroid Build Coastguard Worker // If the image is compressed, adjust to decompressed size.
1965*795d594fSAndroid Build Coastguard Worker size_t uncompressed_size = image_header_.GetImageSize() - sizeof(ImageHeader);
1966*795d594fSAndroid Build Coastguard Worker if (!image_header_.HasCompressedBlock()) {
1967*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(uncompressed_size, data_size) << "Sizes should match for uncompressed image";
1968*795d594fSAndroid Build Coastguard Worker }
1969*795d594fSAndroid Build Coastguard Worker file_bytes += uncompressed_size - data_size;
1970*795d594fSAndroid Build Coastguard Worker stats_.art_file_stats.AddBytes(file_bytes);
1971*795d594fSAndroid Build Coastguard Worker stats_.art_file_stats["Header"].AddBytes(sizeof(ImageHeader));
1972*795d594fSAndroid Build Coastguard Worker }
1973*795d594fSAndroid Build Coastguard Worker
1974*795d594fSAndroid Build Coastguard Worker size_t pointer_size = static_cast<size_t>(image_header_.GetPointerSize());
1975*795d594fSAndroid Build Coastguard Worker CHECK_ALIGNED(image_header_.GetFieldsSection().Offset(), 4);
1976*795d594fSAndroid Build Coastguard Worker CHECK_ALIGNED_PARAM(image_header_.GetMethodsSection().Offset(), pointer_size);
1977*795d594fSAndroid Build Coastguard Worker CHECK_ALIGNED(image_header_.GetInternedStringsSection().Offset(), 8);
1978*795d594fSAndroid Build Coastguard Worker CHECK_ALIGNED(image_header_.GetImageBitmapSection().Offset(), kElfSegmentAlignment);
1979*795d594fSAndroid Build Coastguard Worker
1980*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < ImageHeader::ImageSections::kSectionCount; i++) {
1981*795d594fSAndroid Build Coastguard Worker ImageHeader::ImageSections index = ImageHeader::ImageSections(i);
1982*795d594fSAndroid Build Coastguard Worker const char* name = ImageHeader::GetImageSectionName(index);
1983*795d594fSAndroid Build Coastguard Worker stats_.art_file_stats[name].AddBytes(image_header_.GetImageSection(index).Size());
1984*795d594fSAndroid Build Coastguard Worker }
1985*795d594fSAndroid Build Coastguard Worker
1986*795d594fSAndroid Build Coastguard Worker stats_.object_stats.AddBytes(image_header_.GetObjectsSection().Size());
1987*795d594fSAndroid Build Coastguard Worker stats_.Dump(os);
1988*795d594fSAndroid Build Coastguard Worker os << "\n";
1989*795d594fSAndroid Build Coastguard Worker
1990*795d594fSAndroid Build Coastguard Worker os << std::flush;
1991*795d594fSAndroid Build Coastguard Worker
1992*795d594fSAndroid Build Coastguard Worker return oat_dumper_->Dump(os);
1993*795d594fSAndroid Build Coastguard Worker }
1994*795d594fSAndroid Build Coastguard Worker
1995*795d594fSAndroid Build Coastguard Worker private:
PrettyObjectValue(std::ostream & os,ObjPtr<mirror::Class> type,ObjPtr<mirror::Object> value)1996*795d594fSAndroid Build Coastguard Worker static void PrettyObjectValue(std::ostream& os,
1997*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Class> type,
1998*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Object> value)
1999*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
2000*795d594fSAndroid Build Coastguard Worker CHECK(type != nullptr);
2001*795d594fSAndroid Build Coastguard Worker if (value == nullptr) {
2002*795d594fSAndroid Build Coastguard Worker os << StringPrintf("null %s\n", type->PrettyDescriptor().c_str());
2003*795d594fSAndroid Build Coastguard Worker } else if (type->IsStringClass()) {
2004*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::String> string = value->AsString();
2005*795d594fSAndroid Build Coastguard Worker os << StringPrintf("%p String: %s\n",
2006*795d594fSAndroid Build Coastguard Worker string.Ptr(),
2007*795d594fSAndroid Build Coastguard Worker PrintableString(string->ToModifiedUtf8().c_str()).c_str());
2008*795d594fSAndroid Build Coastguard Worker } else if (type->IsClassClass()) {
2009*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Class> klass = value->AsClass();
2010*795d594fSAndroid Build Coastguard Worker os << StringPrintf("%p Class: %s\n",
2011*795d594fSAndroid Build Coastguard Worker klass.Ptr(),
2012*795d594fSAndroid Build Coastguard Worker mirror::Class::PrettyDescriptor(klass).c_str());
2013*795d594fSAndroid Build Coastguard Worker } else {
2014*795d594fSAndroid Build Coastguard Worker os << StringPrintf("%p %s\n", value.Ptr(), type->PrettyDescriptor().c_str());
2015*795d594fSAndroid Build Coastguard Worker }
2016*795d594fSAndroid Build Coastguard Worker }
2017*795d594fSAndroid Build Coastguard Worker
PrintField(std::ostream & os,ArtField * field,ObjPtr<mirror::Object> obj)2018*795d594fSAndroid Build Coastguard Worker static void PrintField(std::ostream& os, ArtField* field, ObjPtr<mirror::Object> obj)
2019*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
2020*795d594fSAndroid Build Coastguard Worker os << StringPrintf("%s: ", field->GetName());
2021*795d594fSAndroid Build Coastguard Worker switch (field->GetTypeAsPrimitiveType()) {
2022*795d594fSAndroid Build Coastguard Worker case Primitive::kPrimLong:
2023*795d594fSAndroid Build Coastguard Worker os << StringPrintf("%" PRId64 " (0x%" PRIx64 ")\n", field->Get64(obj), field->Get64(obj));
2024*795d594fSAndroid Build Coastguard Worker break;
2025*795d594fSAndroid Build Coastguard Worker case Primitive::kPrimDouble:
2026*795d594fSAndroid Build Coastguard Worker os << StringPrintf("%f (%a)\n", field->GetDouble(obj), field->GetDouble(obj));
2027*795d594fSAndroid Build Coastguard Worker break;
2028*795d594fSAndroid Build Coastguard Worker case Primitive::kPrimFloat:
2029*795d594fSAndroid Build Coastguard Worker os << StringPrintf("%f (%a)\n", field->GetFloat(obj), field->GetFloat(obj));
2030*795d594fSAndroid Build Coastguard Worker break;
2031*795d594fSAndroid Build Coastguard Worker case Primitive::kPrimInt:
2032*795d594fSAndroid Build Coastguard Worker os << StringPrintf("%d (0x%x)\n", field->Get32(obj), field->Get32(obj));
2033*795d594fSAndroid Build Coastguard Worker break;
2034*795d594fSAndroid Build Coastguard Worker case Primitive::kPrimChar:
2035*795d594fSAndroid Build Coastguard Worker os << StringPrintf("%u (0x%x)\n", field->GetChar(obj), field->GetChar(obj));
2036*795d594fSAndroid Build Coastguard Worker break;
2037*795d594fSAndroid Build Coastguard Worker case Primitive::kPrimShort:
2038*795d594fSAndroid Build Coastguard Worker os << StringPrintf("%d (0x%x)\n", field->GetShort(obj), field->GetShort(obj));
2039*795d594fSAndroid Build Coastguard Worker break;
2040*795d594fSAndroid Build Coastguard Worker case Primitive::kPrimBoolean:
2041*795d594fSAndroid Build Coastguard Worker os << StringPrintf("%s (0x%x)\n", field->GetBoolean(obj) ? "true" : "false",
2042*795d594fSAndroid Build Coastguard Worker field->GetBoolean(obj));
2043*795d594fSAndroid Build Coastguard Worker break;
2044*795d594fSAndroid Build Coastguard Worker case Primitive::kPrimByte:
2045*795d594fSAndroid Build Coastguard Worker os << StringPrintf("%d (0x%x)\n", field->GetByte(obj), field->GetByte(obj));
2046*795d594fSAndroid Build Coastguard Worker break;
2047*795d594fSAndroid Build Coastguard Worker case Primitive::kPrimNot: {
2048*795d594fSAndroid Build Coastguard Worker // Get the value, don't compute the type unless it is non-null as we don't want
2049*795d594fSAndroid Build Coastguard Worker // to cause class loading.
2050*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Object> value = field->GetObj(obj);
2051*795d594fSAndroid Build Coastguard Worker if (value == nullptr) {
2052*795d594fSAndroid Build Coastguard Worker os << StringPrintf("null %s\n", PrettyDescriptor(field->GetTypeDescriptor()).c_str());
2053*795d594fSAndroid Build Coastguard Worker } else {
2054*795d594fSAndroid Build Coastguard Worker // Grab the field type without causing resolution.
2055*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Class> field_type = field->LookupResolvedType();
2056*795d594fSAndroid Build Coastguard Worker if (field_type != nullptr) {
2057*795d594fSAndroid Build Coastguard Worker PrettyObjectValue(os, field_type, value);
2058*795d594fSAndroid Build Coastguard Worker } else {
2059*795d594fSAndroid Build Coastguard Worker os << StringPrintf("%p %s\n",
2060*795d594fSAndroid Build Coastguard Worker value.Ptr(),
2061*795d594fSAndroid Build Coastguard Worker PrettyDescriptor(field->GetTypeDescriptor()).c_str());
2062*795d594fSAndroid Build Coastguard Worker }
2063*795d594fSAndroid Build Coastguard Worker }
2064*795d594fSAndroid Build Coastguard Worker break;
2065*795d594fSAndroid Build Coastguard Worker }
2066*795d594fSAndroid Build Coastguard Worker default:
2067*795d594fSAndroid Build Coastguard Worker os << "unexpected field type: " << field->GetTypeDescriptor() << "\n";
2068*795d594fSAndroid Build Coastguard Worker break;
2069*795d594fSAndroid Build Coastguard Worker }
2070*795d594fSAndroid Build Coastguard Worker }
2071*795d594fSAndroid Build Coastguard Worker
DumpFields(std::ostream & os,mirror::Object * obj,ObjPtr<mirror::Class> klass)2072*795d594fSAndroid Build Coastguard Worker static void DumpFields(std::ostream& os, mirror::Object* obj, ObjPtr<mirror::Class> klass)
2073*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
2074*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Class> super = klass->GetSuperClass();
2075*795d594fSAndroid Build Coastguard Worker if (super != nullptr) {
2076*795d594fSAndroid Build Coastguard Worker DumpFields(os, obj, super);
2077*795d594fSAndroid Build Coastguard Worker }
2078*795d594fSAndroid Build Coastguard Worker for (ArtField& field : klass->GetIFields()) {
2079*795d594fSAndroid Build Coastguard Worker PrintField(os, &field, obj);
2080*795d594fSAndroid Build Coastguard Worker }
2081*795d594fSAndroid Build Coastguard Worker }
2082*795d594fSAndroid Build Coastguard Worker
InDumpSpace(const mirror::Object * object)2083*795d594fSAndroid Build Coastguard Worker bool InDumpSpace(const mirror::Object* object) {
2084*795d594fSAndroid Build Coastguard Worker return image_space_.Contains(object);
2085*795d594fSAndroid Build Coastguard Worker }
2086*795d594fSAndroid Build Coastguard Worker
GetQuickOatCodeBegin(ArtMethod * m)2087*795d594fSAndroid Build Coastguard Worker const void* GetQuickOatCodeBegin(ArtMethod* m) REQUIRES_SHARED(Locks::mutator_lock_) {
2088*795d594fSAndroid Build Coastguard Worker const void* quick_code = m->GetEntryPointFromQuickCompiledCodePtrSize(
2089*795d594fSAndroid Build Coastguard Worker image_header_.GetPointerSize());
2090*795d594fSAndroid Build Coastguard Worker ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
2091*795d594fSAndroid Build Coastguard Worker if (class_linker->IsQuickResolutionStub(quick_code) ||
2092*795d594fSAndroid Build Coastguard Worker class_linker->IsQuickToInterpreterBridge(quick_code) ||
2093*795d594fSAndroid Build Coastguard Worker class_linker->IsNterpTrampoline(quick_code) ||
2094*795d594fSAndroid Build Coastguard Worker class_linker->IsQuickGenericJniStub(quick_code) ||
2095*795d594fSAndroid Build Coastguard Worker class_linker->IsJniDlsymLookupStub(quick_code) ||
2096*795d594fSAndroid Build Coastguard Worker class_linker->IsJniDlsymLookupCriticalStub(quick_code)) {
2097*795d594fSAndroid Build Coastguard Worker quick_code = oat_dumper_->GetQuickOatCode(m);
2098*795d594fSAndroid Build Coastguard Worker }
2099*795d594fSAndroid Build Coastguard Worker if (oat_dumper_->GetInstructionSet() == InstructionSet::kThumb2) {
2100*795d594fSAndroid Build Coastguard Worker quick_code = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(quick_code) & ~0x1);
2101*795d594fSAndroid Build Coastguard Worker }
2102*795d594fSAndroid Build Coastguard Worker return quick_code;
2103*795d594fSAndroid Build Coastguard Worker }
2104*795d594fSAndroid Build Coastguard Worker
GetQuickOatCodeSize(ArtMethod * m)2105*795d594fSAndroid Build Coastguard Worker uint32_t GetQuickOatCodeSize(ArtMethod* m)
2106*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
2107*795d594fSAndroid Build Coastguard Worker const uint32_t* oat_code_begin = reinterpret_cast<const uint32_t*>(GetQuickOatCodeBegin(m));
2108*795d594fSAndroid Build Coastguard Worker if (oat_code_begin == nullptr) {
2109*795d594fSAndroid Build Coastguard Worker return 0;
2110*795d594fSAndroid Build Coastguard Worker }
2111*795d594fSAndroid Build Coastguard Worker OatQuickMethodHeader* method_header = reinterpret_cast<OatQuickMethodHeader*>(
2112*795d594fSAndroid Build Coastguard Worker reinterpret_cast<uintptr_t>(oat_code_begin) - sizeof(OatQuickMethodHeader));
2113*795d594fSAndroid Build Coastguard Worker return method_header->GetCodeSize();
2114*795d594fSAndroid Build Coastguard Worker }
2115*795d594fSAndroid Build Coastguard Worker
GetQuickOatCodeEnd(ArtMethod * m)2116*795d594fSAndroid Build Coastguard Worker const void* GetQuickOatCodeEnd(ArtMethod* m)
2117*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
2118*795d594fSAndroid Build Coastguard Worker const uint8_t* oat_code_begin = reinterpret_cast<const uint8_t*>(GetQuickOatCodeBegin(m));
2119*795d594fSAndroid Build Coastguard Worker if (oat_code_begin == nullptr) {
2120*795d594fSAndroid Build Coastguard Worker return nullptr;
2121*795d594fSAndroid Build Coastguard Worker }
2122*795d594fSAndroid Build Coastguard Worker return oat_code_begin + GetQuickOatCodeSize(m);
2123*795d594fSAndroid Build Coastguard Worker }
2124*795d594fSAndroid Build Coastguard Worker
DumpObject(mirror::Object * obj)2125*795d594fSAndroid Build Coastguard Worker void DumpObject(mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_) {
2126*795d594fSAndroid Build Coastguard Worker DCHECK(obj != nullptr);
2127*795d594fSAndroid Build Coastguard Worker if (!InDumpSpace(obj)) {
2128*795d594fSAndroid Build Coastguard Worker return;
2129*795d594fSAndroid Build Coastguard Worker }
2130*795d594fSAndroid Build Coastguard Worker
2131*795d594fSAndroid Build Coastguard Worker std::ostream& os = vios_.Stream();
2132*795d594fSAndroid Build Coastguard Worker
2133*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Class> obj_class = obj->GetClass();
2134*795d594fSAndroid Build Coastguard Worker if (obj_class->IsArrayClass()) {
2135*795d594fSAndroid Build Coastguard Worker os << StringPrintf("%p: %s length:%d\n", obj, obj_class->PrettyDescriptor().c_str(),
2136*795d594fSAndroid Build Coastguard Worker obj->AsArray()->GetLength());
2137*795d594fSAndroid Build Coastguard Worker } else if (obj_class->IsClassClass()) {
2138*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Class> klass = obj->AsClass();
2139*795d594fSAndroid Build Coastguard Worker os << StringPrintf("%p: java.lang.Class \"%s\" (",
2140*795d594fSAndroid Build Coastguard Worker obj,
2141*795d594fSAndroid Build Coastguard Worker mirror::Class::PrettyDescriptor(klass).c_str())
2142*795d594fSAndroid Build Coastguard Worker << klass->GetStatus() << ")\n";
2143*795d594fSAndroid Build Coastguard Worker } else if (obj_class->IsStringClass()) {
2144*795d594fSAndroid Build Coastguard Worker os << StringPrintf("%p: java.lang.String %s\n",
2145*795d594fSAndroid Build Coastguard Worker obj,
2146*795d594fSAndroid Build Coastguard Worker PrintableString(obj->AsString()->ToModifiedUtf8().c_str()).c_str());
2147*795d594fSAndroid Build Coastguard Worker } else {
2148*795d594fSAndroid Build Coastguard Worker os << StringPrintf("%p: %s\n", obj, obj_class->PrettyDescriptor().c_str());
2149*795d594fSAndroid Build Coastguard Worker }
2150*795d594fSAndroid Build Coastguard Worker ScopedIndentation indent1(&vios_);
2151*795d594fSAndroid Build Coastguard Worker DumpFields(os, obj, obj_class);
2152*795d594fSAndroid Build Coastguard Worker if (obj->IsObjectArray()) {
2153*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::ObjectArray<mirror::Object>> obj_array = obj->AsObjectArray<mirror::Object>();
2154*795d594fSAndroid Build Coastguard Worker for (int32_t i = 0, length = obj_array->GetLength(); i < length; i++) {
2155*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Object> value = obj_array->Get(i);
2156*795d594fSAndroid Build Coastguard Worker size_t run = 0;
2157*795d594fSAndroid Build Coastguard Worker for (int32_t j = i + 1; j < length; j++) {
2158*795d594fSAndroid Build Coastguard Worker if (value == obj_array->Get(j)) {
2159*795d594fSAndroid Build Coastguard Worker run++;
2160*795d594fSAndroid Build Coastguard Worker } else {
2161*795d594fSAndroid Build Coastguard Worker break;
2162*795d594fSAndroid Build Coastguard Worker }
2163*795d594fSAndroid Build Coastguard Worker }
2164*795d594fSAndroid Build Coastguard Worker if (run == 0) {
2165*795d594fSAndroid Build Coastguard Worker os << StringPrintf("%d: ", i);
2166*795d594fSAndroid Build Coastguard Worker } else {
2167*795d594fSAndroid Build Coastguard Worker os << StringPrintf("%d to %zd: ", i, i + run);
2168*795d594fSAndroid Build Coastguard Worker i = i + run;
2169*795d594fSAndroid Build Coastguard Worker }
2170*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Class> value_class =
2171*795d594fSAndroid Build Coastguard Worker (value == nullptr) ? obj_class->GetComponentType() : value->GetClass();
2172*795d594fSAndroid Build Coastguard Worker PrettyObjectValue(os, value_class, value);
2173*795d594fSAndroid Build Coastguard Worker }
2174*795d594fSAndroid Build Coastguard Worker } else if (obj_class->IsClassClass()) {
2175*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Class> klass = obj->AsClass();
2176*795d594fSAndroid Build Coastguard Worker
2177*795d594fSAndroid Build Coastguard Worker if (kBitstringSubtypeCheckEnabled) {
2178*795d594fSAndroid Build Coastguard Worker os << "SUBTYPE_CHECK_BITS: ";
2179*795d594fSAndroid Build Coastguard Worker SubtypeCheck<ObjPtr<mirror::Class>>::Dump(klass, os);
2180*795d594fSAndroid Build Coastguard Worker os << "\n";
2181*795d594fSAndroid Build Coastguard Worker }
2182*795d594fSAndroid Build Coastguard Worker
2183*795d594fSAndroid Build Coastguard Worker if (klass->ShouldHaveEmbeddedVTable()) {
2184*795d594fSAndroid Build Coastguard Worker os << "EMBEDDED VTABLE:\n";
2185*795d594fSAndroid Build Coastguard Worker ScopedIndentation indent2(&vios_);
2186*795d594fSAndroid Build Coastguard Worker const PointerSize pointer_size = image_header_.GetPointerSize();
2187*795d594fSAndroid Build Coastguard Worker for (size_t i = 0, length = klass->GetEmbeddedVTableLength(); i != length; ++i) {
2188*795d594fSAndroid Build Coastguard Worker os << i << ": "
2189*795d594fSAndroid Build Coastguard Worker << ArtMethod::PrettyMethod(klass->GetEmbeddedVTableEntry(i, pointer_size)) << '\n';
2190*795d594fSAndroid Build Coastguard Worker }
2191*795d594fSAndroid Build Coastguard Worker }
2192*795d594fSAndroid Build Coastguard Worker
2193*795d594fSAndroid Build Coastguard Worker if (klass->NumStaticFields() != 0) {
2194*795d594fSAndroid Build Coastguard Worker os << "STATICS:\n";
2195*795d594fSAndroid Build Coastguard Worker ScopedIndentation indent2(&vios_);
2196*795d594fSAndroid Build Coastguard Worker for (ArtField& field : klass->GetSFields()) {
2197*795d594fSAndroid Build Coastguard Worker PrintField(os, &field, field.GetDeclaringClass());
2198*795d594fSAndroid Build Coastguard Worker }
2199*795d594fSAndroid Build Coastguard Worker }
2200*795d594fSAndroid Build Coastguard Worker }
2201*795d594fSAndroid Build Coastguard Worker std::string temp;
2202*795d594fSAndroid Build Coastguard Worker const char* desc = obj_class->GetDescriptor(&temp);
2203*795d594fSAndroid Build Coastguard Worker desc = stats_.descriptors.emplace(desc).first->c_str(); // Dedup and keep alive.
2204*795d594fSAndroid Build Coastguard Worker stats_.object_stats[desc].AddBytes(obj->SizeOf());
2205*795d594fSAndroid Build Coastguard Worker }
2206*795d594fSAndroid Build Coastguard Worker
DumpMethod(ArtMethod * method,std::ostream & indent_os)2207*795d594fSAndroid Build Coastguard Worker void DumpMethod(ArtMethod* method, std::ostream& indent_os)
2208*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
2209*795d594fSAndroid Build Coastguard Worker DCHECK(method != nullptr);
2210*795d594fSAndroid Build Coastguard Worker const PointerSize pointer_size = image_header_.GetPointerSize();
2211*795d594fSAndroid Build Coastguard Worker if (method->IsNative()) {
2212*795d594fSAndroid Build Coastguard Worker const void* quick_oat_code_begin = GetQuickOatCodeBegin(method);
2213*795d594fSAndroid Build Coastguard Worker bool first_occurrence;
2214*795d594fSAndroid Build Coastguard Worker uint32_t quick_oat_code_size = GetQuickOatCodeSize(method);
2215*795d594fSAndroid Build Coastguard Worker ComputeOatSize(quick_oat_code_begin, &first_occurrence);
2216*795d594fSAndroid Build Coastguard Worker if (first_occurrence) {
2217*795d594fSAndroid Build Coastguard Worker stats_.oat_file_stats["native_code"].AddBytes(quick_oat_code_size);
2218*795d594fSAndroid Build Coastguard Worker }
2219*795d594fSAndroid Build Coastguard Worker if (quick_oat_code_begin != method->GetEntryPointFromQuickCompiledCodePtrSize(
2220*795d594fSAndroid Build Coastguard Worker image_header_.GetPointerSize())) {
2221*795d594fSAndroid Build Coastguard Worker indent_os << StringPrintf("OAT CODE: %p\n", quick_oat_code_begin);
2222*795d594fSAndroid Build Coastguard Worker }
2223*795d594fSAndroid Build Coastguard Worker } else if (method->IsAbstract() || method->IsClassInitializer()) {
2224*795d594fSAndroid Build Coastguard Worker // Don't print information for these.
2225*795d594fSAndroid Build Coastguard Worker } else if (method->IsRuntimeMethod()) {
2226*795d594fSAndroid Build Coastguard Worker if (method == Runtime::Current()->GetResolutionMethod()) {
2227*795d594fSAndroid Build Coastguard Worker const void* resolution_trampoline =
2228*795d594fSAndroid Build Coastguard Worker method->GetEntryPointFromQuickCompiledCodePtrSize(image_header_.GetPointerSize());
2229*795d594fSAndroid Build Coastguard Worker indent_os << StringPrintf("Resolution trampoline: %p\n", resolution_trampoline);
2230*795d594fSAndroid Build Coastguard Worker const void* critical_native_resolution_trampoline =
2231*795d594fSAndroid Build Coastguard Worker method->GetEntryPointFromJniPtrSize(image_header_.GetPointerSize());
2232*795d594fSAndroid Build Coastguard Worker indent_os << StringPrintf("Resolution trampoline for @CriticalNative: %p\n",
2233*795d594fSAndroid Build Coastguard Worker critical_native_resolution_trampoline);
2234*795d594fSAndroid Build Coastguard Worker } else {
2235*795d594fSAndroid Build Coastguard Worker ImtConflictTable* table = method->GetImtConflictTable(image_header_.GetPointerSize());
2236*795d594fSAndroid Build Coastguard Worker if (table != nullptr) {
2237*795d594fSAndroid Build Coastguard Worker indent_os << "IMT conflict table " << table << " method: ";
2238*795d594fSAndroid Build Coastguard Worker for (size_t i = 0, count = table->NumEntries(pointer_size); i < count; ++i) {
2239*795d594fSAndroid Build Coastguard Worker indent_os << ArtMethod::PrettyMethod(table->GetImplementationMethod(i, pointer_size))
2240*795d594fSAndroid Build Coastguard Worker << " ";
2241*795d594fSAndroid Build Coastguard Worker }
2242*795d594fSAndroid Build Coastguard Worker }
2243*795d594fSAndroid Build Coastguard Worker }
2244*795d594fSAndroid Build Coastguard Worker } else {
2245*795d594fSAndroid Build Coastguard Worker CodeItemDataAccessor code_item_accessor(method->DexInstructionData());
2246*795d594fSAndroid Build Coastguard Worker size_t dex_instruction_bytes = code_item_accessor.InsnsSizeInCodeUnits() * 2;
2247*795d594fSAndroid Build Coastguard Worker stats_.dex_instruction_bytes += dex_instruction_bytes;
2248*795d594fSAndroid Build Coastguard Worker
2249*795d594fSAndroid Build Coastguard Worker const void* quick_oat_code_begin = GetQuickOatCodeBegin(method);
2250*795d594fSAndroid Build Coastguard Worker const void* quick_oat_code_end = GetQuickOatCodeEnd(method);
2251*795d594fSAndroid Build Coastguard Worker
2252*795d594fSAndroid Build Coastguard Worker bool first_occurrence;
2253*795d594fSAndroid Build Coastguard Worker size_t vmap_table_bytes = 0u;
2254*795d594fSAndroid Build Coastguard Worker if (quick_oat_code_begin != nullptr) {
2255*795d594fSAndroid Build Coastguard Worker OatQuickMethodHeader* method_header = reinterpret_cast<OatQuickMethodHeader*>(
2256*795d594fSAndroid Build Coastguard Worker reinterpret_cast<uintptr_t>(quick_oat_code_begin) - sizeof(OatQuickMethodHeader));
2257*795d594fSAndroid Build Coastguard Worker vmap_table_bytes = ComputeOatSize(method_header->GetOptimizedCodeInfoPtr(),
2258*795d594fSAndroid Build Coastguard Worker &first_occurrence);
2259*795d594fSAndroid Build Coastguard Worker if (first_occurrence) {
2260*795d594fSAndroid Build Coastguard Worker stats_.vmap_table_bytes += vmap_table_bytes;
2261*795d594fSAndroid Build Coastguard Worker }
2262*795d594fSAndroid Build Coastguard Worker }
2263*795d594fSAndroid Build Coastguard Worker
2264*795d594fSAndroid Build Coastguard Worker uint32_t quick_oat_code_size = GetQuickOatCodeSize(method);
2265*795d594fSAndroid Build Coastguard Worker ComputeOatSize(quick_oat_code_begin, &first_occurrence);
2266*795d594fSAndroid Build Coastguard Worker if (first_occurrence) {
2267*795d594fSAndroid Build Coastguard Worker stats_.managed_code_bytes += quick_oat_code_size;
2268*795d594fSAndroid Build Coastguard Worker art::Stats& managed_code_stats = stats_.oat_file_stats["managed_code"];
2269*795d594fSAndroid Build Coastguard Worker managed_code_stats.AddBytes(quick_oat_code_size);
2270*795d594fSAndroid Build Coastguard Worker if (method->IsConstructor()) {
2271*795d594fSAndroid Build Coastguard Worker if (method->IsStatic()) {
2272*795d594fSAndroid Build Coastguard Worker managed_code_stats["class_initializer"].AddBytes(quick_oat_code_size);
2273*795d594fSAndroid Build Coastguard Worker } else if (dex_instruction_bytes > kLargeConstructorDexBytes) {
2274*795d594fSAndroid Build Coastguard Worker managed_code_stats["large_initializer"].AddBytes(quick_oat_code_size);
2275*795d594fSAndroid Build Coastguard Worker }
2276*795d594fSAndroid Build Coastguard Worker } else if (dex_instruction_bytes > kLargeMethodDexBytes) {
2277*795d594fSAndroid Build Coastguard Worker managed_code_stats["large_method"].AddBytes(quick_oat_code_size);
2278*795d594fSAndroid Build Coastguard Worker }
2279*795d594fSAndroid Build Coastguard Worker }
2280*795d594fSAndroid Build Coastguard Worker stats_.managed_code_bytes_ignoring_deduplication += quick_oat_code_size;
2281*795d594fSAndroid Build Coastguard Worker
2282*795d594fSAndroid Build Coastguard Worker uint32_t method_access_flags = method->GetAccessFlags();
2283*795d594fSAndroid Build Coastguard Worker
2284*795d594fSAndroid Build Coastguard Worker indent_os << StringPrintf("OAT CODE: %p-%p\n", quick_oat_code_begin, quick_oat_code_end);
2285*795d594fSAndroid Build Coastguard Worker indent_os << StringPrintf("SIZE: Dex Instructions=%zd StackMaps=%zd AccessFlags=0x%x\n",
2286*795d594fSAndroid Build Coastguard Worker dex_instruction_bytes,
2287*795d594fSAndroid Build Coastguard Worker vmap_table_bytes,
2288*795d594fSAndroid Build Coastguard Worker method_access_flags);
2289*795d594fSAndroid Build Coastguard Worker
2290*795d594fSAndroid Build Coastguard Worker size_t total_size = dex_instruction_bytes +
2291*795d594fSAndroid Build Coastguard Worker vmap_table_bytes + quick_oat_code_size + ArtMethod::Size(image_header_.GetPointerSize());
2292*795d594fSAndroid Build Coastguard Worker
2293*795d594fSAndroid Build Coastguard Worker double expansion =
2294*795d594fSAndroid Build Coastguard Worker static_cast<double>(quick_oat_code_size) / static_cast<double>(dex_instruction_bytes);
2295*795d594fSAndroid Build Coastguard Worker stats_.ComputeOutliers(total_size, expansion, method);
2296*795d594fSAndroid Build Coastguard Worker }
2297*795d594fSAndroid Build Coastguard Worker }
2298*795d594fSAndroid Build Coastguard Worker
2299*795d594fSAndroid Build Coastguard Worker std::set<const void*> already_seen_;
2300*795d594fSAndroid Build Coastguard Worker // Compute the size of the given data within the oat file and whether this is the first time
2301*795d594fSAndroid Build Coastguard Worker // this data has been requested
ComputeOatSize(const void * oat_data,bool * first_occurrence)2302*795d594fSAndroid Build Coastguard Worker size_t ComputeOatSize(const void* oat_data, bool* first_occurrence) {
2303*795d594fSAndroid Build Coastguard Worker if (already_seen_.count(oat_data) == 0) {
2304*795d594fSAndroid Build Coastguard Worker *first_occurrence = true;
2305*795d594fSAndroid Build Coastguard Worker already_seen_.insert(oat_data);
2306*795d594fSAndroid Build Coastguard Worker } else {
2307*795d594fSAndroid Build Coastguard Worker *first_occurrence = false;
2308*795d594fSAndroid Build Coastguard Worker }
2309*795d594fSAndroid Build Coastguard Worker return oat_dumper_->ComputeSize(oat_data);
2310*795d594fSAndroid Build Coastguard Worker }
2311*795d594fSAndroid Build Coastguard Worker
2312*795d594fSAndroid Build Coastguard Worker public:
2313*795d594fSAndroid Build Coastguard Worker struct Stats {
2314*795d594fSAndroid Build Coastguard Worker art::Stats art_file_stats;
2315*795d594fSAndroid Build Coastguard Worker art::Stats oat_file_stats;
2316*795d594fSAndroid Build Coastguard Worker art::Stats object_stats;
2317*795d594fSAndroid Build Coastguard Worker std::set<std::string> descriptors;
2318*795d594fSAndroid Build Coastguard Worker
2319*795d594fSAndroid Build Coastguard Worker size_t oat_file_bytes = 0u;
2320*795d594fSAndroid Build Coastguard Worker size_t managed_code_bytes = 0u;
2321*795d594fSAndroid Build Coastguard Worker size_t managed_code_bytes_ignoring_deduplication = 0u;
2322*795d594fSAndroid Build Coastguard Worker
2323*795d594fSAndroid Build Coastguard Worker size_t vmap_table_bytes = 0u;
2324*795d594fSAndroid Build Coastguard Worker
2325*795d594fSAndroid Build Coastguard Worker size_t dex_instruction_bytes = 0u;
2326*795d594fSAndroid Build Coastguard Worker
2327*795d594fSAndroid Build Coastguard Worker std::vector<ArtMethod*> method_outlier;
2328*795d594fSAndroid Build Coastguard Worker std::vector<size_t> method_outlier_size;
2329*795d594fSAndroid Build Coastguard Worker std::vector<double> method_outlier_expansion;
2330*795d594fSAndroid Build Coastguard Worker std::vector<std::pair<std::string, size_t>> oat_dex_file_sizes;
2331*795d594fSAndroid Build Coastguard Worker
Statsart::ImageDumper::Stats2332*795d594fSAndroid Build Coastguard Worker Stats() {}
2333*795d594fSAndroid Build Coastguard Worker
PercentOfOatBytesart::ImageDumper::Stats2334*795d594fSAndroid Build Coastguard Worker double PercentOfOatBytes(size_t size) {
2335*795d594fSAndroid Build Coastguard Worker return (static_cast<double>(size) / static_cast<double>(oat_file_bytes)) * 100;
2336*795d594fSAndroid Build Coastguard Worker }
2337*795d594fSAndroid Build Coastguard Worker
ComputeOutliersart::ImageDumper::Stats2338*795d594fSAndroid Build Coastguard Worker void ComputeOutliers(size_t total_size, double expansion, ArtMethod* method) {
2339*795d594fSAndroid Build Coastguard Worker method_outlier_size.push_back(total_size);
2340*795d594fSAndroid Build Coastguard Worker method_outlier_expansion.push_back(expansion);
2341*795d594fSAndroid Build Coastguard Worker method_outlier.push_back(method);
2342*795d594fSAndroid Build Coastguard Worker }
2343*795d594fSAndroid Build Coastguard Worker
DumpOutliersart::ImageDumper::Stats2344*795d594fSAndroid Build Coastguard Worker void DumpOutliers(std::ostream& os)
2345*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
2346*795d594fSAndroid Build Coastguard Worker size_t sum_of_sizes = 0;
2347*795d594fSAndroid Build Coastguard Worker size_t sum_of_sizes_squared = 0;
2348*795d594fSAndroid Build Coastguard Worker size_t sum_of_expansion = 0;
2349*795d594fSAndroid Build Coastguard Worker size_t sum_of_expansion_squared = 0;
2350*795d594fSAndroid Build Coastguard Worker size_t n = method_outlier_size.size();
2351*795d594fSAndroid Build Coastguard Worker if (n <= 1) {
2352*795d594fSAndroid Build Coastguard Worker return;
2353*795d594fSAndroid Build Coastguard Worker }
2354*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < n; i++) {
2355*795d594fSAndroid Build Coastguard Worker size_t cur_size = method_outlier_size[i];
2356*795d594fSAndroid Build Coastguard Worker sum_of_sizes += cur_size;
2357*795d594fSAndroid Build Coastguard Worker sum_of_sizes_squared += cur_size * cur_size;
2358*795d594fSAndroid Build Coastguard Worker double cur_expansion = method_outlier_expansion[i];
2359*795d594fSAndroid Build Coastguard Worker sum_of_expansion += cur_expansion;
2360*795d594fSAndroid Build Coastguard Worker sum_of_expansion_squared += cur_expansion * cur_expansion;
2361*795d594fSAndroid Build Coastguard Worker }
2362*795d594fSAndroid Build Coastguard Worker size_t size_mean = sum_of_sizes / n;
2363*795d594fSAndroid Build Coastguard Worker size_t size_variance = (sum_of_sizes_squared - sum_of_sizes * size_mean) / (n - 1);
2364*795d594fSAndroid Build Coastguard Worker double expansion_mean = sum_of_expansion / n;
2365*795d594fSAndroid Build Coastguard Worker double expansion_variance =
2366*795d594fSAndroid Build Coastguard Worker (sum_of_expansion_squared - sum_of_expansion * expansion_mean) / (n - 1);
2367*795d594fSAndroid Build Coastguard Worker
2368*795d594fSAndroid Build Coastguard Worker // Dump methods whose size is a certain number of standard deviations from the mean
2369*795d594fSAndroid Build Coastguard Worker size_t dumped_values = 0;
2370*795d594fSAndroid Build Coastguard Worker size_t skipped_values = 0;
2371*795d594fSAndroid Build Coastguard Worker for (size_t i = 100; i > 0; i--) { // i is the current number of standard deviations
2372*795d594fSAndroid Build Coastguard Worker size_t cur_size_variance = i * i * size_variance;
2373*795d594fSAndroid Build Coastguard Worker bool first = true;
2374*795d594fSAndroid Build Coastguard Worker for (size_t j = 0; j < n; j++) {
2375*795d594fSAndroid Build Coastguard Worker size_t cur_size = method_outlier_size[j];
2376*795d594fSAndroid Build Coastguard Worker if (cur_size > size_mean) {
2377*795d594fSAndroid Build Coastguard Worker size_t cur_var = cur_size - size_mean;
2378*795d594fSAndroid Build Coastguard Worker cur_var = cur_var * cur_var;
2379*795d594fSAndroid Build Coastguard Worker if (cur_var > cur_size_variance) {
2380*795d594fSAndroid Build Coastguard Worker if (dumped_values > 20) {
2381*795d594fSAndroid Build Coastguard Worker if (i == 1) {
2382*795d594fSAndroid Build Coastguard Worker skipped_values++;
2383*795d594fSAndroid Build Coastguard Worker } else {
2384*795d594fSAndroid Build Coastguard Worker i = 2; // jump to counting for 1 standard deviation
2385*795d594fSAndroid Build Coastguard Worker break;
2386*795d594fSAndroid Build Coastguard Worker }
2387*795d594fSAndroid Build Coastguard Worker } else {
2388*795d594fSAndroid Build Coastguard Worker if (first) {
2389*795d594fSAndroid Build Coastguard Worker os << "\nBig methods (size > " << i << " standard deviations the norm):\n";
2390*795d594fSAndroid Build Coastguard Worker first = false;
2391*795d594fSAndroid Build Coastguard Worker }
2392*795d594fSAndroid Build Coastguard Worker os << ArtMethod::PrettyMethod(method_outlier[j]) << " requires storage of "
2393*795d594fSAndroid Build Coastguard Worker << PrettySize(cur_size) << "\n";
2394*795d594fSAndroid Build Coastguard Worker method_outlier_size[j] = 0; // don't consider this method again
2395*795d594fSAndroid Build Coastguard Worker dumped_values++;
2396*795d594fSAndroid Build Coastguard Worker }
2397*795d594fSAndroid Build Coastguard Worker }
2398*795d594fSAndroid Build Coastguard Worker }
2399*795d594fSAndroid Build Coastguard Worker }
2400*795d594fSAndroid Build Coastguard Worker }
2401*795d594fSAndroid Build Coastguard Worker if (skipped_values > 0) {
2402*795d594fSAndroid Build Coastguard Worker os << "... skipped " << skipped_values
2403*795d594fSAndroid Build Coastguard Worker << " methods with size > 1 standard deviation from the norm\n";
2404*795d594fSAndroid Build Coastguard Worker }
2405*795d594fSAndroid Build Coastguard Worker os << std::flush;
2406*795d594fSAndroid Build Coastguard Worker
2407*795d594fSAndroid Build Coastguard Worker // Dump methods whose expansion is a certain number of standard deviations from the mean
2408*795d594fSAndroid Build Coastguard Worker dumped_values = 0;
2409*795d594fSAndroid Build Coastguard Worker skipped_values = 0;
2410*795d594fSAndroid Build Coastguard Worker for (size_t i = 10; i > 0; i--) { // i is the current number of standard deviations
2411*795d594fSAndroid Build Coastguard Worker double cur_expansion_variance = i * i * expansion_variance;
2412*795d594fSAndroid Build Coastguard Worker bool first = true;
2413*795d594fSAndroid Build Coastguard Worker for (size_t j = 0; j < n; j++) {
2414*795d594fSAndroid Build Coastguard Worker double cur_expansion = method_outlier_expansion[j];
2415*795d594fSAndroid Build Coastguard Worker if (cur_expansion > expansion_mean) {
2416*795d594fSAndroid Build Coastguard Worker size_t cur_var = cur_expansion - expansion_mean;
2417*795d594fSAndroid Build Coastguard Worker cur_var = cur_var * cur_var;
2418*795d594fSAndroid Build Coastguard Worker if (cur_var > cur_expansion_variance) {
2419*795d594fSAndroid Build Coastguard Worker if (dumped_values > 20) {
2420*795d594fSAndroid Build Coastguard Worker if (i == 1) {
2421*795d594fSAndroid Build Coastguard Worker skipped_values++;
2422*795d594fSAndroid Build Coastguard Worker } else {
2423*795d594fSAndroid Build Coastguard Worker i = 2; // jump to counting for 1 standard deviation
2424*795d594fSAndroid Build Coastguard Worker break;
2425*795d594fSAndroid Build Coastguard Worker }
2426*795d594fSAndroid Build Coastguard Worker } else {
2427*795d594fSAndroid Build Coastguard Worker if (first) {
2428*795d594fSAndroid Build Coastguard Worker os << "\nLarge expansion methods (size > " << i
2429*795d594fSAndroid Build Coastguard Worker << " standard deviations the norm):\n";
2430*795d594fSAndroid Build Coastguard Worker first = false;
2431*795d594fSAndroid Build Coastguard Worker }
2432*795d594fSAndroid Build Coastguard Worker os << ArtMethod::PrettyMethod(method_outlier[j]) << " expanded code by "
2433*795d594fSAndroid Build Coastguard Worker << cur_expansion << "\n";
2434*795d594fSAndroid Build Coastguard Worker method_outlier_expansion[j] = 0.0; // don't consider this method again
2435*795d594fSAndroid Build Coastguard Worker dumped_values++;
2436*795d594fSAndroid Build Coastguard Worker }
2437*795d594fSAndroid Build Coastguard Worker }
2438*795d594fSAndroid Build Coastguard Worker }
2439*795d594fSAndroid Build Coastguard Worker }
2440*795d594fSAndroid Build Coastguard Worker }
2441*795d594fSAndroid Build Coastguard Worker if (skipped_values > 0) {
2442*795d594fSAndroid Build Coastguard Worker os << "... skipped " << skipped_values
2443*795d594fSAndroid Build Coastguard Worker << " methods with expansion > 1 standard deviation from the norm\n";
2444*795d594fSAndroid Build Coastguard Worker }
2445*795d594fSAndroid Build Coastguard Worker os << "\n" << std::flush;
2446*795d594fSAndroid Build Coastguard Worker }
2447*795d594fSAndroid Build Coastguard Worker
Dumpart::ImageDumper::Stats2448*795d594fSAndroid Build Coastguard Worker void Dump(std::ostream& os)
2449*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
2450*795d594fSAndroid Build Coastguard Worker VariableIndentationOutputStream vios(&os);
2451*795d594fSAndroid Build Coastguard Worker art_file_stats.DumpSizes(vios, "ArtFile");
2452*795d594fSAndroid Build Coastguard Worker os << "\n" << std::flush;
2453*795d594fSAndroid Build Coastguard Worker object_stats.DumpSizes(vios, "Objects");
2454*795d594fSAndroid Build Coastguard Worker os << "\n" << std::flush;
2455*795d594fSAndroid Build Coastguard Worker oat_file_stats.DumpSizes(vios, "OatFile");
2456*795d594fSAndroid Build Coastguard Worker os << "\n" << std::flush;
2457*795d594fSAndroid Build Coastguard Worker
2458*795d594fSAndroid Build Coastguard Worker for (const std::pair<std::string, size_t>& oat_dex_file_size : oat_dex_file_sizes) {
2459*795d594fSAndroid Build Coastguard Worker os << StringPrintf("%s = %zd (%2.0f%% of oat file bytes)\n",
2460*795d594fSAndroid Build Coastguard Worker oat_dex_file_size.first.c_str(), oat_dex_file_size.second,
2461*795d594fSAndroid Build Coastguard Worker PercentOfOatBytes(oat_dex_file_size.second));
2462*795d594fSAndroid Build Coastguard Worker }
2463*795d594fSAndroid Build Coastguard Worker
2464*795d594fSAndroid Build Coastguard Worker os << "\n" << StringPrintf("vmap_table_bytes = %7zd (%2.0f%% of oat file bytes)\n\n",
2465*795d594fSAndroid Build Coastguard Worker vmap_table_bytes, PercentOfOatBytes(vmap_table_bytes))
2466*795d594fSAndroid Build Coastguard Worker << std::flush;
2467*795d594fSAndroid Build Coastguard Worker
2468*795d594fSAndroid Build Coastguard Worker os << StringPrintf("dex_instruction_bytes = %zd\n", dex_instruction_bytes)
2469*795d594fSAndroid Build Coastguard Worker << StringPrintf("managed_code_bytes expansion = %.2f (ignoring deduplication %.2f)\n\n",
2470*795d594fSAndroid Build Coastguard Worker static_cast<double>(managed_code_bytes) /
2471*795d594fSAndroid Build Coastguard Worker static_cast<double>(dex_instruction_bytes),
2472*795d594fSAndroid Build Coastguard Worker static_cast<double>(managed_code_bytes_ignoring_deduplication) /
2473*795d594fSAndroid Build Coastguard Worker static_cast<double>(dex_instruction_bytes))
2474*795d594fSAndroid Build Coastguard Worker << std::flush;
2475*795d594fSAndroid Build Coastguard Worker
2476*795d594fSAndroid Build Coastguard Worker DumpOutliers(os);
2477*795d594fSAndroid Build Coastguard Worker }
2478*795d594fSAndroid Build Coastguard Worker } stats_;
2479*795d594fSAndroid Build Coastguard Worker
2480*795d594fSAndroid Build Coastguard Worker private:
2481*795d594fSAndroid Build Coastguard Worker enum {
2482*795d594fSAndroid Build Coastguard Worker // Number of bytes for a constructor to be considered large. Based on the 1000 basic block
2483*795d594fSAndroid Build Coastguard Worker // threshold, we assume 2 bytes per instruction and 2 instructions per block.
2484*795d594fSAndroid Build Coastguard Worker kLargeConstructorDexBytes = 4000,
2485*795d594fSAndroid Build Coastguard Worker // Number of bytes for a method to be considered large. Based on the 4000 basic block
2486*795d594fSAndroid Build Coastguard Worker // threshold, we assume 2 bytes per instruction and 2 instructions per block.
2487*795d594fSAndroid Build Coastguard Worker kLargeMethodDexBytes = 16000
2488*795d594fSAndroid Build Coastguard Worker };
2489*795d594fSAndroid Build Coastguard Worker
2490*795d594fSAndroid Build Coastguard Worker // For performance, use the *os_ directly for anything that doesn't need indentation
2491*795d594fSAndroid Build Coastguard Worker // and prepare an indentation stream with default indentation 1.
2492*795d594fSAndroid Build Coastguard Worker std::ostream* os_;
2493*795d594fSAndroid Build Coastguard Worker VariableIndentationOutputStream vios_;
2494*795d594fSAndroid Build Coastguard Worker ScopedIndentation indent1_;
2495*795d594fSAndroid Build Coastguard Worker
2496*795d594fSAndroid Build Coastguard Worker gc::space::ImageSpace& image_space_;
2497*795d594fSAndroid Build Coastguard Worker const ImageHeader& image_header_;
2498*795d594fSAndroid Build Coastguard Worker std::unique_ptr<OatDumper> oat_dumper_;
2499*795d594fSAndroid Build Coastguard Worker OatDumperOptions* oat_dumper_options_;
2500*795d594fSAndroid Build Coastguard Worker
2501*795d594fSAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(ImageDumper);
2502*795d594fSAndroid Build Coastguard Worker };
2503*795d594fSAndroid Build Coastguard Worker
OpenOat(const std::string & oat_filename,const std::optional<std::string> & dex_filename,std::string * error_msg)2504*795d594fSAndroid Build Coastguard Worker static std::unique_ptr<OatFile> OpenOat(const std::string& oat_filename,
2505*795d594fSAndroid Build Coastguard Worker const std::optional<std::string>& dex_filename,
2506*795d594fSAndroid Build Coastguard Worker std::string* error_msg) {
2507*795d594fSAndroid Build Coastguard Worker if (!dex_filename.has_value()) {
2508*795d594fSAndroid Build Coastguard Worker LOG(WARNING) << "No dex filename provided, "
2509*795d594fSAndroid Build Coastguard Worker << "oatdump might fail if the oat file does not contain the dex code.";
2510*795d594fSAndroid Build Coastguard Worker }
2511*795d594fSAndroid Build Coastguard Worker ArrayRef<const std::string> dex_filenames =
2512*795d594fSAndroid Build Coastguard Worker dex_filename.has_value() ? ArrayRef<const std::string>(&dex_filename.value(), /*size=*/1) :
2513*795d594fSAndroid Build Coastguard Worker ArrayRef<const std::string>();
2514*795d594fSAndroid Build Coastguard Worker return std::unique_ptr<OatFile>(OatFile::Open(/*zip_fd=*/-1,
2515*795d594fSAndroid Build Coastguard Worker oat_filename,
2516*795d594fSAndroid Build Coastguard Worker oat_filename,
2517*795d594fSAndroid Build Coastguard Worker /*executable=*/false,
2518*795d594fSAndroid Build Coastguard Worker /*low_4gb=*/false,
2519*795d594fSAndroid Build Coastguard Worker dex_filenames,
2520*795d594fSAndroid Build Coastguard Worker /*dex_files=*/{},
2521*795d594fSAndroid Build Coastguard Worker /*reservation=*/nullptr,
2522*795d594fSAndroid Build Coastguard Worker error_msg));
2523*795d594fSAndroid Build Coastguard Worker }
2524*795d594fSAndroid Build Coastguard Worker
DumpImage(gc::space::ImageSpace * image_space,OatDumperOptions * options,std::ostream * os)2525*795d594fSAndroid Build Coastguard Worker static int DumpImage(gc::space::ImageSpace* image_space,
2526*795d594fSAndroid Build Coastguard Worker OatDumperOptions* options,
2527*795d594fSAndroid Build Coastguard Worker std::ostream* os) REQUIRES_SHARED(Locks::mutator_lock_) {
2528*795d594fSAndroid Build Coastguard Worker const ImageHeader& image_header = image_space->GetImageHeader();
2529*795d594fSAndroid Build Coastguard Worker if (!image_header.IsValid()) {
2530*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "Invalid image header " << image_space->GetImageLocation();
2531*795d594fSAndroid Build Coastguard Worker return EXIT_FAILURE;
2532*795d594fSAndroid Build Coastguard Worker }
2533*795d594fSAndroid Build Coastguard Worker ImageDumper image_dumper(os, *image_space, image_header, options);
2534*795d594fSAndroid Build Coastguard Worker if (!image_dumper.Dump()) {
2535*795d594fSAndroid Build Coastguard Worker return EXIT_FAILURE;
2536*795d594fSAndroid Build Coastguard Worker }
2537*795d594fSAndroid Build Coastguard Worker return EXIT_SUCCESS;
2538*795d594fSAndroid Build Coastguard Worker }
2539*795d594fSAndroid Build Coastguard Worker
DumpImages(Runtime * runtime,OatDumperOptions * options,std::ostream * os)2540*795d594fSAndroid Build Coastguard Worker static int DumpImages(Runtime* runtime, OatDumperOptions* options, std::ostream* os) {
2541*795d594fSAndroid Build Coastguard Worker // Dumping the image, no explicit class loader.
2542*795d594fSAndroid Build Coastguard Worker ScopedNullHandle<mirror::ClassLoader> null_class_loader;
2543*795d594fSAndroid Build Coastguard Worker options->class_loader_ = &null_class_loader;
2544*795d594fSAndroid Build Coastguard Worker
2545*795d594fSAndroid Build Coastguard Worker if (options->app_image_ != nullptr) {
2546*795d594fSAndroid Build Coastguard Worker if (!options->oat_filename_.has_value()) {
2547*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "Can not dump app image without app oat file";
2548*795d594fSAndroid Build Coastguard Worker return EXIT_FAILURE;
2549*795d594fSAndroid Build Coastguard Worker }
2550*795d594fSAndroid Build Coastguard Worker // We can't know if the app image is 32 bits yet, but it contains pointers into the oat file.
2551*795d594fSAndroid Build Coastguard Worker // We need to map the oat file in the low 4gb or else the fixup wont be able to fit oat file
2552*795d594fSAndroid Build Coastguard Worker // pointers into 32 bit pointer sized ArtMethods.
2553*795d594fSAndroid Build Coastguard Worker std::string error_msg;
2554*795d594fSAndroid Build Coastguard Worker std::unique_ptr<OatFile> oat_file =
2555*795d594fSAndroid Build Coastguard Worker OpenOat(*options->oat_filename_, options->dex_filename_, &error_msg);
2556*795d594fSAndroid Build Coastguard Worker if (oat_file == nullptr) {
2557*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "Failed to open oat file " << *options->oat_filename_ << " with error "
2558*795d594fSAndroid Build Coastguard Worker << error_msg;
2559*795d594fSAndroid Build Coastguard Worker return EXIT_FAILURE;
2560*795d594fSAndroid Build Coastguard Worker }
2561*795d594fSAndroid Build Coastguard Worker std::unique_ptr<gc::space::ImageSpace> space(
2562*795d594fSAndroid Build Coastguard Worker gc::space::ImageSpace::CreateFromAppImage(options->app_image_, oat_file.get(), &error_msg));
2563*795d594fSAndroid Build Coastguard Worker if (space == nullptr) {
2564*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "Failed to open app image " << options->app_image_ << " with error "
2565*795d594fSAndroid Build Coastguard Worker << error_msg;
2566*795d594fSAndroid Build Coastguard Worker return EXIT_FAILURE;
2567*795d594fSAndroid Build Coastguard Worker }
2568*795d594fSAndroid Build Coastguard Worker // Open dex files for the image.
2569*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(Thread::Current());
2570*795d594fSAndroid Build Coastguard Worker std::vector<std::unique_ptr<const DexFile>> dex_files;
2571*795d594fSAndroid Build Coastguard Worker if (!runtime->GetClassLinker()->OpenImageDexFiles(space.get(), &dex_files, &error_msg)) {
2572*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "Failed to open app image dex files " << options->app_image_ << " with error "
2573*795d594fSAndroid Build Coastguard Worker << error_msg;
2574*795d594fSAndroid Build Coastguard Worker return EXIT_FAILURE;
2575*795d594fSAndroid Build Coastguard Worker }
2576*795d594fSAndroid Build Coastguard Worker // Dump the actual image.
2577*795d594fSAndroid Build Coastguard Worker return DumpImage(space.get(), options, os);
2578*795d594fSAndroid Build Coastguard Worker }
2579*795d594fSAndroid Build Coastguard Worker
2580*795d594fSAndroid Build Coastguard Worker gc::Heap* heap = runtime->GetHeap();
2581*795d594fSAndroid Build Coastguard Worker if (!heap->HasBootImageSpace()) {
2582*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "No image spaces";
2583*795d594fSAndroid Build Coastguard Worker return EXIT_FAILURE;
2584*795d594fSAndroid Build Coastguard Worker }
2585*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(Thread::Current());
2586*795d594fSAndroid Build Coastguard Worker for (gc::space::ImageSpace* image_space : heap->GetBootImageSpaces()) {
2587*795d594fSAndroid Build Coastguard Worker int result = DumpImage(image_space, options, os);
2588*795d594fSAndroid Build Coastguard Worker if (result != EXIT_SUCCESS) {
2589*795d594fSAndroid Build Coastguard Worker return result;
2590*795d594fSAndroid Build Coastguard Worker }
2591*795d594fSAndroid Build Coastguard Worker }
2592*795d594fSAndroid Build Coastguard Worker return EXIT_SUCCESS;
2593*795d594fSAndroid Build Coastguard Worker }
2594*795d594fSAndroid Build Coastguard Worker
InstallOatFile(Runtime * runtime,std::unique_ptr<OatFile> oat_file,std::vector<const DexFile * > * class_path)2595*795d594fSAndroid Build Coastguard Worker static jobject InstallOatFile(Runtime* runtime,
2596*795d594fSAndroid Build Coastguard Worker std::unique_ptr<OatFile> oat_file,
2597*795d594fSAndroid Build Coastguard Worker std::vector<const DexFile*>* class_path)
2598*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
2599*795d594fSAndroid Build Coastguard Worker Thread* self = Thread::Current();
2600*795d594fSAndroid Build Coastguard Worker CHECK(self != nullptr);
2601*795d594fSAndroid Build Coastguard Worker // Need well-known-classes.
2602*795d594fSAndroid Build Coastguard Worker WellKnownClasses::Init(self->GetJniEnv());
2603*795d594fSAndroid Build Coastguard Worker
2604*795d594fSAndroid Build Coastguard Worker // Open dex files.
2605*795d594fSAndroid Build Coastguard Worker OatFile* oat_file_ptr = oat_file.get();
2606*795d594fSAndroid Build Coastguard Worker ClassLinker* class_linker = runtime->GetClassLinker();
2607*795d594fSAndroid Build Coastguard Worker runtime->GetOatFileManager().RegisterOatFile(std::move(oat_file));
2608*795d594fSAndroid Build Coastguard Worker for (const OatDexFile* odf : oat_file_ptr->GetOatDexFiles()) {
2609*795d594fSAndroid Build Coastguard Worker std::string error_msg;
2610*795d594fSAndroid Build Coastguard Worker const DexFile* const dex_file = OpenDexFile(odf, &error_msg);
2611*795d594fSAndroid Build Coastguard Worker CHECK(dex_file != nullptr) << error_msg;
2612*795d594fSAndroid Build Coastguard Worker class_path->push_back(dex_file);
2613*795d594fSAndroid Build Coastguard Worker }
2614*795d594fSAndroid Build Coastguard Worker
2615*795d594fSAndroid Build Coastguard Worker // Need a class loader. Fake that we're a compiler.
2616*795d594fSAndroid Build Coastguard Worker // Note: this will run initializers through the unstarted runtime, so make sure it's
2617*795d594fSAndroid Build Coastguard Worker // initialized.
2618*795d594fSAndroid Build Coastguard Worker interpreter::UnstartedRuntime::Initialize();
2619*795d594fSAndroid Build Coastguard Worker
2620*795d594fSAndroid Build Coastguard Worker jobject class_loader = class_linker->CreatePathClassLoader(self, *class_path);
2621*795d594fSAndroid Build Coastguard Worker
2622*795d594fSAndroid Build Coastguard Worker // Need to register dex files to get a working dex cache.
2623*795d594fSAndroid Build Coastguard Worker for (const DexFile* dex_file : *class_path) {
2624*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::DexCache> dex_cache = class_linker->RegisterDexFile(
2625*795d594fSAndroid Build Coastguard Worker *dex_file, self->DecodeJObject(class_loader)->AsClassLoader());
2626*795d594fSAndroid Build Coastguard Worker CHECK(dex_cache != nullptr);
2627*795d594fSAndroid Build Coastguard Worker }
2628*795d594fSAndroid Build Coastguard Worker
2629*795d594fSAndroid Build Coastguard Worker return class_loader;
2630*795d594fSAndroid Build Coastguard Worker }
2631*795d594fSAndroid Build Coastguard Worker
DumpOatWithRuntime(Runtime * runtime,std::unique_ptr<OatFile> oat_file,OatDumperOptions * options,std::ostream * os)2632*795d594fSAndroid Build Coastguard Worker static int DumpOatWithRuntime(Runtime* runtime,
2633*795d594fSAndroid Build Coastguard Worker std::unique_ptr<OatFile> oat_file,
2634*795d594fSAndroid Build Coastguard Worker OatDumperOptions* options,
2635*795d594fSAndroid Build Coastguard Worker std::ostream* os) {
2636*795d594fSAndroid Build Coastguard Worker CHECK(runtime != nullptr && oat_file != nullptr && options != nullptr);
2637*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(Thread::Current());
2638*795d594fSAndroid Build Coastguard Worker
2639*795d594fSAndroid Build Coastguard Worker OatFile* oat_file_ptr = oat_file.get();
2640*795d594fSAndroid Build Coastguard Worker std::vector<const DexFile*> class_path;
2641*795d594fSAndroid Build Coastguard Worker jobject class_loader = InstallOatFile(runtime, std::move(oat_file), &class_path);
2642*795d594fSAndroid Build Coastguard Worker
2643*795d594fSAndroid Build Coastguard Worker // Use the class loader while dumping.
2644*795d594fSAndroid Build Coastguard Worker StackHandleScope<1> scope(soa.Self());
2645*795d594fSAndroid Build Coastguard Worker Handle<mirror::ClassLoader> loader_handle = scope.NewHandle(
2646*795d594fSAndroid Build Coastguard Worker soa.Decode<mirror::ClassLoader>(class_loader));
2647*795d594fSAndroid Build Coastguard Worker options->class_loader_ = &loader_handle;
2648*795d594fSAndroid Build Coastguard Worker
2649*795d594fSAndroid Build Coastguard Worker OatDumper oat_dumper(*oat_file_ptr, *options);
2650*795d594fSAndroid Build Coastguard Worker bool success = oat_dumper.Dump(*os);
2651*795d594fSAndroid Build Coastguard Worker return (success) ? EXIT_SUCCESS : EXIT_FAILURE;
2652*795d594fSAndroid Build Coastguard Worker }
2653*795d594fSAndroid Build Coastguard Worker
DumpOatWithoutRuntime(OatFile * oat_file,OatDumperOptions * options,std::ostream * os)2654*795d594fSAndroid Build Coastguard Worker static int DumpOatWithoutRuntime(OatFile* oat_file, OatDumperOptions* options, std::ostream* os) {
2655*795d594fSAndroid Build Coastguard Worker CHECK(oat_file != nullptr && options != nullptr);
2656*795d594fSAndroid Build Coastguard Worker // No image = no class loader.
2657*795d594fSAndroid Build Coastguard Worker ScopedNullHandle<mirror::ClassLoader> null_class_loader;
2658*795d594fSAndroid Build Coastguard Worker options->class_loader_ = &null_class_loader;
2659*795d594fSAndroid Build Coastguard Worker
2660*795d594fSAndroid Build Coastguard Worker OatDumper oat_dumper(*oat_file, *options);
2661*795d594fSAndroid Build Coastguard Worker bool success = oat_dumper.Dump(*os);
2662*795d594fSAndroid Build Coastguard Worker return (success) ? EXIT_SUCCESS : EXIT_FAILURE;
2663*795d594fSAndroid Build Coastguard Worker }
2664*795d594fSAndroid Build Coastguard Worker
DumpOat(Runtime * runtime,OatDumperOptions * options,std::ostream * os)2665*795d594fSAndroid Build Coastguard Worker static int DumpOat(Runtime* runtime, OatDumperOptions* options, std::ostream* os) {
2666*795d594fSAndroid Build Coastguard Worker std::string error_msg;
2667*795d594fSAndroid Build Coastguard Worker std::unique_ptr<OatFile> oat_file =
2668*795d594fSAndroid Build Coastguard Worker OpenOat(*options->oat_filename_, options->dex_filename_, &error_msg);
2669*795d594fSAndroid Build Coastguard Worker if (oat_file == nullptr) {
2670*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "Failed to open oat file from '" << *options->oat_filename_ << "': " << error_msg;
2671*795d594fSAndroid Build Coastguard Worker return EXIT_FAILURE;
2672*795d594fSAndroid Build Coastguard Worker }
2673*795d594fSAndroid Build Coastguard Worker
2674*795d594fSAndroid Build Coastguard Worker if (runtime != nullptr) {
2675*795d594fSAndroid Build Coastguard Worker return DumpOatWithRuntime(runtime, std::move(oat_file), options, os);
2676*795d594fSAndroid Build Coastguard Worker } else {
2677*795d594fSAndroid Build Coastguard Worker return DumpOatWithoutRuntime(oat_file.get(), options, os);
2678*795d594fSAndroid Build Coastguard Worker }
2679*795d594fSAndroid Build Coastguard Worker }
2680*795d594fSAndroid Build Coastguard Worker
SymbolizeOat(const char * oat_filename,const char * dex_filename,std::string & output_name,bool no_bits)2681*795d594fSAndroid Build Coastguard Worker static int SymbolizeOat(const char* oat_filename,
2682*795d594fSAndroid Build Coastguard Worker const char* dex_filename,
2683*795d594fSAndroid Build Coastguard Worker std::string& output_name,
2684*795d594fSAndroid Build Coastguard Worker bool no_bits) {
2685*795d594fSAndroid Build Coastguard Worker std::string error_msg;
2686*795d594fSAndroid Build Coastguard Worker std::unique_ptr<OatFile> oat_file =
2687*795d594fSAndroid Build Coastguard Worker OpenOat(oat_filename,
2688*795d594fSAndroid Build Coastguard Worker dex_filename != nullptr ? std::make_optional(dex_filename) : std::nullopt,
2689*795d594fSAndroid Build Coastguard Worker &error_msg);
2690*795d594fSAndroid Build Coastguard Worker if (oat_file == nullptr) {
2691*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "Failed to open oat file from '" << oat_filename << "': " << error_msg;
2692*795d594fSAndroid Build Coastguard Worker return EXIT_FAILURE;
2693*795d594fSAndroid Build Coastguard Worker }
2694*795d594fSAndroid Build Coastguard Worker
2695*795d594fSAndroid Build Coastguard Worker bool result;
2696*795d594fSAndroid Build Coastguard Worker // Try to produce an ELF file of the same type. This is finicky, as we have used 32-bit ELF
2697*795d594fSAndroid Build Coastguard Worker // files for 64-bit code in the past.
2698*795d594fSAndroid Build Coastguard Worker if (Is64BitInstructionSet(oat_file->GetOatHeader().GetInstructionSet())) {
2699*795d594fSAndroid Build Coastguard Worker OatSymbolizer<ElfTypes64> oat_symbolizer(oat_file.get(), output_name, no_bits);
2700*795d594fSAndroid Build Coastguard Worker result = oat_symbolizer.Symbolize();
2701*795d594fSAndroid Build Coastguard Worker } else {
2702*795d594fSAndroid Build Coastguard Worker OatSymbolizer<ElfTypes32> oat_symbolizer(oat_file.get(), output_name, no_bits);
2703*795d594fSAndroid Build Coastguard Worker result = oat_symbolizer.Symbolize();
2704*795d594fSAndroid Build Coastguard Worker }
2705*795d594fSAndroid Build Coastguard Worker if (!result) {
2706*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "Failed to symbolize";
2707*795d594fSAndroid Build Coastguard Worker return EXIT_FAILURE;
2708*795d594fSAndroid Build Coastguard Worker }
2709*795d594fSAndroid Build Coastguard Worker
2710*795d594fSAndroid Build Coastguard Worker return EXIT_SUCCESS;
2711*795d594fSAndroid Build Coastguard Worker }
2712*795d594fSAndroid Build Coastguard Worker
2713*795d594fSAndroid Build Coastguard Worker class IMTDumper {
2714*795d594fSAndroid Build Coastguard Worker public:
Dump(Runtime * runtime,const std::string & imt_file,bool dump_imt_stats,const char * oat_filename,const char * dex_filename)2715*795d594fSAndroid Build Coastguard Worker static bool Dump(Runtime* runtime,
2716*795d594fSAndroid Build Coastguard Worker const std::string& imt_file,
2717*795d594fSAndroid Build Coastguard Worker bool dump_imt_stats,
2718*795d594fSAndroid Build Coastguard Worker const char* oat_filename,
2719*795d594fSAndroid Build Coastguard Worker const char* dex_filename) {
2720*795d594fSAndroid Build Coastguard Worker Thread* self = Thread::Current();
2721*795d594fSAndroid Build Coastguard Worker
2722*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(self);
2723*795d594fSAndroid Build Coastguard Worker StackHandleScope<1> scope(self);
2724*795d594fSAndroid Build Coastguard Worker MutableHandle<mirror::ClassLoader> class_loader = scope.NewHandle<mirror::ClassLoader>(nullptr);
2725*795d594fSAndroid Build Coastguard Worker std::vector<const DexFile*> class_path;
2726*795d594fSAndroid Build Coastguard Worker
2727*795d594fSAndroid Build Coastguard Worker if (oat_filename != nullptr) {
2728*795d594fSAndroid Build Coastguard Worker std::string error_msg;
2729*795d594fSAndroid Build Coastguard Worker std::unique_ptr<OatFile> oat_file =
2730*795d594fSAndroid Build Coastguard Worker OpenOat(oat_filename,
2731*795d594fSAndroid Build Coastguard Worker dex_filename != nullptr ? std::make_optional(dex_filename) : std::nullopt,
2732*795d594fSAndroid Build Coastguard Worker &error_msg);
2733*795d594fSAndroid Build Coastguard Worker if (oat_file == nullptr) {
2734*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "Failed to open oat file from '" << oat_filename << "': " << error_msg;
2735*795d594fSAndroid Build Coastguard Worker return false;
2736*795d594fSAndroid Build Coastguard Worker }
2737*795d594fSAndroid Build Coastguard Worker
2738*795d594fSAndroid Build Coastguard Worker class_loader.Assign(soa.Decode<mirror::ClassLoader>(
2739*795d594fSAndroid Build Coastguard Worker InstallOatFile(runtime, std::move(oat_file), &class_path)));
2740*795d594fSAndroid Build Coastguard Worker } else {
2741*795d594fSAndroid Build Coastguard Worker class_loader.Assign(nullptr); // Boot classloader. Just here for explicit documentation.
2742*795d594fSAndroid Build Coastguard Worker class_path = runtime->GetClassLinker()->GetBootClassPath();
2743*795d594fSAndroid Build Coastguard Worker }
2744*795d594fSAndroid Build Coastguard Worker
2745*795d594fSAndroid Build Coastguard Worker if (!imt_file.empty()) {
2746*795d594fSAndroid Build Coastguard Worker return DumpImt(runtime, imt_file, class_loader);
2747*795d594fSAndroid Build Coastguard Worker }
2748*795d594fSAndroid Build Coastguard Worker
2749*795d594fSAndroid Build Coastguard Worker if (dump_imt_stats) {
2750*795d594fSAndroid Build Coastguard Worker return DumpImtStats(runtime, class_path, class_loader);
2751*795d594fSAndroid Build Coastguard Worker }
2752*795d594fSAndroid Build Coastguard Worker
2753*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Should not reach here";
2754*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
2755*795d594fSAndroid Build Coastguard Worker }
2756*795d594fSAndroid Build Coastguard Worker
2757*795d594fSAndroid Build Coastguard Worker private:
DumpImt(Runtime * runtime,const std::string & imt_file,Handle<mirror::ClassLoader> h_class_loader)2758*795d594fSAndroid Build Coastguard Worker static bool DumpImt(Runtime* runtime,
2759*795d594fSAndroid Build Coastguard Worker const std::string& imt_file,
2760*795d594fSAndroid Build Coastguard Worker Handle<mirror::ClassLoader> h_class_loader)
2761*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
2762*795d594fSAndroid Build Coastguard Worker std::vector<std::string> lines = ReadCommentedInputFromFile(imt_file);
2763*795d594fSAndroid Build Coastguard Worker std::unordered_set<std::string> prepared;
2764*795d594fSAndroid Build Coastguard Worker
2765*795d594fSAndroid Build Coastguard Worker for (const std::string& line : lines) {
2766*795d594fSAndroid Build Coastguard Worker // A line should be either a class descriptor, in which case we will dump the complete IMT,
2767*795d594fSAndroid Build Coastguard Worker // or a class descriptor and an interface method, in which case we will lookup the method,
2768*795d594fSAndroid Build Coastguard Worker // determine its IMT slot, and check the class' IMT.
2769*795d594fSAndroid Build Coastguard Worker size_t first_space = line.find(' ');
2770*795d594fSAndroid Build Coastguard Worker if (first_space == std::string::npos) {
2771*795d594fSAndroid Build Coastguard Worker DumpIMTForClass(runtime, line, h_class_loader, &prepared);
2772*795d594fSAndroid Build Coastguard Worker } else {
2773*795d594fSAndroid Build Coastguard Worker DumpIMTForMethod(runtime,
2774*795d594fSAndroid Build Coastguard Worker line.substr(0, first_space),
2775*795d594fSAndroid Build Coastguard Worker line.substr(first_space + 1, std::string::npos),
2776*795d594fSAndroid Build Coastguard Worker h_class_loader,
2777*795d594fSAndroid Build Coastguard Worker &prepared);
2778*795d594fSAndroid Build Coastguard Worker }
2779*795d594fSAndroid Build Coastguard Worker std::cerr << std::endl;
2780*795d594fSAndroid Build Coastguard Worker }
2781*795d594fSAndroid Build Coastguard Worker
2782*795d594fSAndroid Build Coastguard Worker return true;
2783*795d594fSAndroid Build Coastguard Worker }
2784*795d594fSAndroid Build Coastguard Worker
DumpImtStats(Runtime * runtime,const std::vector<const DexFile * > & dex_files,Handle<mirror::ClassLoader> h_class_loader)2785*795d594fSAndroid Build Coastguard Worker static bool DumpImtStats(Runtime* runtime,
2786*795d594fSAndroid Build Coastguard Worker const std::vector<const DexFile*>& dex_files,
2787*795d594fSAndroid Build Coastguard Worker Handle<mirror::ClassLoader> h_class_loader)
2788*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
2789*795d594fSAndroid Build Coastguard Worker size_t without_imt = 0;
2790*795d594fSAndroid Build Coastguard Worker size_t with_imt = 0;
2791*795d594fSAndroid Build Coastguard Worker std::map<size_t, size_t> histogram;
2792*795d594fSAndroid Build Coastguard Worker
2793*795d594fSAndroid Build Coastguard Worker ClassLinker* class_linker = runtime->GetClassLinker();
2794*795d594fSAndroid Build Coastguard Worker const PointerSize pointer_size = class_linker->GetImagePointerSize();
2795*795d594fSAndroid Build Coastguard Worker std::unordered_set<std::string> prepared;
2796*795d594fSAndroid Build Coastguard Worker
2797*795d594fSAndroid Build Coastguard Worker Thread* self = Thread::Current();
2798*795d594fSAndroid Build Coastguard Worker StackHandleScope<1> scope(self);
2799*795d594fSAndroid Build Coastguard Worker MutableHandle<mirror::Class> h_klass(scope.NewHandle<mirror::Class>(nullptr));
2800*795d594fSAndroid Build Coastguard Worker
2801*795d594fSAndroid Build Coastguard Worker for (const DexFile* dex_file : dex_files) {
2802*795d594fSAndroid Build Coastguard Worker for (uint32_t class_def_index = 0;
2803*795d594fSAndroid Build Coastguard Worker class_def_index != dex_file->NumClassDefs();
2804*795d594fSAndroid Build Coastguard Worker ++class_def_index) {
2805*795d594fSAndroid Build Coastguard Worker const dex::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
2806*795d594fSAndroid Build Coastguard Worker h_klass.Assign(
2807*795d594fSAndroid Build Coastguard Worker class_linker->FindClass(self, *dex_file, class_def.class_idx_, h_class_loader));
2808*795d594fSAndroid Build Coastguard Worker if (h_klass == nullptr) {
2809*795d594fSAndroid Build Coastguard Worker std::cerr << "Warning: could not load "
2810*795d594fSAndroid Build Coastguard Worker << dex_file->GetTypeDescriptor(class_def.class_idx_) << std::endl;
2811*795d594fSAndroid Build Coastguard Worker continue;
2812*795d594fSAndroid Build Coastguard Worker }
2813*795d594fSAndroid Build Coastguard Worker
2814*795d594fSAndroid Build Coastguard Worker if (HasNoIMT(runtime, h_klass, pointer_size, &prepared)) {
2815*795d594fSAndroid Build Coastguard Worker without_imt++;
2816*795d594fSAndroid Build Coastguard Worker continue;
2817*795d594fSAndroid Build Coastguard Worker }
2818*795d594fSAndroid Build Coastguard Worker
2819*795d594fSAndroid Build Coastguard Worker ImTable* im_table = PrepareAndGetImTable(runtime, h_klass, pointer_size, &prepared);
2820*795d594fSAndroid Build Coastguard Worker if (im_table == nullptr) {
2821*795d594fSAndroid Build Coastguard Worker // Should not happen, but accept.
2822*795d594fSAndroid Build Coastguard Worker without_imt++;
2823*795d594fSAndroid Build Coastguard Worker continue;
2824*795d594fSAndroid Build Coastguard Worker }
2825*795d594fSAndroid Build Coastguard Worker
2826*795d594fSAndroid Build Coastguard Worker with_imt++;
2827*795d594fSAndroid Build Coastguard Worker for (size_t imt_index = 0; imt_index != ImTable::kSize; ++imt_index) {
2828*795d594fSAndroid Build Coastguard Worker ArtMethod* ptr = im_table->Get(imt_index, pointer_size);
2829*795d594fSAndroid Build Coastguard Worker if (ptr->IsRuntimeMethod()) {
2830*795d594fSAndroid Build Coastguard Worker if (ptr->IsImtUnimplementedMethod()) {
2831*795d594fSAndroid Build Coastguard Worker histogram[0]++;
2832*795d594fSAndroid Build Coastguard Worker } else {
2833*795d594fSAndroid Build Coastguard Worker ImtConflictTable* current_table = ptr->GetImtConflictTable(pointer_size);
2834*795d594fSAndroid Build Coastguard Worker histogram[current_table->NumEntries(pointer_size)]++;
2835*795d594fSAndroid Build Coastguard Worker }
2836*795d594fSAndroid Build Coastguard Worker } else {
2837*795d594fSAndroid Build Coastguard Worker histogram[1]++;
2838*795d594fSAndroid Build Coastguard Worker }
2839*795d594fSAndroid Build Coastguard Worker }
2840*795d594fSAndroid Build Coastguard Worker }
2841*795d594fSAndroid Build Coastguard Worker }
2842*795d594fSAndroid Build Coastguard Worker
2843*795d594fSAndroid Build Coastguard Worker std::cerr << "IMT stats:"
2844*795d594fSAndroid Build Coastguard Worker << std::endl << std::endl;
2845*795d594fSAndroid Build Coastguard Worker
2846*795d594fSAndroid Build Coastguard Worker std::cerr << " " << with_imt << " classes with IMT."
2847*795d594fSAndroid Build Coastguard Worker << std::endl << std::endl;
2848*795d594fSAndroid Build Coastguard Worker std::cerr << " " << without_imt << " classes without IMT (or copy from Object)."
2849*795d594fSAndroid Build Coastguard Worker << std::endl << std::endl;
2850*795d594fSAndroid Build Coastguard Worker
2851*795d594fSAndroid Build Coastguard Worker double sum_one = 0;
2852*795d594fSAndroid Build Coastguard Worker size_t count_one = 0;
2853*795d594fSAndroid Build Coastguard Worker
2854*795d594fSAndroid Build Coastguard Worker std::cerr << " " << "IMT histogram" << std::endl;
2855*795d594fSAndroid Build Coastguard Worker for (auto& bucket : histogram) {
2856*795d594fSAndroid Build Coastguard Worker std::cerr << " " << bucket.first << " " << bucket.second << std::endl;
2857*795d594fSAndroid Build Coastguard Worker if (bucket.first > 0) {
2858*795d594fSAndroid Build Coastguard Worker sum_one += bucket.second * bucket.first;
2859*795d594fSAndroid Build Coastguard Worker count_one += bucket.second;
2860*795d594fSAndroid Build Coastguard Worker }
2861*795d594fSAndroid Build Coastguard Worker }
2862*795d594fSAndroid Build Coastguard Worker
2863*795d594fSAndroid Build Coastguard Worker double count_zero = count_one + histogram[0];
2864*795d594fSAndroid Build Coastguard Worker std::cerr << " Stats:" << std::endl;
2865*795d594fSAndroid Build Coastguard Worker std::cerr << " Average depth (including empty): " << (sum_one / count_zero) << std::endl;
2866*795d594fSAndroid Build Coastguard Worker std::cerr << " Average depth (excluding empty): " << (sum_one / count_one) << std::endl;
2867*795d594fSAndroid Build Coastguard Worker
2868*795d594fSAndroid Build Coastguard Worker return true;
2869*795d594fSAndroid Build Coastguard Worker }
2870*795d594fSAndroid Build Coastguard Worker
2871*795d594fSAndroid Build Coastguard Worker // Return whether the given class has no IMT (or the one shared with java.lang.Object).
HasNoIMT(Runtime * runtime,Handle<mirror::Class> klass,const PointerSize pointer_size,std::unordered_set<std::string> * prepared)2872*795d594fSAndroid Build Coastguard Worker static bool HasNoIMT(Runtime* runtime,
2873*795d594fSAndroid Build Coastguard Worker Handle<mirror::Class> klass,
2874*795d594fSAndroid Build Coastguard Worker const PointerSize pointer_size,
2875*795d594fSAndroid Build Coastguard Worker std::unordered_set<std::string>* prepared)
2876*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
2877*795d594fSAndroid Build Coastguard Worker if (klass->IsObjectClass() || !klass->ShouldHaveImt()) {
2878*795d594fSAndroid Build Coastguard Worker return true;
2879*795d594fSAndroid Build Coastguard Worker }
2880*795d594fSAndroid Build Coastguard Worker
2881*795d594fSAndroid Build Coastguard Worker if (klass->GetImt(pointer_size) == nullptr) {
2882*795d594fSAndroid Build Coastguard Worker PrepareClass(runtime, klass, prepared);
2883*795d594fSAndroid Build Coastguard Worker }
2884*795d594fSAndroid Build Coastguard Worker
2885*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Class> object_class = GetClassRoot<mirror::Object>();
2886*795d594fSAndroid Build Coastguard Worker DCHECK(object_class->IsObjectClass());
2887*795d594fSAndroid Build Coastguard Worker
2888*795d594fSAndroid Build Coastguard Worker bool result = klass->GetImt(pointer_size) == object_class->GetImt(pointer_size);
2889*795d594fSAndroid Build Coastguard Worker
2890*795d594fSAndroid Build Coastguard Worker if (klass->GetIfTable()->Count() == 0) {
2891*795d594fSAndroid Build Coastguard Worker DCHECK(result);
2892*795d594fSAndroid Build Coastguard Worker }
2893*795d594fSAndroid Build Coastguard Worker
2894*795d594fSAndroid Build Coastguard Worker return result;
2895*795d594fSAndroid Build Coastguard Worker }
2896*795d594fSAndroid Build Coastguard Worker
PrintTable(ImtConflictTable * table,PointerSize pointer_size)2897*795d594fSAndroid Build Coastguard Worker static void PrintTable(ImtConflictTable* table, PointerSize pointer_size)
2898*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
2899*795d594fSAndroid Build Coastguard Worker if (table == nullptr) {
2900*795d594fSAndroid Build Coastguard Worker std::cerr << " <No IMT?>" << std::endl;
2901*795d594fSAndroid Build Coastguard Worker return;
2902*795d594fSAndroid Build Coastguard Worker }
2903*795d594fSAndroid Build Coastguard Worker size_t table_index = 0;
2904*795d594fSAndroid Build Coastguard Worker for (;;) {
2905*795d594fSAndroid Build Coastguard Worker ArtMethod* ptr = table->GetInterfaceMethod(table_index, pointer_size);
2906*795d594fSAndroid Build Coastguard Worker if (ptr == nullptr) {
2907*795d594fSAndroid Build Coastguard Worker return;
2908*795d594fSAndroid Build Coastguard Worker }
2909*795d594fSAndroid Build Coastguard Worker table_index++;
2910*795d594fSAndroid Build Coastguard Worker std::cerr << " " << ptr->PrettyMethod(true) << std::endl;
2911*795d594fSAndroid Build Coastguard Worker }
2912*795d594fSAndroid Build Coastguard Worker }
2913*795d594fSAndroid Build Coastguard Worker
PrepareAndGetImTable(Runtime * runtime,Thread * self,Handle<mirror::ClassLoader> h_loader,const std::string & class_name,const PointerSize pointer_size,ObjPtr<mirror::Class> * klass_out,std::unordered_set<std::string> * prepared)2914*795d594fSAndroid Build Coastguard Worker static ImTable* PrepareAndGetImTable(Runtime* runtime,
2915*795d594fSAndroid Build Coastguard Worker Thread* self,
2916*795d594fSAndroid Build Coastguard Worker Handle<mirror::ClassLoader> h_loader,
2917*795d594fSAndroid Build Coastguard Worker const std::string& class_name,
2918*795d594fSAndroid Build Coastguard Worker const PointerSize pointer_size,
2919*795d594fSAndroid Build Coastguard Worker /*out*/ ObjPtr<mirror::Class>* klass_out,
2920*795d594fSAndroid Build Coastguard Worker /*inout*/ std::unordered_set<std::string>* prepared)
2921*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
2922*795d594fSAndroid Build Coastguard Worker if (class_name.empty()) {
2923*795d594fSAndroid Build Coastguard Worker return nullptr;
2924*795d594fSAndroid Build Coastguard Worker }
2925*795d594fSAndroid Build Coastguard Worker
2926*795d594fSAndroid Build Coastguard Worker std::string descriptor;
2927*795d594fSAndroid Build Coastguard Worker if (class_name[0] == 'L') {
2928*795d594fSAndroid Build Coastguard Worker descriptor = class_name;
2929*795d594fSAndroid Build Coastguard Worker } else {
2930*795d594fSAndroid Build Coastguard Worker descriptor = DotToDescriptor(class_name.c_str());
2931*795d594fSAndroid Build Coastguard Worker }
2932*795d594fSAndroid Build Coastguard Worker
2933*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Class> klass = runtime->GetClassLinker()->FindClass(
2934*795d594fSAndroid Build Coastguard Worker self, descriptor.c_str(), descriptor.length(), h_loader);
2935*795d594fSAndroid Build Coastguard Worker
2936*795d594fSAndroid Build Coastguard Worker if (klass == nullptr) {
2937*795d594fSAndroid Build Coastguard Worker self->ClearException();
2938*795d594fSAndroid Build Coastguard Worker std::cerr << "Did not find " << class_name << std::endl;
2939*795d594fSAndroid Build Coastguard Worker *klass_out = nullptr;
2940*795d594fSAndroid Build Coastguard Worker return nullptr;
2941*795d594fSAndroid Build Coastguard Worker }
2942*795d594fSAndroid Build Coastguard Worker
2943*795d594fSAndroid Build Coastguard Worker StackHandleScope<1> scope(Thread::Current());
2944*795d594fSAndroid Build Coastguard Worker Handle<mirror::Class> h_klass = scope.NewHandle<mirror::Class>(klass);
2945*795d594fSAndroid Build Coastguard Worker
2946*795d594fSAndroid Build Coastguard Worker ImTable* ret = PrepareAndGetImTable(runtime, h_klass, pointer_size, prepared);
2947*795d594fSAndroid Build Coastguard Worker *klass_out = h_klass.Get();
2948*795d594fSAndroid Build Coastguard Worker return ret;
2949*795d594fSAndroid Build Coastguard Worker }
2950*795d594fSAndroid Build Coastguard Worker
PrepareAndGetImTable(Runtime * runtime,Handle<mirror::Class> h_klass,const PointerSize pointer_size,std::unordered_set<std::string> * prepared)2951*795d594fSAndroid Build Coastguard Worker static ImTable* PrepareAndGetImTable(Runtime* runtime,
2952*795d594fSAndroid Build Coastguard Worker Handle<mirror::Class> h_klass,
2953*795d594fSAndroid Build Coastguard Worker const PointerSize pointer_size,
2954*795d594fSAndroid Build Coastguard Worker /*inout*/ std::unordered_set<std::string>* prepared)
2955*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
2956*795d594fSAndroid Build Coastguard Worker PrepareClass(runtime, h_klass, prepared);
2957*795d594fSAndroid Build Coastguard Worker return h_klass->GetImt(pointer_size);
2958*795d594fSAndroid Build Coastguard Worker }
2959*795d594fSAndroid Build Coastguard Worker
DumpIMTForClass(Runtime * runtime,const std::string & class_name,Handle<mirror::ClassLoader> h_loader,std::unordered_set<std::string> * prepared)2960*795d594fSAndroid Build Coastguard Worker static void DumpIMTForClass(Runtime* runtime,
2961*795d594fSAndroid Build Coastguard Worker const std::string& class_name,
2962*795d594fSAndroid Build Coastguard Worker Handle<mirror::ClassLoader> h_loader,
2963*795d594fSAndroid Build Coastguard Worker std::unordered_set<std::string>* prepared)
2964*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
2965*795d594fSAndroid Build Coastguard Worker const PointerSize pointer_size = runtime->GetClassLinker()->GetImagePointerSize();
2966*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Class> klass;
2967*795d594fSAndroid Build Coastguard Worker ImTable* imt = PrepareAndGetImTable(runtime,
2968*795d594fSAndroid Build Coastguard Worker Thread::Current(),
2969*795d594fSAndroid Build Coastguard Worker h_loader,
2970*795d594fSAndroid Build Coastguard Worker class_name,
2971*795d594fSAndroid Build Coastguard Worker pointer_size,
2972*795d594fSAndroid Build Coastguard Worker &klass,
2973*795d594fSAndroid Build Coastguard Worker prepared);
2974*795d594fSAndroid Build Coastguard Worker if (imt == nullptr) {
2975*795d594fSAndroid Build Coastguard Worker return;
2976*795d594fSAndroid Build Coastguard Worker }
2977*795d594fSAndroid Build Coastguard Worker
2978*795d594fSAndroid Build Coastguard Worker std::cerr << class_name << std::endl << " IMT:" << std::endl;
2979*795d594fSAndroid Build Coastguard Worker for (size_t index = 0; index < ImTable::kSize; ++index) {
2980*795d594fSAndroid Build Coastguard Worker std::cerr << " " << index << ":" << std::endl;
2981*795d594fSAndroid Build Coastguard Worker ArtMethod* ptr = imt->Get(index, pointer_size);
2982*795d594fSAndroid Build Coastguard Worker if (ptr->IsRuntimeMethod()) {
2983*795d594fSAndroid Build Coastguard Worker if (ptr->IsImtUnimplementedMethod()) {
2984*795d594fSAndroid Build Coastguard Worker std::cerr << " <empty>" << std::endl;
2985*795d594fSAndroid Build Coastguard Worker } else {
2986*795d594fSAndroid Build Coastguard Worker ImtConflictTable* current_table = ptr->GetImtConflictTable(pointer_size);
2987*795d594fSAndroid Build Coastguard Worker PrintTable(current_table, pointer_size);
2988*795d594fSAndroid Build Coastguard Worker }
2989*795d594fSAndroid Build Coastguard Worker } else {
2990*795d594fSAndroid Build Coastguard Worker std::cerr << " " << ptr->PrettyMethod(true) << std::endl;
2991*795d594fSAndroid Build Coastguard Worker }
2992*795d594fSAndroid Build Coastguard Worker }
2993*795d594fSAndroid Build Coastguard Worker
2994*795d594fSAndroid Build Coastguard Worker std::cerr << " Interfaces:" << std::endl;
2995*795d594fSAndroid Build Coastguard Worker // Run through iftable, find methods that slot here, see if they fit.
2996*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::IfTable> if_table = klass->GetIfTable();
2997*795d594fSAndroid Build Coastguard Worker for (size_t i = 0, num_interfaces = klass->GetIfTableCount(); i < num_interfaces; ++i) {
2998*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Class> iface = if_table->GetInterface(i);
2999*795d594fSAndroid Build Coastguard Worker std::string iface_name;
3000*795d594fSAndroid Build Coastguard Worker std::cerr << " " << iface->GetDescriptor(&iface_name) << std::endl;
3001*795d594fSAndroid Build Coastguard Worker
3002*795d594fSAndroid Build Coastguard Worker for (ArtMethod& iface_method : iface->GetVirtualMethods(pointer_size)) {
3003*795d594fSAndroid Build Coastguard Worker uint32_t class_hash, name_hash, signature_hash;
3004*795d594fSAndroid Build Coastguard Worker ImTable::GetImtHashComponents(&iface_method, &class_hash, &name_hash, &signature_hash);
3005*795d594fSAndroid Build Coastguard Worker uint32_t imt_slot = ImTable::GetImtIndex(&iface_method);
3006*795d594fSAndroid Build Coastguard Worker std::cerr << " " << iface_method.PrettyMethod(true)
3007*795d594fSAndroid Build Coastguard Worker << " slot=" << imt_slot
3008*795d594fSAndroid Build Coastguard Worker << std::hex
3009*795d594fSAndroid Build Coastguard Worker << " class_hash=0x" << class_hash
3010*795d594fSAndroid Build Coastguard Worker << " name_hash=0x" << name_hash
3011*795d594fSAndroid Build Coastguard Worker << " signature_hash=0x" << signature_hash
3012*795d594fSAndroid Build Coastguard Worker << std::dec
3013*795d594fSAndroid Build Coastguard Worker << std::endl;
3014*795d594fSAndroid Build Coastguard Worker }
3015*795d594fSAndroid Build Coastguard Worker }
3016*795d594fSAndroid Build Coastguard Worker }
3017*795d594fSAndroid Build Coastguard Worker
DumpIMTForMethod(Runtime * runtime,const std::string & class_name,const std::string & method,Handle<mirror::ClassLoader> h_loader,std::unordered_set<std::string> * prepared)3018*795d594fSAndroid Build Coastguard Worker static void DumpIMTForMethod(Runtime* runtime,
3019*795d594fSAndroid Build Coastguard Worker const std::string& class_name,
3020*795d594fSAndroid Build Coastguard Worker const std::string& method,
3021*795d594fSAndroid Build Coastguard Worker Handle<mirror::ClassLoader> h_loader,
3022*795d594fSAndroid Build Coastguard Worker /*inout*/ std::unordered_set<std::string>* prepared)
3023*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
3024*795d594fSAndroid Build Coastguard Worker const PointerSize pointer_size = runtime->GetClassLinker()->GetImagePointerSize();
3025*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Class> klass;
3026*795d594fSAndroid Build Coastguard Worker ImTable* imt = PrepareAndGetImTable(runtime,
3027*795d594fSAndroid Build Coastguard Worker Thread::Current(),
3028*795d594fSAndroid Build Coastguard Worker h_loader,
3029*795d594fSAndroid Build Coastguard Worker class_name,
3030*795d594fSAndroid Build Coastguard Worker pointer_size,
3031*795d594fSAndroid Build Coastguard Worker &klass,
3032*795d594fSAndroid Build Coastguard Worker prepared);
3033*795d594fSAndroid Build Coastguard Worker if (imt == nullptr) {
3034*795d594fSAndroid Build Coastguard Worker return;
3035*795d594fSAndroid Build Coastguard Worker }
3036*795d594fSAndroid Build Coastguard Worker
3037*795d594fSAndroid Build Coastguard Worker std::cerr << class_name << " <" << method << ">" << std::endl;
3038*795d594fSAndroid Build Coastguard Worker for (size_t index = 0; index < ImTable::kSize; ++index) {
3039*795d594fSAndroid Build Coastguard Worker ArtMethod* ptr = imt->Get(index, pointer_size);
3040*795d594fSAndroid Build Coastguard Worker if (ptr->IsRuntimeMethod()) {
3041*795d594fSAndroid Build Coastguard Worker if (ptr->IsImtUnimplementedMethod()) {
3042*795d594fSAndroid Build Coastguard Worker continue;
3043*795d594fSAndroid Build Coastguard Worker }
3044*795d594fSAndroid Build Coastguard Worker
3045*795d594fSAndroid Build Coastguard Worker ImtConflictTable* current_table = ptr->GetImtConflictTable(pointer_size);
3046*795d594fSAndroid Build Coastguard Worker if (current_table == nullptr) {
3047*795d594fSAndroid Build Coastguard Worker continue;
3048*795d594fSAndroid Build Coastguard Worker }
3049*795d594fSAndroid Build Coastguard Worker
3050*795d594fSAndroid Build Coastguard Worker size_t table_index = 0;
3051*795d594fSAndroid Build Coastguard Worker for (;;) {
3052*795d594fSAndroid Build Coastguard Worker ArtMethod* ptr2 = current_table->GetInterfaceMethod(table_index, pointer_size);
3053*795d594fSAndroid Build Coastguard Worker if (ptr2 == nullptr) {
3054*795d594fSAndroid Build Coastguard Worker break;
3055*795d594fSAndroid Build Coastguard Worker }
3056*795d594fSAndroid Build Coastguard Worker table_index++;
3057*795d594fSAndroid Build Coastguard Worker
3058*795d594fSAndroid Build Coastguard Worker std::string p_name = ptr2->PrettyMethod(true);
3059*795d594fSAndroid Build Coastguard Worker if (p_name.starts_with(method)) {
3060*795d594fSAndroid Build Coastguard Worker std::cerr << " Slot "
3061*795d594fSAndroid Build Coastguard Worker << index
3062*795d594fSAndroid Build Coastguard Worker << " ("
3063*795d594fSAndroid Build Coastguard Worker << current_table->NumEntries(pointer_size)
3064*795d594fSAndroid Build Coastguard Worker << ")"
3065*795d594fSAndroid Build Coastguard Worker << std::endl;
3066*795d594fSAndroid Build Coastguard Worker PrintTable(current_table, pointer_size);
3067*795d594fSAndroid Build Coastguard Worker return;
3068*795d594fSAndroid Build Coastguard Worker }
3069*795d594fSAndroid Build Coastguard Worker }
3070*795d594fSAndroid Build Coastguard Worker } else {
3071*795d594fSAndroid Build Coastguard Worker std::string p_name = ptr->PrettyMethod(true);
3072*795d594fSAndroid Build Coastguard Worker if (p_name.starts_with(method)) {
3073*795d594fSAndroid Build Coastguard Worker std::cerr << " Slot " << index << " (1)" << std::endl;
3074*795d594fSAndroid Build Coastguard Worker std::cerr << " " << p_name << std::endl;
3075*795d594fSAndroid Build Coastguard Worker } else {
3076*795d594fSAndroid Build Coastguard Worker // Run through iftable, find methods that slot here, see if they fit.
3077*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::IfTable> if_table = klass->GetIfTable();
3078*795d594fSAndroid Build Coastguard Worker for (size_t i = 0, num_interfaces = klass->GetIfTableCount(); i < num_interfaces; ++i) {
3079*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Class> iface = if_table->GetInterface(i);
3080*795d594fSAndroid Build Coastguard Worker size_t num_methods = iface->NumDeclaredVirtualMethods();
3081*795d594fSAndroid Build Coastguard Worker if (num_methods > 0) {
3082*795d594fSAndroid Build Coastguard Worker for (ArtMethod& iface_method : iface->GetMethods(pointer_size)) {
3083*795d594fSAndroid Build Coastguard Worker if (ImTable::GetImtIndex(&iface_method) == index) {
3084*795d594fSAndroid Build Coastguard Worker std::string i_name = iface_method.PrettyMethod(true);
3085*795d594fSAndroid Build Coastguard Worker if (i_name.starts_with(method)) {
3086*795d594fSAndroid Build Coastguard Worker std::cerr << " Slot " << index << " (1)" << std::endl;
3087*795d594fSAndroid Build Coastguard Worker std::cerr << " " << p_name << " (" << i_name << ")" << std::endl;
3088*795d594fSAndroid Build Coastguard Worker }
3089*795d594fSAndroid Build Coastguard Worker }
3090*795d594fSAndroid Build Coastguard Worker }
3091*795d594fSAndroid Build Coastguard Worker }
3092*795d594fSAndroid Build Coastguard Worker }
3093*795d594fSAndroid Build Coastguard Worker }
3094*795d594fSAndroid Build Coastguard Worker }
3095*795d594fSAndroid Build Coastguard Worker }
3096*795d594fSAndroid Build Coastguard Worker }
3097*795d594fSAndroid Build Coastguard Worker
3098*795d594fSAndroid Build Coastguard Worker // Read lines from the given stream, dropping comments and empty lines
ReadCommentedInputStream(std::istream & in_stream)3099*795d594fSAndroid Build Coastguard Worker static std::vector<std::string> ReadCommentedInputStream(std::istream& in_stream) {
3100*795d594fSAndroid Build Coastguard Worker std::vector<std::string> output;
3101*795d594fSAndroid Build Coastguard Worker while (in_stream.good()) {
3102*795d594fSAndroid Build Coastguard Worker std::string dot;
3103*795d594fSAndroid Build Coastguard Worker std::getline(in_stream, dot);
3104*795d594fSAndroid Build Coastguard Worker if (dot.starts_with("#") || dot.empty()) {
3105*795d594fSAndroid Build Coastguard Worker continue;
3106*795d594fSAndroid Build Coastguard Worker }
3107*795d594fSAndroid Build Coastguard Worker output.push_back(dot);
3108*795d594fSAndroid Build Coastguard Worker }
3109*795d594fSAndroid Build Coastguard Worker return output;
3110*795d594fSAndroid Build Coastguard Worker }
3111*795d594fSAndroid Build Coastguard Worker
3112*795d594fSAndroid Build Coastguard Worker // Read lines from the given file, dropping comments and empty lines.
ReadCommentedInputFromFile(const std::string & input_filename)3113*795d594fSAndroid Build Coastguard Worker static std::vector<std::string> ReadCommentedInputFromFile(const std::string& input_filename) {
3114*795d594fSAndroid Build Coastguard Worker std::unique_ptr<std::ifstream> input_file(new std::ifstream(input_filename, std::ifstream::in));
3115*795d594fSAndroid Build Coastguard Worker if (input_file.get() == nullptr) {
3116*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "Failed to open input file " << input_filename;
3117*795d594fSAndroid Build Coastguard Worker return std::vector<std::string>();
3118*795d594fSAndroid Build Coastguard Worker }
3119*795d594fSAndroid Build Coastguard Worker std::vector<std::string> result = ReadCommentedInputStream(*input_file);
3120*795d594fSAndroid Build Coastguard Worker input_file->close();
3121*795d594fSAndroid Build Coastguard Worker return result;
3122*795d594fSAndroid Build Coastguard Worker }
3123*795d594fSAndroid Build Coastguard Worker
3124*795d594fSAndroid Build Coastguard Worker // Prepare a class, i.e., ensure it has a filled IMT. Will do so recursively for superclasses,
3125*795d594fSAndroid Build Coastguard Worker // and note in the given set that the work was done.
PrepareClass(Runtime * runtime,Handle<mirror::Class> h_klass,std::unordered_set<std::string> * done)3126*795d594fSAndroid Build Coastguard Worker static void PrepareClass(Runtime* runtime,
3127*795d594fSAndroid Build Coastguard Worker Handle<mirror::Class> h_klass,
3128*795d594fSAndroid Build Coastguard Worker /*inout*/ std::unordered_set<std::string>* done)
3129*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
3130*795d594fSAndroid Build Coastguard Worker if (!h_klass->ShouldHaveImt()) {
3131*795d594fSAndroid Build Coastguard Worker return;
3132*795d594fSAndroid Build Coastguard Worker }
3133*795d594fSAndroid Build Coastguard Worker
3134*795d594fSAndroid Build Coastguard Worker std::string name;
3135*795d594fSAndroid Build Coastguard Worker name = h_klass->GetDescriptor(&name);
3136*795d594fSAndroid Build Coastguard Worker
3137*795d594fSAndroid Build Coastguard Worker if (done->find(name) != done->end()) {
3138*795d594fSAndroid Build Coastguard Worker return;
3139*795d594fSAndroid Build Coastguard Worker }
3140*795d594fSAndroid Build Coastguard Worker done->insert(name);
3141*795d594fSAndroid Build Coastguard Worker
3142*795d594fSAndroid Build Coastguard Worker if (h_klass->HasSuperClass()) {
3143*795d594fSAndroid Build Coastguard Worker StackHandleScope<1> h(Thread::Current());
3144*795d594fSAndroid Build Coastguard Worker PrepareClass(runtime, h.NewHandle<mirror::Class>(h_klass->GetSuperClass()), done);
3145*795d594fSAndroid Build Coastguard Worker }
3146*795d594fSAndroid Build Coastguard Worker
3147*795d594fSAndroid Build Coastguard Worker if (!h_klass->IsTemp()) {
3148*795d594fSAndroid Build Coastguard Worker runtime->GetClassLinker()->FillIMTAndConflictTables(h_klass.Get());
3149*795d594fSAndroid Build Coastguard Worker }
3150*795d594fSAndroid Build Coastguard Worker }
3151*795d594fSAndroid Build Coastguard Worker };
3152*795d594fSAndroid Build Coastguard Worker
3153*795d594fSAndroid Build Coastguard Worker enum class OatDumpMode {
3154*795d594fSAndroid Build Coastguard Worker kSymbolize,
3155*795d594fSAndroid Build Coastguard Worker kDumpImt,
3156*795d594fSAndroid Build Coastguard Worker kDumpImage,
3157*795d594fSAndroid Build Coastguard Worker kDumpOat,
3158*795d594fSAndroid Build Coastguard Worker };
3159*795d594fSAndroid Build Coastguard Worker
3160*795d594fSAndroid Build Coastguard Worker struct OatdumpArgs : public CmdlineArgs {
3161*795d594fSAndroid Build Coastguard Worker protected:
3162*795d594fSAndroid Build Coastguard Worker using Base = CmdlineArgs;
3163*795d594fSAndroid Build Coastguard Worker
ParseCustomart::OatdumpArgs3164*795d594fSAndroid Build Coastguard Worker ParseStatus ParseCustom(const char* raw_option,
3165*795d594fSAndroid Build Coastguard Worker size_t raw_option_length,
3166*795d594fSAndroid Build Coastguard Worker std::string* error_msg) override {
3167*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(strlen(raw_option), raw_option_length);
3168*795d594fSAndroid Build Coastguard Worker {
3169*795d594fSAndroid Build Coastguard Worker ParseStatus base_parse = Base::ParseCustom(raw_option, raw_option_length, error_msg);
3170*795d594fSAndroid Build Coastguard Worker if (base_parse != kParseUnknownArgument) {
3171*795d594fSAndroid Build Coastguard Worker return base_parse;
3172*795d594fSAndroid Build Coastguard Worker }
3173*795d594fSAndroid Build Coastguard Worker }
3174*795d594fSAndroid Build Coastguard Worker
3175*795d594fSAndroid Build Coastguard Worker std::string_view option(raw_option, raw_option_length);
3176*795d594fSAndroid Build Coastguard Worker if (option.starts_with("--oat-file=")) {
3177*795d594fSAndroid Build Coastguard Worker oat_filename_ = raw_option + strlen("--oat-file=");
3178*795d594fSAndroid Build Coastguard Worker } else if (option.starts_with("--dex-file=")) {
3179*795d594fSAndroid Build Coastguard Worker dex_filename_ = raw_option + strlen("--dex-file=");
3180*795d594fSAndroid Build Coastguard Worker } else if (option.starts_with("--image=")) {
3181*795d594fSAndroid Build Coastguard Worker image_location_ = raw_option + strlen("--image=");
3182*795d594fSAndroid Build Coastguard Worker } else if (option == "--no-dump:vmap") {
3183*795d594fSAndroid Build Coastguard Worker dump_vmap_ = false;
3184*795d594fSAndroid Build Coastguard Worker } else if (option =="--dump:code_info_stack_maps") {
3185*795d594fSAndroid Build Coastguard Worker dump_code_info_stack_maps_ = true;
3186*795d594fSAndroid Build Coastguard Worker } else if (option == "--no-disassemble") {
3187*795d594fSAndroid Build Coastguard Worker disassemble_code_ = false;
3188*795d594fSAndroid Build Coastguard Worker } else if (option =="--header-only") {
3189*795d594fSAndroid Build Coastguard Worker dump_header_only_ = true;
3190*795d594fSAndroid Build Coastguard Worker } else if (option.starts_with("--symbolize=")) {
3191*795d594fSAndroid Build Coastguard Worker oat_filename_ = raw_option + strlen("--symbolize=");
3192*795d594fSAndroid Build Coastguard Worker symbolize_ = true;
3193*795d594fSAndroid Build Coastguard Worker } else if (option.starts_with("--only-keep-debug")) {
3194*795d594fSAndroid Build Coastguard Worker only_keep_debug_ = true;
3195*795d594fSAndroid Build Coastguard Worker } else if (option.starts_with("--class-filter=")) {
3196*795d594fSAndroid Build Coastguard Worker class_filter_ = raw_option + strlen("--class-filter=");
3197*795d594fSAndroid Build Coastguard Worker } else if (option.starts_with("--method-filter=")) {
3198*795d594fSAndroid Build Coastguard Worker method_filter_ = raw_option + strlen("--method-filter=");
3199*795d594fSAndroid Build Coastguard Worker } else if (option.starts_with("--list-classes")) {
3200*795d594fSAndroid Build Coastguard Worker list_classes_ = true;
3201*795d594fSAndroid Build Coastguard Worker } else if (option.starts_with("--list-methods")) {
3202*795d594fSAndroid Build Coastguard Worker list_methods_ = true;
3203*795d594fSAndroid Build Coastguard Worker } else if (option.starts_with("--export-dex-to=")) {
3204*795d594fSAndroid Build Coastguard Worker export_dex_location_ = raw_option + strlen("--export-dex-to=");
3205*795d594fSAndroid Build Coastguard Worker } else if (option.starts_with("--addr2instr=")) {
3206*795d594fSAndroid Build Coastguard Worker if (!android::base::ParseUint(raw_option + strlen("--addr2instr="), &addr2instr_)) {
3207*795d594fSAndroid Build Coastguard Worker *error_msg = "Address conversion failed";
3208*795d594fSAndroid Build Coastguard Worker return kParseError;
3209*795d594fSAndroid Build Coastguard Worker }
3210*795d594fSAndroid Build Coastguard Worker } else if (option.starts_with("--app-image=")) {
3211*795d594fSAndroid Build Coastguard Worker app_image_ = raw_option + strlen("--app-image=");
3212*795d594fSAndroid Build Coastguard Worker } else if (option.starts_with("--app-oat=")) {
3213*795d594fSAndroid Build Coastguard Worker app_oat_ = raw_option + strlen("--app-oat=");
3214*795d594fSAndroid Build Coastguard Worker } else if (option.starts_with("--dump-imt=")) {
3215*795d594fSAndroid Build Coastguard Worker imt_dump_ = std::string(option.substr(strlen("--dump-imt=")));
3216*795d594fSAndroid Build Coastguard Worker } else if (option == "--dump-imt-stats") {
3217*795d594fSAndroid Build Coastguard Worker imt_stat_dump_ = true;
3218*795d594fSAndroid Build Coastguard Worker } else if (option == "--dump-method-and-offset-as-json") {
3219*795d594fSAndroid Build Coastguard Worker dump_method_and_offset_as_json = true;
3220*795d594fSAndroid Build Coastguard Worker } else {
3221*795d594fSAndroid Build Coastguard Worker return kParseUnknownArgument;
3222*795d594fSAndroid Build Coastguard Worker }
3223*795d594fSAndroid Build Coastguard Worker
3224*795d594fSAndroid Build Coastguard Worker return kParseOk;
3225*795d594fSAndroid Build Coastguard Worker }
3226*795d594fSAndroid Build Coastguard Worker
ParseChecksart::OatdumpArgs3227*795d594fSAndroid Build Coastguard Worker ParseStatus ParseChecks(std::string* error_msg) override {
3228*795d594fSAndroid Build Coastguard Worker if (image_location_ != nullptr) {
3229*795d594fSAndroid Build Coastguard Worker if (!boot_image_locations_.empty()) {
3230*795d594fSAndroid Build Coastguard Worker std::cerr << "Warning: Invalid combination of --boot-image and --image\n";
3231*795d594fSAndroid Build Coastguard Worker std::cerr << "Use --image alone to dump boot image(s)\n";
3232*795d594fSAndroid Build Coastguard Worker std::cerr << "Ignoring --boot-image\n";
3233*795d594fSAndroid Build Coastguard Worker std::cerr << "\n";
3234*795d594fSAndroid Build Coastguard Worker boot_image_locations_.clear();
3235*795d594fSAndroid Build Coastguard Worker }
3236*795d594fSAndroid Build Coastguard Worker Split(image_location_, ':', &boot_image_locations_);
3237*795d594fSAndroid Build Coastguard Worker }
3238*795d594fSAndroid Build Coastguard Worker
3239*795d594fSAndroid Build Coastguard Worker // Perform the parent checks.
3240*795d594fSAndroid Build Coastguard Worker ParseStatus parent_checks = Base::ParseChecks(error_msg);
3241*795d594fSAndroid Build Coastguard Worker if (parent_checks != kParseOk) {
3242*795d594fSAndroid Build Coastguard Worker return parent_checks;
3243*795d594fSAndroid Build Coastguard Worker }
3244*795d594fSAndroid Build Coastguard Worker
3245*795d594fSAndroid Build Coastguard Worker // Perform our own checks.
3246*795d594fSAndroid Build Coastguard Worker if (image_location_ == nullptr && app_image_ == nullptr && oat_filename_ == nullptr) {
3247*795d594fSAndroid Build Coastguard Worker *error_msg = "Either --image, --app-image, --oat-file, or --symbolize must be specified";
3248*795d594fSAndroid Build Coastguard Worker return kParseError;
3249*795d594fSAndroid Build Coastguard Worker }
3250*795d594fSAndroid Build Coastguard Worker
3251*795d594fSAndroid Build Coastguard Worker if (app_image_ != nullptr && image_location_ != nullptr) {
3252*795d594fSAndroid Build Coastguard Worker std::cerr << "Warning: Combining --app-image with --image is no longer supported\n";
3253*795d594fSAndroid Build Coastguard Worker std::cerr << "Use --app-image alone to dump an app image, and optionally pass --boot-image "
3254*795d594fSAndroid Build Coastguard Worker "to specify the boot image that the app image is based on\n";
3255*795d594fSAndroid Build Coastguard Worker std::cerr << "Use --image alone to dump boot image(s)\n";
3256*795d594fSAndroid Build Coastguard Worker std::cerr << "Ignoring --image\n";
3257*795d594fSAndroid Build Coastguard Worker std::cerr << "\n";
3258*795d594fSAndroid Build Coastguard Worker image_location_ = nullptr;
3259*795d594fSAndroid Build Coastguard Worker }
3260*795d594fSAndroid Build Coastguard Worker
3261*795d594fSAndroid Build Coastguard Worker if (image_location_ != nullptr && oat_filename_ != nullptr) {
3262*795d594fSAndroid Build Coastguard Worker *error_msg =
3263*795d594fSAndroid Build Coastguard Worker "--image and --oat-file must not be specified together\n"
3264*795d594fSAndroid Build Coastguard Worker "Use --image alone to dump both boot image(s) and their oat file(s)\n"
3265*795d594fSAndroid Build Coastguard Worker "Use --oat-file alone to dump an oat file";
3266*795d594fSAndroid Build Coastguard Worker return kParseError;
3267*795d594fSAndroid Build Coastguard Worker }
3268*795d594fSAndroid Build Coastguard Worker
3269*795d594fSAndroid Build Coastguard Worker if (app_oat_ != nullptr) {
3270*795d594fSAndroid Build Coastguard Worker std::cerr << "Warning: --app-oat is deprecated. Use --oat-file instead\n";
3271*795d594fSAndroid Build Coastguard Worker std::cerr << "\n";
3272*795d594fSAndroid Build Coastguard Worker oat_filename_ = app_oat_;
3273*795d594fSAndroid Build Coastguard Worker }
3274*795d594fSAndroid Build Coastguard Worker
3275*795d594fSAndroid Build Coastguard Worker if (boot_image_locations_.empty() && app_image_ != nullptr) {
3276*795d594fSAndroid Build Coastguard Worker // At this point, boot image inference is impossible or has failed, and the user has been
3277*795d594fSAndroid Build Coastguard Worker // warned about the failure.
3278*795d594fSAndroid Build Coastguard Worker // When dumping an app image, we need at least one valid boot image, so we have to stop.
3279*795d594fSAndroid Build Coastguard Worker // When dumping other things, we can continue to start the runtime in imageless mode.
3280*795d594fSAndroid Build Coastguard Worker *error_msg = "--boot-image must be specified";
3281*795d594fSAndroid Build Coastguard Worker return kParseError;
3282*795d594fSAndroid Build Coastguard Worker }
3283*795d594fSAndroid Build Coastguard Worker
3284*795d594fSAndroid Build Coastguard Worker return kParseOk;
3285*795d594fSAndroid Build Coastguard Worker }
3286*795d594fSAndroid Build Coastguard Worker
GetUsageart::OatdumpArgs3287*795d594fSAndroid Build Coastguard Worker std::string GetUsage() const override {
3288*795d594fSAndroid Build Coastguard Worker std::string usage;
3289*795d594fSAndroid Build Coastguard Worker
3290*795d594fSAndroid Build Coastguard Worker usage += R"(
3291*795d594fSAndroid Build Coastguard Worker Usage: oatdump [options] ...
3292*795d594fSAndroid Build Coastguard Worker
3293*795d594fSAndroid Build Coastguard Worker Examples:
3294*795d594fSAndroid Build Coastguard Worker - Dump a primary boot image with its oat file.
3295*795d594fSAndroid Build Coastguard Worker oatdump --image=/system/framework/boot.art
3296*795d594fSAndroid Build Coastguard Worker
3297*795d594fSAndroid Build Coastguard Worker - Dump a primary boot image and extension(s) with their oat files.
3298*795d594fSAndroid Build Coastguard Worker oatdump --image=/system/framework/boot.art:/system/framework/boot-framework-adservices.art
3299*795d594fSAndroid Build Coastguard Worker
3300*795d594fSAndroid Build Coastguard Worker - Dump an app image with its oat file.
3301*795d594fSAndroid Build Coastguard Worker oatdump --app-image=app.art --oat-file=app.odex [--dex-file=app.apk] [--boot-image=boot.art]
3302*795d594fSAndroid Build Coastguard Worker
3303*795d594fSAndroid Build Coastguard Worker - Dump an app oat file.
3304*795d594fSAndroid Build Coastguard Worker oatdump --oat-file=app.odex [--dex-file=app.apk] [--boot-image=boot.art]
3305*795d594fSAndroid Build Coastguard Worker
3306*795d594fSAndroid Build Coastguard Worker - Dump IMT collisions. (See --dump-imt for details.)
3307*795d594fSAndroid Build Coastguard Worker oatdump --oat-file=app.odex --dump-imt=imt.txt [--dex-file=app.apk] [--boot-image=boot.art]
3308*795d594fSAndroid Build Coastguard Worker [--dump-imt-stats]
3309*795d594fSAndroid Build Coastguard Worker
3310*795d594fSAndroid Build Coastguard Worker - Symbolize an oat file. (See --symbolize for details.)
3311*795d594fSAndroid Build Coastguard Worker oatdump --symbolize=app.odex [--dex-file=app.apk] [--only-keep-debug]
3312*795d594fSAndroid Build Coastguard Worker
3313*795d594fSAndroid Build Coastguard Worker Options:
3314*795d594fSAndroid Build Coastguard Worker --oat-file=<file.oat>: dumps an oat file with the given filename.
3315*795d594fSAndroid Build Coastguard Worker Example: --oat-file=/system/framework/arm64/boot.oat
3316*795d594fSAndroid Build Coastguard Worker
3317*795d594fSAndroid Build Coastguard Worker --image=<file.art>: dumps boot image(s) specified at the given location.
3318*795d594fSAndroid Build Coastguard Worker Example: --image=/system/framework/boot.art
3319*795d594fSAndroid Build Coastguard Worker
3320*795d594fSAndroid Build Coastguard Worker --app-image=<file.art>: dumps an app image with the given filename.
3321*795d594fSAndroid Build Coastguard Worker Must also have a specified app oat file (with --oat-file).
3322*795d594fSAndroid Build Coastguard Worker Example: --app-image=app.art
3323*795d594fSAndroid Build Coastguard Worker
3324*795d594fSAndroid Build Coastguard Worker --app-oat=<file.odex>: deprecated. Use --oat-file instead.
3325*795d594fSAndroid Build Coastguard Worker
3326*795d594fSAndroid Build Coastguard Worker )";
3327*795d594fSAndroid Build Coastguard Worker
3328*795d594fSAndroid Build Coastguard Worker usage += Base::GetUsage();
3329*795d594fSAndroid Build Coastguard Worker
3330*795d594fSAndroid Build Coastguard Worker usage += // Optional.
3331*795d594fSAndroid Build Coastguard Worker " --no-dump:vmap may be used to disable vmap dumping.\n"
3332*795d594fSAndroid Build Coastguard Worker " Example: --no-dump:vmap\n"
3333*795d594fSAndroid Build Coastguard Worker "\n"
3334*795d594fSAndroid Build Coastguard Worker " --dump:code_info_stack_maps enables dumping of stack maps in CodeInfo sections.\n"
3335*795d594fSAndroid Build Coastguard Worker " Example: --dump:code_info_stack_maps\n"
3336*795d594fSAndroid Build Coastguard Worker "\n"
3337*795d594fSAndroid Build Coastguard Worker " --no-disassemble may be used to disable disassembly.\n"
3338*795d594fSAndroid Build Coastguard Worker " Example: --no-disassemble\n"
3339*795d594fSAndroid Build Coastguard Worker "\n"
3340*795d594fSAndroid Build Coastguard Worker " --header-only may be used to print only the oat header.\n"
3341*795d594fSAndroid Build Coastguard Worker " Example: --header-only\n"
3342*795d594fSAndroid Build Coastguard Worker "\n"
3343*795d594fSAndroid Build Coastguard Worker " --list-classes may be used to list target file classes (can be used with filters).\n"
3344*795d594fSAndroid Build Coastguard Worker " Example: --list-classes\n"
3345*795d594fSAndroid Build Coastguard Worker " Example: --list-classes --class-filter=com.example.foo\n"
3346*795d594fSAndroid Build Coastguard Worker "\n"
3347*795d594fSAndroid Build Coastguard Worker " --list-methods may be used to list target file methods (can be used with filters).\n"
3348*795d594fSAndroid Build Coastguard Worker " Example: --list-methods\n"
3349*795d594fSAndroid Build Coastguard Worker " Example: --list-methods --class-filter=com.example --method-filter=foo\n"
3350*795d594fSAndroid Build Coastguard Worker "\n"
3351*795d594fSAndroid Build Coastguard Worker " --symbolize=<file.oat>: output a copy of file.oat with elf symbols included.\n"
3352*795d594fSAndroid Build Coastguard Worker " Example: --symbolize=/system/framework/boot.oat\n"
3353*795d594fSAndroid Build Coastguard Worker "\n"
3354*795d594fSAndroid Build Coastguard Worker " --only-keep-debug: modifies the behaviour of --symbolize so that\n"
3355*795d594fSAndroid Build Coastguard Worker " .rodata and .text sections are omitted in the output file to save space.\n"
3356*795d594fSAndroid Build Coastguard Worker " Example: --symbolize=/system/framework/boot.oat --only-keep-debug\n"
3357*795d594fSAndroid Build Coastguard Worker "\n"
3358*795d594fSAndroid Build Coastguard Worker " --class-filter=<class name>: only dumps classes that contain the filter.\n"
3359*795d594fSAndroid Build Coastguard Worker " Example: --class-filter=com.example.foo\n"
3360*795d594fSAndroid Build Coastguard Worker "\n"
3361*795d594fSAndroid Build Coastguard Worker " --method-filter=<method name>: only dumps methods that contain the filter.\n"
3362*795d594fSAndroid Build Coastguard Worker " Example: --method-filter=foo\n"
3363*795d594fSAndroid Build Coastguard Worker "\n"
3364*795d594fSAndroid Build Coastguard Worker " --dump-method-and-offset-as-json: dumps fully qualified method names and\n"
3365*795d594fSAndroid Build Coastguard Worker " signatures ONLY, in a standard json format.\n"
3366*795d594fSAndroid Build Coastguard Worker " Example: --dump-method-and-offset-as-json\n"
3367*795d594fSAndroid Build Coastguard Worker "\n"
3368*795d594fSAndroid Build Coastguard Worker " --export-dex-to=<directory>: may be used to export oat embedded dex files.\n"
3369*795d594fSAndroid Build Coastguard Worker " Example: --export-dex-to=/data/local/tmp\n"
3370*795d594fSAndroid Build Coastguard Worker "\n"
3371*795d594fSAndroid Build Coastguard Worker " --addr2instr=<address>: output matching method disassembled code from relative\n"
3372*795d594fSAndroid Build Coastguard Worker " address (e.g. PC from crash dump)\n"
3373*795d594fSAndroid Build Coastguard Worker " Example: --addr2instr=0x00001a3b\n"
3374*795d594fSAndroid Build Coastguard Worker "\n"
3375*795d594fSAndroid Build Coastguard Worker " --dump-imt=<file.txt>: output IMT collisions (if any) for the given receiver\n"
3376*795d594fSAndroid Build Coastguard Worker " types and interface methods in the given file. The file\n"
3377*795d594fSAndroid Build Coastguard Worker " is read line-wise, where each line should either be a class\n"
3378*795d594fSAndroid Build Coastguard Worker " name or descriptor, or a class name/descriptor and a prefix\n"
3379*795d594fSAndroid Build Coastguard Worker " of a complete method name (separated by a whitespace).\n"
3380*795d594fSAndroid Build Coastguard Worker " Example: --dump-imt=imt.txt\n"
3381*795d594fSAndroid Build Coastguard Worker "\n"
3382*795d594fSAndroid Build Coastguard Worker " --dump-imt-stats: modifies the behavior of --dump-imt to also output IMT statistics\n"
3383*795d594fSAndroid Build Coastguard Worker " for the boot image.\n"
3384*795d594fSAndroid Build Coastguard Worker " Example: --dump-imt-stats"
3385*795d594fSAndroid Build Coastguard Worker "\n";
3386*795d594fSAndroid Build Coastguard Worker
3387*795d594fSAndroid Build Coastguard Worker return usage;
3388*795d594fSAndroid Build Coastguard Worker }
3389*795d594fSAndroid Build Coastguard Worker
3390*795d594fSAndroid Build Coastguard Worker public:
GetModeart::OatdumpArgs3391*795d594fSAndroid Build Coastguard Worker OatDumpMode GetMode() {
3392*795d594fSAndroid Build Coastguard Worker // Keep the order of precedence for backward compatibility.
3393*795d594fSAndroid Build Coastguard Worker if (symbolize_) {
3394*795d594fSAndroid Build Coastguard Worker return OatDumpMode::kSymbolize;
3395*795d594fSAndroid Build Coastguard Worker }
3396*795d594fSAndroid Build Coastguard Worker if (!imt_dump_.empty()) {
3397*795d594fSAndroid Build Coastguard Worker return OatDumpMode::kDumpImt;
3398*795d594fSAndroid Build Coastguard Worker }
3399*795d594fSAndroid Build Coastguard Worker if (image_location_ != nullptr || app_image_ != nullptr) {
3400*795d594fSAndroid Build Coastguard Worker return OatDumpMode::kDumpImage;
3401*795d594fSAndroid Build Coastguard Worker }
3402*795d594fSAndroid Build Coastguard Worker CHECK_NE(oat_filename_, nullptr);
3403*795d594fSAndroid Build Coastguard Worker return OatDumpMode::kDumpOat;
3404*795d594fSAndroid Build Coastguard Worker }
3405*795d594fSAndroid Build Coastguard Worker
3406*795d594fSAndroid Build Coastguard Worker const char* oat_filename_ = nullptr;
3407*795d594fSAndroid Build Coastguard Worker const char* dex_filename_ = nullptr;
3408*795d594fSAndroid Build Coastguard Worker const char* class_filter_ = "";
3409*795d594fSAndroid Build Coastguard Worker const char* method_filter_ = "";
3410*795d594fSAndroid Build Coastguard Worker const char* image_location_ = nullptr;
3411*795d594fSAndroid Build Coastguard Worker std::string elf_filename_prefix_;
3412*795d594fSAndroid Build Coastguard Worker std::string imt_dump_;
3413*795d594fSAndroid Build Coastguard Worker bool dump_vmap_ = true;
3414*795d594fSAndroid Build Coastguard Worker bool dump_code_info_stack_maps_ = false;
3415*795d594fSAndroid Build Coastguard Worker bool disassemble_code_ = true;
3416*795d594fSAndroid Build Coastguard Worker bool symbolize_ = false;
3417*795d594fSAndroid Build Coastguard Worker bool only_keep_debug_ = false;
3418*795d594fSAndroid Build Coastguard Worker bool list_classes_ = false;
3419*795d594fSAndroid Build Coastguard Worker bool list_methods_ = false;
3420*795d594fSAndroid Build Coastguard Worker bool dump_header_only_ = false;
3421*795d594fSAndroid Build Coastguard Worker bool imt_stat_dump_ = false;
3422*795d594fSAndroid Build Coastguard Worker bool dump_method_and_offset_as_json = false;
3423*795d594fSAndroid Build Coastguard Worker uint32_t addr2instr_ = 0;
3424*795d594fSAndroid Build Coastguard Worker const char* export_dex_location_ = nullptr;
3425*795d594fSAndroid Build Coastguard Worker const char* app_image_ = nullptr;
3426*795d594fSAndroid Build Coastguard Worker const char* app_oat_ = nullptr;
3427*795d594fSAndroid Build Coastguard Worker };
3428*795d594fSAndroid Build Coastguard Worker
3429*795d594fSAndroid Build Coastguard Worker struct OatdumpMain : public CmdlineMain<OatdumpArgs> {
NeedsRuntimeart::OatdumpMain3430*795d594fSAndroid Build Coastguard Worker bool NeedsRuntime() override {
3431*795d594fSAndroid Build Coastguard Worker CHECK(args_ != nullptr);
3432*795d594fSAndroid Build Coastguard Worker
3433*795d594fSAndroid Build Coastguard Worker OatDumpMode mode = args_->GetMode();
3434*795d594fSAndroid Build Coastguard Worker
3435*795d594fSAndroid Build Coastguard Worker // Only enable absolute_addresses for image dumping.
3436*795d594fSAndroid Build Coastguard Worker bool absolute_addresses = mode == OatDumpMode::kDumpImage;
3437*795d594fSAndroid Build Coastguard Worker
3438*795d594fSAndroid Build Coastguard Worker oat_dumper_options_.reset(new OatDumperOptions(args_->dump_vmap_,
3439*795d594fSAndroid Build Coastguard Worker args_->dump_code_info_stack_maps_,
3440*795d594fSAndroid Build Coastguard Worker args_->disassemble_code_,
3441*795d594fSAndroid Build Coastguard Worker absolute_addresses,
3442*795d594fSAndroid Build Coastguard Worker args_->class_filter_,
3443*795d594fSAndroid Build Coastguard Worker args_->method_filter_,
3444*795d594fSAndroid Build Coastguard Worker args_->list_classes_,
3445*795d594fSAndroid Build Coastguard Worker args_->list_methods_,
3446*795d594fSAndroid Build Coastguard Worker args_->dump_header_only_,
3447*795d594fSAndroid Build Coastguard Worker args_->dump_method_and_offset_as_json,
3448*795d594fSAndroid Build Coastguard Worker args_->export_dex_location_,
3449*795d594fSAndroid Build Coastguard Worker args_->app_image_,
3450*795d594fSAndroid Build Coastguard Worker args_->oat_filename_,
3451*795d594fSAndroid Build Coastguard Worker args_->dex_filename_,
3452*795d594fSAndroid Build Coastguard Worker args_->addr2instr_));
3453*795d594fSAndroid Build Coastguard Worker
3454*795d594fSAndroid Build Coastguard Worker switch (mode) {
3455*795d594fSAndroid Build Coastguard Worker case OatDumpMode::kDumpImt:
3456*795d594fSAndroid Build Coastguard Worker case OatDumpMode::kDumpImage:
3457*795d594fSAndroid Build Coastguard Worker return true;
3458*795d594fSAndroid Build Coastguard Worker case OatDumpMode::kSymbolize:
3459*795d594fSAndroid Build Coastguard Worker return false;
3460*795d594fSAndroid Build Coastguard Worker case OatDumpMode::kDumpOat:
3461*795d594fSAndroid Build Coastguard Worker std::string error_msg;
3462*795d594fSAndroid Build Coastguard Worker if (CanDumpWithRuntime(&error_msg)) {
3463*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "Dumping oat file with runtime";
3464*795d594fSAndroid Build Coastguard Worker return true;
3465*795d594fSAndroid Build Coastguard Worker } else {
3466*795d594fSAndroid Build Coastguard Worker LOG(INFO) << ART_FORMAT("Cannot dump oat file with runtime: {}. Dumping without runtime",
3467*795d594fSAndroid Build Coastguard Worker error_msg);
3468*795d594fSAndroid Build Coastguard Worker return false;
3469*795d594fSAndroid Build Coastguard Worker }
3470*795d594fSAndroid Build Coastguard Worker }
3471*795d594fSAndroid Build Coastguard Worker }
3472*795d594fSAndroid Build Coastguard Worker
ExecuteWithoutRuntimeart::OatdumpMain3473*795d594fSAndroid Build Coastguard Worker bool ExecuteWithoutRuntime() override {
3474*795d594fSAndroid Build Coastguard Worker CHECK(args_ != nullptr);
3475*795d594fSAndroid Build Coastguard Worker
3476*795d594fSAndroid Build Coastguard Worker OatDumpMode mode = args_->GetMode();
3477*795d594fSAndroid Build Coastguard Worker CHECK(mode == OatDumpMode::kSymbolize || mode == OatDumpMode::kDumpOat);
3478*795d594fSAndroid Build Coastguard Worker
3479*795d594fSAndroid Build Coastguard Worker MemMap::Init();
3480*795d594fSAndroid Build Coastguard Worker
3481*795d594fSAndroid Build Coastguard Worker if (mode == OatDumpMode::kSymbolize) {
3482*795d594fSAndroid Build Coastguard Worker // ELF has special kind of section called SHT_NOBITS which allows us to create
3483*795d594fSAndroid Build Coastguard Worker // sections which exist but their data is omitted from the ELF file to save space.
3484*795d594fSAndroid Build Coastguard Worker // This is what "strip --only-keep-debug" does when it creates separate ELF file
3485*795d594fSAndroid Build Coastguard Worker // with only debug data. We use it in similar way to exclude .rodata and .text.
3486*795d594fSAndroid Build Coastguard Worker bool no_bits = args_->only_keep_debug_;
3487*795d594fSAndroid Build Coastguard Worker return SymbolizeOat(
3488*795d594fSAndroid Build Coastguard Worker args_->oat_filename_, args_->dex_filename_, args_->output_name_, no_bits) ==
3489*795d594fSAndroid Build Coastguard Worker EXIT_SUCCESS;
3490*795d594fSAndroid Build Coastguard Worker }
3491*795d594fSAndroid Build Coastguard Worker
3492*795d594fSAndroid Build Coastguard Worker return DumpOat(nullptr, oat_dumper_options_.get(), args_->os_) == EXIT_SUCCESS;
3493*795d594fSAndroid Build Coastguard Worker }
3494*795d594fSAndroid Build Coastguard Worker
ExecuteWithRuntimeart::OatdumpMain3495*795d594fSAndroid Build Coastguard Worker bool ExecuteWithRuntime(Runtime* runtime) override {
3496*795d594fSAndroid Build Coastguard Worker CHECK(args_ != nullptr);
3497*795d594fSAndroid Build Coastguard Worker OatDumpMode mode = args_->GetMode();
3498*795d594fSAndroid Build Coastguard Worker CHECK(mode == OatDumpMode::kDumpImt || mode == OatDumpMode::kDumpImage ||
3499*795d594fSAndroid Build Coastguard Worker mode == OatDumpMode::kDumpOat);
3500*795d594fSAndroid Build Coastguard Worker
3501*795d594fSAndroid Build Coastguard Worker if (mode == OatDumpMode::kDumpImt) {
3502*795d594fSAndroid Build Coastguard Worker return IMTDumper::Dump(runtime,
3503*795d594fSAndroid Build Coastguard Worker args_->imt_dump_,
3504*795d594fSAndroid Build Coastguard Worker args_->imt_stat_dump_,
3505*795d594fSAndroid Build Coastguard Worker args_->oat_filename_,
3506*795d594fSAndroid Build Coastguard Worker args_->dex_filename_);
3507*795d594fSAndroid Build Coastguard Worker }
3508*795d594fSAndroid Build Coastguard Worker
3509*795d594fSAndroid Build Coastguard Worker if (mode == OatDumpMode::kDumpOat) {
3510*795d594fSAndroid Build Coastguard Worker return DumpOat(runtime, oat_dumper_options_.get(), args_->os_) == EXIT_SUCCESS;
3511*795d594fSAndroid Build Coastguard Worker }
3512*795d594fSAndroid Build Coastguard Worker
3513*795d594fSAndroid Build Coastguard Worker return DumpImages(runtime, oat_dumper_options_.get(), args_->os_) == EXIT_SUCCESS;
3514*795d594fSAndroid Build Coastguard Worker }
3515*795d594fSAndroid Build Coastguard Worker
CanDumpWithRuntimeart::OatdumpMain3516*795d594fSAndroid Build Coastguard Worker bool CanDumpWithRuntime(std::string* error_msg) {
3517*795d594fSAndroid Build Coastguard Worker std::unique_ptr<OatFileAssistantContext> ofa_context =
3518*795d594fSAndroid Build Coastguard Worker args_->GetOatFileAssistantContext(error_msg);
3519*795d594fSAndroid Build Coastguard Worker if (ofa_context == nullptr) {
3520*795d594fSAndroid Build Coastguard Worker return false;
3521*795d594fSAndroid Build Coastguard Worker }
3522*795d594fSAndroid Build Coastguard Worker
3523*795d594fSAndroid Build Coastguard Worker std::unique_ptr<OatFile> oat_file =
3524*795d594fSAndroid Build Coastguard Worker OpenOat(*oat_dumper_options_->oat_filename_, oat_dumper_options_->dex_filename_, error_msg);
3525*795d594fSAndroid Build Coastguard Worker if (oat_file == nullptr) {
3526*795d594fSAndroid Build Coastguard Worker *error_msg = ART_FORMAT(
3527*795d594fSAndroid Build Coastguard Worker "Failed to open oat file from '{}': {}", *oat_dumper_options_->oat_filename_, *error_msg);
3528*795d594fSAndroid Build Coastguard Worker return false;
3529*795d594fSAndroid Build Coastguard Worker }
3530*795d594fSAndroid Build Coastguard Worker
3531*795d594fSAndroid Build Coastguard Worker const std::vector<const OatDexFile*>& dex_files = oat_file->GetOatDexFiles();
3532*795d594fSAndroid Build Coastguard Worker if (dex_files.empty()) {
3533*795d594fSAndroid Build Coastguard Worker // Dump header only. Don't need a runtime.
3534*795d594fSAndroid Build Coastguard Worker *error_msg = "No dex code";
3535*795d594fSAndroid Build Coastguard Worker return false;
3536*795d594fSAndroid Build Coastguard Worker }
3537*795d594fSAndroid Build Coastguard Worker
3538*795d594fSAndroid Build Coastguard Worker OatFileAssistant oat_file_assistant(dex_files[0]->GetLocation().c_str(),
3539*795d594fSAndroid Build Coastguard Worker args_->instruction_set_,
3540*795d594fSAndroid Build Coastguard Worker /*context=*/nullptr,
3541*795d594fSAndroid Build Coastguard Worker /*load_executable=*/false,
3542*795d594fSAndroid Build Coastguard Worker /*only_load_trusted_executable=*/false,
3543*795d594fSAndroid Build Coastguard Worker ofa_context.get());
3544*795d594fSAndroid Build Coastguard Worker
3545*795d594fSAndroid Build Coastguard Worker if (!oat_file_assistant.ValidateBootClassPathChecksums(*oat_file)) {
3546*795d594fSAndroid Build Coastguard Worker *error_msg = "BCP checksum check failed";
3547*795d594fSAndroid Build Coastguard Worker return false;
3548*795d594fSAndroid Build Coastguard Worker }
3549*795d594fSAndroid Build Coastguard Worker
3550*795d594fSAndroid Build Coastguard Worker return true;
3551*795d594fSAndroid Build Coastguard Worker }
3552*795d594fSAndroid Build Coastguard Worker
3553*795d594fSAndroid Build Coastguard Worker std::unique_ptr<OatDumperOptions> oat_dumper_options_;
3554*795d594fSAndroid Build Coastguard Worker };
3555*795d594fSAndroid Build Coastguard Worker
3556*795d594fSAndroid Build Coastguard Worker } // namespace art
3557*795d594fSAndroid Build Coastguard Worker
main(int argc,char ** argv)3558*795d594fSAndroid Build Coastguard Worker int main(int argc, char** argv) {
3559*795d594fSAndroid Build Coastguard Worker // Output all logging to stderr.
3560*795d594fSAndroid Build Coastguard Worker android::base::SetLogger(android::base::StderrLogger);
3561*795d594fSAndroid Build Coastguard Worker
3562*795d594fSAndroid Build Coastguard Worker art::OatdumpMain main;
3563*795d594fSAndroid Build Coastguard Worker return main.Main(argc, argv);
3564*795d594fSAndroid Build Coastguard Worker }
3565