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