OLD | NEW |
| (Empty) |
1 // Copyright 2010 Google, Inc. All Rights reserved | |
2 // | |
3 // Redistribution and use in source and binary forms, with or without | |
4 // modification, are permitted provided that the following conditions are | |
5 // met: | |
6 // | |
7 // * Redistributions of source code must retain the above copyright | |
8 // notice, this list of conditions and the following disclaimer. | |
9 // * Redistributions in binary form must reproduce the above | |
10 // copyright notice, this list of conditions and the following disclaimer | |
11 // in the documentation and/or other materials provided with the | |
12 // distribution. | |
13 // * Neither the path of Google Inc. nor the paths of its | |
14 // contributors may be used to endorse or promote products derived from | |
15 // this software without specific prior written permission. | |
16 // | |
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
28 | |
29 #include <stdlib.h> | |
30 #include <stdio.h> | |
31 #include <string.h> | |
32 | |
33 #include "common/types.h" | |
34 #include "elf_reader/elf_structs.h" | |
35 #include "elf_reader/elf_object.h" | |
36 #include "elf_reader/elf_reader.h" | |
37 | |
38 namespace elf_reader { | |
39 | |
40 static uint8_t s_ident[4] = { 0x7F, 'E', 'L', 'F' }; | |
41 | |
42 ElfObject::ElfObject() | |
43 : path_(NULL), | |
44 length_(0), | |
45 obj_(NULL), | |
46 strings_(NULL) { | |
47 data_.raw_ = 0; | |
48 shdr_.raw_ = 0; | |
49 phdr_.raw_ = 0; | |
50 } | |
51 | |
52 | |
53 ElfObject::~ElfObject() { | |
54 Unload(); | |
55 } | |
56 | |
57 void ElfObject::Unload() { | |
58 if (data_.raw_) | |
59 free(data_.raw_); | |
60 | |
61 if (path_) | |
62 free(path_); | |
63 | |
64 path_ = NULL; | |
65 length_ = 0; | |
66 | |
67 data_.raw_ = NULL; | |
68 shdr_.raw_ = NULL; | |
69 phdr_.raw_ = NULL; | |
70 strings_ = NULL; | |
71 } | |
72 | |
73 bool ElfObject::Load(const char *path) { | |
74 Unload(); | |
75 | |
76 if (NULL == path) | |
77 return false; | |
78 | |
79 FILE *fp = fopen(path, "rb"); | |
80 if (fp) { | |
81 // Copy the path | |
82 path_ = reinterpret_cast<char *>(malloc(strlen(path) + 1)); | |
83 strcpy(path_, path); | |
84 | |
85 // Determine the length | |
86 fseek(fp, 0, SEEK_END); | |
87 length_ = ftell(fp); | |
88 fseek(fp, 0, SEEK_SET); | |
89 | |
90 /// Verify this is large enough to process the headers | |
91 if (length_ < sizeof(ElfHdrDef)) | |
92 goto failed; | |
93 | |
94 // make sure we allocated enough | |
95 void *data = malloc(static_cast<size_t>(length_)); | |
96 if (NULL == data) | |
97 goto failed; | |
98 data_.raw_ = reinterpret_cast<uint8_t *>(data); | |
99 | |
100 // Make sure we load the whole file | |
101 size_t loaded = fread(data_.raw_, 1, length_, fp); | |
102 if (loaded != length_) | |
103 goto failed; | |
104 | |
105 // Verify we have the expected ELF indentifier at the head of the file | |
106 if (memcmp(data_.def_->e_ident, s_ident, sizeof(s_ident))) | |
107 goto failed; | |
108 | |
109 // Set precomputed pointers and verify structure sizes | |
110 switch (GetClassSize()) { | |
111 case ELFCLASS32: { | |
112 // Get the index to the section containing section names | |
113 uint32_t strndx = data_.hdr32_->e_obj.e_shstrndx; | |
114 | |
115 // Set precomputed header offsets | |
116 shdr_.raw_ = &data_.raw_[data_.hdr32_->e_shoff]; | |
117 phdr_.raw_ = &data_.raw_[data_.hdr32_->e_phoff]; | |
118 obj_ = &data_.hdr32_->e_obj; | |
119 | |
120 // Verify headers are the expected sizes for this Class (machine width) | |
121 if (data_.hdr32_->e_obj.e_shentsize != sizeof(ElfShdr32)) | |
122 goto failed; | |
123 if (data_.hdr32_->e_obj.e_phentsize != sizeof(ElfPhdr32)) | |
124 goto failed; | |
125 | |
126 // If everything checks out, we can precompute strings offset | |
127 uint8_t *string_offs = &data_.raw_[ shdr_.shdr32_[strndx].sh_offset ]; | |
128 strings_ = reinterpret_cast<char *>(string_offs); | |
129 break; | |
130 } | |
131 | |
132 | |
133 case ELFCLASS64: { | |
134 // Get the index to the section containing section names | |
135 uint32_t strndx = data_.hdr64_->e_obj.e_shstrndx; | |
136 | |
137 // Set precomputed offsets | |
138 shdr_.raw_ = &data_.raw_[data_.hdr64_->e_shoff]; | |
139 phdr_.raw_ = &data_.raw_[data_.hdr64_->e_phoff]; | |
140 obj_ = &data_.hdr64_->e_obj; | |
141 | |
142 // Verify headers are the expected sizes for this Class (machine width) | |
143 if (data_.hdr64_->e_obj.e_shentsize != sizeof(ElfShdr64)) | |
144 goto failed; | |
145 if (data_.hdr64_->e_obj.e_phentsize != sizeof(ElfPhdr64)) | |
146 goto failed; | |
147 | |
148 // If everything checks out, we can precompute strings offset | |
149 uint64_t offset = shdr_.shdr64_[strndx].sh_offset; | |
150 strings_ = reinterpret_cast<char *>(&data_.raw_[ offset ]); | |
151 break; | |
152 } | |
153 | |
154 // Unknown class | |
155 default: | |
156 goto failed; | |
157 } | |
158 | |
159 fclose(fp); | |
160 return true; | |
161 | |
162 failed: | |
163 Unload(); | |
164 fclose(fp); | |
165 } | |
166 | |
167 return false; | |
168 } | |
169 | |
170 ElfObject::ClassSize ElfObject::GetClassSize() const { | |
171 if (data_.def_) | |
172 return static_cast<ElfObject::ClassSize>(data_.def_->e_class); | |
173 | |
174 return ELFCLASSERR; | |
175 } | |
176 | |
177 ElfObject::Encoding ElfObject::GetEncoding() const { | |
178 if (data_.def_) | |
179 return static_cast<ElfObject::Encoding>(data_.def_->e_encoding); | |
180 | |
181 return ELFDATAERR; | |
182 } | |
183 | |
184 ElfObject::ObjectType ElfObject::GetObjectType() const { | |
185 if (data_.def_) | |
186 return static_cast<ElfObject::ObjectType>(data_.def_->e_type); | |
187 | |
188 return ET_NONE; | |
189 } | |
190 | |
191 | |
192 const char * ElfObject::GetPath() const { | |
193 return path_; | |
194 } | |
195 | |
196 const uint8_t *ElfObject::GetData() const { | |
197 return data_.raw_; | |
198 } | |
199 | |
200 uint16_t ElfObject::GetProgramHeaderCount() const { | |
201 if (obj_) { | |
202 return obj_->e_phnum; | |
203 } | |
204 | |
205 return 0; | |
206 } | |
207 | |
208 uint16_t ElfObject::GetSectionHeaderCount() const { | |
209 if (obj_) { | |
210 return obj_->e_shnum; | |
211 } | |
212 | |
213 return 0; | |
214 } | |
215 | |
216 void ElfObject::Parse(IElfReader* reader) const { | |
217 if (NULL == reader) | |
218 return; | |
219 | |
220 bool lsb = GetEncoding() == ELFDATA2LSB; | |
221 reader->Header(path_, data_.raw_, length_, GetClassSize(), lsb); | |
222 | |
223 if (reader->SectionHeadersStart(GetSectionHeaderCount())) { | |
224 // NOTE: Section index 0, 0xFF00-0xFFFF are special, so we | |
225 // skip '0' since it is invalid and zero filled. | |
226 uint32_t a; | |
227 for (a = 1; a < GetSectionHeaderCount(); a++) { | |
228 const char *path; | |
229 uint32_t type; | |
230 uint32_t flags; | |
231 void* start; | |
232 uint64_t length; | |
233 uint64_t virt; | |
234 | |
235 switch (GetClassSize()) { | |
236 case ELFCLASS32: { | |
237 ElfShdr32 *sec = &shdr_.shdr32_[a]; | |
238 path = &strings_[sec->sh_name]; | |
239 flags = sec->sh_flags; | |
240 length= sec->sh_size; | |
241 start = &data_.raw_[sec->sh_offset]; | |
242 type = sec->sh_type; | |
243 virt = sec->sh_addr; | |
244 break; | |
245 } | |
246 | |
247 case ELFCLASS64: { | |
248 ElfShdr64 *sec = &shdr_.shdr64_[a]; | |
249 path = &strings_[sec->sh_name]; | |
250 flags = static_cast<uint32_t>(sec->sh_flags); | |
251 length= sec->sh_size; | |
252 start = &data_.raw_[sec->sh_offset]; | |
253 type = sec->sh_type; | |
254 virt = sec->sh_addr; | |
255 break; | |
256 } | |
257 | |
258 // This is actually unreachible since we verified the class on load. | |
259 default: | |
260 continue; | |
261 } | |
262 reader->SectionHeader(path, start, virt, type, flags, length); | |
263 } | |
264 reader->SectionHeadersEnd(); | |
265 } | |
266 | |
267 if (reader->ProgramHeadersStart(GetProgramHeaderCount())) { | |
268 uint32_t a; | |
269 for (a = 0; a < GetProgramHeaderCount(); a++) { | |
270 uint32_t type; | |
271 uint32_t flags; | |
272 uint64_t offset; | |
273 uint64_t vaddr; | |
274 uint64_t fsize; | |
275 uint64_t msize; | |
276 | |
277 switch (GetClassSize()) { | |
278 case ELFCLASS32: { | |
279 ElfPhdr32 *prg = &phdr_.phdr32_[a]; | |
280 type = prg->p_type; | |
281 flags = prg->p_flags; | |
282 offset = prg->p_offset; | |
283 vaddr = prg->p_vaddr; | |
284 fsize = prg->p_filesz; | |
285 msize = prg->p_memsz; | |
286 break; | |
287 } | |
288 | |
289 case ELFCLASS64: { | |
290 ElfPhdr64 *prg = &phdr_.phdr64_[a]; | |
291 type = prg->p_type; | |
292 flags = prg->p_flags; | |
293 offset = prg->p_offset; | |
294 vaddr = prg->p_vaddr; | |
295 fsize = prg->p_filesz; | |
296 msize = prg->p_memsz; | |
297 break; | |
298 } | |
299 | |
300 // This is actually unreachible since we verified the class on load. | |
301 default: | |
302 continue; | |
303 } | |
304 reader->ProgramHeader(type, flags, offset, vaddr, fsize, msize); | |
305 } | |
306 reader->ProgramHeadersEnd(); | |
307 } | |
308 } | |
309 | |
310 } // namespace elf_reader | |
311 | |
OLD | NEW |