diff options
-rw-r--r-- | compiler/driver/compiler_driver.h | 8 | ||||
-rw-r--r-- | compiler/driver/compiler_options.h | 15 | ||||
-rw-r--r-- | compiler/elf_writer_quick.cc | 16 | ||||
-rw-r--r-- | compiler/elf_writer_quick.h | 5 | ||||
-rw-r--r-- | compiler/oat_writer.cc | 58 | ||||
-rw-r--r-- | compiler/oat_writer.h | 4 | ||||
-rw-r--r-- | dex2oat/dex2oat.cc | 32 |
7 files changed, 102 insertions, 36 deletions
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index fad6798..9903421 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -28,6 +28,7 @@ #include "compiled_method.h" #include "compiler.h" #include "dex_file.h" +#include "driver/compiler_options.h" #include "instruction_set.h" #include "invoke_type.h" #include "method_reference.h" @@ -105,8 +106,7 @@ class CompilerDriver { InstructionSetFeatures instruction_set_features, bool image, DescriptorSet* image_classes, size_t thread_count, bool dump_stats, bool dump_passes, - CumulativeLogger* timer, - std::string profile_file = ""); + CumulativeLogger* timer, std::string profile_file = ""); ~CompilerDriver(); @@ -394,6 +394,10 @@ class CompilerDriver { return dump_passes_; } + bool DidIncludeDebugSymbols() const { + return compiler_options_->GetIncludeDebugSymbols(); + } + CumulativeLogger* GetTimingsLogger() const { return timings_logger_; } diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h index 05a9ac7..5d1c5da 100644 --- a/compiler/driver/compiler_options.h +++ b/compiler/driver/compiler_options.h @@ -42,6 +42,7 @@ class CompilerOptions { static const size_t kDefaultTinyMethodThreshold = 20; static const size_t kDefaultNumDexMethodsThreshold = 900; static constexpr double kDefaultTopKProfileThreshold = 90.0; + static const bool kDefaultIncludeDebugSymbols = kIsDebugBuild; CompilerOptions() : compiler_filter_(kDefaultCompilerFilter), @@ -51,7 +52,8 @@ class CompilerOptions { tiny_method_threshold_(kDefaultTinyMethodThreshold), num_dex_methods_threshold_(kDefaultNumDexMethodsThreshold), generate_gdb_information_(false), - top_k_profile_threshold_(kDefaultTopKProfileThreshold) + top_k_profile_threshold_(kDefaultTopKProfileThreshold), + include_debug_symbols_(kDefaultIncludeDebugSymbols) #ifdef ART_SEA_IR_MODE , sea_ir_mode_(false) #endif @@ -64,7 +66,8 @@ class CompilerOptions { size_t tiny_method_threshold, size_t num_dex_methods_threshold, bool generate_gdb_information, - double top_k_profile_threshold + double top_k_profile_threshold, + bool include_debug_symbols #ifdef ART_SEA_IR_MODE , bool sea_ir_mode #endif @@ -76,7 +79,8 @@ class CompilerOptions { tiny_method_threshold_(tiny_method_threshold), num_dex_methods_threshold_(num_dex_methods_threshold), generate_gdb_information_(generate_gdb_information), - top_k_profile_threshold_(top_k_profile_threshold) + top_k_profile_threshold_(top_k_profile_threshold), + include_debug_symbols_(include_debug_symbols) #ifdef ART_SEA_IR_MODE , sea_ir_mode_(sea_ir_mode) #endif @@ -139,6 +143,10 @@ class CompilerOptions { return top_k_profile_threshold_; } + bool GetIncludeDebugSymbols() const { + return include_debug_symbols_; + } + #ifdef ART_SEA_IR_MODE bool GetSeaIrMode(); #endif @@ -157,6 +165,7 @@ class CompilerOptions { bool generate_gdb_information_; // When using a profile file only the top K% of the profiled samples will be compiled. double top_k_profile_threshold_; + bool include_debug_symbols_; #ifdef ART_SEA_IR_MODE bool sea_ir_mode_; #endif diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc index cb66e48..78757ec 100644 --- a/compiler/elf_writer_quick.cc +++ b/compiler/elf_writer_quick.cc @@ -807,12 +807,17 @@ bool ElfWriterQuick::Write(OatWriter* oat_writer, const std::string& android_root_unused, bool is_host_unused) { const bool debug = false; + const bool add_symbols = oat_writer->DidAddSymbols(); const OatHeader& oat_header = oat_writer->GetOatHeader(); Elf32_Word oat_data_size = oat_header.GetExecutableOffset(); uint32_t oat_exec_size = oat_writer->GetSize() - oat_data_size; ElfBuilder builder(oat_writer, elf_file_, compiler_driver_->GetInstructionSet(), 0, - oat_data_size, oat_data_size, oat_exec_size, false, debug); + oat_data_size, oat_data_size, oat_exec_size, add_symbols, debug); + + if (add_symbols) { + AddDebugSymbols(builder, oat_writer, debug); + } bool generateDebugInformation = compiler_driver_->GetCallFrameInformation() != nullptr; if (generateDebugInformation) { @@ -833,6 +838,15 @@ bool ElfWriterQuick::Write(OatWriter* oat_writer, return builder.Write(); } +void ElfWriterQuick::AddDebugSymbols(ElfBuilder& builder, OatWriter* oat_writer, bool debug) { + const std::vector<OatWriter::DebugInfo>& method_info = oat_writer->GetCFIMethodInfo(); + ElfSymtabBuilder* symtab = &builder.symtab_builder_; + for (auto it = method_info.begin(); it != method_info.end(); ++it) { + symtab->AddSymbol(it->method_name_, &builder.text_builder_, it->low_pc_, true, + it->high_pc_ - it->low_pc_, STB_GLOBAL, STT_FUNC); + } +} + static void UpdateWord(std::vector<uint8_t>*buf, int offset, int data) { (*buf)[offset+0] = data; (*buf)[offset+1] = data >> 8; diff --git a/compiler/elf_writer_quick.h b/compiler/elf_writer_quick.h index f687d2e..dbdccfc 100644 --- a/compiler/elf_writer_quick.h +++ b/compiler/elf_writer_quick.h @@ -48,6 +48,10 @@ class ElfWriterQuick FINAL : public ElfWriter { ~ElfWriterQuick() {} class ElfBuilder; + void AddDebugSymbols(ElfBuilder& builder, + OatWriter* oat_writer, + bool debug); + class ElfSectionBuilder { public: ElfSectionBuilder(const std::string& sec_name, Elf32_Word type, Elf32_Word flags, @@ -235,7 +239,6 @@ class ElfWriterQuick FINAL : public ElfWriter { ~ElfBuilder() {} bool Write(); - ElfSymtabBuilder* GetDefaultDynsymBuilder() { return &dynsym_builder_; } // Adds the given raw section to the builder. This will copy it. The caller // is responsible for deallocating their copy. diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index 5d532ab..65bc318 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -350,31 +350,14 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { uint32_t thumb_offset = compiled_method->CodeDelta(); quick_code_offset = offset_ + sizeof(OatQuickMethodHeader) + thumb_offset; - std::vector<uint8_t>* cfi_info = writer_->compiler_driver_->GetCallFrameInformation(); - if (cfi_info != nullptr) { - // Copy in the FDE, if present - const std::vector<uint8_t>* fde = compiled_method->GetCFIInfo(); - if (fde != nullptr) { - // Copy the information into cfi_info and then fix the address in the new copy. - int cur_offset = cfi_info->size(); - cfi_info->insert(cfi_info->end(), fde->begin(), fde->end()); - - // Set the 'initial_location' field to address the start of the method. - uint32_t new_value = quick_code_offset - writer_->oat_header_->GetExecutableOffset(); - uint32_t offset_to_update = cur_offset + 2*sizeof(uint32_t); - (*cfi_info)[offset_to_update+0] = new_value; - (*cfi_info)[offset_to_update+1] = new_value >> 8; - (*cfi_info)[offset_to_update+2] = new_value >> 16; - (*cfi_info)[offset_to_update+3] = new_value >> 24; - std::string name = PrettyMethod(it.GetMemberIndex(), *dex_file_, false); - writer_->method_info_.push_back(DebugInfo(name, new_value, new_value + code_size)); - } - } + bool force_debug_capture = false; + bool deduped = false; // Deduplicate code arrays. auto code_iter = dedupe_map_.find(compiled_method); if (code_iter != dedupe_map_.end()) { quick_code_offset = code_iter->second; + deduped = true; } else { dedupe_map_.Put(compiled_method, quick_code_offset); } @@ -409,6 +392,41 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { writer_->oat_header_->UpdateChecksum(&(*quick_code)[0], code_size); offset_ += code_size; } + + uint32_t quick_code_start = quick_code_offset - writer_->oat_header_->GetExecutableOffset(); + std::vector<uint8_t>* cfi_info = writer_->compiler_driver_->GetCallFrameInformation(); + if (cfi_info != nullptr) { + // Copy in the FDE, if present + const std::vector<uint8_t>* fde = compiled_method->GetCFIInfo(); + if (fde != nullptr) { + // Copy the information into cfi_info and then fix the address in the new copy. + int cur_offset = cfi_info->size(); + cfi_info->insert(cfi_info->end(), fde->begin(), fde->end()); + + // Set the 'initial_location' field to address the start of the method. + uint32_t offset_to_update = cur_offset + 2*sizeof(uint32_t); + (*cfi_info)[offset_to_update+0] = quick_code_start; + (*cfi_info)[offset_to_update+1] = quick_code_start >> 8; + (*cfi_info)[offset_to_update+2] = quick_code_start >> 16; + (*cfi_info)[offset_to_update+3] = quick_code_start >> 24; + force_debug_capture = true; + } + } + + + if (writer_->compiler_driver_->DidIncludeDebugSymbols() || force_debug_capture) { + // Record debug information for this function if we are doing that or + // we have CFI and so need it. + std::string name = PrettyMethod(it.GetMemberIndex(), *dex_file_, true); + if (deduped) { + // TODO We should place the DEDUPED tag on the first instance of a + // deduplicated symbol so that it will show up in a debuggerd crash + // report. + name += " [ DEDUPED ]"; + } + writer_->method_info_.push_back(DebugInfo(name, quick_code_start, + quick_code_start + code_size)); + } } if (kIsDebugBuild) { diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h index 8c20aa8..dbecb95 100644 --- a/compiler/oat_writer.h +++ b/compiler/oat_writer.h @@ -108,6 +108,10 @@ class OatWriter { return method_info_; } + bool DidAddSymbols() const { + return compiler_driver_->DidIncludeDebugSymbols(); + } + private: // The DataAccess classes are helper classes that provide access to members related to // a given map, i.e. GC map, mapping table or vmap table. By abstracting these away diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 35149cf..e2943d3 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -203,6 +203,10 @@ static void Usage(const char* fmt, ...) { UsageError(""); UsageError(" --dump-timing: display a breakdown of where time was spent"); UsageError(""); + UsageError(" --include-debug-symbols: Include ELF symbols in this oat file"); + UsageError(""); + UsageError(" --no-include-debug-symbols: Do not include ELF symbols in this oat file"); + UsageError(""); UsageError(" --runtime-arg <argument>: used to specify various arguments for the runtime,"); UsageError(" such as initial heap size, maximum heap size, and verbose output."); UsageError(" Use a separate --runtime-arg switch for each argument."); @@ -816,6 +820,7 @@ static int dex2oat(int argc, char** argv) { bool dump_stats = false; bool dump_timing = false; bool dump_passes = false; + bool include_debug_symbols = kIsDebugBuild; bool dump_slow_timing = kIsDebugBuild; bool watch_dog_enabled = !kIsTargetBuild; bool generate_gdb_information = kIsDebugBuild; @@ -969,6 +974,10 @@ static int dex2oat(int argc, char** argv) { dump_passes = true; } else if (option == "--dump-stats") { dump_stats = true; + } else if (option == "--include-debug-symbols" || option == "--no-strip-symbols") { + include_debug_symbols = true; + } else if (option == "--no-include-debug-symbols" || option == "--strip-symbols") { + include_debug_symbols = false; } else if (option.starts_with("--profile-file=")) { profile_file = option.substr(strlen("--profile-file=")).data(); VLOG(compiler) << "dex2oat: profile file is " << profile_file; @@ -1122,7 +1131,8 @@ static int dex2oat(int argc, char** argv) { tiny_method_threshold, num_dex_methods_threshold, generate_gdb_information, - top_k_profile_threshold + top_k_profile_threshold, + include_debug_symbols #ifdef ART_SEA_IR_MODE , compiler_options.sea_ir_ = true; #endif @@ -1409,16 +1419,20 @@ static int dex2oat(int argc, char** argv) { } #if ART_USE_PORTABLE_COMPILER // We currently only generate symbols on Portable - timings.NewSplit("dex2oat ElfStripper"); - // Strip unneeded sections for target - off_t seek_actual = lseek(oat_file->Fd(), 0, SEEK_SET); - CHECK_EQ(0, seek_actual); - std::string error_msg; - CHECK(ElfStripper::Strip(oat_file.get(), &error_msg)) << error_msg; + if (!compiler_options.GetIncludeDebugSymbols()) { + timings.NewSplit("dex2oat ElfStripper"); + // Strip unneeded sections for target + off_t seek_actual = lseek(oat_file->Fd(), 0, SEEK_SET); + CHECK_EQ(0, seek_actual); + std::string error_msg; + CHECK(ElfStripper::Strip(oat_file.get(), &error_msg)) << error_msg; - // We wrote the oat file successfully, and want to keep it. - VLOG(compiler) << "Oat file written successfully (stripped): " << oat_location; + // We wrote the oat file successfully, and want to keep it. + VLOG(compiler) << "Oat file written successfully (stripped): " << oat_location; + } else { + VLOG(compiler) << "Oat file written successfully without stripping: " << oat_location; + } #endif // ART_USE_PORTABLE_COMPILER timings.EndSplit(); |