Home | History | Annotate | Download | only in jit
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "debugger_interface.h"
     18 
     19 #include "base/logging.h"
     20 #include "base/mutex.h"
     21 #include "thread-current-inl.h"
     22 #include "thread.h"
     23 
     24 #include <unordered_map>
     25 
     26 namespace art {
     27 
     28 // -------------------------------------------------------------------
     29 // Binary GDB JIT Interface as described in
     30 //   http://sourceware.org/gdb/onlinedocs/gdb/Declarations.html
     31 // -------------------------------------------------------------------
     32 extern "C" {
     33   typedef enum {
     34     JIT_NOACTION = 0,
     35     JIT_REGISTER_FN,
     36     JIT_UNREGISTER_FN
     37   } JITAction;
     38 
     39   struct JITCodeEntry {
     40     JITCodeEntry* next_;
     41     JITCodeEntry* prev_;
     42     const uint8_t *symfile_addr_;
     43     uint64_t symfile_size_;
     44   };
     45 
     46   struct JITDescriptor {
     47     uint32_t version_;
     48     uint32_t action_flag_;
     49     JITCodeEntry* relevant_entry_;
     50     JITCodeEntry* first_entry_;
     51   };
     52 
     53   // GDB will place breakpoint into this function.
     54   // To prevent GCC from inlining or removing it we place noinline attribute
     55   // and inline assembler statement inside.
     56   void __attribute__((noinline)) __jit_debug_register_code();
     57   void __attribute__((noinline)) __jit_debug_register_code() {
     58     __asm__("");
     59   }
     60 
     61   // Call __jit_debug_register_code indirectly via global variable.
     62   // This gives the debugger an easy way to inject custom code to handle the events.
     63   void (*__jit_debug_register_code_ptr)() = __jit_debug_register_code;
     64 
     65   // GDB will inspect contents of this descriptor.
     66   // Static initialization is necessary to prevent GDB from seeing
     67   // uninitialized descriptor.
     68   JITDescriptor __jit_debug_descriptor = { 1, JIT_NOACTION, nullptr, nullptr };
     69 }
     70 
     71 static Mutex g_jit_debug_mutex("JIT debug interface lock", kJitDebugInterfaceLock);
     72 
     73 static JITCodeEntry* CreateJITCodeEntryInternal(std::vector<uint8_t> symfile)
     74     REQUIRES(g_jit_debug_mutex) {
     75   DCHECK_NE(symfile.size(), 0u);
     76 
     77   // Make a copy of the buffer. We want to shrink it anyway.
     78   uint8_t* symfile_copy = new uint8_t[symfile.size()];
     79   CHECK(symfile_copy != nullptr);
     80   memcpy(symfile_copy, symfile.data(), symfile.size());
     81 
     82   JITCodeEntry* entry = new JITCodeEntry;
     83   CHECK(entry != nullptr);
     84   entry->symfile_addr_ = symfile_copy;
     85   entry->symfile_size_ = symfile.size();
     86   entry->prev_ = nullptr;
     87 
     88   entry->next_ = __jit_debug_descriptor.first_entry_;
     89   if (entry->next_ != nullptr) {
     90     entry->next_->prev_ = entry;
     91   }
     92   __jit_debug_descriptor.first_entry_ = entry;
     93   __jit_debug_descriptor.relevant_entry_ = entry;
     94 
     95   __jit_debug_descriptor.action_flag_ = JIT_REGISTER_FN;
     96   (*__jit_debug_register_code_ptr)();
     97   return entry;
     98 }
     99 
    100 static void DeleteJITCodeEntryInternal(JITCodeEntry* entry) REQUIRES(g_jit_debug_mutex) {
    101   if (entry->prev_ != nullptr) {
    102     entry->prev_->next_ = entry->next_;
    103   } else {
    104     __jit_debug_descriptor.first_entry_ = entry->next_;
    105   }
    106 
    107   if (entry->next_ != nullptr) {
    108     entry->next_->prev_ = entry->prev_;
    109   }
    110 
    111   __jit_debug_descriptor.relevant_entry_ = entry;
    112   __jit_debug_descriptor.action_flag_ = JIT_UNREGISTER_FN;
    113   (*__jit_debug_register_code_ptr)();
    114   delete[] entry->symfile_addr_;
    115   delete entry;
    116 }
    117 
    118 JITCodeEntry* CreateJITCodeEntry(std::vector<uint8_t> symfile) {
    119   Thread* self = Thread::Current();
    120   MutexLock mu(self, g_jit_debug_mutex);
    121   return CreateJITCodeEntryInternal(std::move(symfile));
    122 }
    123 
    124 void DeleteJITCodeEntry(JITCodeEntry* entry) {
    125   Thread* self = Thread::Current();
    126   MutexLock mu(self, g_jit_debug_mutex);
    127   DeleteJITCodeEntryInternal(entry);
    128 }
    129 
    130 // Mapping from address to entry.  It takes ownership of the entries
    131 // so that the user of the JIT interface does not have to store them.
    132 static std::unordered_map<uintptr_t, JITCodeEntry*> g_jit_code_entries;
    133 
    134 void CreateJITCodeEntryForAddress(uintptr_t address, std::vector<uint8_t> symfile) {
    135   Thread* self = Thread::Current();
    136   MutexLock mu(self, g_jit_debug_mutex);
    137   DCHECK_NE(address, 0u);
    138   DCHECK(g_jit_code_entries.find(address) == g_jit_code_entries.end());
    139   JITCodeEntry* entry = CreateJITCodeEntryInternal(std::move(symfile));
    140   g_jit_code_entries.emplace(address, entry);
    141 }
    142 
    143 bool DeleteJITCodeEntryForAddress(uintptr_t address) {
    144   Thread* self = Thread::Current();
    145   MutexLock mu(self, g_jit_debug_mutex);
    146   const auto it = g_jit_code_entries.find(address);
    147   if (it == g_jit_code_entries.end()) {
    148     return false;
    149   }
    150   DeleteJITCodeEntryInternal(it->second);
    151   g_jit_code_entries.erase(it);
    152   return true;
    153 }
    154 
    155 }  // namespace art
    156