diff options
author | Andreas Gampe <agampe@google.com> | 2014-09-04 21:47:42 -0700 |
---|---|---|
committer | Andreas Gampe <agampe@google.com> | 2014-09-05 21:54:26 -0700 |
commit | 54fc26c7350beb782d042ba61cb06284b3a367e4 (patch) | |
tree | 210758446cb200d1497172e7664152db16118348 /oatdump/oatdump.cc | |
parent | ed20a4d80bcd8d47b5bcdd51ef17c786c0e5015c (diff) | |
download | android_art-54fc26c7350beb782d042ba61cb06284b3a367e4.tar.gz android_art-54fc26c7350beb782d042ba61cb06284b3a367e4.tar.bz2 android_art-54fc26c7350beb782d042ba61cb06284b3a367e4.zip |
ART: Refactor elf_writer_quick, add symbolizer
Refactors some classes in elf_writer_quick.h to elf_builder.h to
be more friendly for re-use. Use this in oatdump to add a symtab
to an oat file.
Bug: 17187621, 17322125
Change-Id: I2333291334fd98bd09cc5717fb83cb18efe3a029
Diffstat (limited to 'oatdump/oatdump.cc')
-rw-r--r-- | oatdump/oatdump.cc | 245 |
1 files changed, 242 insertions, 3 deletions
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 931ee562f3..fff42f6e73 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -20,6 +20,7 @@ #include <fstream> #include <iostream> #include <string> +#include <unordered_map> #include <vector> #include "base/stringpiece.h" @@ -29,6 +30,7 @@ #include "dex_file-inl.h" #include "dex_instruction.h" #include "disassembler.h" +#include "elf_builder.h" #include "field_helper.h" #include "gc_map.h" #include "gc/space/image_space.h" @@ -47,6 +49,7 @@ #include "oat.h" #include "oat_file-inl.h" #include "os.h" +#include "output_stream.h" #include "runtime.h" #include "safe_map.h" #include "scoped_thread_state_change.h" @@ -105,6 +108,224 @@ const char* image_roots_descriptions_[] = { "kClassRoots", }; +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); + 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.GetMemberAccessFlags(), 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) @@ -1537,8 +1758,10 @@ static int oatdump(int argc, char** argv) { std::string elf_filename_prefix; std::ostream* os = &std::cout; std::unique_ptr<std::ofstream> out; + std::string output_name; bool dump_raw_mapping_table = false; bool dump_raw_gc_map = false; + bool symbolize = false; for (int i = 0; i < argc; i++) { const StringPiece option(argv[i]); @@ -1571,13 +1794,17 @@ static int oatdump(int argc, char** argv) { usage(); } } else if (option.starts_with("--output=")) { - const char* filename = option.substr(strlen("--output=")).data(); + output_name = option.substr(strlen("--output=")).ToString(); + const char* filename = output_name.c_str(); out.reset(new std::ofstream(filename)); if (!out->good()) { fprintf(stderr, "Failed to open output filename %s\n", filename); usage(); } os = out.get(); + } else if (option.starts_with("--symbolize=")) { + oat_filename = option.substr(strlen("--symbolize=")).data(); + symbolize = true; } else { fprintf(stderr, "Unknown argument %s\n", option.data()); usage(); @@ -1602,8 +1829,20 @@ static int oatdump(int argc, char** argv) { fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str()); return EXIT_FAILURE; } - OatDumper oat_dumper(*oat_file, dump_raw_mapping_table, dump_raw_gc_map); - oat_dumper.Dump(*os); + if (symbolize) { + OatSymbolizer oat_symbolizer(oat_file, output_name); + if (!oat_symbolizer.Init()) { + fprintf(stderr, "Failed to initialize symbolizer\n"); + return EXIT_FAILURE; + } + if (!oat_symbolizer.Symbolize()) { + fprintf(stderr, "Failed to symbolize\n"); + return EXIT_FAILURE; + } + } else { + OatDumper oat_dumper(*oat_file, dump_raw_mapping_table, dump_raw_gc_map); + oat_dumper.Dump(*os); + } return EXIT_SUCCESS; } |