"kClassRoots",
};
- it.GetMethodCodeItem(), it.GetMemberAccessFlags(), callback);
+class OatSymbolizer : public CodeOutput {
+ public:
+ explicit OatSymbolizer(const OatFile* oat_file, std::string& output_name) :
+ oat_file_(oat_file), builder_(nullptr), elf_output_(nullptr), output_name_(output_name) {}
+
+ bool Init() {
+ Elf32_Word oat_data_size = oat_file_->GetOatHeader().GetExecutableOffset();
+
+ uint32_t diff = static_cast<uint32_t>(oat_file_->End() - oat_file_->Begin());
+ uint32_t oat_exec_size = diff - oat_data_size;
+
+ if (output_name_.empty()) {
+ output_name_ = "symbolized.oat";
+ }
+ elf_output_ = OS::CreateEmptyFile(output_name_.c_str());
+
+ builder_.reset(new ElfBuilder<Elf32_Word, Elf32_Sword, Elf32_Addr, Elf32_Dyn,
+ Elf32_Sym, Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>(
+ this,
+ elf_output_,
+ oat_file_->GetOatHeader().GetInstructionSet(),
+ 0,
+ oat_data_size,
+ oat_data_size,
+ oat_exec_size,
+ true,
+ false));
+
+ if (!builder_->Init()) {
+ builder_.reset(nullptr);
+ return false;
+ }
+
+ return true;
+ }
+
+ typedef void (OatSymbolizer::*Callback)(const DexFile::ClassDef&,
+ uint32_t,
+ const OatFile::OatMethod&,
+ const DexFile&,
+ uint32_t,
+ const DexFile::CodeItem*,
+ uint32_t);
+
+ bool Symbolize() {
+ if (builder_.get() == nullptr) {
+ return false;
+ }
+
+ Walk(&art::OatSymbolizer::RegisterForDedup);
+
+ NormalizeState();
+
+ Walk(&art::OatSymbolizer::AddSymbol);
+
+ bool result = builder_->Write();
+
+ elf_output_->Flush();
+ elf_output_->Close();
+
+ return result;
+ }
+
+ void Walk(Callback callback) {
+ std::vector<const OatFile::OatDexFile*> oat_dex_files = oat_file_->GetOatDexFiles();
+ for (size_t i = 0; i < oat_dex_files.size(); i++) {
+ const OatFile::OatDexFile* oat_dex_file = oat_dex_files[i];
+ CHECK(oat_dex_file != NULL);
+ WalkOatDexFile(oat_dex_file, callback);
+ }
+ }
+
+ void WalkOatDexFile(const OatFile::OatDexFile* oat_dex_file, Callback callback) {
+ std::string error_msg;
+ std::unique_ptr<const DexFile> dex_file(oat_dex_file->OpenDexFile(&error_msg));
+ if (dex_file.get() == nullptr) {
+ return;
+ }
+ for (size_t class_def_index = 0;
+ class_def_index < dex_file->NumClassDefs();
+ class_def_index++) {
+ const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
+ const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
+ OatClassType type = oat_class.GetType();
+ switch (type) {
+ case kOatClassAllCompiled:
+ case kOatClassSomeCompiled:
+ WalkOatClass(oat_class, *dex_file.get(), class_def, callback);
+ break;
+
+ case kOatClassNoneCompiled:
+ case kOatClassMax:
+ // Ignore.
+ break;
+ }
+ }
+ }
+
+ void WalkOatClass(const OatFile::OatClass& oat_class, const DexFile& dex_file,
+ const DexFile::ClassDef& class_def, Callback callback) {
+ const byte* class_data = dex_file.GetClassData(class_def);
+ if (class_data == nullptr) { // empty class such as a marker interface?
+ return;
+ }
+ // Note: even if this is an interface or a native class, we still have to walk it, as there
+ // might be a static initializer.
+ ClassDataItemIterator it(dex_file, class_data);
+ SkipAllFields(&it);
+ uint32_t class_method_idx = 0;
+ while (it.HasNextDirectMethod()) {
+ const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_idx);
+ WalkOatMethod(class_def, class_method_idx, oat_method, dex_file, it.GetMemberIndex(),
- it.GetMethodCodeItem(), it.GetMemberAccessFlags(), callback);
++ it.GetMethodCodeItem(), it.GetMethodAccessFlags(), callback);
+ class_method_idx++;
+ it.Next();
+ }
+ while (it.HasNextVirtualMethod()) {
+ const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_idx);
+ WalkOatMethod(class_def, class_method_idx, oat_method, dex_file, it.GetMemberIndex(),
++ it.GetMethodCodeItem(), it.GetMethodAccessFlags(), callback);
+ class_method_idx++;
+ it.Next();
+ }
+ DCHECK(!it.HasNext());
+ }
+
+ void WalkOatMethod(const DexFile::ClassDef& class_def, uint32_t class_method_index,
+ const OatFile::OatMethod& oat_method, const DexFile& dex_file,
+ uint32_t dex_method_idx, const DexFile::CodeItem* code_item,
+ uint32_t method_access_flags, Callback callback) {
+ if ((method_access_flags & kAccAbstract) != 0) {
+ // Abstract method, no code.
+ return;
+ }
+ if (oat_method.GetCodeOffset() == 0) {
+ // No code.
+ return;
+ }
+
+ (this->*callback)(class_def, class_method_index, oat_method, dex_file, dex_method_idx, code_item,
+ method_access_flags);
+ }
+
+ void RegisterForDedup(const DexFile::ClassDef& class_def, uint32_t class_method_index,
+ const OatFile::OatMethod& oat_method, const DexFile& dex_file,
+ uint32_t dex_method_idx, const DexFile::CodeItem* code_item,
+ uint32_t method_access_flags) {
+ state_[oat_method.GetCodeOffset()]++;
+ }
+
+ void NormalizeState() {
+ for (auto& x : state_) {
+ if (x.second == 1) {
+ state_[x.first] = 0;
+ }
+ }
+ }
+
+ enum class DedupState { // private
+ kNotDeduplicated,
+ kDeduplicatedFirst,
+ kDeduplicatedOther
+ };
+ DedupState IsDuplicated(uint32_t offset) {
+ if (state_[offset] == 0) {
+ return DedupState::kNotDeduplicated;
+ }
+ if (state_[offset] == 1) {
+ return DedupState::kDeduplicatedOther;
+ }
+ state_[offset] = 1;
+ return DedupState::kDeduplicatedFirst;
+ }
+
+ void AddSymbol(const DexFile::ClassDef& class_def, uint32_t class_method_index,
+ const OatFile::OatMethod& oat_method, const DexFile& dex_file,
+ uint32_t dex_method_idx, const DexFile::CodeItem* code_item,
+ uint32_t method_access_flags) {
+ DedupState dedup = IsDuplicated(oat_method.GetCodeOffset());
+ if (dedup != DedupState::kDeduplicatedOther) {
+ std::string pretty_name = PrettyMethod(dex_method_idx, dex_file, true);
+
+ if (dedup == DedupState::kDeduplicatedFirst) {
+ pretty_name = "[Dedup]" + pretty_name;
+ }
+
+ ElfSymtabBuilder<Elf32_Word, Elf32_Sword, Elf32_Addr,
+ Elf32_Sym, Elf32_Shdr>* symtab = &builder_->symtab_builder_;
+
+ symtab->AddSymbol(pretty_name, &builder_->text_builder_, oat_method.GetCodeOffset() -
+ oat_file_->GetOatHeader().GetExecutableOffset(), true,
+ oat_method.GetQuickCodeSize(), STB_GLOBAL, STT_FUNC);
+ }
+ }
+
+ // Write oat code. Required by ElfBuilder/CodeOutput.
+ bool Write(OutputStream* out) {
+ return out->WriteFully(oat_file_->Begin(), oat_file_->End() - oat_file_->Begin());
+ }
+
+ private:
+ static void SkipAllFields(ClassDataItemIterator* it) {
+ while (it->HasNextStaticField()) {
+ it->Next();
+ }
+ while (it->HasNextInstanceField()) {
+ it->Next();
+ }
+ }
+
+ const OatFile* oat_file_;
+ std::unique_ptr<ElfBuilder<Elf32_Word, Elf32_Sword, Elf32_Addr, Elf32_Dyn,
+ Elf32_Sym, Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr> > builder_;
+ File* elf_output_;
+ std::unordered_map<uint32_t, uint32_t> state_;
+ std::string output_name_;
+};
+
class OatDumper {
public:
explicit OatDumper(const OatFile& oat_file, bool dump_raw_mapping_table, bool dump_raw_gc_map)