diff --git a/headers/tools/elfsymbolpatcher/ElfSymbolPatcher.h b/headers/tools/elfsymbolpatcher/ElfSymbolPatcher.h new file mode 100644 index 0000000000..622470e9b0 --- /dev/null +++ b/headers/tools/elfsymbolpatcher/ElfSymbolPatcher.h @@ -0,0 +1,162 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2003, Ingo Weinhold +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: ElfSymbolPatcher.h +// Author: Ingo Weinhold (bonefish@users.sf.net) +// Description: Interface declaration of classes used for patching ELF +// symbols. Central class is ElfSymbolPatcher. It is a kind of +// roster, managing all necessary infos (loaded images) and +// being able to fill ElfSymbolPatchInfos with life. +// An ElfSymbolPatchInfo represents a symbol and is able to +// patch/restore it. An ElfSymbolPatchGroup bundles several +// ElfSymbolPatchInfos and can update their data, e.g. +// when images are loaded/unloaded. It uses a +// ElfSymbolPatcher internally and provides a more convenient +// API for the user. +//------------------------------------------------------------------------------ + +#ifndef ELF_SYMBOL_PATCHER_H +#define ELF_SYMBOL_PATCHER_H + +#include +#include + +class ElfImage; +class ElfSymbolPatcher; +class ElfSymbolPatchGroup; + +// ElfSymbolPatchInfo +class ElfSymbolPatchInfo { +public: + ElfSymbolPatchInfo(); + ~ElfSymbolPatchInfo(); + + status_t InitCheck() const; + + const char* GetSymbolName() const; + void* GetOriginalAddress() const; + image_id GetOriginalAddressImage() const; + + status_t Patch(void* newAddress); + status_t Restore(); + +private: + class Entry; + +private: + void Unset(); + status_t SetSymbolName(const char* name); + void SetOriginalAddress(void* address, + image_id image); + status_t CreateEntry(image_id image, BList* targets); + bool DeleteEntry(image_id image); + Entry* EntryAt(int32 index); + Entry* EntryFor(image_id image); + +private: + friend class ElfSymbolPatcher; + friend class ElfSymbolPatchGroup; + + BString fSymbolName; + void* fOriginalAddress; + image_id fOriginalAddressImage; + BList fEntries; +}; + +// ElfSymbolPatcher +class ElfSymbolPatcher { +public: + class UpdateAdapter; + +public: + ElfSymbolPatcher(); + ~ElfSymbolPatcher(); + + status_t InitCheck() const; + status_t Update(UpdateAdapter* updateAdapter = NULL); + void Unload(); + + status_t GetSymbolPatchInfo(const char* symbolName, + ElfSymbolPatchInfo* info); + status_t UpdateSymbolPatchInfo(ElfSymbolPatchInfo* info, + ElfImage* image); + +private: + status_t _Init(); + void _Cleanup(); + + ElfImage* _ImageAt(int32 index) const; + ElfImage* _ImageForID(image_id id) const; + +private: + BList fImages; + status_t fInitStatus; +}; + +// UpdateAdapter +class ElfSymbolPatcher::UpdateAdapter { +public: + UpdateAdapter(); + virtual ~UpdateAdapter(); + + virtual void ImageAdded(ElfImage* image); + virtual void ImageRemoved(ElfImage* image); +}; + + +// ElfSymbolPatchGroup +class ElfSymbolPatchGroup : private ElfSymbolPatcher::UpdateAdapter { +public: + ElfSymbolPatchGroup( + ElfSymbolPatcher* patcher = NULL); + ~ElfSymbolPatchGroup(); + + ElfSymbolPatcher* GetPatcher() const { return fPatcher; } + + status_t AddPatch(const char* symbolName, + void* newAddress, + void** originalAddress); + + void RemoveAllPatches(); + + status_t Patch(); + status_t Restore(); + + status_t Update(); + +private: + class PatchInfo : public ElfSymbolPatchInfo { + public: + void* fNewAddress; + }; + +private: + virtual void ImageAdded(ElfImage* image); + virtual void ImageRemoved(ElfImage* image); + +private: + ElfSymbolPatcher* fPatcher; + BList fPatchInfos; + bool fOwnsPatcher; + bool fPatched; +}; + +#endif // ELF_SYMBOL_PATCHER_H diff --git a/src/tools/elfsymbolpatcher/Elf.h b/src/tools/elfsymbolpatcher/Elf.h new file mode 100644 index 0000000000..67c01d8a96 --- /dev/null +++ b/src/tools/elfsymbolpatcher/Elf.h @@ -0,0 +1,192 @@ +// Elf.h + +#ifndef _ELF_H +#define _ELF_H + +// types +typedef uint32 Elf32_Addr; +typedef uint16 Elf32_Half; +typedef uint32 Elf32_Off; +typedef int32 Elf32_Sword; +typedef uint32 Elf32_Word; + +// e_ident indices +#define EI_MAG0 0 +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_PAD 7 +#define EI_NIDENT 16 + +// ELF magic +#define ELFMAG0 0x7f +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' + +// class +#define ELFCLASSNONE 0 +#define ELFCLASS32 1 +#define ELFCLASS64 2 + +// version +#define EV_NONE 0 +#define EV_CURRENT 1 + +// object file header +typedef struct { + unsigned char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +} Elf32_Ehdr; + +// e_ident EI_CLASS and EI_DATA values +#define ELFCLASSNONE 0 +#define ELFCLASS32 1 +#define ELFCLASS64 2 +#define ELFDATANONE 0 +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + +// special section header indices +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xff00 +#define SHN_LOPROC 0xff00 +#define SHN_HIPROC 0xff1f +#define SHN_ABS 0xfff1 +#define SHN_COMMON 0xfff2 +#define SHN_HIRESERVE 0xffff + +// program header +typedef struct { + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +} Elf32_Phdr; + +// p_type +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDIR 6 +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7fffffff + +// section header +typedef struct { + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +} Elf32_Shdr; + +// sh_type values +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7fffffff +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0xffffffff + +// relocation entry +typedef struct { + Elf32_Addr r_offset; + Elf32_Word r_info; +} Elf32_Rel; + +// relocation entry with addend +typedef struct { + Elf32_Addr r_offset; + Elf32_Word r_info; + Elf32_Sword r_addend; +} Elf32_Rela; + +// r_info accessors +#define ELF32_R_SYM(i) ((i) >> 8) +#define ELF32_R_TYPE(i) ((unsigned char)(i)) +#define ELF32_R_INFO(s, t) ((s) << 8 + (unsigned char)(t)) + +// relocation types (i368 specific) +#define R_386_NONE 0 +#define R_386_32 1 +#define R_386_PC32 2 +#define R_386_GOT32 3 +#define R_386_PLT32 4 +#define R_386_COPY 5 +#define R_386_GLOB_DAT 6 +#define R_386_JMP_SLOT 7 +#define R_386_RELATIVE 8 +#define R_386_GOTOFF 9 +#define R_386_GOTPC 10 + +// symbol table entry +typedef struct { + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + Elf32_Word st_info; + Elf32_Word st_other; + Elf32_Word st_shndx; +} Elf32_Sym; + +// st_info accessors +#define ELF32_ST_BIND(i) ((i) >> 4) +#define ELF32_ST_TYPE(i) ((i) & 0xf) +#define ELF32_ST_INFO(b, t) ((b) << 4 + (t) & 0xf) + +// symbol binding +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 +#define STB_LOPROC 13 +#define STB_HIPROC 15 + +// symbol types +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_LOPROC 13 +#define STT_HIPROC 15 + + +#endif // _ELF_H diff --git a/src/tools/elfsymbolpatcher/ElfFile.cpp b/src/tools/elfsymbolpatcher/ElfFile.cpp new file mode 100644 index 0000000000..a8bc14852f --- /dev/null +++ b/src/tools/elfsymbolpatcher/ElfFile.cpp @@ -0,0 +1,716 @@ +// ElfFile.cpp +//------------------------------------------------------------------------------ +// Copyright (c) 2003, Ingo Weinhold +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: ElfFile.cpp +// Author: Ingo Weinhold (bonefish@users.sf.net) +// Description: Implementation of classes for accessing ELF file, +// or more precisely for iterating through their relocation +// sections. +//------------------------------------------------------------------------------ + +#include +#include +#include +#include + +#include "ElfFile.h" + +// sanity bounds +static const uint32 kMaxELFHeaderSize = sizeof(Elf32_Ehdr) + 32; + +// read_exactly +static +status_t +read_exactly(BPositionIO &file, off_t position, void *buffer, size_t size, + const char *errorMessage = NULL) +{ + status_t error = B_OK; + ssize_t read = file.ReadAt(position, buffer, size); + if (read < 0) + error = read; + else if ((size_t)read != size) + error = B_ERROR; + if (error != B_OK && errorMessage) + puts(errorMessage); + return error; +} + + +// ElfSection + +class ElfSection { +public: + ElfSection(); + ~ElfSection(); + + void SetTo(ElfFile* file, Elf32_Shdr* header); + void Unset(); + bool IsInitialized() const { return fHeader; } + + ElfFile* GetFile() const; + Elf32_Shdr* GetHeader() const { return fHeader; } + const char* GetName() const; + uint8* GetData() const { return fData; } + size_t GetSize() const; + Elf32_Word GetType() const; + Elf32_Word GetLink() const; + Elf32_Word GetInfo() const; + size_t GetEntrySize() const; + int32 CountEntries() const; + + status_t Load(); + void Unload(); + + void Dump(); + +private: + ElfFile* fFile; + Elf32_Shdr* fHeader; + uint8* fData; +}; + +// constructor +ElfSection::ElfSection() + : fFile(NULL), + fHeader(NULL), + fData(NULL) +{ +} + +// destructor +ElfSection::~ElfSection() +{ + Unset(); +} + +// SetTo +void +ElfSection::SetTo(ElfFile* file, Elf32_Shdr* header) +{ + Unset(); + fFile = file; + fHeader = header; +} + +// Unset +void +ElfSection::Unset() +{ + Unload(); + fFile = NULL; + fHeader = NULL; +} + +// GetFile +ElfFile* +ElfSection::GetFile() const +{ + return fFile; +} + +// GetName +const char* +ElfSection::GetName() const +{ + const char* name = NULL; + if (fHeader && fFile) { + size_t size = 0; + const char* nameSection = fFile->GetSectionHeaderStrings(&size); + if (nameSection && fHeader->sh_name < size) + name = nameSection + fHeader->sh_name; + } + return name; +} + +// GetSize +size_t +ElfSection::GetSize() const +{ + return fHeader->sh_size; +} + +// GetType +Elf32_Word +ElfSection::GetType() const +{ + return fHeader->sh_type; +} + +// GetLink +Elf32_Word +ElfSection::GetLink() const +{ + return fHeader->sh_link; +} + +// GetInfo +Elf32_Word +ElfSection::GetInfo() const +{ + return fHeader->sh_info; +} + +// GetEntrySize +size_t +ElfSection::GetEntrySize() const +{ + return fHeader->sh_entsize; +} + +// CountEntries +int32 +ElfSection::CountEntries() const +{ + int32 count = 0; + if (fHeader) { + if (GetEntrySize() == 0) + return 0; + count = GetSize() / GetEntrySize(); + } + return count; +} + +// Load +status_t +ElfSection::Load() +{ + status_t error = B_ERROR; + if (fHeader && !fData && fHeader->sh_type != SHT_NULL + && fHeader->sh_type != SHT_NOBITS) { + BFile* file = fFile->GetFile(); + // allocate memory + fData = new uint8[fHeader->sh_size]; + if (!fData) + return B_NO_MEMORY; + // read the data + error = read_exactly(*file, fHeader->sh_offset, fData, + fHeader->sh_size, "Failed to read section!\n"); + if (error != B_OK) + Unload(); + } + return error; +} + +// Unload +void +ElfSection::Unload() +{ + if (fData) { + delete[] fData; + fData = NULL; + } +} + +// Dump +void +ElfSection::Dump() +{ + printf("section %32s: size: %lu\n", GetName(), GetSize()); +} + + +// ElfSymbol + +// constructor +ElfSymbol::ElfSymbol(ElfSection* section, int32 index) + : fSection(section), + fIndex(index), + fSymbol(NULL) +{ +} + +// destructor +ElfSymbol::~ElfSymbol() +{ + Unset(); +} + +// SetTo +void +ElfSymbol::SetTo(ElfSection* section, int32 index) +{ + Unset(); + fSection = section; + fIndex = index; +} + +// Unset +void +ElfSymbol::Unset() +{ + fSection = NULL; + fIndex = -1; + fSymbol = NULL; +} + +// GetSymbolStruct +const Elf32_Sym* +ElfSymbol::GetSymbolStruct() +{ + Elf32_Sym* symbol = fSymbol; + if (!symbol && fSection && fSection->GetData()) { + size_t symbolSize = fSection->GetEntrySize(); + if (symbolSize == 0) + return NULL; + int32 symbolCount = fSection->GetSize() / symbolSize; + if (fIndex >= 0 && fIndex < symbolCount) + symbol = (Elf32_Sym*)(fSection->GetData() + fIndex * symbolSize); + } + return symbol; +} + +// GetName +const char* +ElfSymbol::GetName() +{ + const char* name = NULL; + if (const Elf32_Sym* symbol = GetSymbolStruct()) { + size_t size = 0; + const char* data = fSection->GetFile()->GetStringSectionStrings( + fSection->GetLink(), &size); + if (data && symbol->st_name < size) + name = data + symbol->st_name; + } + return name; +} + +// GetBinding +uint32 +ElfSymbol::GetBinding() +{ + uint32 binding = STB_LOCAL; + if (const Elf32_Sym* symbol = GetSymbolStruct()) + binding = ELF32_ST_BIND(symbol->st_info); + return binding; +} + +// GetType +uint32 +ElfSymbol::GetType() +{ + uint32 type = STT_NOTYPE; + if (const Elf32_Sym* symbol = GetSymbolStruct()) + type = ELF32_ST_TYPE(symbol->st_info); + return type; +} + +// GetTargetSectionIndex +uint32 +ElfSymbol::GetTargetSectionIndex() +{ + uint32 index = SHN_UNDEF; + if (const Elf32_Sym* symbol = GetSymbolStruct()) + index = symbol->st_shndx; + return index; +} + + +// ElfRelocation + +// constructor +ElfRelocation::ElfRelocation(ElfSection* section, int32 index) + : fSection(section), + fIndex(index), + fRelocation(NULL) +{ +} + +// destructor +ElfRelocation::~ElfRelocation() +{ + Unset(); +} + +// SetTo +void +ElfRelocation::SetTo(ElfSection* section, int32 index) +{ + Unset(); + fSection = section; + fIndex = index; +} + +// Unset +void +ElfRelocation::Unset() +{ + fSection = NULL; + fIndex = -1; + fRelocation = NULL; +} + +// GetRelocationStruct +Elf32_Rel* +ElfRelocation::GetRelocationStruct() +{ + Elf32_Rel* relocation = fRelocation; + if (!relocation && fSection) { + if (!fSection->GetData()) { + if (fSection->Load() != B_OK) + return NULL; + } + size_t entrySize = fSection->GetEntrySize(); + if (entrySize == 0 || entrySize < sizeof(Elf32_Rel)) + return NULL; + int32 entryCount = fSection->GetSize() / entrySize; + if (fIndex >= 0 && fIndex < entryCount) { + relocation = (Elf32_Rel*)(fSection->GetData() + + fIndex * entrySize); + } + } + return relocation; +} + +// GetType +uint32 +ElfRelocation::GetType() +{ + uint32 type = R_386_NONE; + if (Elf32_Rel* relocation = GetRelocationStruct()) + type = ELF32_R_TYPE(relocation->r_info); + return type; +} + +// GetSymbolIndex +uint32 +ElfRelocation::GetSymbolIndex() +{ + uint32 index = 0; + if (Elf32_Rel* relocation = GetRelocationStruct()) + index = ELF32_R_SYM(relocation->r_info); + return index; +} + +// GetOffset +Elf32_Addr +ElfRelocation::GetOffset() +{ + Elf32_Addr offset = 0; + if (Elf32_Rel* relocation = GetRelocationStruct()) + offset = relocation->r_offset; + return offset; +} + +// GetSymbol +status_t +ElfRelocation::GetSymbol(ElfSymbol* symbol) +{ + status_t error = B_BAD_VALUE; + if (symbol && fSection) { + uint32 index = GetSymbolIndex(); + if (ElfSection* symbols + = fSection->GetFile()->SectionAt(fSection->GetLink(), true)) { + symbol->SetTo(symbols, index); + if (symbol->GetSymbolStruct()) + error = B_OK; + } + } + return error; +} + + +// ElfRelocationIterator + +// constructor +ElfRelocationIterator::ElfRelocationIterator(ElfFile* file) + : fFile(file), + fSectionIndex(-1), + fEntryIndex(-1) +{ +} + +// destructor +ElfRelocationIterator::~ElfRelocationIterator() +{ +} + +// GetNext +bool +ElfRelocationIterator::GetNext(ElfRelocation* relocation) +{ + bool result = false; + if (fFile && relocation) { + // set to possible entry + ElfSection* section = NULL; + if (fSectionIndex < 0) { + fSectionIndex = 0; + fEntryIndex = 0; + section = _FindNextSection(); + } else { + fEntryIndex++; + section = fFile->SectionAt(fSectionIndex); + } + // find next valid entry + while (section && fEntryIndex >= section->CountEntries()) { + fSectionIndex++; + section = _FindNextSection(); + fEntryIndex = 0; + } + // set result + if (section) { + relocation->SetTo(section, fEntryIndex); + result = true; + } + } + return result; +} + +// _FindNextSection +ElfSection* +ElfRelocationIterator::_FindNextSection() +{ + if (fFile) { + for (; fSectionIndex < fFile->CountSections(); fSectionIndex++) { + ElfSection* section = fFile->SectionAt(fSectionIndex); + if (section && section->GetType() == SHT_REL) + return section; + } + } + return NULL; +} + + +// ElfFile + +// constructor +ElfFile::ElfFile() + : fFile(), + fSectionHeaders(NULL), + fSections(NULL), + fSectionCount(0), + fSectionHeaderSize(0) +{ +} + +// destructor +ElfFile::~ElfFile() +{ + Unset(); +} + +// SetTo +status_t +ElfFile::SetTo(const char *filename) +{ + Unset(); + status_t error = _SetTo(filename); + if (error) + Unset(); + return error; +} + +// Unset +void +ElfFile::Unset() +{ + // delete sections + if (fSections) { + delete[] fSections; + fSections = NULL; + } + // delete section headers + if (fSectionHeaders) { + delete[] fSectionHeaders; + fSectionHeaders = NULL; + } + fSectionCount = 0; + fSectionHeaderSize = 0; + fFile.Unset(); +} + +// Unload +void +ElfFile::Unload() +{ + for (int i = 0; i < fSectionCount; i++) + fSections[i].Unload(); +} + +// GetSectionHeaderStrings +const char* +ElfFile::GetSectionHeaderStrings(size_t* size) +{ + return GetStringSectionStrings(fHeader.e_shstrndx, size); +} + +// GetStringSectionStrings +const char* +ElfFile::GetStringSectionStrings(int32 index, size_t* _size) +{ + const char* data = NULL; + size_t size = 0; + if (ElfSection* section = SectionAt(index, true)) { + data = (const char*)section->GetData(); + size = (data ? section->GetSize() : 0); + } + // set results + if (_size) + *_size = size; + return data; +} + +// SectionAt +ElfSection* +ElfFile::SectionAt(int32 index, bool load) +{ + ElfSection* section = NULL; + if (fSections && index >= 0 && index < fSectionCount) { + section = fSections + index; + if (load && !section->GetData()) { + if (section->Load() != B_OK) { + section = NULL; + printf("Failed to load section %ld\n", index); + } + } + } + return section; +} + +// Dump +void +ElfFile::Dump() +{ + printf("%ld sections\n", fSectionCount); + for (int i = 0; i < fSectionCount; i++) + fSections[i].Dump(); +} + +// _SetTo +status_t +ElfFile::_SetTo(const char *filename) +{ + if (!filename) + return B_BAD_VALUE; + // open file + status_t error = fFile.SetTo(filename, B_READ_ONLY); + // get the file size + off_t fileSize = 0; + error = fFile.GetSize(&fileSize); + if (error != B_OK) { + printf("Failed to get file size!\n"); + return error; + } + // read ELF header + error = read_exactly(fFile, 0, &fHeader, sizeof(Elf32_Ehdr), + "Failed to read ELF object header!\n"); + if (error != B_OK) + return error; + // check the ident field + // magic + if (fHeader.e_ident[EI_MAG0] != ELFMAG0 + || fHeader.e_ident[EI_MAG1] != ELFMAG1 + || fHeader.e_ident[EI_MAG2] != ELFMAG2 + || fHeader.e_ident[EI_MAG3] != ELFMAG3) { + printf("Bad ELF file magic!\n"); + return B_BAD_VALUE; + } + // class + if (fHeader.e_ident[EI_CLASS] != ELFCLASS32) { + printf("Wrong ELF class!\n"); + return B_BAD_VALUE; + } + // check data encoding (endianess) + if (fHeader.e_ident[EI_DATA] != ELFDATA2LSB) { + printf("Wrong data encoding!\n"); + return B_BAD_VALUE; + } + // version + if (fHeader.e_ident[EI_VERSION] != EV_CURRENT) { + printf("Wrong data encoding!\n"); + return B_BAD_VALUE; + } + // get the header values + uint32 headerSize = fHeader.e_ehsize; + uint32 sectionHeaderTableOffset = fHeader.e_shoff; + uint32 sectionHeaderSize = fHeader.e_shentsize; + uint32 sectionHeaderCount = fHeader.e_shnum; + // check the sanity of the header values + // ELF header size + if (headerSize < sizeof(Elf32_Ehdr) || headerSize > kMaxELFHeaderSize) { + printf("Invalid ELF header: invalid ELF header size: %lu.", + headerSize); + return B_BAD_VALUE; + } + // section header table offset + if (sectionHeaderTableOffset == 0) { + printf("ELF file has no section header table!\n"); + return B_BAD_VALUE; + } + uint32 sectionHeaderTableSize = 0; + if (sectionHeaderTableOffset < headerSize + || sectionHeaderTableOffset > fileSize) { + printf("Invalid ELF header: invalid section header table offset: %lu.", + sectionHeaderTableOffset); + return B_BAD_VALUE; + } + // section header table offset + sectionHeaderTableSize = sectionHeaderSize * sectionHeaderCount; + if (sectionHeaderSize < sizeof(Elf32_Shdr) + || sectionHeaderTableOffset + sectionHeaderTableSize > fileSize) { + printf("Invalid ELF header: section header table exceeds file: %lu.", + sectionHeaderTableOffset + sectionHeaderTableSize); + return B_BAD_VALUE; + } + // allocate memory for the section header table and read it + fSectionHeaders = new(nothrow) uint8[sectionHeaderTableSize]; + fSectionCount = sectionHeaderCount; + fSectionHeaderSize = sectionHeaderSize; + if (!fSectionHeaders) + return B_NO_MEMORY; + error = read_exactly(fFile, sectionHeaderTableOffset, fSectionHeaders, + sectionHeaderTableSize, + "Failed to read section headers!\n"); + if (error != B_OK) + return error; + // allocate memory for the section pointers + fSections = new(nothrow) ElfSection[fSectionCount]; + if (!fSections) + return B_NO_MEMORY; + // init the sections + for (int i = 0; i < fSectionCount; i++) + fSections[i].SetTo(this, _SectionHeaderAt(i)); + return error; +} + +// _SectionHeaderAt +Elf32_Shdr* +ElfFile::_SectionHeaderAt(int32 index) +{ + Elf32_Shdr* header = NULL; + if (fSectionHeaders && index >= 0 && index < fSectionCount) + header = (Elf32_Shdr*)(fSectionHeaders + index * fSectionHeaderSize); + return header; +} + +// _LoadSection +status_t +ElfFile::_LoadSection(int32 index) +{ + status_t error = B_OK; + if (fSections && index >= 0 && index < fSectionCount) { + ElfSection& section = fSections[index]; + error = section.Load(); + } else + error = B_BAD_VALUE; + return error; +} + diff --git a/src/tools/elfsymbolpatcher/ElfFile.h b/src/tools/elfsymbolpatcher/ElfFile.h new file mode 100644 index 0000000000..b84b34b824 --- /dev/null +++ b/src/tools/elfsymbolpatcher/ElfFile.h @@ -0,0 +1,137 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2003, Ingo Weinhold +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: ElfFile.h +// Author: Ingo Weinhold (bonefish@users.sf.net) +// Description: Interface declarations of classes for accessing ELF file, +// or more precisely for iterating through their relocation +// sections. +//------------------------------------------------------------------------------ + +#ifndef ELF_FILE_H +#define ELF_FILE_H + +#include +#include + +#include "Elf.h" + +class ElfFile; +class ElfSection; + +// ElfSymbol +class ElfSymbol { +public: + ElfSymbol(ElfSection* section = NULL, + int32 index = -1); + ~ElfSymbol(); + + void SetTo(ElfSection* section, int32 index); + void Unset(); + + const Elf32_Sym* GetSymbolStruct(); + const char* GetName(); + uint32 GetBinding(); + uint32 GetType(); + uint32 GetTargetSectionIndex(); + +private: + ElfSection* fSection; + int32 fIndex; + Elf32_Sym* fSymbol; +}; + +// ElfRelocation +class ElfRelocation { +public: + ElfRelocation(ElfSection* section = NULL, + int32 index = -1); + ~ElfRelocation(); + + void SetTo(ElfSection* section, int32 index); + void Unset(); + + Elf32_Rel* GetRelocationStruct(); + uint32 GetType(); + uint32 GetSymbolIndex(); + Elf32_Addr GetOffset(); + status_t GetSymbol(ElfSymbol* symbol); + +private: + ElfSection* fSection; + int32 fIndex; + Elf32_Rel* fRelocation; +}; + +// ElfRelocationIterator +class ElfRelocationIterator { +public: + ElfRelocationIterator(ElfFile* file); + ~ElfRelocationIterator(); + + bool GetNext(ElfRelocation* relocation); + +private: + ElfSection* _FindNextSection(); + +private: + ElfFile* fFile; + int32 fSectionIndex; + int32 fEntryIndex; +}; + +// ElfFile +class ElfFile { +public: + ElfFile(); + ~ElfFile(); + status_t SetTo(const char *filename); + void Unset(); + void Unload(); + + BFile* GetFile() { return &fFile; } + + const char* GetSectionHeaderStrings(size_t* size); + const char* GetStringSectionStrings(int32 index, + size_t* size); + + int32 CountSections() const { return fSectionCount; } + ElfSection* SectionAt(int32 index, bool load = false); + + void Dump(); + +private: + status_t _SetTo(const char *filename); + + Elf32_Shdr* _SectionHeaderAt(int32 index); + + status_t _LoadSection(int32 index); + +private: + BFile fFile; + Elf32_Ehdr fHeader; + uint8* fSectionHeaders; + ElfSection* fSections; + int32 fSectionCount; + size_t fSectionHeaderSize; +}; + +#endif // ELF_FILE_H diff --git a/src/tools/elfsymbolpatcher/ElfImage.cpp b/src/tools/elfsymbolpatcher/ElfImage.cpp new file mode 100644 index 0000000000..b1a31cbf4c --- /dev/null +++ b/src/tools/elfsymbolpatcher/ElfImage.cpp @@ -0,0 +1,148 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2003, Ingo Weinhold +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: ElfImage.cpp +// Author: Ingo Weinhold (bonefish@users.sf.net) +// Description: Implementation of ElfImage, a class encapsulating +// a loaded ELF image, providing support for accessing the +// image's symbols and their relocation entries. +//------------------------------------------------------------------------------ + +#include +#include +#include +#include + +#include + +#include "ElfImage.h" + +// ElfImage + +// constructor +ElfImage::ElfImage() + : fImage(-1), + fFile(), + fTextAddress(NULL), + fDataAddress(NULL), + fGotAddress(NULL) +{ +} + +// destructor +ElfImage::~ElfImage() +{ + Unset(); +} + +// SetTo +status_t +ElfImage::SetTo(image_id image) +{ + Unset(); + status_t error = _SetTo(image); + if (error) + Unset(); + return error; +} + +// Unset +void +ElfImage::Unset() +{ + fFile.Unset(); + fImage = -1; + fTextAddress = NULL; + fDataAddress = NULL; + fGotAddress = NULL; +} + +// Unload +void +ElfImage::Unload() +{ + fFile.Unload(); +} + +// FindSymbol +status_t +ElfImage::FindSymbol(const char* symbolName, void** address) +{ + return get_image_symbol(fImage, symbolName, B_SYMBOL_TYPE_ANY, address); +} + +// GetSymbolRelocations +status_t +ElfImage::GetSymbolRelocations(const char* symbolName, BList* relocations) +{ + status_t error = B_OK; + ElfRelocation relocation; + for (ElfRelocationIterator it(&fFile); it.GetNext(&relocation); ) { + uint32 type = relocation.GetType(); + // get the symbol + ElfSymbol symbol; + if ((type == R_386_GLOB_DAT || type == R_386_JMP_SLOT) + && relocation.GetSymbol(&symbol) == B_OK + && symbol.GetName()) { + // only undefined symbols with global binding + if ((symbol.GetBinding() == STB_GLOBAL + || symbol.GetBinding() == STB_WEAK) + && (symbol.GetTargetSectionIndex() == SHN_UNDEF + || symbol.GetTargetSectionIndex() + >= (uint32)fFile.CountSections()) + && !strcmp(symbol.GetName(), symbolName)) { + // get the address of the GOT entry for the symbol + void** gotEntry + = (void**)(fTextAddress + relocation.GetOffset()); + if (!relocations->AddItem(gotEntry)) { + error = B_NO_MEMORY; + break; + } + } + } + } + return error; +} + +// _SetTo +status_t +ElfImage::_SetTo(image_id image) +{ + // get an image info + image_info imageInfo; + status_t error = get_image_info(image, &imageInfo); + if (error != B_OK) + return error; + fImage = imageInfo.id; + // get the address of global offset table + error = get_image_symbol(image, "_GLOBAL_OFFSET_TABLE_", + B_SYMBOL_TYPE_ANY, (void**)&fGotAddress); + if (error != B_OK) + return error; + fTextAddress = (uint8*)imageInfo.text; + fDataAddress = (uint8*)imageInfo.data; + // init the file + error = fFile.SetTo(imageInfo.name); + if (error != B_OK) + return error; + return B_OK; +} + diff --git a/src/tools/elfsymbolpatcher/ElfImage.h b/src/tools/elfsymbolpatcher/ElfImage.h new file mode 100644 index 0000000000..1564761784 --- /dev/null +++ b/src/tools/elfsymbolpatcher/ElfImage.h @@ -0,0 +1,68 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2003, Ingo Weinhold +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: ElfImage.h +// Author: Ingo Weinhold (bonefish@users.sf.net) +// Description: Interface declaration of ElfImage, a class encapsulating +// a loaded ELF image, providing support for accessing the +// image's symbols and their relocation entries. +//------------------------------------------------------------------------------ + +#ifndef ELF_IMAGE_H +#define ELF_IMAGE_H + +#include +#include + +#include "ElfFile.h" + +class BList; +class ElfSection; +class ElfSymbol; + +// ElfImage +class ElfImage { +public: + ElfImage(); + ~ElfImage(); + status_t SetTo(image_id image); + void Unset(); + void Unload(); + + image_id GetID() const { return fImage; } + + status_t FindSymbol(const char* symbolName, + void** address); + status_t GetSymbolRelocations(const char* symbolName, + BList* relocations); + +private: + status_t _SetTo(image_id image); + +private: + image_id fImage; + ElfFile fFile; + uint8* fTextAddress; + uint8* fDataAddress; + uint8* fGotAddress; +}; + +#endif // ELF_IMAGE_H diff --git a/src/tools/elfsymbolpatcher/ElfSymbolPatcher.cpp b/src/tools/elfsymbolpatcher/ElfSymbolPatcher.cpp new file mode 100644 index 0000000000..1118b01e5c --- /dev/null +++ b/src/tools/elfsymbolpatcher/ElfSymbolPatcher.cpp @@ -0,0 +1,627 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2003, Ingo Weinhold +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: ElfSymbolPatcher.cpp +// Author: Ingo Weinhold (bonefish@users.sf.net) +// Description: Interface declaration of classes used for patching ELF +// symbols. Central class is ElfSymbolPatcher. It is a kind of +// roster, managing all necessary infos (loaded images) and +// being able to fill ElfSymbolPatchInfos with life. +// An ElfSymbolPatchInfo represents a symbol and is able to +// patch/restore it. An ElfSymbolPatchGroup bundles several +// ElfSymbolPatchInfos and can update their data, e.g. +// when images are loaded/unloaded. It uses a +// ElfSymbolPatcher internally and provides a more convenient +// API for the user. +//------------------------------------------------------------------------------ + +#include +#include +#include +#include + +#include "ElfImage.h" +#include "ElfSymbolPatcher.h" + +///////////////////////////// +// ElfSymbolPatchInfo::Entry +// + +class ElfSymbolPatchInfo::Entry { +public: + static Entry* Create(image_id image, void*** targets, + int32 targetCount); + void Delete(); + + image_id GetImage() const { return fImage; } + + void Patch(void* newAddress); + +private: + Entry(); + Entry(const Entry&); + Entry(image_id image, void*** targets, + int32 targetCount); + ~Entry(); + +private: + image_id fImage; + int32 fPatchTargetCount; + void** fPatchTargets[1]; +}; + +// Create +ElfSymbolPatchInfo::Entry* +ElfSymbolPatchInfo::Entry::Create(image_id image, void*** targets, + int32 targetCount) +{ + if (!targets || targetCount <= 0) + return NULL; + void* buffer = malloc(sizeof(Entry) + sizeof(void**) * (targetCount - 1)); + Entry* entry = NULL; + if (buffer) + entry = new(buffer) Entry(image, targets, targetCount); + return entry; +} + +// Delete +void +ElfSymbolPatchInfo::Entry::Delete() +{ + this->~Entry(); + free(this); +} + +// Patch +void +ElfSymbolPatchInfo::Entry::Patch(void* newAddress) +{ +//printf("ElfSymbolPatchInfo::Entry::Patch(): patching %ld addresses\n", +//fPatchTargetCount); + for (int i = 0; i < fPatchTargetCount; i++) + *fPatchTargets[i] = newAddress; +} + +// constructor +ElfSymbolPatchInfo::Entry::Entry(image_id image, void*** targets, + int32 targetCount) + : fImage(image), + fPatchTargetCount(targetCount) +{ + memcpy(fPatchTargets + 0, targets, targetCount * sizeof(void**)); +} + +// destructor +ElfSymbolPatchInfo::Entry::~Entry() +{ +} + + +////////////////////// +// ElfSymbolPatchInfo +// + +// constructor +ElfSymbolPatchInfo::ElfSymbolPatchInfo() + : fSymbolName(), + fOriginalAddress(NULL), + fOriginalAddressImage(-1), + fEntries() +{ +} + +// destructor +ElfSymbolPatchInfo::~ElfSymbolPatchInfo() +{ + Unset(); +} + +// InitCheck +status_t +ElfSymbolPatchInfo::InitCheck() const +{ + return (fOriginalAddress && fSymbolName.Length() ? B_OK : B_NO_INIT); +} + +// GetSymbolName +const char* +ElfSymbolPatchInfo::GetSymbolName() const +{ + return fSymbolName.String(); +} + +// GetOriginalAddress +void* +ElfSymbolPatchInfo::GetOriginalAddress() const +{ + return fOriginalAddress; +} + +// GetOriginalAddressImage +image_id +ElfSymbolPatchInfo::GetOriginalAddressImage() const +{ + return fOriginalAddressImage; +} + +// Patch +status_t +ElfSymbolPatchInfo::Patch(void* newAddress) +{ +//printf("ElfSymbolPatchInfo::Patch(): patching %ld images\n", +//fEntries.CountItems()); + status_t error = InitCheck(); + if (error == B_OK) { + for (int i = 0; Entry* entry = EntryAt(i); i++) + entry->Patch(newAddress); + } + return error; +} + +// Restore +status_t +ElfSymbolPatchInfo::Restore() +{ + return Patch(fOriginalAddress); +} + +// Unset +void +ElfSymbolPatchInfo::Unset() +{ + for (int i = 0; Entry* entry = EntryAt(i); i++) + entry->Delete(); + fEntries.MakeEmpty(); + fSymbolName.SetTo(""); + fOriginalAddress = NULL; + fOriginalAddressImage = -1; +} + +// SetSymbolName +status_t +ElfSymbolPatchInfo::SetSymbolName(const char* name) +{ + fSymbolName.SetTo(name); + if (name && fSymbolName != name) + return B_NO_MEMORY; + return B_OK; +} + +// SetOriginalAddress +void +ElfSymbolPatchInfo::SetOriginalAddress(void* address, image_id image) +{ + fOriginalAddress = address; + fOriginalAddressImage = image; +} + +// CreateEntry +status_t +ElfSymbolPatchInfo::CreateEntry(image_id image, BList* targets) +{ + if (!targets || targets->CountItems() == 0) + return B_BAD_VALUE; + Entry* entry = Entry::Create(image, (void***)targets->Items(), + targets->CountItems()); + if (!entry) + return B_NO_MEMORY; + if (!fEntries.AddItem(entry)) { + entry->Delete(); + return B_NO_MEMORY; + } + return B_OK; +} + +// DeleteEntry +bool +ElfSymbolPatchInfo::DeleteEntry(image_id image) +{ + for (int i = 0; Entry* entry = EntryAt(i); i++) { + if (entry->GetImage() == image) { + fEntries.RemoveItem(i); + entry->Delete(); + return true; + } + } + return false; +} + +// EntryAt +ElfSymbolPatchInfo::Entry* +ElfSymbolPatchInfo::EntryAt(int32 index) +{ + return (Entry*)fEntries.ItemAt(index); +} + +// EntryFor +ElfSymbolPatchInfo::Entry* +ElfSymbolPatchInfo::EntryFor(image_id image) +{ + for (int i = 0; Entry* entry = EntryAt(i); i++) { + if (entry->GetImage() == image) + return entry; + } + return NULL; +} + + +///////////////// +// UpdateAdapter +// + +// constructor +ElfSymbolPatcher::UpdateAdapter::UpdateAdapter() +{ +} + +// destructor +ElfSymbolPatcher::UpdateAdapter::~UpdateAdapter() +{ +} + +// ImageAdded +void +ElfSymbolPatcher::UpdateAdapter::ImageAdded(ElfImage* image) +{ +} + +// ImageRemoved +void +ElfSymbolPatcher::UpdateAdapter::ImageRemoved(ElfImage* image) +{ +} + + +//////////////////// +// ElfSymbolPatcher +// + +// constructor +ElfSymbolPatcher::ElfSymbolPatcher() + : fImages(), + fInitStatus(B_NO_INIT) +{ + fInitStatus = _Init(); + if (fInitStatus != B_OK) + _Cleanup(); +} + +// destructor +ElfSymbolPatcher::~ElfSymbolPatcher() +{ + _Cleanup(); +} + +// InitCheck +status_t +ElfSymbolPatcher::InitCheck() const +{ + return fInitStatus; +} + +// Update +status_t +ElfSymbolPatcher::Update(UpdateAdapter* updateAdapter) +{ + if (InitCheck() != B_OK) + return B_NO_INIT; + // remove obsolete images + int32 count = fImages.CountItems(); + for (int i = count - 1; i >= 0; i--) { + ElfImage* image = _ImageAt(i); + image_info info; + if (get_image_info(image->GetID(), &info) != B_OK) { + if (updateAdapter) + updateAdapter->ImageRemoved(image); + fImages.RemoveItem(i); + delete image; + } + } + // add new images + status_t error = B_OK; + image_info info; + int32 cookie = 0; + while (get_next_image_info(0, &cookie, &info) == B_OK) { + ElfImage* image = _ImageForID(info.id); + if (image) + continue; + image = new(nothrow) ElfImage; + if (!image) + return B_NO_MEMORY; + if (!fImages.AddItem(image)) { + delete image; + return B_NO_MEMORY; + } + error = image->SetTo(info.id); + if (updateAdapter) + updateAdapter->ImageAdded(image); + } + return error; +} + +// Unload +void +ElfSymbolPatcher::Unload() +{ + for (int i = 0; ElfImage* image = _ImageAt(i); i++) + image->Unload(); +} + +// GetSymbolPatchInfo +status_t +ElfSymbolPatcher::GetSymbolPatchInfo(const char* symbolName, + ElfSymbolPatchInfo* info) +{ + // check parameters and intialization + if (!symbolName || !info) + return B_BAD_VALUE; + if (InitCheck() != B_OK) + return B_NO_INIT; + // set the symbol name + info->Unset(); + status_t error = info->SetSymbolName(symbolName); + if (error != B_OK) + return error; + for (int i = 0; ElfImage* image = _ImageAt(i); i++) { +//printf("searching in image: %ld\n", image->GetID()); + // get the symbol's relocations + BList patchTargets; + error = image->GetSymbolRelocations(symbolName, &patchTargets); + if (error != B_OK) + break; + if (patchTargets.CountItems() > 0) { + error = info->CreateEntry(image->GetID(), &patchTargets); + if (error != B_OK) + break; + } + // get the symbol's address + void* address = NULL; + if (image->FindSymbol(symbolName, &address) == B_OK && address) { + if (info->GetOriginalAddress()) { + // A symbol with that name lives in at least two images. + // Better bail out. +//printf("Found the symbol in more than one image!\n"); + error = B_ERROR; + break; + } else + info->SetOriginalAddress(address, image->GetID()); + } + } + // set the symbol address + if (!info->GetOriginalAddress()) +{ +//printf("Symbol not found in any image!\n"); + error = B_ERROR; +} + // cleanup on error + if (error != B_OK) + info->Unset(); + return error; +} + +// UpdateSymbolPatchInfo +status_t +ElfSymbolPatcher::UpdateSymbolPatchInfo(ElfSymbolPatchInfo* info, + ElfImage* image) +{ + if (!info || !image || !info->GetSymbolName()) + return B_BAD_VALUE; + // get the symbol's relocations + BList patchTargets; + status_t error + = image->GetSymbolRelocations(info->GetSymbolName(), &patchTargets); + if (error == B_OK) + error = info->CreateEntry(image->GetID(), &patchTargets); + return error; +} + +// _Init +status_t +ElfSymbolPatcher::_Init() +{ + status_t error = B_OK; + image_info info; + int32 cookie = 0; + while (get_next_image_info(0, &cookie, &info) == B_OK) { + ElfImage* image = new(nothrow) ElfImage; + if (!image) + return B_NO_MEMORY; + if (!fImages.AddItem(image)) { + delete image; + return B_NO_MEMORY; + } + error = image->SetTo(info.id); + } + return error; +} + +// _Cleanup +void +ElfSymbolPatcher::_Cleanup() +{ + for (int i = 0; ElfImage* image = _ImageAt(i); i++) + delete image; + fImages.MakeEmpty(); +} + +// _ImageAt +ElfImage* +ElfSymbolPatcher::_ImageAt(int32 index) const +{ + return (ElfImage*)fImages.ItemAt(index); +} + +// _ImageForID +ElfImage* +ElfSymbolPatcher::_ImageForID(image_id id) const +{ + for (int i = 0; ElfImage* image = _ImageAt(i); i++) { + if (image->GetID() == id) + return image; + } + return NULL; +} + + +/////////////////////// +// ElfSymbolPatchGroup +// + +// constructor +ElfSymbolPatchGroup::ElfSymbolPatchGroup(ElfSymbolPatcher* patcher) + : fPatcher(patcher), + fPatchInfos(), + fOwnsPatcher(false), + fPatched(false) +{ + // create a patcher if none has been supplied + if (!fPatcher) { + fPatcher = new(nothrow) ElfSymbolPatcher; + if (fPatcher) { + if (fPatcher->InitCheck() == B_OK) + fOwnsPatcher = true; + else { + delete fPatcher; + fPatcher = NULL; + } + } + } +} + +// destructor +ElfSymbolPatchGroup::~ElfSymbolPatchGroup() +{ + RemoveAllPatches(); + if (fPatcher && fOwnsPatcher) + delete fPatcher; +} + +// AddPatch +status_t +ElfSymbolPatchGroup::AddPatch(const char* symbolName, void* newAddress, + void** originalAddress) +{ + // check initialization and parameters + if (!fPatcher) + return B_NO_INIT; + if (!symbolName || !originalAddress) + return B_BAD_VALUE; + // allocate patch info + PatchInfo* patchInfo = new(nothrow) PatchInfo; + if (!patchInfo) + return B_NO_MEMORY; + // init and add the patch info + status_t error = fPatcher->GetSymbolPatchInfo(symbolName, patchInfo); + if (error == B_OK) { + if (fPatchInfos.AddItem(patchInfo)) { + patchInfo->fNewAddress = newAddress; + *originalAddress = patchInfo->GetOriginalAddress(); + } else + error = B_NO_MEMORY; + } + // cleanup on failure + if (error != B_OK && patchInfo) { + fPatchInfos.RemoveItem(patchInfo); + delete patchInfo; + } + return error; +} + +// RemoveAllPatches +void +ElfSymbolPatchGroup::RemoveAllPatches() +{ + for (int i = 0; PatchInfo* info = (PatchInfo*)fPatchInfos.ItemAt(i); i++) + delete info; + fPatchInfos.MakeEmpty(); + fPatched = false; +} + +// Patch +status_t +ElfSymbolPatchGroup::Patch() +{ +//printf("ElfSymbolPatchGroup::Patch(): patching %ld symbols\n", +//fPatchInfos.CountItems()); + if (!fPatcher) + return B_NO_INIT; + if (fPatched) + return B_OK; + for (int i = 0; PatchInfo* info = (PatchInfo*)fPatchInfos.ItemAt(i); i++) + info->Patch(info->fNewAddress); + fPatched = true; + return B_OK; +} + +// Restore +status_t +ElfSymbolPatchGroup::Restore() +{ + if (!fPatcher) + return B_NO_INIT; + if (!fPatched) + return B_OK; + for (int i = 0; PatchInfo* info = (PatchInfo*)fPatchInfos.ItemAt(i); i++) + info->Restore(); + fPatched = false; + return B_OK; +} + +// Update +status_t +ElfSymbolPatchGroup::Update() +{ + if (!fPatcher) + return B_NO_INIT; + return fPatcher->Update(this); +} + +// ImageAdded +void +ElfSymbolPatchGroup::ImageAdded(ElfImage* image) +{ + for (int i = 0; PatchInfo* info = (PatchInfo*)fPatchInfos.ItemAt(i); i++) { + fPatcher->UpdateSymbolPatchInfo(info, image); + if (fPatched) { + ElfSymbolPatchInfo::Entry* entry = info->EntryFor(image->GetID()); + if (entry) + info->Patch(info->fNewAddress); + } + } +} + +// ImageRemoved +void +ElfSymbolPatchGroup::ImageRemoved(ElfImage* image) +{ + int32 count = fPatchInfos.CountItems(); + for (int i = count - 1; i >= 0; i--) { + PatchInfo* info = (PatchInfo*)fPatchInfos.ItemAt(i); + if (info->GetOriginalAddressImage() == image->GetID()) { + // the image the symbol lives in, has been removed: remove the + // complete patch info + fPatchInfos.RemoveItem(i); + delete info; + } else + info->DeleteEntry(image->GetID()); + } +} + diff --git a/src/tools/elfsymbolpatcher/Jamfile b/src/tools/elfsymbolpatcher/Jamfile new file mode 100644 index 0000000000..fc0fb7d84b --- /dev/null +++ b/src/tools/elfsymbolpatcher/Jamfile @@ -0,0 +1,9 @@ +SubDir OBOS_TOP src tools elfsymbolpatcher ; + +UseHeaders [ FDirName $(OBOS_TOP) headers tools elfsymbolpatcher ] ; + +StaticLibrary elfsymbolpatcher + : ElfFile.cpp + ElfImage.cpp + ElfSymbolPatcher.cpp +;