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-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();
__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 
CreateJITCodeEntryInternal(std::vector<uint8_t> symfile)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 
DeleteJITCodeEntryInternal(JITCodeEntry * entry)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 
CreateJITCodeEntry(std::vector<uint8_t> symfile)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 
DeleteJITCodeEntry(JITCodeEntry * entry)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 
CreateJITCodeEntryForAddress(uintptr_t address,std::vector<uint8_t> symfile)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 
DeleteJITCodeEntryForAddress(uintptr_t address)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