summaryrefslogtreecommitdiffstats
path: root/oatdump/oatdump.cc
diff options
context:
space:
mode:
authorAndreas Gampe <agampe@google.com>2014-09-04 21:47:42 -0700
committerAndreas Gampe <agampe@google.com>2014-09-05 21:54:26 -0700
commit54fc26c7350beb782d042ba61cb06284b3a367e4 (patch)
tree210758446cb200d1497172e7664152db16118348 /oatdump/oatdump.cc
parented20a4d80bcd8d47b5bcdd51ef17c786c0e5015c (diff)
downloadandroid_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.cc245
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;
}