blob: 8a85607cbd2b35d4dc408198b48be8136ab9bdf3 [file] [log] [blame]
Christopher Ferris150db122017-12-20 18:49:01 -08001/*
2 * Copyright (C) 2017 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 <stdint.h>
18#include <sys/mman.h>
19
20#include <memory>
21#include <vector>
22
23#include <unwindstack/Elf.h>
24#include <unwindstack/JitDebug.h>
25#include <unwindstack/Maps.h>
Casey Dahlin6b95a0e2019-03-12 17:50:52 -070026
27#include "MemoryRange.h"
Christopher Ferris150db122017-12-20 18:49:01 -080028
29// This implements the JIT Compilation Interface.
30// See https://sourceware.org/gdb/onlinedocs/gdb/JIT-Interface.html
31
32namespace unwindstack {
33
David Srbeckyb9cc4fb2019-04-05 18:23:32 +000034struct JITCodeEntry32Pack {
35 uint32_t next;
36 uint32_t prev;
37 uint32_t symfile_addr;
38 uint64_t symfile_size;
Christopher Ferris150db122017-12-20 18:49:01 -080039} __attribute__((packed));
40
David Srbeckyb9cc4fb2019-04-05 18:23:32 +000041struct JITCodeEntry32Pad {
42 uint32_t next;
43 uint32_t prev;
44 uint32_t symfile_addr;
45 uint32_t pad;
46 uint64_t symfile_size;
Christopher Ferris150db122017-12-20 18:49:01 -080047};
48
David Srbeckyb9cc4fb2019-04-05 18:23:32 +000049struct JITCodeEntry64 {
50 uint64_t next;
51 uint64_t prev;
52 uint64_t symfile_addr;
53 uint64_t symfile_size;
Christopher Ferris150db122017-12-20 18:49:01 -080054};
55
David Srbeckyb9cc4fb2019-04-05 18:23:32 +000056struct JITDescriptorHeader {
57 uint32_t version;
58 uint32_t action_flag;
59};
David Srbecky85b5fec2018-02-23 18:06:13 +000060
David Srbeckyb9cc4fb2019-04-05 18:23:32 +000061struct JITDescriptor32 {
62 JITDescriptorHeader header;
63 uint32_t relevant_entry;
64 uint32_t first_entry;
65};
David Srbecky85b5fec2018-02-23 18:06:13 +000066
David Srbeckyb9cc4fb2019-04-05 18:23:32 +000067struct JITDescriptor64 {
68 JITDescriptorHeader header;
69 uint64_t relevant_entry;
70 uint64_t first_entry;
71};
David Srbecky85b5fec2018-02-23 18:06:13 +000072
David Srbeckyb9cc4fb2019-04-05 18:23:32 +000073JitDebug::JitDebug(std::shared_ptr<Memory>& memory) : Global(memory) {}
David Srbecky85b5fec2018-02-23 18:06:13 +000074
David Srbeckyb9cc4fb2019-04-05 18:23:32 +000075JitDebug::JitDebug(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
76 : Global(memory, search_libs) {}
77
78JitDebug::~JitDebug() {
79 for (auto* elf : elf_list_) {
80 delete elf;
81 }
82}
83
84uint64_t JitDebug::ReadDescriptor32(uint64_t addr) {
85 JITDescriptor32 desc;
86 if (!memory_->ReadFully(addr, &desc, sizeof(desc))) {
87 return 0;
David Srbecky85b5fec2018-02-23 18:06:13 +000088 }
89
David Srbeckyb9cc4fb2019-04-05 18:23:32 +000090 if (desc.header.version != 1 || desc.first_entry == 0) {
91 // Either unknown version, or no jit entries.
92 return 0;
93 }
David Srbecky85b5fec2018-02-23 18:06:13 +000094
David Srbeckyb9cc4fb2019-04-05 18:23:32 +000095 return desc.first_entry;
96}
David Srbecky85b5fec2018-02-23 18:06:13 +000097
David Srbeckyb9cc4fb2019-04-05 18:23:32 +000098uint64_t JitDebug::ReadDescriptor64(uint64_t addr) {
99 JITDescriptor64 desc;
100 if (!memory_->ReadFully(addr, &desc, sizeof(desc))) {
101 return 0;
102 }
David Srbecky85b5fec2018-02-23 18:06:13 +0000103
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000104 if (desc.header.version != 1 || desc.first_entry == 0) {
105 // Either unknown version, or no jit entries.
106 return 0;
107 }
Christopher Ferris150db122017-12-20 18:49:01 -0800108
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000109 return desc.first_entry;
110}
111
112uint64_t JitDebug::ReadEntry32Pack(uint64_t* start, uint64_t* size) {
113 JITCodeEntry32Pack code;
114 if (!memory_->ReadFully(entry_addr_, &code, sizeof(code))) {
115 return 0;
116 }
117
118 *start = code.symfile_addr;
119 *size = code.symfile_size;
120 return code.next;
121}
122
123uint64_t JitDebug::ReadEntry32Pad(uint64_t* start, uint64_t* size) {
124 JITCodeEntry32Pad code;
125 if (!memory_->ReadFully(entry_addr_, &code, sizeof(code))) {
126 return 0;
127 }
128
129 *start = code.symfile_addr;
130 *size = code.symfile_size;
131 return code.next;
132}
133
134uint64_t JitDebug::ReadEntry64(uint64_t* start, uint64_t* size) {
135 JITCodeEntry64 code;
136 if (!memory_->ReadFully(entry_addr_, &code, sizeof(code))) {
137 return 0;
138 }
139
140 *start = code.symfile_addr;
141 *size = code.symfile_size;
142 return code.next;
143}
144
145void JitDebug::ProcessArch() {
146 switch (arch()) {
Christopher Ferris150db122017-12-20 18:49:01 -0800147 case ARCH_X86:
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000148 read_descriptor_func_ = &JitDebug::ReadDescriptor32;
149 read_entry_func_ = &JitDebug::ReadEntry32Pack;
Christopher Ferris150db122017-12-20 18:49:01 -0800150 break;
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000151
Christopher Ferris150db122017-12-20 18:49:01 -0800152 case ARCH_ARM:
153 case ARCH_MIPS:
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000154 read_descriptor_func_ = &JitDebug::ReadDescriptor32;
155 read_entry_func_ = &JitDebug::ReadEntry32Pad;
Christopher Ferris150db122017-12-20 18:49:01 -0800156 break;
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000157
Christopher Ferris150db122017-12-20 18:49:01 -0800158 case ARCH_ARM64:
159 case ARCH_X86_64:
160 case ARCH_MIPS64:
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000161 read_descriptor_func_ = &JitDebug::ReadDescriptor64;
162 read_entry_func_ = &JitDebug::ReadEntry64;
Christopher Ferris150db122017-12-20 18:49:01 -0800163 break;
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000164 case ARCH_UNKNOWN:
Christopher Ferris150db122017-12-20 18:49:01 -0800165 abort();
166 }
167}
168
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000169bool JitDebug::ReadVariableData(uint64_t ptr) {
170 entry_addr_ = (this->*read_descriptor_func_)(ptr);
171 return entry_addr_ != 0;
Christopher Ferris150db122017-12-20 18:49:01 -0800172}
173
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000174void JitDebug::Init(Maps* maps) {
175 if (initialized_) {
176 return;
David Srbecky85b5fec2018-02-23 18:06:13 +0000177 }
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000178 // Regardless of what happens below, consider the init finished.
179 initialized_ = true;
180
181 FindAndReadVariable(maps, "__jit_debug_descriptor");
David Srbecky85b5fec2018-02-23 18:06:13 +0000182}
183
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000184Elf* JitDebug::GetElf(Maps* maps, uint64_t pc) {
185 // Use a single lock, this object should be used so infrequently that
186 // a fine grain lock is unnecessary.
Christopher Ferris150db122017-12-20 18:49:01 -0800187 std::lock_guard<std::mutex> guard(lock_);
188 if (!initialized_) {
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000189 Init(maps);
Christopher Ferris150db122017-12-20 18:49:01 -0800190 }
191
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000192 // Search the existing elf object first.
193 for (Elf* elf : elf_list_) {
194 if (elf->IsValidPc(pc)) {
195 return elf;
David Srbecky85b5fec2018-02-23 18:06:13 +0000196 }
197 }
198
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000199 while (entry_addr_ != 0) {
200 uint64_t start;
201 uint64_t size;
202 entry_addr_ = (this->*read_entry_func_)(&start, &size);
David Srbecky85b5fec2018-02-23 18:06:13 +0000203
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000204 Elf* elf = new Elf(new MemoryRange(memory_, start, size, 0));
205 elf->Init();
206 if (!elf->valid()) {
207 // The data is not formatted in a way we understand, do not attempt
208 // to process any other entries.
209 entry_addr_ = 0;
210 delete elf;
211 return nullptr;
212 }
213 elf_list_.push_back(elf);
214
215 if (elf->IsValidPc(pc)) {
216 return elf;
217 }
David Srbecky85b5fec2018-02-23 18:06:13 +0000218 }
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000219 return nullptr;
David Srbecky85b5fec2018-02-23 18:06:13 +0000220}
221
Christopher Ferris150db122017-12-20 18:49:01 -0800222} // namespace unwindstack