diff options
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/class_linker.cc | 13 | ||||
-rw-r--r-- | runtime/elf_file.cc | 85 | ||||
-rw-r--r-- | runtime/elf_file_impl.h | 9 | ||||
-rw-r--r-- | runtime/gc/heap.cc | 1 | ||||
-rw-r--r-- | runtime/gc/space/image_space.cc | 5 | ||||
-rw-r--r-- | runtime/gc/space/image_space.h | 4 | ||||
-rw-r--r-- | runtime/mem_map.cc | 8 | ||||
-rw-r--r-- | runtime/mem_map.h | 6 | ||||
-rw-r--r-- | runtime/native/dalvik_system_ZygoteHooks.cc | 10 | ||||
-rw-r--r-- | runtime/oat_file.cc | 61 | ||||
-rw-r--r-- | runtime/oat_file.h | 3 |
11 files changed, 120 insertions, 85 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 91812e7..ae952e6 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -808,18 +808,11 @@ static void FreeDexFilesInHeap(std::priority_queue<DexFileAndClassPair>* heap) { } const OatFile* ClassLinker::GetBootOatFile() { - // To grab the boot oat, look at the dex files in the boot classpath. Any of those is fine, as - // they were all compiled into the same oat file. So grab the first one, which is guaranteed to - // exist if the boot class-path isn't empty. - if (boot_class_path_.empty()) { + gc::space::ImageSpace* image_space = Runtime::Current()->GetHeap()->GetImageSpace(); + if (image_space == nullptr) { return nullptr; } - const DexFile* boot_dex_file = boot_class_path_[0]; - // Is it from an oat file? - if (boot_dex_file->GetOatDexFile() != nullptr) { - return boot_dex_file->GetOatDexFile()->GetOatFile(); - } - return nullptr; + return image_space->GetOatFile(); } const OatFile* ClassLinker::GetPrimaryOatFile() { diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc index 0c5210d..9fd8c87 100644 --- a/runtime/elf_file.cc +++ b/runtime/elf_file.cc @@ -1401,88 +1401,53 @@ typename ElfTypes::Shdr* ElfFileImpl<ElfTypes>::FindSectionByName( } template <typename ElfTypes> -bool ElfFileImpl<ElfTypes>::FixupDebugSections(typename std::make_signed<Elf_Off>::type base_address_delta) { - const Elf_Shdr* debug_info = FindSectionByName(".debug_info"); - const Elf_Shdr* debug_abbrev = FindSectionByName(".debug_abbrev"); - const Elf_Shdr* debug_str = FindSectionByName(".debug_str"); - const Elf_Shdr* strtab_sec = FindSectionByName(".strtab"); - const Elf_Shdr* symtab_sec = FindSectionByName(".symtab"); - - if (debug_info == nullptr || debug_abbrev == nullptr || - debug_str == nullptr || strtab_sec == nullptr || symtab_sec == nullptr) { - // Release version of ART does not generate debug info. - return true; - } +bool ElfFileImpl<ElfTypes>::FixupDebugSections(Elf_Addr base_address_delta) { if (base_address_delta == 0) { return true; } - if (!ApplyOatPatchesTo(".debug_info", base_address_delta)) { - return false; - } - if (!ApplyOatPatchesTo(".debug_line", base_address_delta)) { - return false; - } - return true; + return ApplyOatPatchesTo(".debug_frame", base_address_delta) && + ApplyOatPatchesTo(".debug_info", base_address_delta) && + ApplyOatPatchesTo(".debug_line", base_address_delta); } template <typename ElfTypes> bool ElfFileImpl<ElfTypes>::ApplyOatPatchesTo( - const char* target_section_name, - typename std::make_signed<Elf_Off>::type delta) { - auto patches_section = FindSectionByName(".oat_patches"); + const char* target_section_name, Elf_Addr delta) { + auto target_section = FindSectionByName(target_section_name); + if (target_section == nullptr) { + return true; + } + std::string patches_name = target_section_name + std::string(".oat_patches"); + auto patches_section = FindSectionByName(patches_name.c_str()); if (patches_section == nullptr) { - LOG(ERROR) << ".oat_patches section not found."; + LOG(ERROR) << patches_name << " section not found."; return false; } if (patches_section->sh_type != SHT_OAT_PATCH) { - LOG(ERROR) << "Unexpected type of .oat_patches."; - return false; - } - auto target_section = FindSectionByName(target_section_name); - if (target_section == nullptr) { - LOG(ERROR) << target_section_name << " section not found."; + LOG(ERROR) << "Unexpected type of " << patches_name; return false; } - if (!ApplyOatPatches( + ApplyOatPatches( Begin() + patches_section->sh_offset, Begin() + patches_section->sh_offset + patches_section->sh_size, - target_section_name, delta, + delta, Begin() + target_section->sh_offset, - Begin() + target_section->sh_offset + target_section->sh_size)) { - LOG(ERROR) << target_section_name << " section not found in .oat_patches."; - } + Begin() + target_section->sh_offset + target_section->sh_size); return true; } -// Apply .oat_patches to given section. +// Apply LEB128 encoded patches to given section. template <typename ElfTypes> -bool ElfFileImpl<ElfTypes>::ApplyOatPatches( - const uint8_t* patches, const uint8_t* patches_end, - const char* target_section_name, - typename std::make_signed<Elf_Off>::type delta, +void ElfFileImpl<ElfTypes>::ApplyOatPatches( + const uint8_t* patches, const uint8_t* patches_end, Elf_Addr delta, uint8_t* to_patch, const uint8_t* to_patch_end) { - // Read null-terminated section name. - const char* section_name; - while ((section_name = reinterpret_cast<const char*>(patches))[0] != '\0') { - patches += strlen(section_name) + 1; - uint32_t length = DecodeUnsignedLeb128(&patches); - const uint8_t* next_section = patches + length; - // Is it the section we want to patch? - if (strcmp(section_name, target_section_name) == 0) { - // Read LEB128 encoded list of advances. - while (patches < next_section) { - DCHECK_LT(patches, patches_end) << "Unexpected end of .oat_patches."; - to_patch += DecodeUnsignedLeb128(&patches); - DCHECK_LT(to_patch, to_patch_end) << "Patch past the end of " << section_name; - // TODO: 32-bit vs 64-bit. What is the right type to use here? - auto* patch_loc = reinterpret_cast<typename std::make_signed<Elf_Off>::type*>(to_patch); - *patch_loc += delta; - } - return true; - } - patches = next_section; + typedef __attribute__((__aligned__(1))) Elf_Addr UnalignedAddress; + while (patches < patches_end) { + to_patch += DecodeUnsignedLeb128(&patches); + DCHECK_LE(patches, patches_end) << "Unexpected end of patch list."; + DCHECK_LT(to_patch, to_patch_end) << "Patch past the end of section."; + *reinterpret_cast<UnalignedAddress*>(to_patch) += delta; } - return false; } template <typename ElfTypes> diff --git a/runtime/elf_file_impl.h b/runtime/elf_file_impl.h index 3ad096f..0f466bd 100644 --- a/runtime/elf_file_impl.h +++ b/runtime/elf_file_impl.h @@ -119,12 +119,9 @@ class ElfFileImpl { bool FixupProgramHeaders(Elf_Addr base_address); bool FixupSymbols(Elf_Addr base_address, bool dynamic); bool FixupRelocations(Elf_Addr base_address); - bool FixupDebugSections(typename std::make_signed<Elf_Off>::type base_address_delta); - bool ApplyOatPatchesTo(const char* target_section_name, - typename std::make_signed<Elf_Off>::type base_address_delta); - static bool ApplyOatPatches(const uint8_t* patches, const uint8_t* patches_end, - const char* target_section_name, - typename std::make_signed<Elf_Off>::type delta, + bool FixupDebugSections(Elf_Addr base_address_delta); + bool ApplyOatPatchesTo(const char* target_section_name, Elf_Addr base_address_delta); + static void ApplyOatPatches(const uint8_t* patches, const uint8_t* patches_end, Elf_Addr delta, uint8_t* to_patch, const uint8_t* to_patch_end); bool Strip(std::string* error_msg); diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index eabbbec..9a70d69 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -502,6 +502,7 @@ Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max bool no_gap = MemMap::CheckNoGaps(GetImageSpace()->GetMemMap(), non_moving_space_->GetMemMap()); if (!no_gap) { + PrintFileToLog("/proc/self/maps", LogSeverity::ERROR); MemMap::DumpMaps(LOG(ERROR), true); LOG(FATAL) << "There's a gap between the image space and the non-moving space"; } diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index f7ceb84..1923d24 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -755,6 +755,7 @@ ImageSpace* ImageSpace::Init(const char* image_filename, const char* image_locat DCHECK(!error_msg->empty()); return nullptr; } + space->oat_file_non_owned_ = space->oat_file_.get(); if (validate_oat_file && !space->ValidateOatFile(error_msg)) { DCHECK(!error_msg->empty()); @@ -838,10 +839,12 @@ bool ImageSpace::ValidateOatFile(std::string* error_msg) const { return true; } + const OatFile* ImageSpace::GetOatFile() const { - return oat_file_.get(); + return oat_file_non_owned_; } + OatFile* ImageSpace::ReleaseOatFile() { CHECK(oat_file_.get() != nullptr); return oat_file_.release(); diff --git a/runtime/gc/space/image_space.h b/runtime/gc/space/image_space.h index 54dc7a6..93ff8aa 100644 --- a/runtime/gc/space/image_space.h +++ b/runtime/gc/space/image_space.h @@ -152,6 +152,10 @@ class ImageSpace : public MemMapSpace { // the ClassLinker during it's initialization. std::unique_ptr<OatFile> oat_file_; + // There are times when we need to find the boot image oat file. As + // we release ownership during startup, keep a non-owned reference. + const OatFile* oat_file_non_owned_; + const std::string image_location_; DISALLOW_COPY_AND_ASSIGN(ImageSpace); diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc index d6d71f2..6566060 100644 --- a/runtime/mem_map.cc +++ b/runtime/mem_map.cc @@ -439,6 +439,14 @@ MemMap* MemMap::MapAnonymous(const char* name, uint8_t* expected_ptr, size_t byt page_aligned_byte_count, prot, false); } +MemMap* MemMap::MapDummy(const char* name, uint8_t* addr, size_t byte_count) { + if (byte_count == 0) { + return new MemMap(name, nullptr, 0, nullptr, 0, 0, false); + } + const size_t page_aligned_byte_count = RoundUp(byte_count, kPageSize); + return new MemMap(name, addr, byte_count, addr, page_aligned_byte_count, 0, true /* reuse */); +} + MemMap* MemMap::MapFileAtAddress(uint8_t* expected_ptr, size_t byte_count, int prot, int flags, int fd, off_t start, bool reuse, const char* filename, std::string* error_msg) { diff --git a/runtime/mem_map.h b/runtime/mem_map.h index 6023a70..14387ee 100644 --- a/runtime/mem_map.h +++ b/runtime/mem_map.h @@ -64,6 +64,12 @@ class MemMap { static MemMap* MapAnonymous(const char* ashmem_name, uint8_t* addr, size_t byte_count, int prot, bool low_4gb, bool reuse, std::string* error_msg); + // Create placeholder for a region allocated by direct call to mmap. + // This is useful when we do not have control over the code calling mmap, + // but when we still want to keep track of it in the list. + // The region is not considered to be owned and will not be unmmaped. + static MemMap* MapDummy(const char* name, uint8_t* addr, size_t byte_count); + // Map part of a file, taking care of non-page aligned offsets. The // "start" offset is absolute, not relative. // diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc index 1a7a3e5..1d06706 100644 --- a/runtime/native/dalvik_system_ZygoteHooks.cc +++ b/runtime/native/dalvik_system_ZygoteHooks.cc @@ -65,7 +65,7 @@ static void EnableDebugFeatures(uint32_t debug_flags) { DEBUG_ENABLE_SAFEMODE = 1 << 3, DEBUG_ENABLE_JNI_LOGGING = 1 << 4, DEBUG_ENABLE_JIT = 1 << 5, - DEBUG_GENERATE_CFI = 1 << 6, + DEBUG_GENERATE_DEBUG_INFO = 1 << 6, }; Runtime* const runtime = Runtime::Current(); @@ -112,10 +112,10 @@ static void EnableDebugFeatures(uint32_t debug_flags) { } runtime->GetJITOptions()->SetUseJIT(use_jit); - const bool generate_cfi = (debug_flags & DEBUG_GENERATE_CFI) != 0; - if (generate_cfi) { - runtime->AddCompilerOption("--include-cfi"); - debug_flags &= ~DEBUG_GENERATE_CFI; + const bool generate_debug_info = (debug_flags & DEBUG_GENERATE_DEBUG_INFO) != 0; + if (generate_debug_info) { + runtime->AddCompilerOption("--generate-debug-info"); + debug_flags &= ~DEBUG_GENERATE_DEBUG_INFO; } // This is for backwards compatibility with Dalvik. diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index 6fda790..ad5741e 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -21,6 +21,9 @@ #include <unistd.h> #include <cstdlib> +#ifndef __APPLE__ +#include <link.h> // for dl_iterate_phdr. +#endif #include <sstream> // dlopen_ext support from bionic. @@ -35,6 +38,7 @@ #include "elf_file.h" #include "elf_utils.h" #include "oat.h" +#include "mem_map.h" #include "mirror/class.h" #include "mirror/object-inl.h" #include "os.h" @@ -45,13 +49,13 @@ namespace art { // Whether OatFile::Open will try DlOpen() first. Fallback is our own ELF loader. -static constexpr bool kUseDlopen = false; +static constexpr bool kUseDlopen = true; // Whether OatFile::Open will try DlOpen() on the host. On the host we're not linking against // bionic, so cannot take advantage of the support for changed semantics (loading the same soname // multiple times). However, if/when we switch the above, we likely want to switch this, too, // to get test coverage of the code paths. -static constexpr bool kUseDlopenOnHost = false; +static constexpr bool kUseDlopenOnHost = true; // For debugging, Open will print DlOpen error message if set to true. static constexpr bool kPrintDlOpenErrorMessage = false; @@ -210,6 +214,15 @@ OatFile::~OatFile() { bool OatFile::Dlopen(const std::string& elf_filename, uint8_t* requested_base, const char* abs_dex_location, std::string* error_msg) { +#ifdef __APPLE__ + // The dl_iterate_phdr syscall is missing. There is similar API on OSX, + // but let's fallback to the custom loading code for the time being. + UNUSED(elf_filename); + UNUSED(requested_base); + UNUSED(abs_dex_location); + UNUSED(error_msg); + return false; +#else std::unique_ptr<char> absolute_path(realpath(elf_filename.c_str(), nullptr)); if (absolute_path == nullptr) { *error_msg = StringPrintf("Failed to find absolute path for '%s'", elf_filename.c_str()); @@ -217,7 +230,7 @@ bool OatFile::Dlopen(const std::string& elf_filename, uint8_t* requested_base, } #ifdef HAVE_ANDROID_OS android_dlextinfo extinfo; - extinfo.flags = ANDROID_DLEXT_FORCE_LOAD; + extinfo.flags = ANDROID_DLEXT_FORCE_LOAD | ANDROID_DLEXT_FORCE_FIXED_VADDR; dlopen_handle_ = android_dlopen_ext(absolute_path.get(), RTLD_NOW, &extinfo); #else dlopen_handle_ = dlopen(absolute_path.get(), RTLD_NOW); @@ -264,7 +277,49 @@ bool OatFile::Dlopen(const std::string& elf_filename, uint8_t* requested_base, bss_end_ += sizeof(uint32_t); } + // Ask the linker where it mmaped the file and notify our mmap wrapper of the regions. + struct dl_iterate_context { + static int callback(struct dl_phdr_info *info, size_t /* size */, void *data) { + auto* context = reinterpret_cast<dl_iterate_context*>(data); + // See whether this callback corresponds to the file which we have just loaded. + bool contains_begin = false; + for (int i = 0; i < info->dlpi_phnum; i++) { + if (info->dlpi_phdr[i].p_type == PT_LOAD) { + uint8_t* vaddr = reinterpret_cast<uint8_t*>(info->dlpi_addr + + info->dlpi_phdr[i].p_vaddr); + size_t memsz = info->dlpi_phdr[i].p_memsz; + if (vaddr <= context->begin_ && context->begin_ < vaddr + memsz) { + contains_begin = true; + break; + } + } + } + // Add dummy mmaps for this file. + if (contains_begin) { + for (int i = 0; i < info->dlpi_phnum; i++) { + if (info->dlpi_phdr[i].p_type == PT_LOAD) { + uint8_t* vaddr = reinterpret_cast<uint8_t*>(info->dlpi_addr + + info->dlpi_phdr[i].p_vaddr); + size_t memsz = info->dlpi_phdr[i].p_memsz; + MemMap* mmap = MemMap::MapDummy(info->dlpi_name, vaddr, memsz); + context->dlopen_mmaps_->push_back(std::unique_ptr<MemMap>(mmap)); + } + } + return 1; // Stop iteration and return 1 from dl_iterate_phdr. + } + return 0; // Continue iteration and return 0 from dl_iterate_phdr when finished. + } + const uint8_t* const begin_; + std::vector<std::unique_ptr<MemMap>>* const dlopen_mmaps_; + } context = { begin_, &dlopen_mmaps_ }; + + if (dl_iterate_phdr(dl_iterate_context::callback, &context) == 0) { + PrintFileToLog("/proc/self/maps", LogSeverity::WARNING); + LOG(ERROR) << "File " << elf_filename << " loaded with dlopen but can not find its mmaps."; + } + return Setup(abs_dex_location, error_msg); +#endif // __APPLE__ } bool OatFile::ElfFileOpen(File* file, uint8_t* requested_base, uint8_t* oat_file_begin, diff --git a/runtime/oat_file.h b/runtime/oat_file.h index c58b029..1a782de 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -321,6 +321,9 @@ class OatFile FINAL { // dlopen handle during runtime. void* dlopen_handle_; + // Dummy memory map objects corresponding to the regions mapped by dlopen. + std::vector<std::unique_ptr<MemMap>> dlopen_mmaps_; + // Owning storage for the OatDexFile objects. std::vector<const OatDexFile*> oat_dex_files_storage_; |