1 /*
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>
26 
27 #include "MemoryRange.h"
28 
29 // This implements the JIT Compilation Interface.
30 // See https://sourceware.org/gdb/onlinedocs/gdb/JIT-Interface.html
31 
32 namespace unwindstack {
33 
34 struct JITCodeEntry32Pack {
35   uint32_t next;
36   uint32_t prev;
37   uint32_t symfile_addr;
38   uint64_t symfile_size;
39 } __attribute__((packed));
40 
41 struct JITCodeEntry32Pad {
42   uint32_t next;
43   uint32_t prev;
44   uint32_t symfile_addr;
45   uint32_t pad;
46   uint64_t symfile_size;
47 };
48 
49 struct JITCodeEntry64 {
50   uint64_t next;
51   uint64_t prev;
52   uint64_t symfile_addr;
53   uint64_t symfile_size;
54 };
55 
56 struct JITDescriptorHeader {
57   uint32_t version;
58   uint32_t action_flag;
59 };
60 
61 struct JITDescriptor32 {
62   JITDescriptorHeader header;
63   uint32_t relevant_entry;
64   uint32_t first_entry;
65 };
66 
67 struct JITDescriptor64 {
68   JITDescriptorHeader header;
69   uint64_t relevant_entry;
70   uint64_t first_entry;
71 };
72 
JitDebug(std::shared_ptr<Memory> & memory)73 JitDebug::JitDebug(std::shared_ptr<Memory>& memory) : Global(memory) {}
74 
JitDebug(std::shared_ptr<Memory> & memory,std::vector<std::string> & search_libs)75 JitDebug::JitDebug(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
76     : Global(memory, search_libs) {}
77 
~JitDebug()78 JitDebug::~JitDebug() {
79   for (auto* elf : elf_list_) {
80     delete elf;
81   }
82 }
83 
ReadDescriptor32(uint64_t addr)84 uint64_t JitDebug::ReadDescriptor32(uint64_t addr) {
85   JITDescriptor32 desc;
86   if (!memory_->ReadFully(addr, &desc, sizeof(desc))) {
87     return 0;
88   }
89 
90   if (desc.header.version != 1 || desc.first_entry == 0) {
91     // Either unknown version, or no jit entries.
92     return 0;
93   }
94 
95   return desc.first_entry;
96 }
97 
ReadDescriptor64(uint64_t addr)98 uint64_t JitDebug::ReadDescriptor64(uint64_t addr) {
99   JITDescriptor64 desc;
100   if (!memory_->ReadFully(addr, &desc, sizeof(desc))) {
101     return 0;
102   }
103 
104   if (desc.header.version != 1 || desc.first_entry == 0) {
105     // Either unknown version, or no jit entries.
106     return 0;
107   }
108 
109   return desc.first_entry;
110 }
111 
ReadEntry32Pack(uint64_t * start,uint64_t * size)112 uint64_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 
ReadEntry32Pad(uint64_t * start,uint64_t * size)123 uint64_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 
ReadEntry64(uint64_t * start,uint64_t * size)134 uint64_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 
ProcessArch()145 void JitDebug::ProcessArch() {
146   switch (arch()) {
147     case ARCH_X86:
148       read_descriptor_func_ = &JitDebug::ReadDescriptor32;
149       read_entry_func_ = &JitDebug::ReadEntry32Pack;
150       break;
151 
152     case ARCH_ARM:
153     case ARCH_MIPS:
154       read_descriptor_func_ = &JitDebug::ReadDescriptor32;
155       read_entry_func_ = &JitDebug::ReadEntry32Pad;
156       break;
157 
158     case ARCH_ARM64:
159     case ARCH_X86_64:
160     case ARCH_MIPS64:
161       read_descriptor_func_ = &JitDebug::ReadDescriptor64;
162       read_entry_func_ = &JitDebug::ReadEntry64;
163       break;
164     case ARCH_UNKNOWN:
165       abort();
166   }
167 }
168 
ReadVariableData(uint64_t ptr)169 bool JitDebug::ReadVariableData(uint64_t ptr) {
170   entry_addr_ = (this->*read_descriptor_func_)(ptr);
171   return entry_addr_ != 0;
172 }
173 
Init(Maps * maps)174 void JitDebug::Init(Maps* maps) {
175   if (initialized_) {
176     return;
177   }
178   // Regardless of what happens below, consider the init finished.
179   initialized_ = true;
180 
181   FindAndReadVariable(maps, "__jit_debug_descriptor");
182 }
183 
GetElf(Maps * maps,uint64_t pc)184 Elf* 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.
187   std::lock_guard<std::mutex> guard(lock_);
188   if (!initialized_) {
189     Init(maps);
190   }
191 
192   // Search the existing elf object first.
193   for (Elf* elf : elf_list_) {
194     if (elf->IsValidPc(pc)) {
195       return elf;
196     }
197   }
198 
199   while (entry_addr_ != 0) {
200     uint64_t start;
201     uint64_t size;
202     entry_addr_ = (this->*read_entry_func_)(&start, &size);
203 
204     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     }
218   }
219   return nullptr;
220 }
221 
222 }  // namespace unwindstack
223