diff options
author | Vladimir Marko <vmarko@google.com> | 2015-03-02 20:10:51 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2015-03-02 20:10:52 +0000 |
commit | 0b25c71ac93fb10c484dbacb9e23db505a8e2353 (patch) | |
tree | e219fd8919e6edd4fa2033faa35628ee9d59261e /runtime | |
parent | 02f28fd679942fdad1b819baa947cd4e6eb99e3f (diff) | |
parent | 5c42c29b89286e5efa4a4613132b09051ce5945b (diff) | |
download | android_art-0b25c71ac93fb10c484dbacb9e23db505a8e2353.tar.gz android_art-0b25c71ac93fb10c484dbacb9e23db505a8e2353.tar.bz2 android_art-0b25c71ac93fb10c484dbacb9e23db505a8e2353.zip |
Merge "Add support for .bss section in oat files."
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/base/arena_allocator.cc | 2 | ||||
-rw-r--r-- | runtime/elf_file.cc | 80 | ||||
-rw-r--r-- | runtime/gc/accounting/atomic_stack.h | 4 | ||||
-rw-r--r-- | runtime/gc/accounting/bitmap.cc | 3 | ||||
-rw-r--r-- | runtime/gc/accounting/card_table.cc | 2 | ||||
-rw-r--r-- | runtime/gc/accounting/read_barrier_table.h | 2 | ||||
-rw-r--r-- | runtime/gc/accounting/space_bitmap.cc | 3 | ||||
-rw-r--r-- | runtime/gc/allocator/rosalloc.cc | 5 | ||||
-rw-r--r-- | runtime/gc/collector/mark_sweep.cc | 2 | ||||
-rw-r--r-- | runtime/gc/heap.cc | 5 | ||||
-rw-r--r-- | runtime/gc/space/bump_pointer_space.cc | 3 | ||||
-rw-r--r-- | runtime/gc/space/large_object_space.cc | 13 | ||||
-rw-r--r-- | runtime/gc/space/malloc_space.cc | 2 | ||||
-rw-r--r-- | runtime/gc/space/region_space.cc | 3 | ||||
-rw-r--r-- | runtime/indirect_reference_table.cc | 2 | ||||
-rw-r--r-- | runtime/jit/jit_code_cache.cc | 2 | ||||
-rw-r--r-- | runtime/mem_map.cc | 22 | ||||
-rw-r--r-- | runtime/mem_map.h | 3 | ||||
-rw-r--r-- | runtime/mem_map_test.cc | 121 | ||||
-rw-r--r-- | runtime/oat_file.cc | 90 | ||||
-rw-r--r-- | runtime/oat_file.h | 24 | ||||
-rw-r--r-- | runtime/thread_pool.cc | 2 | ||||
-rw-r--r-- | runtime/zip_archive.cc | 3 |
23 files changed, 231 insertions, 167 deletions
diff --git a/runtime/base/arena_allocator.cc b/runtime/base/arena_allocator.cc index b3f812e5e0..e6380bfe5b 100644 --- a/runtime/base/arena_allocator.cc +++ b/runtime/base/arena_allocator.cc @@ -129,7 +129,7 @@ Arena::Arena(size_t size) next_(nullptr) { if (kUseMemMap) { std::string error_msg; - map_ = MemMap::MapAnonymous("dalvik-arena", NULL, size, PROT_READ | PROT_WRITE, false, + map_ = MemMap::MapAnonymous("dalvik-arena", nullptr, size, PROT_READ | PROT_WRITE, false, false, &error_msg); CHECK(map_ != nullptr) << error_msg; memory_ = map_->Begin(); diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc index a22e2741ce..3490bcf862 100644 --- a/runtime/elf_file.cc +++ b/runtime/elf_file.cc @@ -1370,7 +1370,7 @@ bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, reservation_name += file_->GetPath(); std::unique_ptr<MemMap> reserve(MemMap::MapAnonymous(reservation_name.c_str(), reserve_base_override, - GetLoadedSize(), PROT_NONE, false, + GetLoadedSize(), PROT_NONE, false, false, error_msg)); if (reserve.get() == nullptr) { *error_msg = StringPrintf("Failed to allocate %s: %s", @@ -1411,32 +1411,72 @@ bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, } else { flags |= MAP_PRIVATE; } - if (file_length < (program_header->p_offset + program_header->p_memsz)) { - *error_msg = StringPrintf("File size of %zd bytes not large enough to contain ELF segment " - "%d of %" PRIu64 " bytes: '%s'", file_length, i, - static_cast<uint64_t>(program_header->p_offset + program_header->p_memsz), + if (program_header->p_filesz > program_header->p_memsz) { + *error_msg = StringPrintf("Invalid p_filesz > p_memsz (%" PRIu64 " > %" PRIu64 "): %s", + static_cast<uint64_t>(program_header->p_filesz), + static_cast<uint64_t>(program_header->p_memsz), file_->GetPath().c_str()); return false; } - std::unique_ptr<MemMap> segment(MemMap::MapFileAtAddress(p_vaddr, - program_header->p_memsz, - prot, flags, file_->Fd(), - program_header->p_offset, - true, // implies MAP_FIXED - file_->GetPath().c_str(), - error_msg)); - if (segment.get() == nullptr) { - *error_msg = StringPrintf("Failed to map ELF file segment %d from %s: %s", - i, file_->GetPath().c_str(), error_msg->c_str()); + if (program_header->p_filesz < program_header->p_memsz && + !IsAligned<kPageSize>(program_header->p_filesz)) { + *error_msg = StringPrintf("Unsupported unaligned p_filesz < p_memsz (%" PRIu64 + " < %" PRIu64 "): %s", + static_cast<uint64_t>(program_header->p_filesz), + static_cast<uint64_t>(program_header->p_memsz), + file_->GetPath().c_str()); return false; } - if (segment->Begin() != p_vaddr) { - *error_msg = StringPrintf("Failed to map ELF file segment %d from %s at expected address %p, " - "instead mapped to %p", - i, file_->GetPath().c_str(), p_vaddr, segment->Begin()); + if (file_length < (program_header->p_offset + program_header->p_filesz)) { + *error_msg = StringPrintf("File size of %zd bytes not large enough to contain ELF segment " + "%d of %" PRIu64 " bytes: '%s'", file_length, i, + static_cast<uint64_t>(program_header->p_offset + program_header->p_filesz), + file_->GetPath().c_str()); return false; } - segments_.push_back(segment.release()); + if (program_header->p_filesz != 0u) { + std::unique_ptr<MemMap> segment( + MemMap::MapFileAtAddress(p_vaddr, + program_header->p_filesz, + prot, flags, file_->Fd(), + program_header->p_offset, + true, // implies MAP_FIXED + file_->GetPath().c_str(), + error_msg)); + if (segment.get() == nullptr) { + *error_msg = StringPrintf("Failed to map ELF file segment %d from %s: %s", + i, file_->GetPath().c_str(), error_msg->c_str()); + return false; + } + if (segment->Begin() != p_vaddr) { + *error_msg = StringPrintf("Failed to map ELF file segment %d from %s at expected address %p, " + "instead mapped to %p", + i, file_->GetPath().c_str(), p_vaddr, segment->Begin()); + return false; + } + segments_.push_back(segment.release()); + } + if (program_header->p_filesz < program_header->p_memsz) { + std::string name = StringPrintf("Zero-initialized segment %" PRIu64 " of ELF file %s", + static_cast<uint64_t>(i), file_->GetPath().c_str()); + std::unique_ptr<MemMap> segment( + MemMap::MapAnonymous(name.c_str(), + p_vaddr + program_header->p_filesz, + program_header->p_memsz - program_header->p_filesz, + prot, false, true /* reuse */, error_msg)); + if (segment == nullptr) { + *error_msg = StringPrintf("Failed to map zero-initialized ELF file segment %d from %s: %s", + i, file_->GetPath().c_str(), error_msg->c_str()); + return false; + } + if (segment->Begin() != p_vaddr) { + *error_msg = StringPrintf("Failed to map zero-initialized ELF file segment %d from %s " + "at expected address %p, instead mapped to %p", + i, file_->GetPath().c_str(), p_vaddr, segment->Begin()); + return false; + } + segments_.push_back(segment.release()); + } } // Now that we are done loading, .dynamic should be in memory to find .dynstr, .dynsym, .hash diff --git a/runtime/gc/accounting/atomic_stack.h b/runtime/gc/accounting/atomic_stack.h index 72734e95ac..5224d64efc 100644 --- a/runtime/gc/accounting/atomic_stack.h +++ b/runtime/gc/accounting/atomic_stack.h @@ -236,8 +236,8 @@ class AtomicStack { // Size in number of elements. void Init() { std::string error_msg; - mem_map_.reset(MemMap::MapAnonymous(name_.c_str(), NULL, capacity_ * sizeof(begin_[0]), - PROT_READ | PROT_WRITE, false, &error_msg)); + mem_map_.reset(MemMap::MapAnonymous(name_.c_str(), nullptr, capacity_ * sizeof(begin_[0]), + PROT_READ | PROT_WRITE, false, false, &error_msg)); CHECK(mem_map_.get() != NULL) << "couldn't allocate mark stack.\n" << error_msg; uint8_t* addr = mem_map_->Begin(); CHECK(addr != NULL); diff --git a/runtime/gc/accounting/bitmap.cc b/runtime/gc/accounting/bitmap.cc index de47f6094e..20984fda96 100644 --- a/runtime/gc/accounting/bitmap.cc +++ b/runtime/gc/accounting/bitmap.cc @@ -40,7 +40,8 @@ MemMap* Bitmap::AllocateMemMap(const std::string& name, size_t num_bits) { RoundUp(num_bits, kBitsPerBitmapWord) / kBitsPerBitmapWord * sizeof(uintptr_t), kPageSize); std::string error_msg; std::unique_ptr<MemMap> mem_map(MemMap::MapAnonymous(name.c_str(), nullptr, bitmap_size, - PROT_READ | PROT_WRITE, false, &error_msg)); + PROT_READ | PROT_WRITE, false, false, + &error_msg)); if (UNLIKELY(mem_map.get() == nullptr)) { LOG(ERROR) << "Failed to allocate bitmap " << name << ": " << error_msg; return nullptr; diff --git a/runtime/gc/accounting/card_table.cc b/runtime/gc/accounting/card_table.cc index ca1e7c1316..ad1f192dd6 100644 --- a/runtime/gc/accounting/card_table.cc +++ b/runtime/gc/accounting/card_table.cc @@ -62,7 +62,7 @@ CardTable* CardTable::Create(const uint8_t* heap_begin, size_t heap_capacity) { std::string error_msg; std::unique_ptr<MemMap> mem_map( MemMap::MapAnonymous("card table", nullptr, capacity + 256, PROT_READ | PROT_WRITE, - false, &error_msg)); + false, false, &error_msg)); CHECK(mem_map.get() != NULL) << "couldn't allocate card table: " << error_msg; // All zeros is the correct initial value; all clean. Anonymous mmaps are initialized to zero, we // don't clear the card table to avoid unnecessary pages being allocated diff --git a/runtime/gc/accounting/read_barrier_table.h b/runtime/gc/accounting/read_barrier_table.h index 84d5da3ba7..bb9aae7886 100644 --- a/runtime/gc/accounting/read_barrier_table.h +++ b/runtime/gc/accounting/read_barrier_table.h @@ -37,7 +37,7 @@ class ReadBarrierTable { static_cast<uint64_t>(static_cast<size_t>(kHeapCapacity / kRegionSize))); std::string error_msg; MemMap* mem_map = MemMap::MapAnonymous("read barrier table", nullptr, capacity, - PROT_READ | PROT_WRITE, false, &error_msg); + PROT_READ | PROT_WRITE, false, false, &error_msg); CHECK(mem_map != nullptr && mem_map->Begin() != nullptr) << "couldn't allocate read barrier table: " << error_msg; mem_map_.reset(mem_map); diff --git a/runtime/gc/accounting/space_bitmap.cc b/runtime/gc/accounting/space_bitmap.cc index f5d3b47d49..ad8d9884ec 100644 --- a/runtime/gc/accounting/space_bitmap.cc +++ b/runtime/gc/accounting/space_bitmap.cc @@ -63,7 +63,8 @@ SpaceBitmap<kAlignment>* SpaceBitmap<kAlignment>::Create( const size_t bitmap_size = ComputeBitmapSize(heap_capacity); std::string error_msg; std::unique_ptr<MemMap> mem_map(MemMap::MapAnonymous(name.c_str(), nullptr, bitmap_size, - PROT_READ | PROT_WRITE, false, &error_msg)); + PROT_READ | PROT_WRITE, false, false, + &error_msg)); if (UNLIKELY(mem_map.get() == nullptr)) { LOG(ERROR) << "Failed to allocate bitmap " << name << ": " << error_msg; return nullptr; diff --git a/runtime/gc/allocator/rosalloc.cc b/runtime/gc/allocator/rosalloc.cc index 72aacf5157..f51093aa57 100644 --- a/runtime/gc/allocator/rosalloc.cc +++ b/runtime/gc/allocator/rosalloc.cc @@ -80,8 +80,9 @@ RosAlloc::RosAlloc(void* base, size_t capacity, size_t max_capacity, size_t num_of_pages = footprint_ / kPageSize; size_t max_num_of_pages = max_capacity_ / kPageSize; std::string error_msg; - page_map_mem_map_.reset(MemMap::MapAnonymous("rosalloc page map", NULL, RoundUp(max_num_of_pages, kPageSize), - PROT_READ | PROT_WRITE, false, &error_msg)); + page_map_mem_map_.reset(MemMap::MapAnonymous("rosalloc page map", nullptr, + RoundUp(max_num_of_pages, kPageSize), + PROT_READ | PROT_WRITE, false, false, &error_msg)); CHECK(page_map_mem_map_.get() != nullptr) << "Couldn't allocate the page map : " << error_msg; page_map_ = page_map_mem_map_->Begin(); page_map_size_ = num_of_pages; diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc index cd63d2646b..8aac484f7f 100644 --- a/runtime/gc/collector/mark_sweep.cc +++ b/runtime/gc/collector/mark_sweep.cc @@ -106,7 +106,7 @@ MarkSweep::MarkSweep(Heap* heap, bool is_concurrent, const std::string& name_pre MemMap* mem_map = MemMap::MapAnonymous( "mark sweep sweep array free buffer", nullptr, RoundUp(kSweepArrayChunkFreeSize * sizeof(mirror::Object*), kPageSize), - PROT_READ | PROT_WRITE, false, &error_msg); + PROT_READ | PROT_WRITE, false, false, &error_msg); CHECK(mem_map != nullptr) << "Couldn't allocate sweep array free buffer: " << error_msg; sweep_array_free_buffer_mem_map_.reset(mem_map); } diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index a4bc941a60..9343622fda 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -284,7 +284,8 @@ Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max // address. non_moving_space_mem_map.reset( MemMap::MapAnonymous(space_name, requested_alloc_space_begin, - non_moving_space_capacity, PROT_READ | PROT_WRITE, true, &error_str)); + non_moving_space_capacity, PROT_READ | PROT_WRITE, true, false, + &error_str)); CHECK(non_moving_space_mem_map != nullptr) << error_str; // Try to reserve virtual memory at a lower address if we have a separate non moving space. request_begin = reinterpret_cast<uint8_t*>(300 * MB); @@ -476,7 +477,7 @@ MemMap* Heap::MapAnonymousPreferredAddress(const char* name, uint8_t* request_be size_t capacity, std::string* out_error_str) { while (true) { MemMap* map = MemMap::MapAnonymous(name, request_begin, capacity, - PROT_READ | PROT_WRITE, true, out_error_str); + PROT_READ | PROT_WRITE, true, false, out_error_str); if (map != nullptr || request_begin == nullptr) { return map; } diff --git a/runtime/gc/space/bump_pointer_space.cc b/runtime/gc/space/bump_pointer_space.cc index 9675ba6f50..fbfc4495e0 100644 --- a/runtime/gc/space/bump_pointer_space.cc +++ b/runtime/gc/space/bump_pointer_space.cc @@ -29,7 +29,8 @@ BumpPointerSpace* BumpPointerSpace::Create(const std::string& name, size_t capac capacity = RoundUp(capacity, kPageSize); std::string error_msg; std::unique_ptr<MemMap> mem_map(MemMap::MapAnonymous(name.c_str(), requested_begin, capacity, - PROT_READ | PROT_WRITE, true, &error_msg)); + PROT_READ | PROT_WRITE, true, false, + &error_msg)); if (mem_map.get() == nullptr) { LOG(ERROR) << "Failed to allocate pages for alloc space (" << name << ") of size " << PrettySize(capacity) << " with message " << error_msg; diff --git a/runtime/gc/space/large_object_space.cc b/runtime/gc/space/large_object_space.cc index c0c6444306..7523de58bf 100644 --- a/runtime/gc/space/large_object_space.cc +++ b/runtime/gc/space/large_object_space.cc @@ -110,8 +110,8 @@ LargeObjectMapSpace* LargeObjectMapSpace::Create(const std::string& name) { mirror::Object* LargeObjectMapSpace::Alloc(Thread* self, size_t num_bytes, size_t* bytes_allocated, size_t* usable_size) { std::string error_msg; - MemMap* mem_map = MemMap::MapAnonymous("large object space allocation", NULL, num_bytes, - PROT_READ | PROT_WRITE, true, &error_msg); + MemMap* mem_map = MemMap::MapAnonymous("large object space allocation", nullptr, num_bytes, + PROT_READ | PROT_WRITE, true, false, &error_msg); if (UNLIKELY(mem_map == NULL)) { LOG(WARNING) << "Large object allocation failed: " << error_msg; return NULL; @@ -291,7 +291,7 @@ FreeListSpace* FreeListSpace::Create(const std::string& name, uint8_t* requested CHECK_EQ(size % kAlignment, 0U); std::string error_msg; MemMap* mem_map = MemMap::MapAnonymous(name.c_str(), requested_begin, size, - PROT_READ | PROT_WRITE, true, &error_msg); + PROT_READ | PROT_WRITE, true, false, &error_msg); CHECK(mem_map != NULL) << "Failed to allocate large object space mem map: " << error_msg; return new FreeListSpace(name, mem_map, mem_map->Begin(), mem_map->End()); } @@ -305,9 +305,10 @@ FreeListSpace::FreeListSpace(const std::string& name, MemMap* mem_map, uint8_t* CHECK_ALIGNED(space_capacity, kAlignment); const size_t alloc_info_size = sizeof(AllocationInfo) * (space_capacity / kAlignment); std::string error_msg; - allocation_info_map_.reset(MemMap::MapAnonymous("large object free list space allocation info map", - nullptr, alloc_info_size, PROT_READ | PROT_WRITE, - false, &error_msg)); + allocation_info_map_.reset( + MemMap::MapAnonymous("large object free list space allocation info map", + nullptr, alloc_info_size, PROT_READ | PROT_WRITE, + false, false, &error_msg)); CHECK(allocation_info_map_.get() != nullptr) << "Failed to allocate allocation info map" << error_msg; allocation_info_ = reinterpret_cast<AllocationInfo*>(allocation_info_map_->Begin()); diff --git a/runtime/gc/space/malloc_space.cc b/runtime/gc/space/malloc_space.cc index 9bbbb3cbdf..67e8847acd 100644 --- a/runtime/gc/space/malloc_space.cc +++ b/runtime/gc/space/malloc_space.cc @@ -90,7 +90,7 @@ MemMap* MallocSpace::CreateMemMap(const std::string& name, size_t starting_size, std::string error_msg; MemMap* mem_map = MemMap::MapAnonymous(name.c_str(), requested_begin, *capacity, - PROT_READ | PROT_WRITE, true, &error_msg); + PROT_READ | PROT_WRITE, true, false, &error_msg); if (mem_map == nullptr) { LOG(ERROR) << "Failed to allocate pages for alloc space (" << name << ") of size " << PrettySize(*capacity) << ": " << error_msg; diff --git a/runtime/gc/space/region_space.cc b/runtime/gc/space/region_space.cc index 2c556d9ff7..8bb73d614c 100644 --- a/runtime/gc/space/region_space.cc +++ b/runtime/gc/space/region_space.cc @@ -33,7 +33,8 @@ RegionSpace* RegionSpace::Create(const std::string& name, size_t capacity, capacity = RoundUp(capacity, kRegionSize); std::string error_msg; std::unique_ptr<MemMap> mem_map(MemMap::MapAnonymous(name.c_str(), requested_begin, capacity, - PROT_READ | PROT_WRITE, true, &error_msg)); + PROT_READ | PROT_WRITE, true, false, + &error_msg)); if (mem_map.get() == nullptr) { LOG(ERROR) << "Failed to allocate pages for alloc space (" << name << ") of size " << PrettySize(capacity) << " with message " << error_msg; diff --git a/runtime/indirect_reference_table.cc b/runtime/indirect_reference_table.cc index aa2a6b58f1..1a3f1074e6 100644 --- a/runtime/indirect_reference_table.cc +++ b/runtime/indirect_reference_table.cc @@ -74,7 +74,7 @@ IndirectReferenceTable::IndirectReferenceTable(size_t initialCount, std::string error_str; const size_t table_bytes = maxCount * sizeof(IrtEntry); table_mem_map_.reset(MemMap::MapAnonymous("indirect ref table", nullptr, table_bytes, - PROT_READ | PROT_WRITE, false, &error_str)); + PROT_READ | PROT_WRITE, false, false, &error_str)); CHECK(table_mem_map_.get() != nullptr) << error_str; CHECK_EQ(table_mem_map_->Size(), table_bytes); table_ = reinterpret_cast<IrtEntry*>(table_mem_map_->Begin()); diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc index 8d4965e70f..4ae4d570fc 100644 --- a/runtime/jit/jit_code_cache.cc +++ b/runtime/jit/jit_code_cache.cc @@ -31,7 +31,7 @@ JitCodeCache* JitCodeCache::Create(size_t capacity, std::string* error_msg) { std::string error_str; // Map name specific for android_os_Debug.cpp accounting. MemMap* map = MemMap::MapAnonymous("jit-code-cache", nullptr, capacity, - PROT_READ | PROT_WRITE | PROT_EXEC, false, &error_str); + PROT_READ | PROT_WRITE | PROT_EXEC, false, false, &error_str); if (map == nullptr) { std::ostringstream oss; oss << "Failed to create read write execute cache: " << error_str << " size=" << capacity; diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc index 4b85469fdf..588615f9d4 100644 --- a/runtime/mem_map.cc +++ b/runtime/mem_map.cc @@ -138,9 +138,10 @@ uintptr_t MemMap::next_mem_pos_ = GenerateNextMemPos(); #endif // Return true if the address range is contained in a single /proc/self/map entry. -static bool ContainedWithinExistingMap(uintptr_t begin, - uintptr_t end, +static bool ContainedWithinExistingMap(uint8_t* ptr, size_t size, std::string* error_msg) { + uintptr_t begin = reinterpret_cast<uintptr_t>(ptr); + uintptr_t end = begin + size; std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(getpid(), true)); if (map.get() == nullptr) { *error_msg = StringPrintf("Failed to build process map"); @@ -240,7 +241,7 @@ static bool CheckMapRequest(uint8_t* expected_ptr, void* actual_ptr, size_t byte } MemMap* MemMap::MapAnonymous(const char* name, uint8_t* expected_ptr, size_t byte_count, int prot, - bool low_4gb, std::string* error_msg) { + bool low_4gb, bool reuse, std::string* error_msg) { #ifndef __LP64__ UNUSED(low_4gb); #endif @@ -250,6 +251,15 @@ MemMap* MemMap::MapAnonymous(const char* name, uint8_t* expected_ptr, size_t byt size_t page_aligned_byte_count = RoundUp(byte_count, kPageSize); int flags = MAP_PRIVATE | MAP_ANONYMOUS; + if (reuse) { + // reuse means it is okay that it overlaps an existing page mapping. + // Only use this if you actually made the page reservation yourself. + CHECK(expected_ptr != nullptr); + + DCHECK(ContainedWithinExistingMap(expected_ptr, byte_count, error_msg)) << error_msg; + flags |= MAP_FIXED; + } + ScopedFd fd(-1); #ifdef USE_ASHMEM @@ -273,7 +283,7 @@ MemMap* MemMap::MapAnonymous(const char* name, uint8_t* expected_ptr, size_t byt *error_msg = StringPrintf("ashmem_create_region failed for '%s': %s", name, strerror(errno)); return nullptr; } - flags = MAP_PRIVATE; + flags &= ~MAP_ANONYMOUS; } #endif @@ -393,8 +403,6 @@ MemMap* MemMap::MapFileAtAddress(uint8_t* expected_ptr, size_t byte_count, int p std::string* error_msg) { CHECK_NE(0, prot); CHECK_NE(0, flags & (MAP_SHARED | MAP_PRIVATE)); - uintptr_t expected = reinterpret_cast<uintptr_t>(expected_ptr); - uintptr_t limit = expected + byte_count; // Note that we do not allow MAP_FIXED unless reuse == true, i.e we // expect his mapping to be contained within an existing map. @@ -403,7 +411,7 @@ MemMap* MemMap::MapFileAtAddress(uint8_t* expected_ptr, size_t byte_count, int p // Only use this if you actually made the page reservation yourself. CHECK(expected_ptr != nullptr); - DCHECK(ContainedWithinExistingMap(expected, limit, error_msg)); + DCHECK(ContainedWithinExistingMap(expected_ptr, byte_count, error_msg)) << error_msg; flags |= MAP_FIXED; } else { CHECK_EQ(0, flags & MAP_FIXED); diff --git a/runtime/mem_map.h b/runtime/mem_map.h index dc337e0564..11b2569c30 100644 --- a/runtime/mem_map.h +++ b/runtime/mem_map.h @@ -54,6 +54,7 @@ class MemMap { public: // Request an anonymous region of length 'byte_count' and a requested base address. // Use NULL as the requested base address if you don't care. + // "reuse" allows re-mapping an address range from an existing mapping. // // The word "anonymous" in this context means "not backed by a file". The supplied // 'ashmem_name' will be used -- on systems that support it -- to give the mapping @@ -61,7 +62,7 @@ class MemMap { // // On success, returns returns a MemMap instance. On failure, returns a NULL; static MemMap* MapAnonymous(const char* ashmem_name, uint8_t* addr, size_t byte_count, int prot, - bool low_4gb, std::string* error_msg); + bool low_4gb, bool reuse, std::string* error_msg); // Map part of a file, taking care of non-page aligned offsets. The // "start" offset is absolute, not relative. diff --git a/runtime/mem_map_test.cc b/runtime/mem_map_test.cc index 14a72b9b1b..f635b5d62f 100644 --- a/runtime/mem_map_test.cc +++ b/runtime/mem_map_test.cc @@ -43,6 +43,7 @@ class MemMapTest : public testing::Test { 2 * page_size, PROT_READ | PROT_WRITE, low_4gb, + false, &error_msg); // Check its state and write to it. uint8_t* base0 = m0->Begin(); @@ -129,11 +130,12 @@ TEST_F(MemMapTest, MapAnonymousEmpty) { CommonInit(); std::string error_msg; std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousEmpty", - nullptr, - 0, - PROT_READ, - false, - &error_msg)); + nullptr, + 0, + PROT_READ, + false, + false, + &error_msg)); ASSERT_TRUE(map.get() != nullptr) << error_msg; ASSERT_TRUE(error_msg.empty()); map.reset(MemMap::MapAnonymous("MapAnonymousEmpty", @@ -141,6 +143,7 @@ TEST_F(MemMapTest, MapAnonymousEmpty) { kPageSize, PROT_READ | PROT_WRITE, false, + false, &error_msg)); ASSERT_TRUE(map.get() != nullptr) << error_msg; ASSERT_TRUE(error_msg.empty()); @@ -151,11 +154,12 @@ TEST_F(MemMapTest, MapAnonymousEmpty32bit) { CommonInit(); std::string error_msg; std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousEmpty", - nullptr, - kPageSize, - PROT_READ | PROT_WRITE, - true, - &error_msg)); + nullptr, + kPageSize, + PROT_READ | PROT_WRITE, + true, + false, + &error_msg)); ASSERT_TRUE(map.get() != nullptr) << error_msg; ASSERT_TRUE(error_msg.empty()); ASSERT_LT(reinterpret_cast<uintptr_t>(BaseBegin(map.get())), 1ULL << 32); @@ -167,31 +171,34 @@ TEST_F(MemMapTest, MapAnonymousExactAddr) { std::string error_msg; // Map at an address that should work, which should succeed. std::unique_ptr<MemMap> map0(MemMap::MapAnonymous("MapAnonymous0", - reinterpret_cast<uint8_t*>(ART_BASE_ADDRESS), - kPageSize, - PROT_READ | PROT_WRITE, - false, - &error_msg)); + reinterpret_cast<uint8_t*>(ART_BASE_ADDRESS), + kPageSize, + PROT_READ | PROT_WRITE, + false, + false, + &error_msg)); ASSERT_TRUE(map0.get() != nullptr) << error_msg; ASSERT_TRUE(error_msg.empty()); ASSERT_TRUE(map0->BaseBegin() == reinterpret_cast<void*>(ART_BASE_ADDRESS)); // Map at an unspecified address, which should succeed. std::unique_ptr<MemMap> map1(MemMap::MapAnonymous("MapAnonymous1", - nullptr, - kPageSize, - PROT_READ | PROT_WRITE, - false, - &error_msg)); + nullptr, + kPageSize, + PROT_READ | PROT_WRITE, + false, + false, + &error_msg)); ASSERT_TRUE(map1.get() != nullptr) << error_msg; ASSERT_TRUE(error_msg.empty()); ASSERT_TRUE(map1->BaseBegin() != nullptr); // Attempt to map at the same address, which should fail. std::unique_ptr<MemMap> map2(MemMap::MapAnonymous("MapAnonymous2", - reinterpret_cast<uint8_t*>(map1->BaseBegin()), - kPageSize, - PROT_READ | PROT_WRITE, - false, - &error_msg)); + reinterpret_cast<uint8_t*>(map1->BaseBegin()), + kPageSize, + PROT_READ | PROT_WRITE, + false, + false, + &error_msg)); ASSERT_TRUE(map2.get() == nullptr) << error_msg; ASSERT_TRUE(!error_msg.empty()); } @@ -217,6 +224,7 @@ TEST_F(MemMapTest, MapAnonymousExactAddr32bitHighAddr) { 0x21000000, PROT_READ | PROT_WRITE, true, + false, &error_msg)); ASSERT_TRUE(map.get() != nullptr) << error_msg; ASSERT_TRUE(error_msg.empty()); @@ -230,11 +238,12 @@ TEST_F(MemMapTest, MapAnonymousOverflow) { uintptr_t ptr = 0; ptr -= kPageSize; // Now it's close to the top. std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousOverflow", - reinterpret_cast<uint8_t*>(ptr), - 2 * kPageSize, // brings it over the top. - PROT_READ | PROT_WRITE, - false, - &error_msg)); + reinterpret_cast<uint8_t*>(ptr), + 2 * kPageSize, // brings it over the top. + PROT_READ | PROT_WRITE, + false, + false, + &error_msg)); ASSERT_EQ(nullptr, map.get()); ASSERT_FALSE(error_msg.empty()); } @@ -243,12 +252,14 @@ TEST_F(MemMapTest, MapAnonymousOverflow) { TEST_F(MemMapTest, MapAnonymousLow4GBExpectedTooHigh) { CommonInit(); std::string error_msg; - std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousLow4GBExpectedTooHigh", - reinterpret_cast<uint8_t*>(UINT64_C(0x100000000)), - kPageSize, - PROT_READ | PROT_WRITE, - true, - &error_msg)); + std::unique_ptr<MemMap> map( + MemMap::MapAnonymous("MapAnonymousLow4GBExpectedTooHigh", + reinterpret_cast<uint8_t*>(UINT64_C(0x100000000)), + kPageSize, + PROT_READ | PROT_WRITE, + true, + false, + &error_msg)); ASSERT_EQ(nullptr, map.get()); ASSERT_FALSE(error_msg.empty()); } @@ -257,16 +268,40 @@ TEST_F(MemMapTest, MapAnonymousLow4GBRangeTooHigh) { CommonInit(); std::string error_msg; std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousLow4GBRangeTooHigh", - reinterpret_cast<uint8_t*>(0xF0000000), - 0x20000000, - PROT_READ | PROT_WRITE, - true, - &error_msg)); + reinterpret_cast<uint8_t*>(0xF0000000), + 0x20000000, + PROT_READ | PROT_WRITE, + true, + false, + &error_msg)); ASSERT_EQ(nullptr, map.get()); ASSERT_FALSE(error_msg.empty()); } #endif +TEST_F(MemMapTest, MapAnonymousReuse) { + CommonInit(); + std::string error_msg; + std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousReserve", + nullptr, + 0x20000, + PROT_READ | PROT_WRITE, + false, + false, + &error_msg)); + ASSERT_NE(nullptr, map.get()); + ASSERT_TRUE(error_msg.empty()); + std::unique_ptr<MemMap> map2(MemMap::MapAnonymous("MapAnonymousReused", + reinterpret_cast<uint8_t*>(map->BaseBegin()), + 0x10000, + PROT_READ | PROT_WRITE, + false, + true, + &error_msg)); + ASSERT_NE(nullptr, map2.get()); + ASSERT_TRUE(error_msg.empty()); +} + TEST_F(MemMapTest, CheckNoGaps) { CommonInit(); std::string error_msg; @@ -277,6 +312,7 @@ TEST_F(MemMapTest, CheckNoGaps) { kPageSize * kNumPages, PROT_READ | PROT_WRITE, false, + false, &error_msg)); ASSERT_TRUE(map.get() != nullptr) << error_msg; ASSERT_TRUE(error_msg.empty()); @@ -292,6 +328,7 @@ TEST_F(MemMapTest, CheckNoGaps) { kPageSize, PROT_READ | PROT_WRITE, false, + false, &error_msg)); ASSERT_TRUE(map0.get() != nullptr) << error_msg; ASSERT_TRUE(error_msg.empty()); @@ -300,6 +337,7 @@ TEST_F(MemMapTest, CheckNoGaps) { kPageSize, PROT_READ | PROT_WRITE, false, + false, &error_msg)); ASSERT_TRUE(map1.get() != nullptr) << error_msg; ASSERT_TRUE(error_msg.empty()); @@ -308,6 +346,7 @@ TEST_F(MemMapTest, CheckNoGaps) { kPageSize, PROT_READ | PROT_WRITE, false, + false, &error_msg)); ASSERT_TRUE(map2.get() != nullptr) << error_msg; ASSERT_TRUE(error_msg.empty()); diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index 739d62cb39..356e3d2509 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -52,17 +52,7 @@ OatFile* OatFile::OpenWithElfFile(ElfFile* elf_file, CHECK(has_section); oat_file->begin_ = elf_file->Begin() + offset; oat_file->end_ = elf_file->Begin() + size + offset; - return oat_file->Setup(error_msg) ? oat_file.release() : nullptr; -} - -OatFile* OatFile::OpenMemory(std::vector<uint8_t>& oat_contents, - const std::string& location, - std::string* error_msg) { - CHECK(!oat_contents.empty()) << location; - CheckLocation(location); - std::unique_ptr<OatFile> oat_file(new OatFile(location, false)); - oat_file->begin_ = &oat_contents[0]; - oat_file->end_ = &oat_contents[oat_contents.size()]; + // Ignore the optional .bss section when opening non-executable. return oat_file->Setup(error_msg) ? oat_file.release() : nullptr; } @@ -108,18 +98,6 @@ OatFile* OatFile::OpenReadable(File* file, const std::string& location, std::str return OpenElfFile(file, location, nullptr, nullptr, false, false, error_msg); } -OatFile* OatFile::OpenDlopen(const std::string& elf_filename, - const std::string& location, - uint8_t* requested_base, - std::string* error_msg) { - std::unique_ptr<OatFile> oat_file(new OatFile(location, true)); - bool success = oat_file->Dlopen(elf_filename, requested_base, error_msg); - if (!success) { - return nullptr; - } - return oat_file.release(); -} - OatFile* OatFile::OpenElfFile(File* file, const std::string& location, uint8_t* requested_base, @@ -138,8 +116,8 @@ OatFile* OatFile::OpenElfFile(File* file, } OatFile::OatFile(const std::string& location, bool is_executable) - : location_(location), begin_(NULL), end_(NULL), is_executable_(is_executable), - dlopen_handle_(NULL), + : location_(location), begin_(NULL), end_(NULL), bss_begin_(nullptr), bss_end_(nullptr), + is_executable_(is_executable), dlopen_handle_(NULL), secondary_lookup_lock_("OatFile secondary lookup lock", kOatFileSecondaryLookupLock) { CHECK(!location_.empty()); } @@ -151,43 +129,6 @@ OatFile::~OatFile() { } } -bool OatFile::Dlopen(const std::string& elf_filename, uint8_t* requested_base, - std::string* error_msg) { - char* absolute_path = realpath(elf_filename.c_str(), NULL); - if (absolute_path == NULL) { - *error_msg = StringPrintf("Failed to find absolute path for '%s'", elf_filename.c_str()); - return false; - } - dlopen_handle_ = dlopen(absolute_path, RTLD_NOW); - free(absolute_path); - if (dlopen_handle_ == NULL) { - *error_msg = StringPrintf("Failed to dlopen '%s': %s", elf_filename.c_str(), dlerror()); - return false; - } - begin_ = reinterpret_cast<uint8_t*>(dlsym(dlopen_handle_, "oatdata")); - if (begin_ == NULL) { - *error_msg = StringPrintf("Failed to find oatdata symbol in '%s': %s", elf_filename.c_str(), - dlerror()); - return false; - } - if (requested_base != NULL && begin_ != requested_base) { - PrintFileToLog("/proc/self/maps", LogSeverity::WARNING); - *error_msg = StringPrintf("Failed to find oatdata symbol at expected address: " - "oatdata=%p != expected=%p. See process maps in the log.", - begin_, requested_base); - return false; - } - end_ = reinterpret_cast<uint8_t*>(dlsym(dlopen_handle_, "oatlastword")); - if (end_ == NULL) { - *error_msg = StringPrintf("Failed to find oatlastword symbol in '%s': %s", elf_filename.c_str(), - dlerror()); - return false; - } - // Readjust to be non-inclusive upper bound. - end_ += sizeof(uint32_t); - return Setup(error_msg); -} - bool OatFile::ElfFileOpen(File* file, uint8_t* requested_base, uint8_t* oat_file_begin, bool writable, bool executable, std::string* error_msg) { @@ -222,6 +163,23 @@ bool OatFile::ElfFileOpen(File* file, uint8_t* requested_base, uint8_t* oat_file } // Readjust to be non-inclusive upper bound. end_ += sizeof(uint32_t); + + bss_begin_ = elf_file_->FindDynamicSymbolAddress("oatbss"); + if (bss_begin_ == nullptr) { + // No .bss section. Clear dlerror(). + bss_end_ = nullptr; + dlerror(); + } else { + bss_end_ = elf_file_->FindDynamicSymbolAddress("oatbsslastword"); + if (bss_end_ == nullptr) { + *error_msg = StringPrintf("Failed to find oatbasslastword symbol in '%s'", + file->GetPath().c_str()); + return false; + } + // Readjust to be non-inclusive upper bound. + bss_end_ += sizeof(uint32_t); + } + return Setup(error_msg); } @@ -363,6 +321,14 @@ const uint8_t* OatFile::End() const { return end_; } +const uint8_t* OatFile::BssBegin() const { + return bss_begin_; +} + +const uint8_t* OatFile::BssEnd() const { + return bss_end_; +} + const OatFile::OatDexFile* OatFile::GetOatDexFile(const char* dex_location, const uint32_t* dex_location_checksum, bool warn_if_not_found) const { diff --git a/runtime/oat_file.h b/runtime/oat_file.h index 5e6843923e..564185cc75 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -62,11 +62,6 @@ class OatFile { // Opens an oat file from an already opened File. Maps it PROT_READ, MAP_PRIVATE. static OatFile* OpenReadable(File* file, const std::string& location, std::string* error_msg); - // Open an oat file backed by a std::vector with the given location. - static OatFile* OpenMemory(std::vector<uint8_t>& oat_contents, - const std::string& location, - std::string* error_msg); - ~OatFile(); bool IsExecutable() const { @@ -274,17 +269,19 @@ class OatFile { return End() - Begin(); } + size_t BssSize() const { + return BssEnd() - BssBegin(); + } + const uint8_t* Begin() const; const uint8_t* End() const; + const uint8_t* BssBegin() const; + const uint8_t* BssEnd() const; + private: static void CheckLocation(const std::string& location); - static OatFile* OpenDlopen(const std::string& elf_filename, - const std::string& location, - uint8_t* requested_base, - std::string* error_msg); - static OatFile* OpenElfFile(File* file, const std::string& location, uint8_t* requested_base, @@ -294,7 +291,6 @@ class OatFile { std::string* error_msg); explicit OatFile(const std::string& filename, bool executable); - bool Dlopen(const std::string& elf_filename, uint8_t* requested_base, std::string* error_msg); bool ElfFileOpen(File* file, uint8_t* requested_base, uint8_t* oat_file_begin, // Override where the file is loaded to if not null bool writable, bool executable, @@ -312,6 +308,12 @@ class OatFile { // Pointer to end of oat region for bounds checking. const uint8_t* end_; + // Pointer to the .bss section, if present, otherwise nullptr. + const uint8_t* bss_begin_; + + // Pointer to the end of the .bss section, if present, otherwise nullptr. + const uint8_t* bss_end_; + // Was this oat_file loaded executable? const bool is_executable_; diff --git a/runtime/thread_pool.cc b/runtime/thread_pool.cc index 587eb320cd..2a82285bbe 100644 --- a/runtime/thread_pool.cc +++ b/runtime/thread_pool.cc @@ -31,7 +31,7 @@ ThreadPoolWorker::ThreadPoolWorker(ThreadPool* thread_pool, const std::string& n name_(name) { std::string error_msg; stack_.reset(MemMap::MapAnonymous(name.c_str(), nullptr, stack_size, PROT_READ | PROT_WRITE, - false, &error_msg)); + false, false, &error_msg)); CHECK(stack_.get() != nullptr) << error_msg; const char* reason = "new thread pool worker thread"; pthread_attr_t attr; diff --git a/runtime/zip_archive.cc b/runtime/zip_archive.cc index 63bfc44797..ffab674be1 100644 --- a/runtime/zip_archive.cc +++ b/runtime/zip_archive.cc @@ -57,7 +57,8 @@ MemMap* ZipEntry::ExtractToMemMap(const char* zip_filename, const char* entry_fi name += zip_filename; std::unique_ptr<MemMap> map(MemMap::MapAnonymous(name.c_str(), NULL, GetUncompressedLength(), - PROT_READ | PROT_WRITE, false, error_msg)); + PROT_READ | PROT_WRITE, false, false, + error_msg)); if (map.get() == nullptr) { DCHECK(!error_msg->empty()); return nullptr; |