• 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 <elf.h>
18 #include <stdint.h>
19 
20 #include <memory>
21 #include <string>
22 #include <utility>
23 
24 #include <unwindstack/DwarfError.h>
25 #include <unwindstack/DwarfSection.h>
26 #include <unwindstack/ElfInterface.h>
27 #include <unwindstack/Log.h>
28 #include <unwindstack/Regs.h>
29 
30 #include "DwarfDebugFrame.h"
31 #include "DwarfEhFrame.h"
32 #include "DwarfEhFrameWithHdr.h"
33 #include "MemoryBuffer.h"
34 #include "MemoryXz.h"
35 #include "Symbols.h"
36 
37 namespace unwindstack {
38 
~ElfInterface()39 ElfInterface::~ElfInterface() {
40   for (auto symbol : symbols_) {
41     delete symbol;
42   }
43 }
44 
IsValidPc(uint64_t pc)45 bool ElfInterface::IsValidPc(uint64_t pc) {
46   if (!pt_loads_.empty()) {
47     for (auto& entry : pt_loads_) {
48       uint64_t start = entry.second.table_offset;
49       uint64_t end = start + entry.second.table_size;
50       if (pc >= start && pc < end) {
51         return true;
52       }
53     }
54     return false;
55   }
56 
57   // No PT_LOAD data, look for a fde for this pc in the section data.
58   if (debug_frame_ != nullptr && debug_frame_->GetFdeFromPc(pc) != nullptr) {
59     return true;
60   }
61 
62   if (eh_frame_ != nullptr && eh_frame_->GetFdeFromPc(pc) != nullptr) {
63     return true;
64   }
65 
66   return false;
67 }
68 
GetTextRange(uint64_t * addr,uint64_t * size)69 bool ElfInterface::GetTextRange(uint64_t* addr, uint64_t* size) {
70   if (text_size_ != 0) {
71     *addr = text_addr_;
72     *size = text_size_;
73     return true;
74   }
75   return false;
76 }
77 
CreateGnuDebugdataMemory()78 std::unique_ptr<Memory> ElfInterface::CreateGnuDebugdataMemory() {
79   if (gnu_debugdata_offset_ == 0 || gnu_debugdata_size_ == 0) {
80     return nullptr;
81   }
82 
83   auto decompressed =
84       std::make_unique<MemoryXz>(memory_, gnu_debugdata_offset_, gnu_debugdata_size_, GetSoname());
85   if (!decompressed || !decompressed->Init()) {
86     gnu_debugdata_offset_ = 0;
87     gnu_debugdata_size_ = 0;
88     return nullptr;
89   }
90   return decompressed;
91 }
92 
93 template <typename ElfTypes>
InitHeaders()94 void ElfInterfaceImpl<ElfTypes>::InitHeaders() {
95   if (eh_frame_hdr_offset_ != 0) {
96     DwarfEhFrameWithHdr<AddressType>* eh_frame_hdr = new DwarfEhFrameWithHdr<AddressType>(memory_);
97     eh_frame_.reset(eh_frame_hdr);
98     if (!eh_frame_hdr->EhFrameInit(eh_frame_offset_, eh_frame_size_, eh_frame_section_bias_) ||
99         !eh_frame_->Init(eh_frame_hdr_offset_, eh_frame_hdr_size_, eh_frame_hdr_section_bias_)) {
100       eh_frame_.reset(nullptr);
101     }
102   }
103 
104   if (eh_frame_.get() == nullptr && eh_frame_offset_ != 0) {
105     // If there is an eh_frame section without an eh_frame_hdr section,
106     // or using the frame hdr object failed to init.
107     eh_frame_.reset(new DwarfEhFrame<AddressType>(memory_));
108     if (!eh_frame_->Init(eh_frame_offset_, eh_frame_size_, eh_frame_section_bias_)) {
109       eh_frame_.reset(nullptr);
110     }
111   }
112 
113   if (eh_frame_.get() == nullptr) {
114     eh_frame_hdr_offset_ = 0;
115     eh_frame_hdr_section_bias_ = 0;
116     eh_frame_hdr_size_ = static_cast<uint64_t>(-1);
117     eh_frame_offset_ = 0;
118     eh_frame_section_bias_ = 0;
119     eh_frame_size_ = static_cast<uint64_t>(-1);
120   }
121 
122   if (debug_frame_offset_ != 0) {
123     debug_frame_.reset(new DwarfDebugFrame<AddressType>(memory_));
124     if (!debug_frame_->Init(debug_frame_offset_, debug_frame_size_, debug_frame_section_bias_)) {
125       debug_frame_.reset(nullptr);
126       debug_frame_offset_ = 0;
127       debug_frame_size_ = static_cast<uint64_t>(-1);
128     }
129   }
130 }
131 
132 template <typename ElfTypes>
ReadAllHeaders(int64_t * load_bias)133 bool ElfInterfaceImpl<ElfTypes>::ReadAllHeaders(int64_t* load_bias) {
134   EhdrType ehdr;
135   if (!memory_->ReadFully(0, &ehdr, sizeof(ehdr))) {
136     last_error_.code = ERROR_MEMORY_INVALID;
137     last_error_.address = 0;
138     return false;
139   }
140 
141   // If we have enough information that this is an elf file, then allow
142   // malformed program and section headers.
143   ReadProgramHeaders(ehdr, load_bias);
144   ReadSectionHeaders(ehdr);
145   return true;
146 }
147 
148 template <typename EhdrType, typename PhdrType>
GetLoadBias(Memory * memory)149 int64_t ElfInterface::GetLoadBias(Memory* memory) {
150   EhdrType ehdr;
151   if (!memory->ReadFully(0, &ehdr, sizeof(ehdr))) {
152     return false;
153   }
154 
155   uint64_t offset = ehdr.e_phoff;
156   for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
157     PhdrType phdr;
158     if (!memory->ReadFully(offset, &phdr, sizeof(phdr))) {
159       return 0;
160     }
161 
162     // Find the first executable load when looking for the load bias.
163     if (phdr.p_type == PT_LOAD && (phdr.p_flags & PF_X)) {
164       return static_cast<uint64_t>(phdr.p_vaddr) - phdr.p_offset;
165     }
166   }
167   return 0;
168 }
169 
170 template <typename ElfTypes>
ReadProgramHeaders(const EhdrType & ehdr,int64_t * load_bias)171 void ElfInterfaceImpl<ElfTypes>::ReadProgramHeaders(const EhdrType& ehdr, int64_t* load_bias) {
172   uint64_t offset = ehdr.e_phoff;
173   bool first_exec_load_header = true;
174   for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
175     PhdrType phdr;
176     if (!memory_->ReadFully(offset, &phdr, sizeof(phdr))) {
177       return;
178     }
179 
180     switch (phdr.p_type) {
181     case PT_LOAD:
182     {
183       if ((phdr.p_flags & PF_X) == 0) {
184         continue;
185       }
186 
187       pt_loads_[phdr.p_offset] = LoadInfo{phdr.p_offset, phdr.p_vaddr,
188                                           static_cast<size_t>(phdr.p_memsz)};
189       // Only set the load bias from the first executable load header.
190       if (first_exec_load_header) {
191         *load_bias = static_cast<uint64_t>(phdr.p_vaddr) - phdr.p_offset;
192       }
193       first_exec_load_header = false;
194       break;
195     }
196 
197     case PT_GNU_EH_FRAME:
198       // This is really the pointer to the .eh_frame_hdr section.
199       eh_frame_hdr_offset_ = phdr.p_offset;
200       eh_frame_hdr_section_bias_ = static_cast<uint64_t>(phdr.p_vaddr) - phdr.p_offset;
201       eh_frame_hdr_size_ = phdr.p_memsz;
202       break;
203 
204     case PT_DYNAMIC:
205       dynamic_offset_ = phdr.p_offset;
206       dynamic_vaddr_start_ = phdr.p_vaddr;
207       if (__builtin_add_overflow(dynamic_vaddr_start_, phdr.p_memsz, &dynamic_vaddr_end_)) {
208         dynamic_offset_ = 0;
209         dynamic_vaddr_start_ = 0;
210         dynamic_vaddr_end_ = 0;
211       }
212       break;
213 
214     default:
215       HandleUnknownType(phdr.p_type, phdr.p_offset, phdr.p_filesz);
216       break;
217     }
218   }
219 }
220 
221 template <typename ElfTypes>
ReadBuildID()222 std::string ElfInterfaceImpl<ElfTypes>::ReadBuildID() {
223   // Ensure there is no overflow in any of the calulations below.
224   uint64_t tmp;
225   if (__builtin_add_overflow(gnu_build_id_offset_, gnu_build_id_size_, &tmp)) {
226     return "";
227   }
228 
229   uint64_t offset = 0;
230   while (offset < gnu_build_id_size_) {
231     if (gnu_build_id_size_ - offset < sizeof(NhdrType)) {
232       return "";
233     }
234     NhdrType hdr;
235     if (!memory_->ReadFully(gnu_build_id_offset_ + offset, &hdr, sizeof(hdr))) {
236       return "";
237     }
238     offset += sizeof(hdr);
239 
240     if (gnu_build_id_size_ - offset < hdr.n_namesz) {
241       return "";
242     }
243     if (hdr.n_namesz > 0) {
244       std::string name(hdr.n_namesz, '\0');
245       if (!memory_->ReadFully(gnu_build_id_offset_ + offset, &(name[0]), hdr.n_namesz)) {
246         return "";
247       }
248 
249       // Trim trailing \0 as GNU is stored as a C string in the ELF file.
250       if (name.back() == '\0')
251         name.resize(name.size() - 1);
252 
253       // Align hdr.n_namesz to next power multiple of 4. See man 5 elf.
254       offset += (hdr.n_namesz + 3) & ~3;
255 
256       if (name == "GNU" && hdr.n_type == NT_GNU_BUILD_ID) {
257         if (gnu_build_id_size_ - offset < hdr.n_descsz || hdr.n_descsz == 0) {
258           return "";
259         }
260         std::string build_id(hdr.n_descsz, '\0');
261         if (memory_->ReadFully(gnu_build_id_offset_ + offset, &build_id[0], hdr.n_descsz)) {
262           return build_id;
263         }
264         return "";
265       }
266     }
267     // Align hdr.n_descsz to next power multiple of 4. See man 5 elf.
268     offset += (hdr.n_descsz + 3) & ~3;
269   }
270   return "";
271 }
272 template <typename ElfTypes>
ReadSectionHeaders(const EhdrType & ehdr)273 void ElfInterfaceImpl<ElfTypes>::ReadSectionHeaders(const EhdrType& ehdr) {
274   uint64_t offset = ehdr.e_shoff;
275   uint64_t sec_offset = 0;
276   uint64_t sec_size = 0;
277 
278   // Get the location of the section header names.
279   // If something is malformed in the header table data, we aren't going
280   // to terminate, we'll simply ignore this part.
281   ShdrType shdr;
282   if (ehdr.e_shstrndx < ehdr.e_shnum) {
283     uint64_t sh_offset = offset + ehdr.e_shstrndx * ehdr.e_shentsize;
284     if (memory_->ReadFully(sh_offset, &shdr, sizeof(shdr))) {
285       sec_offset = shdr.sh_offset;
286       sec_size = shdr.sh_size;
287     }
288   }
289 
290   // Skip the first header, it's always going to be NULL.
291   offset += ehdr.e_shentsize;
292   for (size_t i = 1; i < ehdr.e_shnum; i++, offset += ehdr.e_shentsize) {
293     if (!memory_->ReadFully(offset, &shdr, sizeof(shdr))) {
294       return;
295     }
296 
297     if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) {
298       // Need to go get the information about the section that contains
299       // the string terminated names.
300       ShdrType str_shdr;
301       if (shdr.sh_link >= ehdr.e_shnum) {
302         continue;
303       }
304       uint64_t str_offset = ehdr.e_shoff + shdr.sh_link * ehdr.e_shentsize;
305       if (!memory_->ReadFully(str_offset, &str_shdr, sizeof(str_shdr))) {
306         continue;
307       }
308       if (str_shdr.sh_type != SHT_STRTAB) {
309         continue;
310       }
311       symbols_.push_back(new Symbols(shdr.sh_offset, shdr.sh_size, shdr.sh_entsize,
312                                      str_shdr.sh_offset, str_shdr.sh_size));
313     } else if ((shdr.sh_type == SHT_PROGBITS || shdr.sh_type == SHT_NOBITS) && sec_size != 0) {
314       // Look for the .debug_frame and .gnu_debugdata.
315       if (shdr.sh_name < sec_size) {
316         std::string name;
317         if (memory_->ReadString(sec_offset + shdr.sh_name, &name, sec_size - shdr.sh_name)) {
318           if (name == ".debug_frame") {
319             debug_frame_offset_ = shdr.sh_offset;
320             debug_frame_size_ = shdr.sh_size;
321             debug_frame_section_bias_ = static_cast<uint64_t>(shdr.sh_addr) - shdr.sh_offset;
322           } else if (name == ".gnu_debugdata") {
323             gnu_debugdata_offset_ = shdr.sh_offset;
324             gnu_debugdata_size_ = shdr.sh_size;
325           } else if (name == ".eh_frame") {
326             eh_frame_offset_ = shdr.sh_offset;
327             eh_frame_section_bias_ = static_cast<uint64_t>(shdr.sh_addr) - shdr.sh_offset;
328             eh_frame_size_ = shdr.sh_size;
329           } else if (eh_frame_hdr_offset_ == 0 && name == ".eh_frame_hdr") {
330             eh_frame_hdr_offset_ = shdr.sh_offset;
331             eh_frame_hdr_section_bias_ = static_cast<uint64_t>(shdr.sh_addr) - shdr.sh_offset;
332             eh_frame_hdr_size_ = shdr.sh_size;
333           } else if (name == ".data") {
334             data_offset_ = shdr.sh_offset;
335             data_vaddr_start_ = shdr.sh_addr;
336             if (__builtin_add_overflow(data_vaddr_start_, shdr.sh_size, &data_vaddr_end_)) {
337               data_offset_ = 0;
338               data_vaddr_start_ = 0;
339               data_vaddr_end_ = 0;
340             }
341           } else if (name == ".text") {
342             text_addr_ = shdr.sh_addr;
343             text_size_ = shdr.sh_size;
344           }
345         }
346       }
347     } else if (shdr.sh_type == SHT_STRTAB) {
348       // In order to read soname, keep track of address to offset mapping.
349       strtabs_.push_back(std::make_pair<uint64_t, uint64_t>(static_cast<uint64_t>(shdr.sh_addr),
350                                                             static_cast<uint64_t>(shdr.sh_offset)));
351     } else if (shdr.sh_type == SHT_NOTE) {
352       if (shdr.sh_name < sec_size) {
353         std::string name;
354         if (memory_->ReadString(sec_offset + shdr.sh_name, &name, sec_size - shdr.sh_name) &&
355             name == ".note.gnu.build-id") {
356           gnu_build_id_offset_ = shdr.sh_offset;
357           gnu_build_id_size_ = shdr.sh_size;
358         }
359       }
360     }
361   }
362 }
363 
364 template <typename ElfTypes>
GetSoname()365 std::string ElfInterfaceImpl<ElfTypes>::GetSoname() {
366   if (soname_type_ == SONAME_INVALID) {
367     return "";
368   }
369   if (soname_type_ == SONAME_VALID) {
370     return soname_;
371   }
372 
373   soname_type_ = SONAME_INVALID;
374 
375   uint64_t soname_offset = 0;
376   uint64_t strtab_addr = 0;
377   uint64_t strtab_size = 0;
378 
379   // Find the soname location from the dynamic headers section.
380   DynType dyn;
381   uint64_t offset = dynamic_offset_;
382   uint64_t max_offset = offset + dynamic_vaddr_end_ - dynamic_vaddr_start_;
383   for (uint64_t offset = dynamic_offset_; offset < max_offset; offset += sizeof(DynType)) {
384     if (!memory_->ReadFully(offset, &dyn, sizeof(dyn))) {
385       last_error_.code = ERROR_MEMORY_INVALID;
386       last_error_.address = offset;
387       return "";
388     }
389 
390     if (dyn.d_tag == DT_STRTAB) {
391       strtab_addr = dyn.d_un.d_ptr;
392     } else if (dyn.d_tag == DT_STRSZ) {
393       strtab_size = dyn.d_un.d_val;
394     } else if (dyn.d_tag == DT_SONAME) {
395       soname_offset = dyn.d_un.d_val;
396     } else if (dyn.d_tag == DT_NULL) {
397       break;
398     }
399   }
400 
401   // Need to map the strtab address to the real offset.
402   for (const auto& entry : strtabs_) {
403     if (entry.first == strtab_addr) {
404       soname_offset = entry.second + soname_offset;
405       uint64_t soname_max = entry.second + strtab_size;
406       if (soname_offset >= soname_max) {
407         return "";
408       }
409       if (!memory_->ReadString(soname_offset, &soname_, soname_max - soname_offset)) {
410         return "";
411       }
412       soname_type_ = SONAME_VALID;
413       return soname_;
414     }
415   }
416   return "";
417 }
418 
419 template <typename ElfTypes>
GetFunctionName(uint64_t addr,SharedString * name,uint64_t * func_offset)420 bool ElfInterfaceImpl<ElfTypes>::GetFunctionName(uint64_t addr, SharedString* name,
421                                                  uint64_t* func_offset) {
422   if (symbols_.empty()) {
423     return false;
424   }
425 
426   for (const auto symbol : symbols_) {
427     if (symbol->template GetName<SymType>(addr, memory_, name, func_offset)) {
428       return true;
429     }
430   }
431   return false;
432 }
433 
434 template <typename ElfTypes>
GetGlobalVariable(const std::string & name,uint64_t * memory_address)435 bool ElfInterfaceImpl<ElfTypes>::GetGlobalVariable(const std::string& name,
436                                                    uint64_t* memory_address) {
437   if (symbols_.empty()) {
438     return false;
439   }
440 
441   for (const auto symbol : symbols_) {
442     if (symbol->template GetGlobal<SymType>(memory_, name, memory_address)) {
443       return true;
444     }
445   }
446   return false;
447 }
448 
Step(uint64_t pc,Regs * regs,Memory * process_memory,bool * finished,bool * is_signal_frame)449 bool ElfInterface::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished,
450                         bool* is_signal_frame) {
451   last_error_.code = ERROR_NONE;
452   last_error_.address = 0;
453 
454   // Try the debug_frame first since it contains the most specific unwind
455   // information.
456   DwarfSection* debug_frame = debug_frame_.get();
457   if (debug_frame != nullptr &&
458       debug_frame->Step(pc, regs, process_memory, finished, is_signal_frame)) {
459     return true;
460   }
461 
462   // Try the eh_frame next.
463   DwarfSection* eh_frame = eh_frame_.get();
464   if (eh_frame != nullptr && eh_frame->Step(pc, regs, process_memory, finished, is_signal_frame)) {
465     return true;
466   }
467 
468   if (gnu_debugdata_interface_ != nullptr &&
469       gnu_debugdata_interface_->Step(pc, regs, process_memory, finished, is_signal_frame)) {
470     return true;
471   }
472 
473   // Set the error code based on the first error encountered.
474   DwarfSection* section = nullptr;
475   if (debug_frame_ != nullptr) {
476     section = debug_frame_.get();
477   } else if (eh_frame_ != nullptr) {
478     section = eh_frame_.get();
479   } else if (gnu_debugdata_interface_ != nullptr) {
480     last_error_ = gnu_debugdata_interface_->last_error();
481     return false;
482   } else {
483     return false;
484   }
485 
486   // Convert the DWARF ERROR to an external error.
487   DwarfErrorCode code = section->LastErrorCode();
488   switch (code) {
489     case DWARF_ERROR_NONE:
490       last_error_.code = ERROR_NONE;
491       break;
492 
493     case DWARF_ERROR_MEMORY_INVALID:
494       last_error_.code = ERROR_MEMORY_INVALID;
495       last_error_.address = section->LastErrorAddress();
496       break;
497 
498     case DWARF_ERROR_ILLEGAL_VALUE:
499     case DWARF_ERROR_ILLEGAL_STATE:
500     case DWARF_ERROR_STACK_INDEX_NOT_VALID:
501     case DWARF_ERROR_TOO_MANY_ITERATIONS:
502     case DWARF_ERROR_CFA_NOT_DEFINED:
503     case DWARF_ERROR_NO_FDES:
504       last_error_.code = ERROR_UNWIND_INFO;
505       break;
506 
507     case DWARF_ERROR_NOT_IMPLEMENTED:
508     case DWARF_ERROR_UNSUPPORTED_VERSION:
509       last_error_.code = ERROR_UNSUPPORTED;
510       break;
511   }
512   return false;
513 }
514 
515 // This is an estimation of the size of the elf file using the location
516 // of the section headers and size. This assumes that the section headers
517 // are at the end of the elf file. If the elf has a load bias, the size
518 // will be too large, but this is acceptable.
519 template <typename ElfTypes>
GetMaxSize(Memory * memory,uint64_t * size)520 void ElfInterfaceImpl<ElfTypes>::GetMaxSize(Memory* memory, uint64_t* size) {
521   EhdrType ehdr;
522   if (!memory->ReadFully(0, &ehdr, sizeof(ehdr))) {
523     *size = 0;
524     return;
525   }
526 
527   // If this winds up as zero, the PT_LOAD reading will get a better value.
528   uint64_t elf_size = ehdr.e_shoff + ehdr.e_shentsize * ehdr.e_shnum;
529 
530   // Search through the PT_LOAD values and if any result in a larger elf
531   // size, use that.
532   uint64_t offset = ehdr.e_phoff;
533   for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
534     PhdrType phdr;
535     if (!memory->ReadFully(offset, &phdr, sizeof(phdr))) {
536       break;
537     }
538     if (phdr.p_type == PT_LOAD) {
539       uint64_t end_offset;
540       if (__builtin_add_overflow(phdr.p_offset, phdr.p_memsz, &end_offset)) {
541         continue;
542       }
543       if (end_offset > elf_size) {
544         elf_size = end_offset;
545       }
546     }
547   }
548 
549   *size = elf_size;
550 }
551 
552 template <typename EhdrType, typename ShdrType>
GetBuildIDInfo(Memory * memory,uint64_t * build_id_offset,uint64_t * build_id_size)553 bool GetBuildIDInfo(Memory* memory, uint64_t* build_id_offset, uint64_t* build_id_size) {
554   EhdrType ehdr;
555   if (!memory->ReadFully(0, &ehdr, sizeof(ehdr))) {
556     return false;
557   }
558 
559   uint64_t offset = ehdr.e_shoff;
560   uint64_t sec_offset;
561   uint64_t sec_size;
562   ShdrType shdr;
563   if (ehdr.e_shstrndx >= ehdr.e_shnum) {
564     return false;
565   }
566 
567   uint64_t sh_offset = offset + ehdr.e_shstrndx * ehdr.e_shentsize;
568   if (!memory->ReadFully(sh_offset, &shdr, sizeof(shdr))) {
569     return false;
570   }
571   sec_offset = shdr.sh_offset;
572   sec_size = shdr.sh_size;
573 
574   // Skip the first header, it's always going to be NULL.
575   offset += ehdr.e_shentsize;
576   for (size_t i = 1; i < ehdr.e_shnum; i++, offset += ehdr.e_shentsize) {
577     if (!memory->ReadFully(offset, &shdr, sizeof(shdr))) {
578       return false;
579     }
580     std::string name;
581     if (shdr.sh_type == SHT_NOTE && shdr.sh_name < sec_size &&
582         memory->ReadString(sec_offset + shdr.sh_name, &name, sec_size - shdr.sh_name) &&
583         name == ".note.gnu.build-id") {
584       *build_id_offset = shdr.sh_offset;
585       *build_id_size = shdr.sh_size;
586       return true;
587     }
588   }
589 
590   return false;
591 }
592 
593 template <typename EhdrType, typename ShdrType, typename NhdrType>
ReadBuildIDFromMemory(Memory * memory)594 std::string ElfInterface::ReadBuildIDFromMemory(Memory* memory) {
595   uint64_t note_offset;
596   uint64_t note_size;
597   if (!GetBuildIDInfo<EhdrType, ShdrType>(memory, &note_offset, &note_size)) {
598     return "";
599   }
600 
601   // Ensure there is no overflow in any of the calculations below.
602   uint64_t tmp;
603   if (__builtin_add_overflow(note_offset, note_size, &tmp)) {
604     return "";
605   }
606 
607   uint64_t offset = 0;
608   while (offset < note_size) {
609     if (note_size - offset < sizeof(NhdrType)) {
610       return "";
611     }
612     NhdrType hdr;
613     if (!memory->ReadFully(note_offset + offset, &hdr, sizeof(hdr))) {
614       return "";
615     }
616     offset += sizeof(hdr);
617 
618     if (note_size - offset < hdr.n_namesz) {
619       return "";
620     }
621     if (hdr.n_namesz > 0) {
622       std::string name(hdr.n_namesz, '\0');
623       if (!memory->ReadFully(note_offset + offset, &(name[0]), hdr.n_namesz)) {
624         return "";
625       }
626 
627       // Trim trailing \0 as GNU is stored as a C string in the ELF file.
628       if (name.back() == '\0') name.resize(name.size() - 1);
629 
630       // Align hdr.n_namesz to next power multiple of 4. See man 5 elf.
631       offset += (hdr.n_namesz + 3) & ~3;
632 
633       if (name == "GNU" && hdr.n_type == NT_GNU_BUILD_ID) {
634         if (note_size - offset < hdr.n_descsz || hdr.n_descsz == 0) {
635           return "";
636         }
637         std::string build_id(hdr.n_descsz, '\0');
638         if (memory->ReadFully(note_offset + offset, &build_id[0], hdr.n_descsz)) {
639           return build_id;
640         }
641         return "";
642       }
643     }
644     // Align hdr.n_descsz to next power multiple of 4. See man 5 elf.
645     offset += (hdr.n_descsz + 3) & ~3;
646   }
647   return "";
648 }
649 
650 // Instantiate all of the needed template functions.
651 template class ElfInterfaceImpl<ElfTypes32>;
652 template class ElfInterfaceImpl<ElfTypes64>;
653 
654 template int64_t ElfInterface::GetLoadBias<Elf32_Ehdr, Elf32_Phdr>(Memory*);
655 template int64_t ElfInterface::GetLoadBias<Elf64_Ehdr, Elf64_Phdr>(Memory*);
656 
657 template std::string ElfInterface::ReadBuildIDFromMemory<Elf32_Ehdr, Elf32_Shdr, Elf32_Nhdr>(
658     Memory*);
659 template std::string ElfInterface::ReadBuildIDFromMemory<Elf64_Ehdr, Elf64_Shdr, Elf64_Nhdr>(
660     Memory*);
661 
662 }  // namespace unwindstack
663