HaikuDepot: notify work status from main window
[haiku.git] / src / tools / elfsymbolpatcher / ElfFile.cpp
blob7c9f7e10b11031e73b147eb41a4d66eae9ad55bb
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:
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
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.
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 //------------------------------------------------------------------------------
30 #include <new>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
35 #include "ElfFile.h"
37 // sanity bounds
38 static const uint32 kMaxELFHeaderSize = sizeof(Elf32_Ehdr) + 32;
40 // read_exactly
41 static
42 status_t
43 read_exactly(BPositionIO &file, off_t position, void *buffer, size_t size,
44 const char *errorMessage = NULL)
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;
58 // ElfSection
60 class SymbolPatcher::ElfSection {
61 public:
62 ElfSection();
63 ~ElfSection();
65 void SetTo(ElfFile* file, Elf32_Shdr* header);
66 void Unset();
67 bool IsInitialized() const { return fHeader; }
69 ElfFile* GetFile() const;
70 Elf32_Shdr* GetHeader() const { return fHeader; }
71 const char* GetName() const;
72 uint8* GetData() const { return fData; }
73 size_t GetSize() const;
74 Elf32_Word GetType() const;
75 Elf32_Word GetLink() const;
76 Elf32_Word GetInfo() const;
77 size_t GetEntrySize() const;
78 int32 CountEntries() const;
80 status_t Load();
81 void Unload();
83 void Dump();
85 private:
86 ElfFile* fFile;
87 Elf32_Shdr* fHeader;
88 uint8* fData;
91 // constructor
92 ElfSection::ElfSection()
93 : fFile(NULL),
94 fHeader(NULL),
95 fData(NULL)
99 // destructor
100 ElfSection::~ElfSection()
102 Unset();
105 // SetTo
106 void
107 ElfSection::SetTo(ElfFile* file, Elf32_Shdr* header)
109 Unset();
110 fFile = file;
111 fHeader = header;
114 // Unset
115 void
116 ElfSection::Unset()
118 Unload();
119 fFile = NULL;
120 fHeader = NULL;
123 // GetFile
124 ElfFile*
125 ElfSection::GetFile() const
127 return fFile;
130 // GetName
131 const char*
132 ElfSection::GetName() const
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;
141 return name;
144 // GetSize
145 size_t
146 ElfSection::GetSize() const
148 return fHeader->sh_size;
151 // GetType
152 Elf32_Word
153 ElfSection::GetType() const
155 return fHeader->sh_type;
158 // GetLink
159 Elf32_Word
160 ElfSection::GetLink() const
162 return fHeader->sh_link;
165 // GetInfo
166 Elf32_Word
167 ElfSection::GetInfo() const
169 return fHeader->sh_info;
172 // GetEntrySize
173 size_t
174 ElfSection::GetEntrySize() const
176 return fHeader->sh_entsize;
179 // CountEntries
180 int32
181 ElfSection::CountEntries() const
183 int32 count = 0;
184 if (fHeader) {
185 if (GetEntrySize() == 0)
186 return 0;
187 count = GetSize() / GetEntrySize();
189 return count;
192 // Load
193 status_t
194 ElfSection::Load()
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();
210 return error;
213 // Unload
214 void
215 ElfSection::Unload()
217 if (fData) {
218 delete[] fData;
219 fData = NULL;
223 // Dump
224 void
225 ElfSection::Dump()
227 printf("section %32s: size: %lu\n", GetName(), GetSize());
231 // ElfSymbol
233 // constructor
234 ElfSymbol::ElfSymbol(ElfSection* section, int32 index)
235 : fSection(section),
236 fIndex(index),
237 fSymbol(NULL)
241 // destructor
242 ElfSymbol::~ElfSymbol()
244 Unset();
247 // SetTo
248 void
249 ElfSymbol::SetTo(ElfSection* section, int32 index)
251 Unset();
252 fSection = section;
253 fIndex = index;
256 // Unset
257 void
258 ElfSymbol::Unset()
260 fSection = NULL;
261 fIndex = -1;
262 fSymbol = NULL;
265 // GetSymbolStruct
266 const Elf32_Sym*
267 ElfSymbol::GetSymbolStruct()
269 Elf32_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 = (Elf32_Sym*)(fSection->GetData() + fIndex * symbolSize);
278 return symbol;
281 // GetName
282 const char*
283 ElfSymbol::GetName()
285 const char* name = NULL;
286 if (const Elf32_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;
293 return name;
296 // GetBinding
297 uint32
298 ElfSymbol::GetBinding()
300 uint32 binding = STB_LOCAL;
301 if (const Elf32_Sym* symbol = GetSymbolStruct())
302 binding = ELF32_ST_BIND(symbol->st_info);
303 return binding;
306 // GetType
307 uint32
308 ElfSymbol::GetType()
310 uint32 type = STT_NOTYPE;
311 if (const Elf32_Sym* symbol = GetSymbolStruct())
312 type = ELF32_ST_TYPE(symbol->st_info);
313 return type;
316 // GetTargetSectionIndex
317 uint32
318 ElfSymbol::GetTargetSectionIndex()
320 uint32 index = SHN_UNDEF;
321 if (const Elf32_Sym* symbol = GetSymbolStruct())
322 index = symbol->st_shndx;
323 return index;
327 // ElfRelocation
329 // constructor
330 ElfRelocation::ElfRelocation(ElfSection* section, int32 index)
331 : fSection(section),
332 fIndex(index),
333 fRelocation(NULL)
337 // destructor
338 ElfRelocation::~ElfRelocation()
340 Unset();
343 // SetTo
344 void
345 ElfRelocation::SetTo(ElfSection* section, int32 index)
347 Unset();
348 fSection = section;
349 fIndex = index;
352 // Unset
353 void
354 ElfRelocation::Unset()
356 fSection = NULL;
357 fIndex = -1;
358 fRelocation = NULL;
361 // GetRelocationStruct
362 Elf32_Rel*
363 ElfRelocation::GetRelocationStruct()
365 Elf32_Rel* relocation = fRelocation;
366 if (!relocation && fSection) {
367 if (!fSection->GetData()) {
368 if (fSection->Load() != B_OK)
369 return NULL;
371 size_t entrySize = fSection->GetEntrySize();
372 if (entrySize == 0 || entrySize < sizeof(Elf32_Rel))
373 return NULL;
374 int32 entryCount = fSection->GetSize() / entrySize;
375 if (fIndex >= 0 && fIndex < entryCount) {
376 relocation = (Elf32_Rel*)(fSection->GetData()
377 + fIndex * entrySize);
380 return relocation;
383 // GetType
384 uint32
385 ElfRelocation::GetType()
387 uint32 type = R_386_NONE;
388 if (Elf32_Rel* relocation = GetRelocationStruct())
389 type = ELF32_R_TYPE(relocation->r_info);
390 return type;
393 // GetSymbolIndex
394 uint32
395 ElfRelocation::GetSymbolIndex()
397 uint32 index = 0;
398 if (Elf32_Rel* relocation = GetRelocationStruct())
399 index = ELF32_R_SYM(relocation->r_info);
400 return index;
403 // GetOffset
404 Elf32_Addr
405 ElfRelocation::GetOffset()
407 Elf32_Addr offset = 0;
408 if (Elf32_Rel* relocation = GetRelocationStruct())
409 offset = relocation->r_offset;
410 return offset;
413 // GetSymbol
414 status_t
415 ElfRelocation::GetSymbol(ElfSymbol* symbol)
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;
427 return error;
431 // ElfRelocationIterator
433 // constructor
434 ElfRelocationIterator::ElfRelocationIterator(ElfFile* file)
435 : fFile(file),
436 fSectionIndex(-1),
437 fEntryIndex(-1)
441 // destructor
442 ElfRelocationIterator::~ElfRelocationIterator()
446 // GetNext
447 bool
448 ElfRelocationIterator::GetNext(ElfRelocation* relocation)
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);
462 // find next valid entry
463 while (section && fEntryIndex >= section->CountEntries()) {
464 fSectionIndex++;
465 section = _FindNextSection();
466 fEntryIndex = 0;
468 // set result
469 if (section) {
470 relocation->SetTo(section, fEntryIndex);
471 result = true;
474 return result;
477 // _FindNextSection
478 ElfSection*
479 ElfRelocationIterator::_FindNextSection()
481 if (fFile) {
482 for (; fSectionIndex < fFile->CountSections(); fSectionIndex++) {
483 ElfSection* section = fFile->SectionAt(fSectionIndex);
484 if (section && section->GetType() == SHT_REL)
485 return section;
488 return NULL;
492 // ElfFile
494 // constructor
495 ElfFile::ElfFile()
496 : fFile(),
497 fSectionHeaders(NULL),
498 fSections(NULL),
499 fSectionCount(0),
500 fSectionHeaderSize(0)
504 // destructor
505 ElfFile::~ElfFile()
507 Unset();
510 // SetTo
511 status_t
512 ElfFile::SetTo(const char *filename)
514 Unset();
515 status_t error = _SetTo(filename);
516 if (error)
517 Unset();
518 return error;
521 // Unset
522 void
523 ElfFile::Unset()
525 // delete sections
526 if (fSections) {
527 delete[] fSections;
528 fSections = NULL;
530 // delete section headers
531 if (fSectionHeaders) {
532 delete[] fSectionHeaders;
533 fSectionHeaders = NULL;
535 fSectionCount = 0;
536 fSectionHeaderSize = 0;
537 fFile.Unset();
540 // Unload
541 void
542 ElfFile::Unload()
544 for (int i = 0; i < fSectionCount; i++)
545 fSections[i].Unload();
548 // GetSectionHeaderStrings
549 const char*
550 ElfFile::GetSectionHeaderStrings(size_t* size)
552 return GetStringSectionStrings(fHeader.e_shstrndx, size);
555 // GetStringSectionStrings
556 const char*
557 ElfFile::GetStringSectionStrings(int32 index, size_t* _size)
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);
565 // set results
566 if (_size)
567 *_size = size;
568 return data;
571 // SectionAt
572 ElfSection*
573 ElfFile::SectionAt(int32 index, bool load)
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 %ld\n", index);
585 return section;
588 // Dump
589 void
590 ElfFile::Dump()
592 printf("%ld sections\n", fSectionCount);
593 for (int i = 0; i < fSectionCount; i++)
594 fSections[i].Dump();
597 // _SetTo
598 status_t
599 ElfFile::_SetTo(const char *filename)
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;
612 // read ELF header
613 error = read_exactly(fFile, 0, &fHeader, sizeof(Elf32_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;
626 // class
627 if (fHeader.e_ident[EI_CLASS] != ELFCLASS32) {
628 printf("Wrong ELF class!\n");
629 return B_BAD_VALUE;
631 // check data encoding (endianess)
632 if (fHeader.e_ident[EI_DATA] != ELFDATA2LSB) {
633 printf("Wrong data encoding!\n");
634 return B_BAD_VALUE;
636 // version
637 if (fHeader.e_ident[EI_VERSION] != EV_CURRENT) {
638 printf("Wrong data encoding!\n");
639 return B_BAD_VALUE;
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(Elf32_Ehdr) || headerSize > kMaxELFHeaderSize) {
649 printf("Invalid ELF header: invalid ELF header size: %lu.",
650 headerSize);
651 return B_BAD_VALUE;
653 // section header table offset
654 if (sectionHeaderTableOffset == 0) {
655 printf("ELF file has no section header table!\n");
656 return B_BAD_VALUE;
658 uint32 sectionHeaderTableSize = 0;
659 if (sectionHeaderTableOffset < headerSize
660 || sectionHeaderTableOffset > fileSize) {
661 printf("Invalid ELF header: invalid section header table offset: %lu.",
662 sectionHeaderTableOffset);
663 return B_BAD_VALUE;
665 // section header table offset
666 sectionHeaderTableSize = sectionHeaderSize * sectionHeaderCount;
667 if (sectionHeaderSize < sizeof(Elf32_Shdr)
668 || sectionHeaderTableOffset + sectionHeaderTableSize > fileSize) {
669 printf("Invalid ELF header: section header table exceeds file: %lu.",
670 sectionHeaderTableOffset + sectionHeaderTableSize);
671 return B_BAD_VALUE;
673 // allocate memory for the section header table and read it
674 fSectionHeaders = new(std::nothrow) uint8[sectionHeaderTableSize];
675 fSectionCount = sectionHeaderCount;
676 fSectionHeaderSize = sectionHeaderSize;
677 if (!fSectionHeaders)
678 return B_NO_MEMORY;
679 error = read_exactly(fFile, sectionHeaderTableOffset, fSectionHeaders,
680 sectionHeaderTableSize,
681 "Failed to read section headers!\n");
682 if (error != B_OK)
683 return error;
684 // allocate memory for the section pointers
685 fSections = new(std::nothrow) ElfSection[fSectionCount];
686 if (!fSections)
687 return B_NO_MEMORY;
688 // init the sections
689 for (int i = 0; i < fSectionCount; i++)
690 fSections[i].SetTo(this, _SectionHeaderAt(i));
691 return error;
694 // _SectionHeaderAt
695 Elf32_Shdr*
696 ElfFile::_SectionHeaderAt(int32 index)
698 Elf32_Shdr* header = NULL;
699 if (fSectionHeaders && index >= 0 && index < fSectionCount)
700 header = (Elf32_Shdr*)(fSectionHeaders + index * fSectionHeaderSize);
701 return header;
704 // _LoadSection
705 status_t
706 ElfFile::_LoadSection(int32 index)
708 status_t error = B_OK;
709 if (fSections && index >= 0 && index < fSectionCount) {
710 ElfSection& section = fSections[index];
711 error = section.Load();
712 } else
713 error = B_BAD_VALUE;
714 return error;