diff options
| author | 2018-01-29 16:11:49 +0000 | |
|---|---|---|
| committer | 2018-02-02 14:14:08 +0000 | |
| commit | fb3de3d72832177e4a8d1f322ed11cbe58e45c9f (patch) | |
| tree | de8cded0436b54b2e5b1142b07fa75f0ed9791b0 | |
| parent | 2827ff64c7a385cfb9d6e01e6385708461eb65fc (diff) | |
Create list of open dex files for libbacktrace.
This fixes unwinds after recent changes (oob apks; cdex data sharing).
Bug: 72520014
Test: m test-art-host-gtest
Change-Id: Ie2a02657b2afbe899acd2e61f0a57d207e688b99
| -rw-r--r-- | compiler/jit/jit_compiler.cc | 2 | ||||
| -rw-r--r-- | compiler/optimizing/optimizing_compiler.cc | 2 | ||||
| -rw-r--r-- | runtime/base/mutex.cc | 6 | ||||
| -rw-r--r-- | runtime/base/mutex.h | 6 | ||||
| -rw-r--r-- | runtime/class_linker.cc | 2 | ||||
| -rw-r--r-- | runtime/jit/debugger_interface.cc | 62 | ||||
| -rw-r--r-- | runtime/jit/debugger_interface.h | 20 | ||||
| -rw-r--r-- | runtime/jit/jit_code_cache.cc | 4 | ||||
| -rw-r--r-- | runtime/native/dalvik_system_DexFile.cc | 2 |
9 files changed, 91 insertions, 15 deletions
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc index 2c62095458..17b94d3bdf 100644 --- a/compiler/jit/jit_compiler.cc +++ b/compiler/jit/jit_compiler.cc @@ -76,7 +76,7 @@ extern "C" void jit_types_loaded(void* handle, mirror::Class** types, size_t cou const ArrayRef<mirror::Class*> types_array(types, count); std::vector<uint8_t> elf_file = debug::WriteDebugElfFileForClasses( kRuntimeISA, jit_compiler->GetCompilerDriver()->GetInstructionSetFeatures(), types_array); - MutexLock mu(Thread::Current(), g_jit_debug_mutex); + MutexLock mu(Thread::Current(), *Locks::native_debug_interface_lock_); CreateJITCodeEntry(std::move(elf_file)); } } diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 47ef194574..b3f23a0dcd 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -1410,7 +1410,7 @@ void OptimizingCompiler::GenerateJitDebugInfo(ArtMethod* method, debug::MethodDe GetCompilerDriver()->GetInstructionSetFeatures(), mini_debug_info, ArrayRef<const debug::MethodDebugInfo>(&info, 1)); - MutexLock mu(Thread::Current(), g_jit_debug_mutex); + MutexLock mu(Thread::Current(), *Locks::native_debug_interface_lock_); JITCodeEntry* entry = CreateJITCodeEntry(elf_file); IncrementJITCodeEntryRefcount(entry, info.code_address); diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc index 9f17ad051c..a4c32dd814 100644 --- a/runtime/base/mutex.cc +++ b/runtime/base/mutex.cc @@ -74,6 +74,7 @@ Uninterruptible Roles::uninterruptible_; ReaderWriterMutex* Locks::jni_globals_lock_ = nullptr; Mutex* Locks::jni_weak_globals_lock_ = nullptr; ReaderWriterMutex* Locks::dex_lock_ = nullptr; +Mutex* Locks::native_debug_interface_lock_ = nullptr; std::vector<BaseMutex*> Locks::expected_mutexes_on_weak_ref_access_; Atomic<const BaseMutex*> Locks::expected_mutexes_on_weak_ref_access_guard_; @@ -1073,6 +1074,7 @@ void Locks::Init() { DCHECK(unexpected_signal_lock_ != nullptr); DCHECK(user_code_suspension_lock_ != nullptr); DCHECK(dex_lock_ != nullptr); + DCHECK(native_debug_interface_lock_ != nullptr); } else { // Create global locks in level order from highest lock level to lowest. LockLevel current_lock_level = kInstrumentEntrypointsLock; @@ -1228,6 +1230,10 @@ void Locks::Init() { DCHECK(unexpected_signal_lock_ == nullptr); unexpected_signal_lock_ = new Mutex("unexpected signal lock", current_lock_level, true); + UPDATE_CURRENT_LOCK_LEVEL(kNativeDebugInterfaceLock); + DCHECK(native_debug_interface_lock_ == nullptr); + native_debug_interface_lock_ = new Mutex("Native debug interface lock", current_lock_level); + UPDATE_CURRENT_LOCK_LEVEL(kLoggingLock); DCHECK(logging_lock_ == nullptr); logging_lock_ = new Mutex("logging lock", current_lock_level, true); diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h index d541b79a98..075122b6f8 100644 --- a/runtime/base/mutex.h +++ b/runtime/base/mutex.h @@ -58,6 +58,7 @@ class Thread; // [1] http://www.drdobbs.com/parallel/use-lock-hierarchies-to-avoid-deadlock/204801163 enum LockLevel { kLoggingLock = 0, + kNativeDebugInterfaceLock, kSwapMutexesLock, kUnexpectedSignalLock, kThreadSuspendCountLock, @@ -745,8 +746,11 @@ class Locks { // One unexpected signal at a time lock. static Mutex* unexpected_signal_lock_ ACQUIRED_AFTER(thread_suspend_count_lock_); + // Guards the magic global variables used by native tools (e.g. libunwind). + static Mutex* native_debug_interface_lock_ ACQUIRED_AFTER(unexpected_signal_lock_); + // Have an exclusive logging thread. - static Mutex* logging_lock_ ACQUIRED_AFTER(unexpected_signal_lock_); + static Mutex* logging_lock_ ACQUIRED_AFTER(native_debug_interface_lock_); // List of mutexes that we expect a thread may hold when accessing weak refs. This is used to // avoid a deadlock in the empty checkpoint while weak ref access is disabled (b/34964016). If we diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 32d304073c..c9ebed288c 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -73,6 +73,7 @@ #include "intern_table.h" #include "interpreter/interpreter.h" #include "java_vm_ext.h" +#include "jit/debugger_interface.h" #include "jit/jit.h" #include "jit/jit_code_cache.h" #include "jit/profile_compilation_info.h" @@ -3432,6 +3433,7 @@ void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file, data.weak_root = dex_cache_jweak; data.dex_file = dex_cache->GetDexFile(); data.class_table = ClassTableForClassLoader(class_loader); + RegisterDexFileForNative(self, data.dex_file->Begin()); DCHECK(data.class_table != nullptr); // Make sure to hold the dex cache live in the class table. This case happens for the boot class // path dex caches without an image. diff --git a/runtime/jit/debugger_interface.cc b/runtime/jit/debugger_interface.cc index 0e295e2442..d60f70a54f 100644 --- a/runtime/jit/debugger_interface.cc +++ b/runtime/jit/debugger_interface.cc @@ -68,11 +68,65 @@ extern "C" { // Static initialization is necessary to prevent GDB from seeing // uninitialized descriptor. JITDescriptor __jit_debug_descriptor = { 1, JIT_NOACTION, nullptr, nullptr }; + + // Incremented whenever __jit_debug_descriptor is modified. + uint32_t __jit_debug_descriptor_timestamp = 0; + + struct DEXFileEntry { + DEXFileEntry* next_; + DEXFileEntry* prev_; + const void* dexfile_; + }; + + DEXFileEntry* __art_debug_dexfiles = nullptr; + + // Incremented whenever __art_debug_dexfiles is modified. + uint32_t __art_debug_dexfiles_timestamp = 0; } -Mutex g_jit_debug_mutex("JIT debug interface lock", kJitDebugInterfaceLock); +static size_t g_jit_debug_mem_usage + GUARDED_BY(Locks::native_debug_interface_lock_) = 0; + +static std::unordered_map<const void*, DEXFileEntry*> g_dexfile_entries + GUARDED_BY(Locks::native_debug_interface_lock_); + +void RegisterDexFileForNative(Thread* current_thread, const void* dexfile_header) { + MutexLock mu(current_thread, *Locks::native_debug_interface_lock_); + if (g_dexfile_entries.count(dexfile_header) == 0) { + DEXFileEntry* entry = new DEXFileEntry(); + CHECK(entry != nullptr); + entry->dexfile_ = dexfile_header; + entry->prev_ = nullptr; + entry->next_ = __art_debug_dexfiles; + if (entry->next_ != nullptr) { + entry->next_->prev_ = entry; + } + __art_debug_dexfiles = entry; + __art_debug_dexfiles_timestamp++; + g_dexfile_entries.emplace(dexfile_header, entry); + } +} -static size_t g_jit_debug_mem_usage = 0; +void DeregisterDexFileForNative(Thread* current_thread, const void* dexfile_header) { + MutexLock mu(current_thread, *Locks::native_debug_interface_lock_); + auto it = g_dexfile_entries.find(dexfile_header); + // We register dex files in the class linker and free them in DexFile_closeDexFile, + // but might be cases where we load the dex file without using it in the class linker. + if (it != g_dexfile_entries.end()) { + DEXFileEntry* entry = it->second; + if (entry->prev_ != nullptr) { + entry->prev_->next_ = entry->next_; + } else { + __art_debug_dexfiles = entry->next_; + } + if (entry->next_ != nullptr) { + entry->next_->prev_ = entry->prev_; + } + __art_debug_dexfiles_timestamp++; + delete entry; + g_dexfile_entries.erase(it); + } +} JITCodeEntry* CreateJITCodeEntry(const std::vector<uint8_t>& symfile) { DCHECK_NE(symfile.size(), 0u); @@ -96,6 +150,7 @@ JITCodeEntry* CreateJITCodeEntry(const std::vector<uint8_t>& symfile) { __jit_debug_descriptor.first_entry_ = entry; __jit_debug_descriptor.relevant_entry_ = entry; __jit_debug_descriptor.action_flag_ = JIT_REGISTER_FN; + __jit_debug_descriptor_timestamp++; (*__jit_debug_register_code_ptr)(); return entry; } @@ -114,6 +169,7 @@ void DeleteJITCodeEntry(JITCodeEntry* entry) { g_jit_debug_mem_usage -= sizeof(JITCodeEntry) + entry->symfile_size_; __jit_debug_descriptor.relevant_entry_ = entry; __jit_debug_descriptor.action_flag_ = JIT_UNREGISTER_FN; + __jit_debug_descriptor_timestamp++; (*__jit_debug_register_code_ptr)(); delete[] entry->symfile_addr_; delete entry; @@ -121,7 +177,7 @@ void DeleteJITCodeEntry(JITCodeEntry* entry) { // Mapping from code address to entry. Used to manage life-time of the entries. static std::unordered_map<uintptr_t, JITCodeEntry*> g_jit_code_entries - GUARDED_BY(g_jit_debug_mutex); + GUARDED_BY(Locks::native_debug_interface_lock_); void IncrementJITCodeEntryRefcount(JITCodeEntry* entry, uintptr_t code_address) { DCHECK(entry != nullptr); diff --git a/runtime/jit/debugger_interface.h b/runtime/jit/debugger_interface.h index 9aec988f67..8c4bb3fdf4 100644 --- a/runtime/jit/debugger_interface.h +++ b/runtime/jit/debugger_interface.h @@ -30,36 +30,42 @@ extern "C" { struct JITCodeEntry; } -extern Mutex g_jit_debug_mutex; +// Notify native tools (e.g. libunwind) that DEX file has been opened. +// The pointer needs to point the start of the dex data (not the DexFile* object). +void RegisterDexFileForNative(Thread* current_thread, const void* dexfile_header); + +// Notify native tools (e.g. libunwind) that DEX file has been closed. +// The pointer needs to point the start of the dex data (not the DexFile* object). +void DeregisterDexFileForNative(Thread* current_thread, const void* dexfile_header); // Notify native debugger about new JITed code by passing in-memory ELF. // It takes ownership of the in-memory ELF file. JITCodeEntry* CreateJITCodeEntry(const std::vector<uint8_t>& symfile) - REQUIRES(g_jit_debug_mutex); + REQUIRES(Locks::native_debug_interface_lock_); // Notify native debugger that JITed code has been removed. // It also releases the associated in-memory ELF file. void DeleteJITCodeEntry(JITCodeEntry* entry) - REQUIRES(g_jit_debug_mutex); + REQUIRES(Locks::native_debug_interface_lock_); // Helper method to track life-time of JITCodeEntry. // It registers given code address as being described by the given entry. void IncrementJITCodeEntryRefcount(JITCodeEntry* entry, uintptr_t code_address) - REQUIRES(g_jit_debug_mutex); + REQUIRES(Locks::native_debug_interface_lock_); // Helper method to track life-time of JITCodeEntry. // It de-registers given code address as being described by the given entry. void DecrementJITCodeEntryRefcount(JITCodeEntry* entry, uintptr_t code_address) - REQUIRES(g_jit_debug_mutex); + REQUIRES(Locks::native_debug_interface_lock_); // Find the registered JITCodeEntry for given code address. // There can be only one entry per address at any given time. JITCodeEntry* GetJITCodeEntry(uintptr_t code_address) - REQUIRES(g_jit_debug_mutex); + REQUIRES(Locks::native_debug_interface_lock_); // Returns approximate memory used by all JITCodeEntries. size_t GetJITCodeEntryMemUsage() - REQUIRES(g_jit_debug_mutex); + REQUIRES(Locks::native_debug_interface_lock_); } // namespace art diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc index 7f0447732e..c8c13cb20f 100644 --- a/runtime/jit/jit_code_cache.cc +++ b/runtime/jit/jit_code_cache.cc @@ -549,7 +549,7 @@ void JitCodeCache::FreeCode(const void* code_ptr) { uintptr_t allocation = FromCodeToAllocation(code_ptr); // Notify native debugger that we are about to remove the code. // It does nothing if we are not using native debugger. - MutexLock mu(Thread::Current(), g_jit_debug_mutex); + MutexLock mu(Thread::Current(), *Locks::native_debug_interface_lock_); JITCodeEntry* entry = GetJITCodeEntry(reinterpret_cast<uintptr_t>(code_ptr)); if (entry != nullptr) { DecrementJITCodeEntryRefcount(entry, reinterpret_cast<uintptr_t>(code_ptr)); @@ -1825,7 +1825,7 @@ void JitCodeCache::FreeData(uint8_t* data) { void JitCodeCache::Dump(std::ostream& os) { MutexLock mu(Thread::Current(), lock_); - MutexLock mu2(Thread::Current(), g_jit_debug_mutex); + MutexLock mu2(Thread::Current(), *Locks::native_debug_interface_lock_); os << "Current JIT code cache size: " << PrettySize(used_memory_for_code_) << "\n" << "Current JIT data cache size: " << PrettySize(used_memory_for_data_) << "\n" << "Current JIT mini-debug-info size: " << PrettySize(GetJITCodeEntryMemUsage()) << "\n" diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc index 0f430874cf..6ea9a7ad62 100644 --- a/runtime/native/dalvik_system_DexFile.cc +++ b/runtime/native/dalvik_system_DexFile.cc @@ -30,6 +30,7 @@ #include "dex/art_dex_file_loader.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_loader.h" +#include "jit/debugger_interface.h" #include "jni_internal.h" #include "mirror/class_loader.h" #include "mirror/object-inl.h" @@ -331,6 +332,7 @@ static jboolean DexFile_closeDexFile(JNIEnv* env, jclass, jobject cookie) { int32_t i = kDexFileIndexStart; // Oat file is at index 0. for (const DexFile* dex_file : dex_files) { if (dex_file != nullptr) { + DeregisterDexFileForNative(soa.Self(), dex_file->Begin()); // Only delete the dex file if the dex cache is not found to prevent runtime crashes if there // are calls to DexFile.close while the ART DexFile is still in use. if (!class_linker->IsDexFileRegistered(soa.Self(), *dex_file)) { |