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:
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
;
|
||||
Reference in New Issue
Block a user