• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <unwindstack/Memory.h>
27 
28 // This implements the JIT Compilation Interface.
29 // See https://sourceware.org/gdb/onlinedocs/gdb/JIT-Interface.html
30 
31 namespace unwindstack {
32 
33 struct JITCodeEntry32Pack {
34   uint32_t next;
35   uint32_t prev;
36   uint32_t symfile_addr;
37   uint64_t symfile_size;
38 } __attribute__((packed));
39 
40 struct JITCodeEntry32Pad {
41   uint32_t next;
42   uint32_t prev;
43   uint32_t symfile_addr;
44   uint32_t pad;
45   uint64_t symfile_size;
46 };
47 
48 struct JITCodeEntry64 {
49   uint64_t next;
50   uint64_t prev;
51   uint64_t symfile_addr;
52   uint64_t symfile_size;
53 };
54 
55 struct JITDescriptorHeader {
56   uint32_t version;
57   uint32_t action_flag;
58 };
59 
60 struct JITDescriptor32 {
61   JITDescriptorHeader header;
62   uint32_t relevant_entry;
63   uint32_t first_entry;
64 };
65 
66 struct JITDescriptor64 {
67   JITDescriptorHeader header;
68   uint64_t relevant_entry;
69   uint64_t first_entry;
70 };
71 
JitDebug(std::shared_ptr<Memory> & memory)72 JitDebug::JitDebug(std::shared_ptr<Memory>& memory) : Global(memory) {}
73 
JitDebug(std::shared_ptr<Memory> & memory,std::vector<std::string> & search_libs)74 JitDebug::JitDebug(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
75     : Global(memory, search_libs) {}
76 
~JitDebug()77 JitDebug::~JitDebug() {
78   for (auto* elf : elf_list_) {
79     delete elf;
80   }
81 }
82 
ReadDescriptor32(uint64_t addr)83 uint64_t JitDebug::ReadDescriptor32(uint64_t addr) {
84   JITDescriptor32 desc;
85   if (!memory_->ReadFully(addr, &desc, sizeof(desc))) {
86     return 0;
87   }
88 
89   if (desc.header.version != 1 || desc.first_entry == 0) {
90     // Either unknown version, or no jit entries.
91     return 0;
92   }
93 
94   return desc.first_entry;
95 }
96 
ReadDescriptor64(uint64_t addr)97 uint64_t JitDebug::ReadDescriptor64(uint64_t addr) {
98   JITDescriptor64 desc;
99   if (!memory_->ReadFully(addr, &desc, sizeof(desc))) {
100     return 0;
101   }
102 
103   if (desc.header.version != 1 || desc.first_entry == 0) {
104     // Either unknown version, or no jit entries.
105     return 0;
106   }
107 
108   return desc.first_entry;
109 }
110 
ReadEntry32Pack(uint64_t * start,uint64_t * size)111 uint64_t JitDebug::ReadEntry32Pack(uint64_t* start, uint64_t* size) {
112   JITCodeEntry32Pack code;
113   if (!memory_->ReadFully(entry_addr_, &code, sizeof(code))) {
114     return 0;
115   }
116 
117   *start = code.symfile_addr;
118   *size = code.symfile_size;
119   return code.next;
120 }
121 
ReadEntry32Pad(uint64_t * start,uint64_t * size)122 uint64_t JitDebug::ReadEntry32Pad(uint64_t* start, uint64_t* size) {
123   JITCodeEntry32Pad code;
124   if (!memory_->ReadFully(entry_addr_, &code, sizeof(code))) {
125     return 0;
126   }
127 
128   *start = code.symfile_addr;
129   *size = code.symfile_size;
130   return code.next;
131 }
132 
ReadEntry64(uint64_t * start,uint64_t * size)133 uint64_t JitDebug::ReadEntry64(uint64_t* start, uint64_t* size) {
134   JITCodeEntry64 code;
135   if (!memory_->ReadFully(entry_addr_, &code, sizeof(code))) {
136     return 0;
137   }
138 
139   *start = code.symfile_addr;
140   *size = code.symfile_size;
141   return code.next;
142 }
143 
ProcessArch()144 void JitDebug::ProcessArch() {
145   switch (arch()) {
146     case ARCH_X86:
147       read_descriptor_func_ = &JitDebug::ReadDescriptor32;
148       read_entry_func_ = &JitDebug::ReadEntry32Pack;
149       break;
150 
151     case ARCH_ARM:
152     case ARCH_MIPS:
153       read_descriptor_func_ = &JitDebug::ReadDescriptor32;
154       read_entry_func_ = &JitDebug::ReadEntry32Pad;
155       break;
156 
157     case ARCH_ARM64:
158     case ARCH_X86_64:
159     case ARCH_MIPS64:
160       read_descriptor_func_ = &JitDebug::ReadDescriptor64;
161       read_entry_func_ = &JitDebug::ReadEntry64;
162       break;
163     case ARCH_UNKNOWN:
164       abort();
165   }
166 }
167 
ReadVariableData(uint64_t ptr)168 bool JitDebug::ReadVariableData(uint64_t ptr) {
169   entry_addr_ = (this->*read_descriptor_func_)(ptr);
170   return entry_addr_ != 0;
171 }
172 
Init(Maps * maps)173 void JitDebug::Init(Maps* maps) {
174   if (initialized_) {
175     return;
176   }
177   // Regardless of what happens below, consider the init finished.
178   initialized_ = true;
179 
180   FindAndReadVariable(maps, "__jit_debug_descriptor");
181 }
182 
GetElf(Maps * maps,uint64_t pc)183 Elf* JitDebug::GetElf(Maps* maps, uint64_t pc) {
184   // Use a single lock, this object should be used so infrequently that
185   // a fine grain lock is unnecessary.
186   std::lock_guard<std::mutex> guard(lock_);
187   if (!initialized_) {
188     Init(maps);
189   }
190 
191   // Search the existing elf object first.
192   for (Elf* elf : elf_list_) {
193     if (elf->IsValidPc(pc)) {
194       return elf;
195     }
196   }
197 
198   while (entry_addr_ != 0) {
199     uint64_t start;
200     uint64_t size;
201     entry_addr_ = (this->*read_entry_func_)(&start, &size);
202 
203     Elf* elf = new Elf(new MemoryRange(memory_, start, size, 0));
204     elf->Init();
205     if (!elf->valid()) {
206       // The data is not formatted in a way we understand, do not attempt
207       // to process any other entries.
208       entry_addr_ = 0;
209       delete elf;
210       return nullptr;
211     }
212     elf_list_.push_back(elf);
213 
214     if (elf->IsValidPc(pc)) {
215       return elf;
216     }
217   }
218   return nullptr;
219 }
220 
221 }  // namespace unwindstack
222