blob: d60f70a54f002bd1f9beb0ffd5234f43ac32a985 [file] [log] [blame]
David Srbecky67feb172015-12-17 19:57:44 +00001/*
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
Andreas Gampe57943812017-12-06 21:39:13 -080019#include <android-base/logging.h>
20
David Srbecky5cc349f2015-12-18 15:04:48 +000021#include "base/mutex.h"
Andreas Gampeb486a982017-06-01 13:45:54 -070022#include "thread-current-inl.h"
David Srbecky5cc349f2015-12-18 15:04:48 +000023#include "thread.h"
24
25#include <unordered_map>
26
David Srbecky67feb172015-12-17 19:57:44 +000027namespace art {
28
29// -------------------------------------------------------------------
30// Binary GDB JIT Interface as described in
31// http://sourceware.org/gdb/onlinedocs/gdb/Declarations.html
32// -------------------------------------------------------------------
33extern "C" {
34 typedef enum {
35 JIT_NOACTION = 0,
36 JIT_REGISTER_FN,
37 JIT_UNREGISTER_FN
38 } JITAction;
39
40 struct JITCodeEntry {
41 JITCodeEntry* next_;
42 JITCodeEntry* prev_;
43 const uint8_t *symfile_addr_;
44 uint64_t symfile_size_;
David Srbeckyc684f332018-01-19 17:38:06 +000045 uint32_t ref_count; // ART internal field.
David Srbecky67feb172015-12-17 19:57:44 +000046 };
47
48 struct JITDescriptor {
49 uint32_t version_;
50 uint32_t action_flag_;
51 JITCodeEntry* relevant_entry_;
52 JITCodeEntry* first_entry_;
53 };
54
55 // GDB will place breakpoint into this function.
56 // To prevent GCC from inlining or removing it we place noinline attribute
57 // and inline assembler statement inside.
58 void __attribute__((noinline)) __jit_debug_register_code();
59 void __attribute__((noinline)) __jit_debug_register_code() {
60 __asm__("");
61 }
62
David Srbeckye8b4e852016-03-15 17:02:41 +000063 // Call __jit_debug_register_code indirectly via global variable.
64 // This gives the debugger an easy way to inject custom code to handle the events.
65 void (*__jit_debug_register_code_ptr)() = __jit_debug_register_code;
66
David Srbecky67feb172015-12-17 19:57:44 +000067 // GDB will inspect contents of this descriptor.
68 // Static initialization is necessary to prevent GDB from seeing
69 // uninitialized descriptor.
70 JITDescriptor __jit_debug_descriptor = { 1, JIT_NOACTION, nullptr, nullptr };
David Srbeckyfb3de3d2018-01-29 16:11:49 +000071
72 // Incremented whenever __jit_debug_descriptor is modified.
73 uint32_t __jit_debug_descriptor_timestamp = 0;
74
75 struct DEXFileEntry {
76 DEXFileEntry* next_;
77 DEXFileEntry* prev_;
78 const void* dexfile_;
79 };
80
81 DEXFileEntry* __art_debug_dexfiles = nullptr;
82
83 // Incremented whenever __art_debug_dexfiles is modified.
84 uint32_t __art_debug_dexfiles_timestamp = 0;
David Srbecky67feb172015-12-17 19:57:44 +000085}
86
David Srbeckyfb3de3d2018-01-29 16:11:49 +000087static size_t g_jit_debug_mem_usage
88 GUARDED_BY(Locks::native_debug_interface_lock_) = 0;
David Srbecky5cc349f2015-12-18 15:04:48 +000089
David Srbeckyfb3de3d2018-01-29 16:11:49 +000090static std::unordered_map<const void*, DEXFileEntry*> g_dexfile_entries
91 GUARDED_BY(Locks::native_debug_interface_lock_);
92
93void RegisterDexFileForNative(Thread* current_thread, const void* dexfile_header) {
94 MutexLock mu(current_thread, *Locks::native_debug_interface_lock_);
95 if (g_dexfile_entries.count(dexfile_header) == 0) {
96 DEXFileEntry* entry = new DEXFileEntry();
97 CHECK(entry != nullptr);
98 entry->dexfile_ = dexfile_header;
99 entry->prev_ = nullptr;
100 entry->next_ = __art_debug_dexfiles;
101 if (entry->next_ != nullptr) {
102 entry->next_->prev_ = entry;
103 }
104 __art_debug_dexfiles = entry;
105 __art_debug_dexfiles_timestamp++;
106 g_dexfile_entries.emplace(dexfile_header, entry);
107 }
108}
109
110void DeregisterDexFileForNative(Thread* current_thread, const void* dexfile_header) {
111 MutexLock mu(current_thread, *Locks::native_debug_interface_lock_);
112 auto it = g_dexfile_entries.find(dexfile_header);
113 // We register dex files in the class linker and free them in DexFile_closeDexFile,
114 // but might be cases where we load the dex file without using it in the class linker.
115 if (it != g_dexfile_entries.end()) {
116 DEXFileEntry* entry = it->second;
117 if (entry->prev_ != nullptr) {
118 entry->prev_->next_ = entry->next_;
119 } else {
120 __art_debug_dexfiles = entry->next_;
121 }
122 if (entry->next_ != nullptr) {
123 entry->next_->prev_ = entry->prev_;
124 }
125 __art_debug_dexfiles_timestamp++;
126 delete entry;
127 g_dexfile_entries.erase(it);
128 }
129}
David Srbeckyc684f332018-01-19 17:38:06 +0000130
131JITCodeEntry* CreateJITCodeEntry(const std::vector<uint8_t>& symfile) {
Vladimir Marko93205e32016-04-13 11:59:46 +0100132 DCHECK_NE(symfile.size(), 0u);
133
134 // Make a copy of the buffer. We want to shrink it anyway.
135 uint8_t* symfile_copy = new uint8_t[symfile.size()];
136 CHECK(symfile_copy != nullptr);
137 memcpy(symfile_copy, symfile.data(), symfile.size());
David Srbecky5cc349f2015-12-18 15:04:48 +0000138
David Srbecky67feb172015-12-17 19:57:44 +0000139 JITCodeEntry* entry = new JITCodeEntry;
Vladimir Marko93205e32016-04-13 11:59:46 +0100140 CHECK(entry != nullptr);
141 entry->symfile_addr_ = symfile_copy;
142 entry->symfile_size_ = symfile.size();
David Srbecky67feb172015-12-17 19:57:44 +0000143 entry->prev_ = nullptr;
David Srbeckyc684f332018-01-19 17:38:06 +0000144 entry->ref_count = 0;
David Srbecky67feb172015-12-17 19:57:44 +0000145 entry->next_ = __jit_debug_descriptor.first_entry_;
146 if (entry->next_ != nullptr) {
147 entry->next_->prev_ = entry;
148 }
David Srbeckyc684f332018-01-19 17:38:06 +0000149 g_jit_debug_mem_usage += sizeof(JITCodeEntry) + entry->symfile_size_;
David Srbecky67feb172015-12-17 19:57:44 +0000150 __jit_debug_descriptor.first_entry_ = entry;
151 __jit_debug_descriptor.relevant_entry_ = entry;
David Srbecky67feb172015-12-17 19:57:44 +0000152 __jit_debug_descriptor.action_flag_ = JIT_REGISTER_FN;
David Srbeckyfb3de3d2018-01-29 16:11:49 +0000153 __jit_debug_descriptor_timestamp++;
David Srbeckye8b4e852016-03-15 17:02:41 +0000154 (*__jit_debug_register_code_ptr)();
David Srbecky67feb172015-12-17 19:57:44 +0000155 return entry;
156}
157
David Srbeckyc684f332018-01-19 17:38:06 +0000158void DeleteJITCodeEntry(JITCodeEntry* entry) {
David Srbecky67feb172015-12-17 19:57:44 +0000159 if (entry->prev_ != nullptr) {
160 entry->prev_->next_ = entry->next_;
161 } else {
162 __jit_debug_descriptor.first_entry_ = entry->next_;
163 }
164
165 if (entry->next_ != nullptr) {
166 entry->next_->prev_ = entry->prev_;
167 }
168
David Srbeckyc684f332018-01-19 17:38:06 +0000169 g_jit_debug_mem_usage -= sizeof(JITCodeEntry) + entry->symfile_size_;
David Srbecky67feb172015-12-17 19:57:44 +0000170 __jit_debug_descriptor.relevant_entry_ = entry;
171 __jit_debug_descriptor.action_flag_ = JIT_UNREGISTER_FN;
David Srbeckyfb3de3d2018-01-29 16:11:49 +0000172 __jit_debug_descriptor_timestamp++;
David Srbeckye8b4e852016-03-15 17:02:41 +0000173 (*__jit_debug_register_code_ptr)();
David Srbecky5cc349f2015-12-18 15:04:48 +0000174 delete[] entry->symfile_addr_;
David Srbecky67feb172015-12-17 19:57:44 +0000175 delete entry;
176}
177
David Srbeckyc684f332018-01-19 17:38:06 +0000178// Mapping from code address to entry. Used to manage life-time of the entries.
179static std::unordered_map<uintptr_t, JITCodeEntry*> g_jit_code_entries
David Srbeckyfb3de3d2018-01-29 16:11:49 +0000180 GUARDED_BY(Locks::native_debug_interface_lock_);
David Srbeckyc684f332018-01-19 17:38:06 +0000181
182void IncrementJITCodeEntryRefcount(JITCodeEntry* entry, uintptr_t code_address) {
183 DCHECK(entry != nullptr);
184 DCHECK_EQ(g_jit_code_entries.count(code_address), 0u);
185 entry->ref_count++;
186 g_jit_code_entries.emplace(code_address, entry);
David Srbecky5cc349f2015-12-18 15:04:48 +0000187}
188
David Srbeckyc684f332018-01-19 17:38:06 +0000189void DecrementJITCodeEntryRefcount(JITCodeEntry* entry, uintptr_t code_address) {
190 DCHECK(entry != nullptr);
191 DCHECK(g_jit_code_entries[code_address] == entry);
192 if (--entry->ref_count == 0) {
193 DeleteJITCodeEntry(entry);
David Srbecky5cc349f2015-12-18 15:04:48 +0000194 }
David Srbeckyc684f332018-01-19 17:38:06 +0000195 g_jit_code_entries.erase(code_address);
196}
197
198JITCodeEntry* GetJITCodeEntry(uintptr_t code_address) {
199 auto it = g_jit_code_entries.find(code_address);
200 return it == g_jit_code_entries.end() ? nullptr : it->second;
201}
202
203size_t GetJITCodeEntryMemUsage() {
204 return g_jit_debug_mem_usage + g_jit_code_entries.size() * 2 * sizeof(void*);
David Srbecky5cc349f2015-12-18 15:04:48 +0000205}
206
David Srbecky67feb172015-12-17 19:57:44 +0000207} // namespace art