1 // ElfFile.cpp
2 //------------------------------------------------------------------------------
3 // Copyright (c) 2003, Ingo Weinhold
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a
6 // copy of this software and associated documentation files (the "Software"),
7 // to deal in the Software without restriction, including without limitation
8 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 // and/or sell copies of the Software, and to permit persons to whom the
10 // Software is furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 // DEALINGS IN THE SOFTWARE.
22 //
23 // File Name: ElfFile.cpp
24 // Author: Ingo Weinhold (bonefish@users.sf.net)
25 // Description: Implementation of classes for accessing ELF file,
26 // or more precisely for iterating through their relocation
27 // sections.
28 //------------------------------------------------------------------------------
29
30 #include <new>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include "ElfFile.h"
36
37 // sanity bounds
38 static const uint32 kMaxELFHeaderSize = sizeof(Elf_Ehdr) + 32;
39
40 // read_exactly
41 static
42 status_t
read_exactly(BPositionIO & file,off_t position,void * buffer,size_t size,const char * errorMessage=NULL)43 read_exactly(BPositionIO &file, off_t position, void *buffer, size_t size,
44 const char *errorMessage = NULL)
45 {
46 status_t error = B_OK;
47 ssize_t read = file.ReadAt(position, buffer, size);
48 if (read < 0)
49 error = read;
50 else if ((size_t)read != size)
51 error = B_ERROR;
52 if (error != B_OK && errorMessage)
53 puts(errorMessage);
54 return error;
55 }
56
57
58 // ElfSection
59
60 class SymbolPatcher::ElfSection {
61 public:
62 ElfSection();
63 ~ElfSection();
64
65 void SetTo(ElfFile* file, Elf_Shdr* header);
66 void Unset();
IsInitialized() const67 bool IsInitialized() const { return fHeader; }
68
69 ElfFile* GetFile() const;
GetHeader() const70 Elf_Shdr* GetHeader() const { return fHeader; }
71 const char* GetName() const;
GetData() const72 uint8* GetData() const { return fData; }
73 size_t GetSize() const;
74 Elf_Word GetType() const;
75 Elf_Word GetLink() const;
76 Elf_Word GetInfo() const;
77 size_t GetEntrySize() const;
78 int32 CountEntries() const;
79
80 status_t Load();
81 void Unload();
82
83 void Dump();
84
85 private:
86 ElfFile* fFile;
87 Elf_Shdr* fHeader;
88 uint8* fData;
89 };
90
91 // constructor
ElfSection()92 ElfSection::ElfSection()
93 : fFile(NULL),
94 fHeader(NULL),
95 fData(NULL)
96 {
97 }
98
99 // destructor
~ElfSection()100 ElfSection::~ElfSection()
101 {
102 Unset();
103 }
104
105 // SetTo
106 void
SetTo(ElfFile * file,Elf_Shdr * header)107 ElfSection::SetTo(ElfFile* file, Elf_Shdr* header)
108 {
109 Unset();
110 fFile = file;
111 fHeader = header;
112 }
113
114 // Unset
115 void
Unset()116 ElfSection::Unset()
117 {
118 Unload();
119 fFile = NULL;
120 fHeader = NULL;
121 }
122
123 // GetFile
124 ElfFile*
GetFile() const125 ElfSection::GetFile() const
126 {
127 return fFile;
128 }
129
130 // GetName
131 const char*
GetName() const132 ElfSection::GetName() const
133 {
134 const char* name = NULL;
135 if (fHeader && fFile) {
136 size_t size = 0;
137 const char* nameSection = fFile->GetSectionHeaderStrings(&size);
138 if (nameSection && fHeader->sh_name < size)
139 name = nameSection + fHeader->sh_name;
140 }
141 return name;
142 }
143
144 // GetSize
145 size_t
GetSize() const146 ElfSection::GetSize() const
147 {
148 return fHeader->sh_size;
149 }
150
151 // GetType
152 Elf_Word
GetType() const153 ElfSection::GetType() const
154 {
155 return fHeader->sh_type;
156 }
157
158 // GetLink
159 Elf_Word
GetLink() const160 ElfSection::GetLink() const
161 {
162 return fHeader->sh_link;
163 }
164
165 // GetInfo
166 Elf_Word
GetInfo() const167 ElfSection::GetInfo() const
168 {
169 return fHeader->sh_info;
170 }
171
172 // GetEntrySize
173 size_t
GetEntrySize() const174 ElfSection::GetEntrySize() const
175 {
176 return fHeader->sh_entsize;
177 }
178
179 // CountEntries
180 int32
CountEntries() const181 ElfSection::CountEntries() const
182 {
183 int32 count = 0;
184 if (fHeader) {
185 if (GetEntrySize() == 0)
186 return 0;
187 count = GetSize() / GetEntrySize();
188 }
189 return count;
190 }
191
192 // Load
193 status_t
Load()194 ElfSection::Load()
195 {
196 status_t error = B_ERROR;
197 if (fHeader && !fData && fHeader->sh_type != SHT_NULL
198 && fHeader->sh_type != SHT_NOBITS) {
199 BFile* file = fFile->GetFile();
200 // allocate memory
201 fData = new uint8[fHeader->sh_size];
202 if (!fData)
203 return B_NO_MEMORY;
204 // read the data
205 error = read_exactly(*file, fHeader->sh_offset, fData,
206 fHeader->sh_size, "Failed to read section!\n");
207 if (error != B_OK)
208 Unload();
209 }
210 return error;
211 }
212
213 // Unload
214 void
Unload()215 ElfSection::Unload()
216 {
217 if (fData) {
218 delete[] fData;
219 fData = NULL;
220 }
221 }
222
223 // Dump
224 void
Dump()225 ElfSection::Dump()
226 {
227 printf("section %32s: size: %lu\n", GetName(), GetSize());
228 }
229
230
231 // ElfSymbol
232
233 // constructor
ElfSymbol(ElfSection * section,int32 index)234 ElfSymbol::ElfSymbol(ElfSection* section, int32 index)
235 : fSection(section),
236 fIndex(index),
237 fSymbol(NULL)
238 {
239 }
240
241 // destructor
~ElfSymbol()242 ElfSymbol::~ElfSymbol()
243 {
244 Unset();
245 }
246
247 // SetTo
248 void
SetTo(ElfSection * section,int32 index)249 ElfSymbol::SetTo(ElfSection* section, int32 index)
250 {
251 Unset();
252 fSection = section;
253 fIndex = index;
254 }
255
256 // Unset
257 void
Unset()258 ElfSymbol::Unset()
259 {
260 fSection = NULL;
261 fIndex = -1;
262 fSymbol = NULL;
263 }
264
265 // GetSymbolStruct
266 const Elf_Sym*
GetSymbolStruct()267 ElfSymbol::GetSymbolStruct()
268 {
269 Elf_Sym* symbol = fSymbol;
270 if (!symbol && fSection && fSection->GetData()) {
271 size_t symbolSize = fSection->GetEntrySize();
272 if (symbolSize == 0)
273 return NULL;
274 int32 symbolCount = fSection->GetSize() / symbolSize;
275 if (fIndex >= 0 && fIndex < symbolCount)
276 symbol = (Elf_Sym*)(fSection->GetData() + fIndex * symbolSize);
277 }
278 return symbol;
279 }
280
281 // GetName
282 const char*
GetName()283 ElfSymbol::GetName()
284 {
285 const char* name = NULL;
286 if (const Elf_Sym* symbol = GetSymbolStruct()) {
287 size_t size = 0;
288 const char* data = fSection->GetFile()->GetStringSectionStrings(
289 fSection->GetLink(), &size);
290 if (data && symbol->st_name < size)
291 name = data + symbol->st_name;
292 }
293 return name;
294 }
295
296 // GetBinding
297 uint32
GetBinding()298 ElfSymbol::GetBinding()
299 {
300 uint32 binding = STB_LOCAL;
301 if (const Elf_Sym* symbol = GetSymbolStruct())
302 binding = ELF_ST_BIND(symbol->st_info);
303 return binding;
304 }
305
306 // GetType
307 uint32
GetType()308 ElfSymbol::GetType()
309 {
310 uint32 type = STT_NOTYPE;
311 if (const Elf_Sym* symbol = GetSymbolStruct())
312 type = ELF_ST_TYPE(symbol->st_info);
313 return type;
314 }
315
316 // GetTargetSectionIndex
317 uint32
GetTargetSectionIndex()318 ElfSymbol::GetTargetSectionIndex()
319 {
320 uint32 index = SHN_UNDEF;
321 if (const Elf_Sym* symbol = GetSymbolStruct())
322 index = symbol->st_shndx;
323 return index;
324 }
325
326
327 // ElfRelocation
328
329 // constructor
ElfRelocation(ElfSection * section,int32 index)330 ElfRelocation::ElfRelocation(ElfSection* section, int32 index)
331 : fSection(section),
332 fIndex(index),
333 fRelocation(NULL)
334 {
335 }
336
337 // destructor
~ElfRelocation()338 ElfRelocation::~ElfRelocation()
339 {
340 Unset();
341 }
342
343 // SetTo
344 void
SetTo(ElfSection * section,int32 index)345 ElfRelocation::SetTo(ElfSection* section, int32 index)
346 {
347 Unset();
348 fSection = section;
349 fIndex = index;
350 }
351
352 // Unset
353 void
Unset()354 ElfRelocation::Unset()
355 {
356 fSection = NULL;
357 fIndex = -1;
358 fRelocation = NULL;
359 }
360
361 // GetRelocationStruct
362 Elf_Rel*
GetRelocationStruct()363 ElfRelocation::GetRelocationStruct()
364 {
365 Elf_Rel* relocation = fRelocation;
366 if (!relocation && fSection) {
367 if (!fSection->GetData()) {
368 if (fSection->Load() != B_OK)
369 return NULL;
370 }
371 size_t entrySize = fSection->GetEntrySize();
372 if (entrySize == 0 || entrySize < sizeof(Elf_Rel))
373 return NULL;
374 int32 entryCount = fSection->GetSize() / entrySize;
375 if (fIndex >= 0 && fIndex < entryCount) {
376 relocation = (Elf_Rel*)(fSection->GetData()
377 + fIndex * entrySize);
378 }
379 }
380 return relocation;
381 }
382
383 // GetType
384 uint32
GetType()385 ElfRelocation::GetType()
386 {
387 uint32 type = R_NONE;
388 if (Elf_Rel* relocation = GetRelocationStruct())
389 type = ELF_R_TYPE(relocation->r_info);
390 return type;
391 }
392
393 // GetSymbolIndex
394 uint32
GetSymbolIndex()395 ElfRelocation::GetSymbolIndex()
396 {
397 uint32 index = 0;
398 if (Elf_Rel* relocation = GetRelocationStruct())
399 index = ELF_R_SYM(relocation->r_info);
400 return index;
401 }
402
403 // GetOffset
404 Elf_Addr
GetOffset()405 ElfRelocation::GetOffset()
406 {
407 Elf_Addr offset = 0;
408 if (Elf_Rel* relocation = GetRelocationStruct())
409 offset = relocation->r_offset;
410 return offset;
411 }
412
413 // GetSymbol
414 status_t
GetSymbol(ElfSymbol * symbol)415 ElfRelocation::GetSymbol(ElfSymbol* symbol)
416 {
417 status_t error = B_BAD_VALUE;
418 if (symbol && fSection) {
419 uint32 index = GetSymbolIndex();
420 if (ElfSection* symbols
421 = fSection->GetFile()->SectionAt(fSection->GetLink(), true)) {
422 symbol->SetTo(symbols, index);
423 if (symbol->GetSymbolStruct())
424 error = B_OK;
425 }
426 }
427 return error;
428 }
429
430
431 // ElfRelocationIterator
432
433 // constructor
ElfRelocationIterator(ElfFile * file)434 ElfRelocationIterator::ElfRelocationIterator(ElfFile* file)
435 : fFile(file),
436 fSectionIndex(-1),
437 fEntryIndex(-1)
438 {
439 }
440
441 // destructor
~ElfRelocationIterator()442 ElfRelocationIterator::~ElfRelocationIterator()
443 {
444 }
445
446 // GetNext
447 bool
GetNext(ElfRelocation * relocation)448 ElfRelocationIterator::GetNext(ElfRelocation* relocation)
449 {
450 bool result = false;
451 if (fFile && relocation) {
452 // set to possible entry
453 ElfSection* section = NULL;
454 if (fSectionIndex < 0) {
455 fSectionIndex = 0;
456 fEntryIndex = 0;
457 section = _FindNextSection();
458 } else {
459 fEntryIndex++;
460 section = fFile->SectionAt(fSectionIndex);
461 }
462 // find next valid entry
463 while (section && fEntryIndex >= section->CountEntries()) {
464 fSectionIndex++;
465 section = _FindNextSection();
466 fEntryIndex = 0;
467 }
468 // set result
469 if (section) {
470 relocation->SetTo(section, fEntryIndex);
471 result = true;
472 }
473 }
474 return result;
475 }
476
477 // _FindNextSection
478 ElfSection*
_FindNextSection()479 ElfRelocationIterator::_FindNextSection()
480 {
481 if (fFile) {
482 for (; fSectionIndex < fFile->CountSections(); fSectionIndex++) {
483 ElfSection* section = fFile->SectionAt(fSectionIndex);
484 if (section && (section->GetType() == SHT_REL || section->GetType() == SHT_RELA))
485 return section;
486 }
487 }
488 return NULL;
489 }
490
491
492 // ElfFile
493
494 // constructor
ElfFile()495 ElfFile::ElfFile()
496 : fFile(),
497 fSectionHeaders(NULL),
498 fSections(NULL),
499 fSectionCount(0),
500 fSectionHeaderSize(0)
501 {
502 }
503
504 // destructor
~ElfFile()505 ElfFile::~ElfFile()
506 {
507 Unset();
508 }
509
510 // SetTo
511 status_t
SetTo(const char * filename)512 ElfFile::SetTo(const char *filename)
513 {
514 Unset();
515 status_t error = _SetTo(filename);
516 if (error)
517 Unset();
518 return error;
519 }
520
521 // Unset
522 void
Unset()523 ElfFile::Unset()
524 {
525 // delete sections
526 if (fSections) {
527 delete[] fSections;
528 fSections = NULL;
529 }
530 // delete section headers
531 if (fSectionHeaders) {
532 delete[] fSectionHeaders;
533 fSectionHeaders = NULL;
534 }
535 fSectionCount = 0;
536 fSectionHeaderSize = 0;
537 fFile.Unset();
538 }
539
540 // Unload
541 void
Unload()542 ElfFile::Unload()
543 {
544 for (int i = 0; i < fSectionCount; i++)
545 fSections[i].Unload();
546 }
547
548 // GetSectionHeaderStrings
549 const char*
GetSectionHeaderStrings(size_t * size)550 ElfFile::GetSectionHeaderStrings(size_t* size)
551 {
552 return GetStringSectionStrings(fHeader.e_shstrndx, size);
553 }
554
555 // GetStringSectionStrings
556 const char*
GetStringSectionStrings(int32 index,size_t * _size)557 ElfFile::GetStringSectionStrings(int32 index, size_t* _size)
558 {
559 const char* data = NULL;
560 size_t size = 0;
561 if (ElfSection* section = SectionAt(index, true)) {
562 data = (const char*)section->GetData();
563 size = (data ? section->GetSize() : 0);
564 }
565 // set results
566 if (_size)
567 *_size = size;
568 return data;
569 }
570
571 // SectionAt
572 ElfSection*
SectionAt(int32 index,bool load)573 ElfFile::SectionAt(int32 index, bool load)
574 {
575 ElfSection* section = NULL;
576 if (fSections && index >= 0 && index < fSectionCount) {
577 section = fSections + index;
578 if (load && !section->GetData()) {
579 if (section->Load() != B_OK) {
580 section = NULL;
581 printf("Failed to load section %" B_PRId32 "\n", index);
582 }
583 }
584 }
585 return section;
586 }
587
588 // Dump
589 void
Dump()590 ElfFile::Dump()
591 {
592 printf("%" B_PRId32 " sections\n", fSectionCount);
593 for (int i = 0; i < fSectionCount; i++)
594 fSections[i].Dump();
595 }
596
597 // _SetTo
598 status_t
_SetTo(const char * filename)599 ElfFile::_SetTo(const char *filename)
600 {
601 if (!filename)
602 return B_BAD_VALUE;
603 // open file
604 status_t error = fFile.SetTo(filename, B_READ_ONLY);
605 // get the file size
606 off_t fileSize = 0;
607 error = fFile.GetSize(&fileSize);
608 if (error != B_OK) {
609 printf("Failed to get file size!\n");
610 return error;
611 }
612 // read ELF header
613 error = read_exactly(fFile, 0, &fHeader, sizeof(Elf_Ehdr),
614 "Failed to read ELF object header!\n");
615 if (error != B_OK)
616 return error;
617 // check the ident field
618 // magic
619 if (fHeader.e_ident[EI_MAG0] != ELFMAG0
620 || fHeader.e_ident[EI_MAG1] != ELFMAG1
621 || fHeader.e_ident[EI_MAG2] != ELFMAG2
622 || fHeader.e_ident[EI_MAG3] != ELFMAG3) {
623 printf("Bad ELF file magic!\n");
624 return B_BAD_VALUE;
625 }
626 // class
627 if (fHeader.e_ident[EI_CLASS] != ELFCLASS) {
628 printf("Wrong ELF class!\n");
629 return B_BAD_VALUE;
630 }
631 // check data encoding (endianess)
632 if (fHeader.e_ident[EI_DATA] != ELFDATA2LSB) {
633 printf("Wrong data encoding!\n");
634 return B_BAD_VALUE;
635 }
636 // version
637 if (fHeader.e_ident[EI_VERSION] != EV_CURRENT) {
638 printf("Wrong data encoding!\n");
639 return B_BAD_VALUE;
640 }
641 // get the header values
642 uint32 headerSize = fHeader.e_ehsize;
643 uint32 sectionHeaderTableOffset = fHeader.e_shoff;
644 uint32 sectionHeaderSize = fHeader.e_shentsize;
645 uint32 sectionHeaderCount = fHeader.e_shnum;
646 // check the sanity of the header values
647 // ELF header size
648 if (headerSize < sizeof(Elf_Ehdr) || headerSize > kMaxELFHeaderSize) {
649 printf("Invalid ELF header: invalid ELF header size: %" B_PRIu32 ".", headerSize);
650 return B_BAD_VALUE;
651 }
652 // section header table offset
653 if (sectionHeaderTableOffset == 0) {
654 printf("ELF file has no section header table!\n");
655 return B_BAD_VALUE;
656 }
657 uint32 sectionHeaderTableSize = 0;
658 if (sectionHeaderTableOffset < headerSize
659 || sectionHeaderTableOffset > fileSize) {
660 printf("Invalid ELF header: invalid section header table offset: %" B_PRIu32 ".",
661 sectionHeaderTableOffset);
662 return B_BAD_VALUE;
663 }
664 // section header table offset
665 sectionHeaderTableSize = sectionHeaderSize * sectionHeaderCount;
666 if (sectionHeaderSize < sizeof(Elf_Shdr)
667 || sectionHeaderTableOffset + sectionHeaderTableSize > fileSize) {
668 printf("Invalid ELF header: section header table exceeds file: %" B_PRIu32 ".",
669 sectionHeaderTableOffset + sectionHeaderTableSize);
670 return B_BAD_VALUE;
671 }
672 // allocate memory for the section header table and read it
673 fSectionHeaders = new(std::nothrow) uint8[sectionHeaderTableSize];
674 fSectionCount = sectionHeaderCount;
675 fSectionHeaderSize = sectionHeaderSize;
676 if (!fSectionHeaders)
677 return B_NO_MEMORY;
678 error = read_exactly(fFile, sectionHeaderTableOffset, fSectionHeaders,
679 sectionHeaderTableSize,
680 "Failed to read section headers!\n");
681 if (error != B_OK)
682 return error;
683 // allocate memory for the section pointers
684 fSections = new(std::nothrow) ElfSection[fSectionCount];
685 if (!fSections)
686 return B_NO_MEMORY;
687 // init the sections
688 for (int i = 0; i < fSectionCount; i++)
689 fSections[i].SetTo(this, _SectionHeaderAt(i));
690 return error;
691 }
692
693 // _SectionHeaderAt
694 Elf_Shdr*
_SectionHeaderAt(int32 index)695 ElfFile::_SectionHeaderAt(int32 index)
696 {
697 Elf_Shdr* header = NULL;
698 if (fSectionHeaders && index >= 0 && index < fSectionCount)
699 header = (Elf_Shdr*)(fSectionHeaders + index * fSectionHeaderSize);
700 return header;
701 }
702
703 // _LoadSection
704 status_t
_LoadSection(int32 index)705 ElfFile::_LoadSection(int32 index)
706 {
707 status_t error = B_OK;
708 if (fSections && index >= 0 && index < fSectionCount) {
709 ElfSection& section = fSections[index];
710 error = section.Load();
711 } else
712 error = B_BAD_VALUE;
713 return error;
714 }
715
716