• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 <elf.h>
18 #include <string.h>
19 
20 #include <memory>
21 #include <mutex>
22 #include <string>
23 #include <utility>
24 
25 #define LOG_TAG "unwind"
26 #include <log/log.h>
27 
28 #include <unwindstack/Elf.h>
29 #include <unwindstack/ElfInterface.h>
30 #include <unwindstack/MapInfo.h>
31 #include <unwindstack/Memory.h>
32 #include <unwindstack/Regs.h>
33 
34 #include "ElfInterfaceArm.h"
35 #include "Symbols.h"
36 
37 namespace unwindstack {
38 
39 bool Elf::cache_enabled_;
40 std::unordered_map<std::string, std::pair<std::shared_ptr<Elf>, bool>>* Elf::cache_;
41 std::mutex* Elf::cache_lock_;
42 
Init(bool init_gnu_debugdata)43 bool Elf::Init(bool init_gnu_debugdata) {
44   load_bias_ = 0;
45   if (!memory_) {
46     return false;
47   }
48 
49   interface_.reset(CreateInterfaceFromMemory(memory_.get()));
50   if (!interface_) {
51     return false;
52   }
53 
54   valid_ = interface_->Init(&load_bias_);
55   if (valid_) {
56     interface_->InitHeaders();
57     if (init_gnu_debugdata) {
58       InitGnuDebugdata();
59     } else {
60       gnu_debugdata_interface_.reset(nullptr);
61     }
62   } else {
63     interface_.reset(nullptr);
64   }
65   return valid_;
66 }
67 
68 // It is expensive to initialize the .gnu_debugdata section. Provide a method
69 // to initialize this data separately.
InitGnuDebugdata()70 void Elf::InitGnuDebugdata() {
71   if (!valid_ || interface_->gnu_debugdata_offset() == 0) {
72     return;
73   }
74 
75   gnu_debugdata_memory_.reset(interface_->CreateGnuDebugdataMemory());
76   gnu_debugdata_interface_.reset(CreateInterfaceFromMemory(gnu_debugdata_memory_.get()));
77   ElfInterface* gnu = gnu_debugdata_interface_.get();
78   if (gnu == nullptr) {
79     return;
80   }
81 
82   // Ignore the load_bias from the compressed section, the correct load bias
83   // is in the uncompressed data.
84   uint64_t load_bias;
85   if (gnu->Init(&load_bias)) {
86     gnu->InitHeaders();
87     interface_->SetGnuDebugdataInterface(gnu);
88   } else {
89     // Free all of the memory associated with the gnu_debugdata section.
90     gnu_debugdata_memory_.reset(nullptr);
91     gnu_debugdata_interface_.reset(nullptr);
92   }
93 }
94 
GetSoname(std::string * name)95 bool Elf::GetSoname(std::string* name) {
96   std::lock_guard<std::mutex> guard(lock_);
97   return valid_ && interface_->GetSoname(name);
98 }
99 
GetRelPc(uint64_t pc,const MapInfo * map_info)100 uint64_t Elf::GetRelPc(uint64_t pc, const MapInfo* map_info) {
101   return pc - map_info->start + load_bias_ + map_info->elf_offset;
102 }
103 
GetFunctionName(uint64_t addr,std::string * name,uint64_t * func_offset)104 bool Elf::GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) {
105   std::lock_guard<std::mutex> guard(lock_);
106   return valid_ && (interface_->GetFunctionName(addr, load_bias_, name, func_offset) ||
107                     (gnu_debugdata_interface_ && gnu_debugdata_interface_->GetFunctionName(
108                                                      addr, load_bias_, name, func_offset)));
109 }
110 
GetGlobalVariable(const std::string & name,uint64_t * memory_address)111 bool Elf::GetGlobalVariable(const std::string& name, uint64_t* memory_address) {
112   if (!valid_) {
113     return false;
114   }
115 
116   if (!interface_->GetGlobalVariable(name, memory_address) &&
117       (gnu_debugdata_interface_ == nullptr ||
118        !gnu_debugdata_interface_->GetGlobalVariable(name, memory_address))) {
119     return false;
120   }
121 
122   // Adjust by the load bias.
123   if (*memory_address < load_bias_) {
124     return false;
125   }
126 
127   *memory_address -= load_bias_;
128 
129   // If this winds up in the dynamic section, then we might need to adjust
130   // the address.
131   uint64_t dynamic_end = interface_->dynamic_vaddr() + interface_->dynamic_size();
132   if (*memory_address >= interface_->dynamic_vaddr() && *memory_address < dynamic_end) {
133     if (interface_->dynamic_vaddr() > interface_->dynamic_offset()) {
134       *memory_address -= interface_->dynamic_vaddr() - interface_->dynamic_offset();
135     } else {
136       *memory_address += interface_->dynamic_offset() - interface_->dynamic_vaddr();
137     }
138   }
139   return true;
140 }
141 
GetLastError(ErrorData * data)142 void Elf::GetLastError(ErrorData* data) {
143   if (valid_) {
144     *data = interface_->last_error();
145   }
146 }
147 
GetLastErrorCode()148 ErrorCode Elf::GetLastErrorCode() {
149   if (valid_) {
150     return interface_->LastErrorCode();
151   }
152   return ERROR_NONE;
153 }
154 
GetLastErrorAddress()155 uint64_t Elf::GetLastErrorAddress() {
156   if (valid_) {
157     return interface_->LastErrorAddress();
158   }
159   return 0;
160 }
161 
162 // The relative pc is always relative to the start of the map from which it comes.
Step(uint64_t rel_pc,uint64_t adjusted_rel_pc,Regs * regs,Memory * process_memory,bool * finished)163 bool Elf::Step(uint64_t rel_pc, uint64_t adjusted_rel_pc, Regs* regs, Memory* process_memory,
164                bool* finished) {
165   if (!valid_) {
166     return false;
167   }
168 
169   // The relative pc expectd by StepIfSignalHandler is relative to the start of the elf.
170   if (regs->StepIfSignalHandler(rel_pc, this, process_memory)) {
171     *finished = false;
172     return true;
173   }
174 
175   // Lock during the step which can update information in the object.
176   std::lock_guard<std::mutex> guard(lock_);
177   return interface_->Step(adjusted_rel_pc, load_bias_, regs, process_memory, finished);
178 }
179 
IsValidElf(Memory * memory)180 bool Elf::IsValidElf(Memory* memory) {
181   if (memory == nullptr) {
182     return false;
183   }
184 
185   // Verify that this is a valid elf file.
186   uint8_t e_ident[SELFMAG + 1];
187   if (!memory->ReadFully(0, e_ident, SELFMAG)) {
188     return false;
189   }
190 
191   if (memcmp(e_ident, ELFMAG, SELFMAG) != 0) {
192     return false;
193   }
194   return true;
195 }
196 
GetInfo(Memory * memory,bool * valid,uint64_t * size)197 void Elf::GetInfo(Memory* memory, bool* valid, uint64_t* size) {
198   if (!IsValidElf(memory)) {
199     *valid = false;
200     return;
201   }
202   *size = 0;
203   *valid = true;
204 
205   // Now read the section header information.
206   uint8_t class_type;
207   if (!memory->ReadFully(EI_CLASS, &class_type, 1)) {
208     return;
209   }
210   if (class_type == ELFCLASS32) {
211     ElfInterface32::GetMaxSize(memory, size);
212   } else if (class_type == ELFCLASS64) {
213     ElfInterface64::GetMaxSize(memory, size);
214   } else {
215     *valid = false;
216   }
217 }
218 
IsValidPc(uint64_t pc)219 bool Elf::IsValidPc(uint64_t pc) {
220   if (!valid_ || pc < load_bias_) {
221     return false;
222   }
223   pc -= load_bias_;
224 
225   if (interface_->IsValidPc(pc)) {
226     return true;
227   }
228 
229   if (gnu_debugdata_interface_ != nullptr && gnu_debugdata_interface_->IsValidPc(pc)) {
230     return true;
231   }
232 
233   return false;
234 }
235 
CreateInterfaceFromMemory(Memory * memory)236 ElfInterface* Elf::CreateInterfaceFromMemory(Memory* memory) {
237   if (!IsValidElf(memory)) {
238     return nullptr;
239   }
240 
241   std::unique_ptr<ElfInterface> interface;
242   if (!memory->ReadFully(EI_CLASS, &class_type_, 1)) {
243     return nullptr;
244   }
245   if (class_type_ == ELFCLASS32) {
246     Elf32_Half e_machine;
247     if (!memory->ReadFully(EI_NIDENT + sizeof(Elf32_Half), &e_machine, sizeof(e_machine))) {
248       return nullptr;
249     }
250 
251     machine_type_ = e_machine;
252     if (e_machine == EM_ARM) {
253       arch_ = ARCH_ARM;
254       interface.reset(new ElfInterfaceArm(memory));
255     } else if (e_machine == EM_386) {
256       arch_ = ARCH_X86;
257       interface.reset(new ElfInterface32(memory));
258     } else if (e_machine == EM_MIPS) {
259       arch_ = ARCH_MIPS;
260       interface.reset(new ElfInterface32(memory));
261     } else {
262       // Unsupported.
263       ALOGI("32 bit elf that is neither arm nor x86 nor mips: e_machine = %d\n", e_machine);
264       return nullptr;
265     }
266   } else if (class_type_ == ELFCLASS64) {
267     Elf64_Half e_machine;
268     if (!memory->ReadFully(EI_NIDENT + sizeof(Elf64_Half), &e_machine, sizeof(e_machine))) {
269       return nullptr;
270     }
271 
272     machine_type_ = e_machine;
273     if (e_machine == EM_AARCH64) {
274       arch_ = ARCH_ARM64;
275     } else if (e_machine == EM_X86_64) {
276       arch_ = ARCH_X86_64;
277     } else if (e_machine == EM_MIPS) {
278       arch_ = ARCH_MIPS64;
279     } else {
280       // Unsupported.
281       ALOGI("64 bit elf that is neither aarch64 nor x86_64 nor mips64: e_machine = %d\n",
282             e_machine);
283       return nullptr;
284     }
285     interface.reset(new ElfInterface64(memory));
286   }
287 
288   return interface.release();
289 }
290 
GetLoadBias(Memory * memory)291 uint64_t Elf::GetLoadBias(Memory* memory) {
292   if (!IsValidElf(memory)) {
293     return 0;
294   }
295 
296   uint8_t class_type;
297   if (!memory->Read(EI_CLASS, &class_type, 1)) {
298     return 0;
299   }
300 
301   if (class_type == ELFCLASS32) {
302     return ElfInterface::GetLoadBias<Elf32_Ehdr, Elf32_Phdr>(memory);
303   } else if (class_type == ELFCLASS64) {
304     return ElfInterface::GetLoadBias<Elf64_Ehdr, Elf64_Phdr>(memory);
305   }
306   return 0;
307 }
308 
SetCachingEnabled(bool enable)309 void Elf::SetCachingEnabled(bool enable) {
310   if (!cache_enabled_ && enable) {
311     cache_enabled_ = true;
312     cache_ = new std::unordered_map<std::string, std::pair<std::shared_ptr<Elf>, bool>>;
313     cache_lock_ = new std::mutex;
314   } else if (cache_enabled_ && !enable) {
315     cache_enabled_ = false;
316     delete cache_;
317     delete cache_lock_;
318   }
319 }
320 
CacheLock()321 void Elf::CacheLock() {
322   cache_lock_->lock();
323 }
324 
CacheUnlock()325 void Elf::CacheUnlock() {
326   cache_lock_->unlock();
327 }
328 
CacheAdd(MapInfo * info)329 void Elf::CacheAdd(MapInfo* info) {
330   // If elf_offset != 0, then cache both name:offset and name.
331   // The cached name is used to do lookups if multiple maps for the same
332   // named elf file exist.
333   // For example, if there are two maps boot.odex:1000 and boot.odex:2000
334   // where each reference the entire boot.odex, the cache will properly
335   // use the same cached elf object.
336 
337   if (info->offset == 0 || info->elf_offset != 0) {
338     (*cache_)[info->name] = std::make_pair(info->elf, true);
339   }
340 
341   if (info->offset != 0) {
342     // The second element in the pair indicates whether elf_offset should
343     // be set to offset when getting out of the cache.
344     (*cache_)[info->name + ':' + std::to_string(info->offset)] =
345         std::make_pair(info->elf, info->elf_offset != 0);
346   }
347 }
348 
CacheAfterCreateMemory(MapInfo * info)349 bool Elf::CacheAfterCreateMemory(MapInfo* info) {
350   if (info->name.empty() || info->offset == 0 || info->elf_offset == 0) {
351     return false;
352   }
353 
354   auto entry = cache_->find(info->name);
355   if (entry == cache_->end()) {
356     return false;
357   }
358 
359   // In this case, the whole file is the elf, and the name has already
360   // been cached. Add an entry at name:offset to get this directly out
361   // of the cache next time.
362   info->elf = entry->second.first;
363   (*cache_)[info->name + ':' + std::to_string(info->offset)] = std::make_pair(info->elf, true);
364   return true;
365 }
366 
CacheGet(MapInfo * info)367 bool Elf::CacheGet(MapInfo* info) {
368   std::string name(info->name);
369   if (info->offset != 0) {
370     name += ':' + std::to_string(info->offset);
371   }
372   auto entry = cache_->find(name);
373   if (entry != cache_->end()) {
374     info->elf = entry->second.first;
375     if (entry->second.second) {
376       info->elf_offset = info->offset;
377     }
378     return true;
379   }
380   return false;
381 }
382 
383 }  // namespace unwindstack
384