A little library for patching symbols at runtime.

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5296 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2003-11-10 00:38:35 +00:00
parent 51fde20c1e
commit e79e4e7c9e
8 changed files with 2059 additions and 0 deletions
@@ -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 ([email protected])
// 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 <List.h>
#include <String.h>
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
+192
View File
@@ -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
+716
View File
@@ -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 ([email protected])
// Description: Implementation of classes for accessing ELF file,
// or more precisely for iterating through their relocation
// sections.
//------------------------------------------------------------------------------
#include <new>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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;
}
+137
View File
@@ -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 ([email protected])
// 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 <File.h>
#include <image.h>
#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
+148
View File
@@ -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 ([email protected])
// Description: Implementation of ElfImage, a class encapsulating
// a loaded ELF image, providing support for accessing the
// image's symbols and their relocation entries.
//------------------------------------------------------------------------------
#include <new>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <List.h>
#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;
}
+68
View File
@@ -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 ([email protected])
// 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 <File.h>
#include <image.h>
#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
@@ -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 ([email protected])
// 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 <new>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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());
}
}
+9
View File
@@ -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
;