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 
23 #include "ElfInterface.h"
24 #include "Memory.h"
25 #include "Regs.h"
26 
27 template <typename EhdrType, typename PhdrType, typename ShdrType>
ReadAllHeaders()28 bool ElfInterface::ReadAllHeaders() {
29   EhdrType ehdr;
30   if (!memory_->Read(0, &ehdr, sizeof(ehdr))) {
31     return false;
32   }
33 
34   if (!ReadProgramHeaders<EhdrType, PhdrType>(ehdr)) {
35     return false;
36   }
37   return ReadSectionHeaders<EhdrType, ShdrType>(ehdr);
38 }
39 
40 template <typename EhdrType, typename PhdrType>
ReadProgramHeaders(const EhdrType & ehdr)41 bool ElfInterface::ReadProgramHeaders(const EhdrType& ehdr) {
42   uint64_t offset = ehdr.e_phoff;
43   for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
44     PhdrType phdr;
45     if (!memory_->Read(offset, &phdr, &phdr.p_type, sizeof(phdr.p_type))) {
46       return false;
47     }
48 
49     if (HandleType(offset, phdr.p_type)) {
50       continue;
51     }
52 
53     switch (phdr.p_type) {
54     case PT_LOAD:
55     {
56       // Get the flags first, if this isn't an executable header, ignore it.
57       if (!memory_->Read(offset, &phdr, &phdr.p_flags, sizeof(phdr.p_flags))) {
58         return false;
59       }
60       if ((phdr.p_flags & PF_X) == 0) {
61         continue;
62       }
63 
64       if (!memory_->Read(offset, &phdr, &phdr.p_vaddr, sizeof(phdr.p_vaddr))) {
65         return false;
66       }
67       if (!memory_->Read(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
68         return false;
69       }
70       if (!memory_->Read(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
71         return false;
72       }
73       pt_loads_[phdr.p_offset] = LoadInfo{phdr.p_offset, phdr.p_vaddr,
74                                           static_cast<size_t>(phdr.p_memsz)};
75       if (phdr.p_offset == 0) {
76         load_bias_ = phdr.p_vaddr;
77       }
78       break;
79     }
80 
81     case PT_GNU_EH_FRAME:
82       if (!memory_->Read(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
83         return false;
84       }
85       eh_frame_offset_ = phdr.p_offset;
86       if (!memory_->Read(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
87         return false;
88       }
89       eh_frame_size_ = phdr.p_memsz;
90       break;
91 
92     case PT_DYNAMIC:
93       if (!memory_->Read(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
94         return false;
95       }
96       dynamic_offset_ = phdr.p_offset;
97       if (!memory_->Read(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
98         return false;
99       }
100       dynamic_size_ = phdr.p_memsz;
101       break;
102     }
103   }
104   return true;
105 }
106 
107 template <typename EhdrType, typename ShdrType>
ReadSectionHeaders(const EhdrType & ehdr)108 bool ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) {
109   uint64_t offset = ehdr.e_shoff;
110   uint64_t sec_offset = 0;
111   uint64_t sec_size = 0;
112 
113   // Get the location of the section header names.
114   // If something is malformed in the header table data, we aren't going
115   // to terminate, we'll simply ignore this part.
116   ShdrType shdr;
117   if (ehdr.e_shstrndx < ehdr.e_shnum) {
118     uint64_t sh_offset = offset + ehdr.e_shstrndx * ehdr.e_shentsize;
119     if (memory_->Read(sh_offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset))
120         && memory_->Read(sh_offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) {
121       sec_offset = shdr.sh_offset;
122       sec_size = shdr.sh_size;
123     }
124   }
125 
126   // Skip the first header, it's always going to be NULL.
127   for (size_t i = 1; i < ehdr.e_shnum; i++, offset += ehdr.e_shentsize) {
128     if (!memory_->Read(offset, &shdr, &shdr.sh_type, sizeof(shdr.sh_type))) {
129       return false;
130     }
131 
132     if (shdr.sh_type == SHT_PROGBITS) {
133       // Look for the .debug_frame and .gnu_debugdata.
134       if (!memory_->Read(offset, &shdr, &shdr.sh_name, sizeof(shdr.sh_name))) {
135         return false;
136       }
137       if (shdr.sh_name < sec_size) {
138         std::string name;
139         if (memory_->ReadString(sec_offset + shdr.sh_name, &name)) {
140           if (name == ".debug_frame") {
141             if (memory_->Read(offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset))
142                 && memory_->Read(offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) {
143               debug_frame_offset_ = shdr.sh_offset;
144               debug_frame_size_ = shdr.sh_size;
145             }
146           } else if (name == ".gnu_debugdata") {
147             if (memory_->Read(offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset))
148                 && memory_->Read(offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) {
149               gnu_debugdata_offset_ = shdr.sh_offset;
150               gnu_debugdata_size_ = shdr.sh_size;
151             }
152           }
153         }
154       }
155     }
156   }
157   return true;
158 }
159 
160 template <typename DynType>
GetSonameWithTemplate(std::string * soname)161 bool ElfInterface::GetSonameWithTemplate(std::string* soname) {
162   if (soname_type_ == SONAME_INVALID) {
163     return false;
164   }
165   if (soname_type_ == SONAME_VALID) {
166     *soname = soname_;
167     return true;
168   }
169 
170   soname_type_ = SONAME_INVALID;
171 
172   uint64_t soname_offset = 0;
173   uint64_t strtab_offset = 0;
174   uint64_t strtab_size = 0;
175 
176   // Find the soname location from the dynamic headers section.
177   DynType dyn;
178   uint64_t offset = dynamic_offset_;
179   uint64_t max_offset = offset + dynamic_size_;
180   for (uint64_t offset = dynamic_offset_; offset < max_offset; offset += sizeof(DynType)) {
181     if (!memory_->Read(offset, &dyn, sizeof(dyn))) {
182       return false;
183     }
184 
185     if (dyn.d_tag == DT_STRTAB) {
186       strtab_offset = dyn.d_un.d_ptr;
187     } else if (dyn.d_tag == DT_STRSZ) {
188       strtab_size = dyn.d_un.d_val;
189     } else if (dyn.d_tag == DT_SONAME) {
190       soname_offset = dyn.d_un.d_val;
191     } else if (dyn.d_tag == DT_NULL) {
192       break;
193     }
194   }
195 
196   soname_offset += strtab_offset;
197   if (soname_offset >= strtab_offset + strtab_size) {
198     return false;
199   }
200   if (!memory_->ReadString(soname_offset, &soname_)) {
201     return false;
202   }
203   soname_type_ = SONAME_VALID;
204   *soname = soname_;
205   return true;
206 }
207 
Step(uint64_t,Regs *,Memory *)208 bool ElfInterface::Step(uint64_t, Regs*, Memory*) {
209   return false;
210 }
211 
212 // Instantiate all of the needed template functions.
213 template bool ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>();
214 template bool ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>();
215 
216 template bool ElfInterface::ReadProgramHeaders<Elf32_Ehdr, Elf32_Phdr>(const Elf32_Ehdr&);
217 template bool ElfInterface::ReadProgramHeaders<Elf64_Ehdr, Elf64_Phdr>(const Elf64_Ehdr&);
218 
219 template bool ElfInterface::ReadSectionHeaders<Elf32_Ehdr, Elf32_Shdr>(const Elf32_Ehdr&);
220 template bool ElfInterface::ReadSectionHeaders<Elf64_Ehdr, Elf64_Shdr>(const Elf64_Ehdr&);
221 
222 template bool ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(std::string*);
223 template bool ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(std::string*);
224