21 changed files with 10936 additions and 0 deletions
@ -0,0 +1,226 @@ |
|||
|
|||
|
|||
/* this ALWAYS GENERATED file contains the definitions for the interfaces */ |
|||
|
|||
|
|||
/* File created by MIDL compiler version 8.01.0628 */ |
|||
/* at Tue Jan 19 12:14:07 2038
|
|||
*/ |
|||
/* Compiler settings for IncSourceTestDlg.idl:
|
|||
Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 8.01.0628 |
|||
protocol : dce , ms_ext, c_ext, robust |
|||
error checks: allocation ref bounds_check enum stub_data |
|||
VC __declspec() decoration level: |
|||
__declspec(uuid()), __declspec(selectany), __declspec(novtable) |
|||
DECLSPEC_UUID(), MIDL_INTERFACE() |
|||
*/ |
|||
/* @@MIDL_FILE_HEADING( ) */ |
|||
|
|||
|
|||
|
|||
/* verify that the <rpcndr.h> version is high enough to compile this file*/ |
|||
#ifndef __REQUIRED_RPCNDR_H_VERSION__ |
|||
#define __REQUIRED_RPCNDR_H_VERSION__ 500 |
|||
#endif |
|||
|
|||
#include "rpc.h" |
|||
#include "rpcndr.h" |
|||
|
|||
#ifndef __RPCNDR_H_VERSION__ |
|||
#error this stub requires an updated version of <rpcndr.h> |
|||
#endif /* __RPCNDR_H_VERSION__ */ |
|||
|
|||
|
|||
#ifndef __IncSourceTestDlg_h_h__ |
|||
#define __IncSourceTestDlg_h_h__ |
|||
|
|||
#if defined(_MSC_VER) && (_MSC_VER >= 1020) |
|||
#pragma once |
|||
#endif |
|||
|
|||
#ifndef DECLSPEC_XFGVIRT |
|||
#if defined(_CONTROL_FLOW_GUARD_XFG) |
|||
#define DECLSPEC_XFGVIRT(base, func) __declspec(xfg_virtual(base, func)) |
|||
#else |
|||
#define DECLSPEC_XFGVIRT(base, func) |
|||
#endif |
|||
#endif |
|||
|
|||
/* Forward Declarations */ |
|||
|
|||
#ifndef __IIncSourceTestDlg_FWD_DEFINED__ |
|||
#define __IIncSourceTestDlg_FWD_DEFINED__ |
|||
typedef interface IIncSourceTestDlg IIncSourceTestDlg; |
|||
|
|||
#endif /* __IIncSourceTestDlg_FWD_DEFINED__ */ |
|||
|
|||
|
|||
#ifndef __IncSourceTestDlg_FWD_DEFINED__ |
|||
#define __IncSourceTestDlg_FWD_DEFINED__ |
|||
|
|||
#ifdef __cplusplus |
|||
typedef class IncSourceTestDlg IncSourceTestDlg; |
|||
#else |
|||
typedef struct IncSourceTestDlg IncSourceTestDlg; |
|||
#endif /* __cplusplus */ |
|||
|
|||
#endif /* __IncSourceTestDlg_FWD_DEFINED__ */ |
|||
|
|||
|
|||
#ifdef __cplusplus |
|||
extern "C"{ |
|||
#endif |
|||
|
|||
|
|||
|
|||
#ifndef __IncSourceTestDlg_LIBRARY_DEFINED__ |
|||
#define __IncSourceTestDlg_LIBRARY_DEFINED__ |
|||
|
|||
/* library IncSourceTestDlg */ |
|||
/* [version][uuid] */ |
|||
|
|||
|
|||
EXTERN_C const IID LIBID_IncSourceTestDlg; |
|||
|
|||
#ifndef __IIncSourceTestDlg_DISPINTERFACE_DEFINED__ |
|||
#define __IIncSourceTestDlg_DISPINTERFACE_DEFINED__ |
|||
|
|||
/* dispinterface IIncSourceTestDlg */ |
|||
/* [uuid] */ |
|||
|
|||
|
|||
EXTERN_C const IID DIID_IIncSourceTestDlg; |
|||
|
|||
#if defined(__cplusplus) && !defined(CINTERFACE) |
|||
|
|||
MIDL_INTERFACE("2ef56b3a-ca68-4764-8fdd-5d19ec609144") |
|||
IIncSourceTestDlg : public IDispatch |
|||
{ |
|||
}; |
|||
|
|||
#else /* C style interface */ |
|||
|
|||
typedef struct IIncSourceTestDlgVtbl |
|||
{ |
|||
BEGIN_INTERFACE |
|||
|
|||
DECLSPEC_XFGVIRT(IUnknown, QueryInterface) |
|||
HRESULT ( STDMETHODCALLTYPE *QueryInterface )( |
|||
IIncSourceTestDlg * This, |
|||
/* [in] */ REFIID riid, |
|||
/* [annotation][iid_is][out] */ |
|||
_COM_Outptr_ void **ppvObject); |
|||
|
|||
DECLSPEC_XFGVIRT(IUnknown, AddRef) |
|||
ULONG ( STDMETHODCALLTYPE *AddRef )( |
|||
IIncSourceTestDlg * This); |
|||
|
|||
DECLSPEC_XFGVIRT(IUnknown, Release) |
|||
ULONG ( STDMETHODCALLTYPE *Release )( |
|||
IIncSourceTestDlg * This); |
|||
|
|||
DECLSPEC_XFGVIRT(IDispatch, GetTypeInfoCount) |
|||
HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )( |
|||
IIncSourceTestDlg * This, |
|||
/* [out] */ UINT *pctinfo); |
|||
|
|||
DECLSPEC_XFGVIRT(IDispatch, GetTypeInfo) |
|||
HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )( |
|||
IIncSourceTestDlg * This, |
|||
/* [in] */ UINT iTInfo, |
|||
/* [in] */ LCID lcid, |
|||
/* [out] */ ITypeInfo **ppTInfo); |
|||
|
|||
DECLSPEC_XFGVIRT(IDispatch, GetIDsOfNames) |
|||
HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )( |
|||
IIncSourceTestDlg * This, |
|||
/* [in] */ REFIID riid, |
|||
/* [size_is][in] */ LPOLESTR *rgszNames, |
|||
/* [range][in] */ UINT cNames, |
|||
/* [in] */ LCID lcid, |
|||
/* [size_is][out] */ DISPID *rgDispId); |
|||
|
|||
DECLSPEC_XFGVIRT(IDispatch, Invoke) |
|||
/* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )( |
|||
IIncSourceTestDlg * This, |
|||
/* [annotation][in] */ |
|||
_In_ DISPID dispIdMember, |
|||
/* [annotation][in] */ |
|||
_In_ REFIID riid, |
|||
/* [annotation][in] */ |
|||
_In_ LCID lcid, |
|||
/* [annotation][in] */ |
|||
_In_ WORD wFlags, |
|||
/* [annotation][out][in] */ |
|||
_In_ DISPPARAMS *pDispParams, |
|||
/* [annotation][out] */ |
|||
_Out_opt_ VARIANT *pVarResult, |
|||
/* [annotation][out] */ |
|||
_Out_opt_ EXCEPINFO *pExcepInfo, |
|||
/* [annotation][out] */ |
|||
_Out_opt_ UINT *puArgErr); |
|||
|
|||
END_INTERFACE |
|||
} IIncSourceTestDlgVtbl; |
|||
|
|||
interface IIncSourceTestDlg |
|||
{ |
|||
CONST_VTBL struct IIncSourceTestDlgVtbl *lpVtbl; |
|||
}; |
|||
|
|||
|
|||
|
|||
#ifdef COBJMACROS |
|||
|
|||
|
|||
#define IIncSourceTestDlg_QueryInterface(This,riid,ppvObject) \ |
|||
( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) |
|||
|
|||
#define IIncSourceTestDlg_AddRef(This) \ |
|||
( (This)->lpVtbl -> AddRef(This) ) |
|||
|
|||
#define IIncSourceTestDlg_Release(This) \ |
|||
( (This)->lpVtbl -> Release(This) ) |
|||
|
|||
|
|||
#define IIncSourceTestDlg_GetTypeInfoCount(This,pctinfo) \ |
|||
( (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo) ) |
|||
|
|||
#define IIncSourceTestDlg_GetTypeInfo(This,iTInfo,lcid,ppTInfo) \ |
|||
( (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo) ) |
|||
|
|||
#define IIncSourceTestDlg_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) \ |
|||
( (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) ) |
|||
|
|||
#define IIncSourceTestDlg_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) \ |
|||
( (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) ) |
|||
|
|||
#endif /* COBJMACROS */ |
|||
|
|||
|
|||
#endif /* C style interface */ |
|||
|
|||
|
|||
#endif /* __IIncSourceTestDlg_DISPINTERFACE_DEFINED__ */ |
|||
|
|||
|
|||
EXTERN_C const CLSID CLSID_IncSourceTestDlg; |
|||
|
|||
#ifdef __cplusplus |
|||
|
|||
class DECLSPEC_UUID("485ee25e-0171-42b5-8cf0-7883ae87945e") |
|||
IncSourceTestDlg; |
|||
#endif |
|||
#endif /* __IncSourceTestDlg_LIBRARY_DEFINED__ */ |
|||
|
|||
/* Additional Prototypes for ALL interfaces */ |
|||
|
|||
/* end of Additional Prototypes */ |
|||
|
|||
#ifdef __cplusplus |
|||
} |
|||
#endif |
|||
|
|||
#endif |
|||
|
|||
|
|||
@ -0,0 +1,84 @@ |
|||
|
|||
|
|||
/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */ |
|||
|
|||
/* link this file in with the server and any clients */ |
|||
|
|||
|
|||
/* File created by MIDL compiler version 8.01.0628 */ |
|||
/* at Tue Jan 19 12:14:07 2038
|
|||
*/ |
|||
/* Compiler settings for IncSourceTestDlg.idl:
|
|||
Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 8.01.0628 |
|||
protocol : dce , ms_ext, c_ext, robust |
|||
error checks: allocation ref bounds_check enum stub_data |
|||
VC __declspec() decoration level: |
|||
__declspec(uuid()), __declspec(selectany), __declspec(novtable) |
|||
DECLSPEC_UUID(), MIDL_INTERFACE() |
|||
*/ |
|||
/* @@MIDL_FILE_HEADING( ) */ |
|||
|
|||
|
|||
|
|||
#ifdef __cplusplus |
|||
extern "C"{ |
|||
#endif |
|||
|
|||
|
|||
#include <rpc.h> |
|||
#include <rpcndr.h> |
|||
|
|||
#ifdef _MIDL_USE_GUIDDEF_ |
|||
|
|||
#ifndef INITGUID |
|||
#define INITGUID |
|||
#include <guiddef.h> |
|||
#undef INITGUID |
|||
#else |
|||
#include <guiddef.h> |
|||
#endif |
|||
|
|||
#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \ |
|||
DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) |
|||
|
|||
#else // !_MIDL_USE_GUIDDEF_
|
|||
|
|||
#ifndef __IID_DEFINED__ |
|||
#define __IID_DEFINED__ |
|||
|
|||
typedef struct _IID |
|||
{ |
|||
unsigned long x; |
|||
unsigned short s1; |
|||
unsigned short s2; |
|||
unsigned char c[8]; |
|||
} IID; |
|||
|
|||
#endif // __IID_DEFINED__
|
|||
|
|||
#ifndef CLSID_DEFINED |
|||
#define CLSID_DEFINED |
|||
typedef IID CLSID; |
|||
#endif // CLSID_DEFINED
|
|||
|
|||
#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \ |
|||
EXTERN_C __declspec(selectany) const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}} |
|||
|
|||
#endif // !_MIDL_USE_GUIDDEF_
|
|||
|
|||
MIDL_DEFINE_GUID(IID, LIBID_IncSourceTestDlg,0xfdcaae6b,0x3d5c,0x4612,0x8b,0xfc,0x6b,0x4e,0x40,0xf2,0x51,0x8d); |
|||
|
|||
|
|||
MIDL_DEFINE_GUID(IID, DIID_IIncSourceTestDlg,0x2ef56b3a,0xca68,0x4764,0x8f,0xdd,0x5d,0x19,0xec,0x60,0x91,0x44); |
|||
|
|||
|
|||
MIDL_DEFINE_GUID(CLSID, CLSID_IncSourceTestDlg,0x485ee25e,0x0171,0x42b5,0x8c,0xf0,0x78,0x83,0xae,0x87,0x94,0x5e); |
|||
|
|||
#undef MIDL_DEFINE_GUID |
|||
|
|||
#ifdef __cplusplus |
|||
} |
|||
#endif |
|||
|
|||
|
|||
|
|||
File diff suppressed because it is too large
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -0,0 +1,119 @@ |
|||
/*
|
|||
Copyright (C) 2001-present by Serge Lamikhov-Center |
|||
|
|||
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. |
|||
*/ |
|||
|
|||
#ifndef ELFIO_ARRAY_HPP |
|||
#define ELFIO_ARRAY_HPP |
|||
|
|||
#include <algorithm> |
|||
|
|||
namespace ELFIO { |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// Template class for accessing array sections
|
|||
template <class S, typename T> class array_section_accessor_template |
|||
{ |
|||
public: |
|||
//------------------------------------------------------------------------------
|
|||
// Constructor
|
|||
explicit array_section_accessor_template( const elfio& elf_file, |
|||
S* section ); |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// Returns the number of entries in the array section
|
|||
Elf_Xword get_entries_num() const; |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// Retrieves an entry from the array section
|
|||
bool get_entry( Elf_Xword index, Elf64_Addr& address ) const; |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// Adds an entry to the array section
|
|||
void add_entry( Elf64_Addr address ); |
|||
|
|||
private: |
|||
//------------------------------------------------------------------------------
|
|||
// Reference to the ELF file
|
|||
const elfio& elf_file; |
|||
//------------------------------------------------------------------------------
|
|||
// Pointer to the array section
|
|||
S* array_section; |
|||
}; |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// Constructor
|
|||
template <class S, typename T> |
|||
array_section_accessor_template<S, T>::array_section_accessor_template( |
|||
const elfio& elf_file, S* section ) |
|||
: elf_file( elf_file ), array_section( section ) |
|||
{ |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// Returns the number of entries in the array section
|
|||
template <class S, typename T> |
|||
Elf_Xword array_section_accessor_template<S, T>::get_entries_num() const |
|||
{ |
|||
Elf_Xword entry_size = sizeof( T ); |
|||
return array_section->get_size() / entry_size; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// Retrieves an entry from the array section
|
|||
template <class S, typename T> |
|||
bool array_section_accessor_template<S, T>::get_entry( |
|||
Elf_Xword index, Elf64_Addr& address ) const |
|||
{ |
|||
if ( index >= get_entries_num() ) { // Is index valid
|
|||
return false; |
|||
} |
|||
|
|||
const auto& convertor = elf_file.get_convertor(); |
|||
|
|||
const T temp = *reinterpret_cast<const T*>( array_section->get_data() + |
|||
index * sizeof( T ) ); |
|||
address = ( *convertor )( temp ); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// Adds an entry to the array section
|
|||
template <class S, typename T> |
|||
void array_section_accessor_template<S, T>::add_entry( Elf64_Addr address ) |
|||
{ |
|||
const auto& convertor = elf_file.get_convertor(); |
|||
|
|||
T temp = ( *convertor )( (T)address ); |
|||
array_section->append_data( reinterpret_cast<char*>( &temp ), |
|||
sizeof( temp ) ); |
|||
} |
|||
|
|||
// Type aliases for array section accessors
|
|||
template <typename T = Elf32_Word> |
|||
using array_section_accessor = array_section_accessor_template<section, T>; |
|||
template <typename T = Elf32_Word> |
|||
using const_array_section_accessor = |
|||
array_section_accessor_template<const section, T>; |
|||
|
|||
} // namespace ELFIO
|
|||
|
|||
#endif // ELFIO_ARRAY_HPP
|
|||
File diff suppressed because it is too large
@ -0,0 +1,300 @@ |
|||
/*
|
|||
Copyright (C) 2001-present by Serge Lamikhov-Center |
|||
|
|||
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. |
|||
*/ |
|||
|
|||
#ifndef ELFIO_DYNAMIC_HPP |
|||
#define ELFIO_DYNAMIC_HPP |
|||
|
|||
#include <algorithm> |
|||
|
|||
namespace ELFIO { |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// Template class for accessing dynamic sections
|
|||
template <class S> class dynamic_section_accessor_template |
|||
{ |
|||
public: |
|||
//------------------------------------------------------------------------------
|
|||
// Constructor
|
|||
explicit dynamic_section_accessor_template( const elfio& elf_file, |
|||
S* section ) |
|||
: elf_file( elf_file ), dynamic_section( section ), entries_num( 0 ) |
|||
{ |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// Returns the number of entries in the dynamic section
|
|||
Elf_Xword get_entries_num() const |
|||
{ |
|||
size_t needed_entry_size = -1; |
|||
if ( elf_file.get_class() == ELFCLASS32 ) { |
|||
needed_entry_size = sizeof( Elf32_Dyn ); |
|||
} |
|||
else { |
|||
needed_entry_size = sizeof( Elf64_Dyn ); |
|||
} |
|||
|
|||
if ( ( 0 == entries_num ) && |
|||
( 0 != dynamic_section->get_entry_size() && |
|||
dynamic_section->get_entry_size() >= needed_entry_size ) ) { |
|||
entries_num = |
|||
dynamic_section->get_size() / dynamic_section->get_entry_size(); |
|||
Elf_Xword i; |
|||
Elf_Xword tag = DT_NULL; |
|||
Elf_Xword value = 0; |
|||
std::string str; |
|||
for ( i = 0; i < entries_num; i++ ) { |
|||
get_entry( i, tag, value, str ); |
|||
if ( tag == DT_NULL ) |
|||
break; |
|||
} |
|||
entries_num = std::min<Elf_Xword>( entries_num, i + 1 ); |
|||
} |
|||
|
|||
return entries_num; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// Retrieves an entry from the dynamic section
|
|||
bool get_entry( Elf_Xword index, |
|||
Elf_Xword& tag, |
|||
Elf_Xword& value, |
|||
std::string& str ) const |
|||
{ |
|||
if ( index >= get_entries_num() ) { // Is index valid
|
|||
return false; |
|||
} |
|||
|
|||
if ( elf_file.get_class() == ELFCLASS32 ) { |
|||
generic_get_entry_dyn<Elf32_Dyn>( index, tag, value ); |
|||
} |
|||
else { |
|||
generic_get_entry_dyn<Elf64_Dyn>( index, tag, value ); |
|||
} |
|||
|
|||
// If the tag has a string table reference - prepare the string
|
|||
if ( tag == DT_NEEDED || tag == DT_SONAME || tag == DT_RPATH || |
|||
tag == DT_RUNPATH ) { |
|||
string_section_accessor strsec( |
|||
elf_file.sections[get_string_table_index()] ); |
|||
const char* result = strsec.get_string( (Elf_Word)value ); |
|||
if ( nullptr == result ) { |
|||
str.clear(); |
|||
return false; |
|||
} |
|||
str = result; |
|||
} |
|||
else { |
|||
str.clear(); |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// Adds an entry to the dynamic section
|
|||
void add_entry( Elf_Xword tag, Elf_Xword value ) |
|||
{ |
|||
if ( elf_file.get_class() == ELFCLASS32 ) { |
|||
generic_add_entry_dyn<Elf32_Dyn>( tag, value ); |
|||
} |
|||
else { |
|||
generic_add_entry_dyn<Elf64_Dyn>( tag, value ); |
|||
} |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// Adds an entry with a string value to the dynamic section
|
|||
void add_entry( Elf_Xword tag, const std::string& str ) |
|||
{ |
|||
string_section_accessor strsec( |
|||
elf_file.sections[get_string_table_index()] ); |
|||
Elf_Xword value = strsec.add_string( str ); |
|||
add_entry( tag, value ); |
|||
} |
|||
|
|||
private: |
|||
//------------------------------------------------------------------------------
|
|||
// Returns the index of the string table
|
|||
Elf_Half get_string_table_index() const |
|||
{ |
|||
return (Elf_Half)dynamic_section->get_link(); |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// Retrieves a generic entry from the dynamic section
|
|||
template <class T> |
|||
void generic_get_entry_dyn( Elf_Xword index, |
|||
Elf_Xword& tag, |
|||
Elf_Xword& value ) const |
|||
{ |
|||
const auto& convertor = elf_file.get_convertor(); |
|||
|
|||
// Check unusual case when dynamic section has no data
|
|||
if ( dynamic_section->get_data() == nullptr || |
|||
dynamic_section->get_entry_size() < sizeof( T ) ) { |
|||
tag = DT_NULL; |
|||
value = 0; |
|||
return; |
|||
} |
|||
|
|||
// Check for integer overflow in size calculation
|
|||
if ( index > ( dynamic_section->get_size() / |
|||
dynamic_section->get_entry_size() ) - |
|||
1 ) { |
|||
tag = DT_NULL; |
|||
value = 0; |
|||
return; |
|||
} |
|||
|
|||
// Check for integer overflow in pointer arithmetic
|
|||
Elf_Xword offset = index * dynamic_section->get_entry_size(); |
|||
if ( offset > dynamic_section->get_size() - sizeof( T ) ) { |
|||
tag = DT_NULL; |
|||
value = 0; |
|||
return; |
|||
} |
|||
|
|||
const T* pEntry = |
|||
reinterpret_cast<const T*>( dynamic_section->get_data() + offset ); |
|||
tag = ( *convertor )( pEntry->d_tag ); |
|||
switch ( tag ) { |
|||
case DT_NULL: |
|||
case DT_SYMBOLIC: |
|||
case DT_TEXTREL: |
|||
case DT_BIND_NOW: |
|||
value = 0; |
|||
break; |
|||
case DT_NEEDED: |
|||
case DT_PLTRELSZ: |
|||
case DT_RELASZ: |
|||
case DT_RELAENT: |
|||
case DT_STRSZ: |
|||
case DT_SYMENT: |
|||
case DT_SONAME: |
|||
case DT_RPATH: |
|||
case DT_RELSZ: |
|||
case DT_RELENT: |
|||
case DT_PLTREL: |
|||
case DT_INIT_ARRAYSZ: |
|||
case DT_FINI_ARRAYSZ: |
|||
case DT_RUNPATH: |
|||
case DT_FLAGS: |
|||
case DT_PREINIT_ARRAYSZ: |
|||
value = ( *convertor )( pEntry->d_un.d_val ); |
|||
break; |
|||
case DT_PLTGOT: |
|||
case DT_HASH: |
|||
case DT_STRTAB: |
|||
case DT_SYMTAB: |
|||
case DT_RELA: |
|||
case DT_INIT: |
|||
case DT_FINI: |
|||
case DT_REL: |
|||
case DT_DEBUG: |
|||
case DT_JMPREL: |
|||
case DT_INIT_ARRAY: |
|||
case DT_FINI_ARRAY: |
|||
case DT_PREINIT_ARRAY: |
|||
default: |
|||
value = ( *convertor )( pEntry->d_un.d_ptr ); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// Adds a generic entry to the dynamic section
|
|||
template <class T> |
|||
void generic_add_entry_dyn( Elf_Xword tag, Elf_Xword value ) |
|||
{ |
|||
const auto& convertor = elf_file.get_convertor(); |
|||
|
|||
T entry; |
|||
|
|||
switch ( tag ) { |
|||
case DT_NULL: |
|||
case DT_SYMBOLIC: |
|||
case DT_TEXTREL: |
|||
case DT_BIND_NOW: |
|||
entry.d_un.d_val = |
|||
( *convertor )( decltype( entry.d_un.d_val )( 0 ) ); |
|||
break; |
|||
case DT_NEEDED: |
|||
case DT_PLTRELSZ: |
|||
case DT_RELASZ: |
|||
case DT_RELAENT: |
|||
case DT_STRSZ: |
|||
case DT_SYMENT: |
|||
case DT_SONAME: |
|||
case DT_RPATH: |
|||
case DT_RELSZ: |
|||
case DT_RELENT: |
|||
case DT_PLTREL: |
|||
case DT_INIT_ARRAYSZ: |
|||
case DT_FINI_ARRAYSZ: |
|||
case DT_RUNPATH: |
|||
case DT_FLAGS: |
|||
case DT_PREINIT_ARRAYSZ: |
|||
entry.d_un.d_val = |
|||
( *convertor )( decltype( entry.d_un.d_val )( value ) ); |
|||
break; |
|||
case DT_PLTGOT: |
|||
case DT_HASH: |
|||
case DT_STRTAB: |
|||
case DT_SYMTAB: |
|||
case DT_RELA: |
|||
case DT_INIT: |
|||
case DT_FINI: |
|||
case DT_REL: |
|||
case DT_DEBUG: |
|||
case DT_JMPREL: |
|||
case DT_INIT_ARRAY: |
|||
case DT_FINI_ARRAY: |
|||
case DT_PREINIT_ARRAY: |
|||
default: |
|||
entry.d_un.d_ptr = |
|||
( *convertor )( decltype( entry.d_un.d_val )( value ) ); |
|||
break; |
|||
} |
|||
|
|||
entry.d_tag = ( *convertor )( decltype( entry.d_tag )( tag ) ); |
|||
|
|||
dynamic_section->append_data( reinterpret_cast<char*>( &entry ), |
|||
sizeof( entry ) ); |
|||
} |
|||
|
|||
private: |
|||
// Reference to the ELF file
|
|||
const elfio& elf_file; |
|||
// Pointer to the dynamic section
|
|||
S* dynamic_section; |
|||
// Number of entries in the dynamic section
|
|||
mutable Elf_Xword entries_num; |
|||
}; |
|||
|
|||
// Type aliases for dynamic section accessors
|
|||
using dynamic_section_accessor = dynamic_section_accessor_template<section>; |
|||
using const_dynamic_section_accessor = |
|||
dynamic_section_accessor_template<const section>; |
|||
|
|||
} // namespace ELFIO
|
|||
|
|||
#endif // ELFIO_DYNAMIC_HPP
|
|||
@ -0,0 +1,192 @@ |
|||
/*
|
|||
Copyright (C) 2001-present by Serge Lamikhov-Center |
|||
|
|||
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. |
|||
*/ |
|||
|
|||
#ifndef ELF_HEADER_HPP |
|||
#define ELF_HEADER_HPP |
|||
|
|||
#include <iostream> |
|||
|
|||
namespace ELFIO { |
|||
|
|||
/**
|
|||
* @class elf_header |
|||
* @brief Abstract base class for ELF header. |
|||
*/ |
|||
class elf_header |
|||
{ |
|||
public: |
|||
/**
|
|||
* @brief Virtual destructor. |
|||
*/ |
|||
virtual ~elf_header() = default; |
|||
|
|||
/**
|
|||
* @brief Load ELF header from stream. |
|||
* @param stream Input stream. |
|||
* @return True if successful, false otherwise. |
|||
*/ |
|||
virtual bool load( std::istream& stream ) = 0; |
|||
|
|||
/**
|
|||
* @brief Save ELF header to stream. |
|||
* @param stream Output stream. |
|||
* @return True if successful, false otherwise. |
|||
*/ |
|||
virtual bool save( std::ostream& stream ) const = 0; |
|||
|
|||
// ELF header functions
|
|||
ELFIO_GET_ACCESS_DECL( unsigned char, class ); |
|||
ELFIO_GET_ACCESS_DECL( unsigned char, elf_version ); |
|||
ELFIO_GET_ACCESS_DECL( unsigned char, encoding ); |
|||
ELFIO_GET_ACCESS_DECL( Elf_Half, header_size ); |
|||
ELFIO_GET_ACCESS_DECL( Elf_Half, section_entry_size ); |
|||
ELFIO_GET_ACCESS_DECL( Elf_Half, segment_entry_size ); |
|||
|
|||
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, version ); |
|||
ELFIO_GET_SET_ACCESS_DECL( unsigned char, os_abi ); |
|||
ELFIO_GET_SET_ACCESS_DECL( unsigned char, abi_version ); |
|||
ELFIO_GET_SET_ACCESS_DECL( Elf_Half, type ); |
|||
ELFIO_GET_SET_ACCESS_DECL( Elf_Half, machine ); |
|||
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, flags ); |
|||
ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, entry ); |
|||
ELFIO_GET_SET_ACCESS_DECL( Elf_Half, sections_num ); |
|||
ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, sections_offset ); |
|||
ELFIO_GET_SET_ACCESS_DECL( Elf_Half, segments_num ); |
|||
ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, segments_offset ); |
|||
ELFIO_GET_SET_ACCESS_DECL( Elf_Half, section_name_str_index ); |
|||
}; |
|||
|
|||
/**
|
|||
* @struct elf_header_impl_types |
|||
* @brief Template specialization for ELF header implementation types. |
|||
*/ |
|||
template <class T> struct elf_header_impl_types; |
|||
template <> struct elf_header_impl_types<Elf32_Ehdr> |
|||
{ |
|||
using Phdr_type = Elf32_Phdr; |
|||
using Shdr_type = Elf32_Shdr; |
|||
static const unsigned char file_class = ELFCLASS32; |
|||
}; |
|||
template <> struct elf_header_impl_types<Elf64_Ehdr> |
|||
{ |
|||
using Phdr_type = Elf64_Phdr; |
|||
using Shdr_type = Elf64_Shdr; |
|||
static const unsigned char file_class = ELFCLASS64; |
|||
}; |
|||
|
|||
/**
|
|||
* @class elf_header_impl |
|||
* @brief Template class for ELF header implementation. |
|||
*/ |
|||
template <class T> class elf_header_impl : public elf_header |
|||
{ |
|||
public: |
|||
/**
|
|||
* @brief Constructor. |
|||
* @param convertor Endianness convertor. |
|||
* @param encoding Encoding type. |
|||
* @param translator Address translator. |
|||
*/ |
|||
elf_header_impl( std::shared_ptr<endianness_convertor> convertor, |
|||
unsigned char encoding, |
|||
std::shared_ptr<address_translator> translator ) |
|||
: convertor( convertor ), translator( translator ) |
|||
{ |
|||
header.e_ident[EI_MAG0] = ELFMAG0; |
|||
header.e_ident[EI_MAG1] = ELFMAG1; |
|||
header.e_ident[EI_MAG2] = ELFMAG2; |
|||
header.e_ident[EI_MAG3] = ELFMAG3; |
|||
header.e_ident[EI_CLASS] = elf_header_impl_types<T>::file_class; |
|||
header.e_ident[EI_DATA] = encoding; |
|||
header.e_ident[EI_VERSION] = EV_CURRENT; |
|||
header.e_version = ( *convertor )( (Elf_Word)EV_CURRENT ); |
|||
header.e_ehsize = ( sizeof( header ) ); |
|||
header.e_ehsize = ( *convertor )( header.e_ehsize ); |
|||
header.e_shstrndx = ( *convertor )( (Elf_Half)1 ); |
|||
header.e_phentsize = |
|||
sizeof( typename elf_header_impl_types<T>::Phdr_type ); |
|||
header.e_shentsize = |
|||
sizeof( typename elf_header_impl_types<T>::Shdr_type ); |
|||
header.e_phentsize = ( *convertor )( header.e_phentsize ); |
|||
header.e_shentsize = ( *convertor )( header.e_shentsize ); |
|||
} |
|||
|
|||
/**
|
|||
* @brief Load ELF header from stream. |
|||
* @param stream Input stream. |
|||
* @return True if successful, false otherwise. |
|||
*/ |
|||
bool load( std::istream& stream ) override |
|||
{ |
|||
stream.seekg( ( *translator )[0] ); |
|||
stream.read( reinterpret_cast<char*>( &header ), sizeof( header ) ); |
|||
|
|||
return ( stream.gcount() == sizeof( header ) ); |
|||
} |
|||
|
|||
/**
|
|||
* @brief Save ELF header to stream. |
|||
* @param stream Output stream. |
|||
* @return True if successful, false otherwise. |
|||
*/ |
|||
bool save( std::ostream& stream ) const override |
|||
{ |
|||
stream.seekp( ( *translator )[0] ); |
|||
stream.write( reinterpret_cast<const char*>( &header ), |
|||
sizeof( header ) ); |
|||
|
|||
return stream.good(); |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// ELF header functions
|
|||
ELFIO_GET_ACCESS( unsigned char, class, header.e_ident[EI_CLASS] ); |
|||
ELFIO_GET_ACCESS( unsigned char, elf_version, header.e_ident[EI_VERSION] ); |
|||
ELFIO_GET_ACCESS( unsigned char, encoding, header.e_ident[EI_DATA] ); |
|||
ELFIO_GET_ACCESS( Elf_Half, header_size, header.e_ehsize ); |
|||
ELFIO_GET_ACCESS( Elf_Half, section_entry_size, header.e_shentsize ); |
|||
ELFIO_GET_ACCESS( Elf_Half, segment_entry_size, header.e_phentsize ); |
|||
|
|||
ELFIO_GET_SET_ACCESS( Elf_Word, version, header.e_version ); |
|||
ELFIO_GET_SET_ACCESS( unsigned char, os_abi, header.e_ident[EI_OSABI] ); |
|||
ELFIO_GET_SET_ACCESS( unsigned char, |
|||
abi_version, |
|||
header.e_ident[EI_ABIVERSION] ); |
|||
ELFIO_GET_SET_ACCESS( Elf_Half, type, header.e_type ); |
|||
ELFIO_GET_SET_ACCESS( Elf_Half, machine, header.e_machine ); |
|||
ELFIO_GET_SET_ACCESS( Elf_Word, flags, header.e_flags ); |
|||
ELFIO_GET_SET_ACCESS( Elf_Half, section_name_str_index, header.e_shstrndx ); |
|||
ELFIO_GET_SET_ACCESS( Elf64_Addr, entry, header.e_entry ); |
|||
ELFIO_GET_SET_ACCESS( Elf_Half, sections_num, header.e_shnum ); |
|||
ELFIO_GET_SET_ACCESS( Elf64_Off, sections_offset, header.e_shoff ); |
|||
ELFIO_GET_SET_ACCESS( Elf_Half, segments_num, header.e_phnum ); |
|||
ELFIO_GET_SET_ACCESS( Elf64_Off, segments_offset, header.e_phoff ); |
|||
|
|||
private: |
|||
T header = {}; |
|||
std::shared_ptr<endianness_convertor> convertor = nullptr; |
|||
std::shared_ptr<address_translator> translator = nullptr; |
|||
}; |
|||
|
|||
} // namespace ELFIO
|
|||
|
|||
#endif // ELF_HEADER_HPP
|
|||
@ -0,0 +1,168 @@ |
|||
/*
|
|||
Copyright (C) 2001-present by Serge Lamikhov-Center |
|||
|
|||
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. |
|||
*/ |
|||
|
|||
#ifndef ELFIO_MODINFO_HPP |
|||
#define ELFIO_MODINFO_HPP |
|||
|
|||
#include <string_view> |
|||
#include <vector> |
|||
|
|||
namespace ELFIO { |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
/**
|
|||
* @class modinfo_section_accessor_template |
|||
* @brief A template class to access modinfo section. |
|||
* |
|||
* @tparam S The section type. |
|||
*/ |
|||
template <class S> class modinfo_section_accessor_template |
|||
{ |
|||
public: |
|||
//------------------------------------------------------------------------------
|
|||
/**
|
|||
* @brief Construct a new modinfo section accessor template object. |
|||
* |
|||
* @param section The section to be accessed. |
|||
*/ |
|||
explicit modinfo_section_accessor_template( S* section ) |
|||
: modinfo_section( section ) |
|||
{ |
|||
process_section(); |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
/**
|
|||
* @brief Get the number of attributes. |
|||
* |
|||
* @return Elf_Word The number of attributes. |
|||
*/ |
|||
Elf_Word get_attribute_num() const { return (Elf_Word)content.size(); } |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
/**
|
|||
* @brief Get the attribute by index. |
|||
* |
|||
* @param no The index of the attribute. |
|||
* @param field The field name of the attribute. |
|||
* @param value The value of the attribute. |
|||
* @return true If the attribute is found. |
|||
* @return false If the attribute is not found. |
|||
*/ |
|||
bool |
|||
get_attribute( Elf_Word no, std::string& field, std::string& value ) const |
|||
{ |
|||
if ( no < content.size() ) { |
|||
field = content[no].first; |
|||
value = content[no].second; |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
/**
|
|||
* @brief Get the attribute by field name. |
|||
* |
|||
* @param field_name The field name of the attribute. |
|||
* @param value The value of the attribute. |
|||
* @return true If the attribute is found. |
|||
* @return false If the attribute is not found. |
|||
*/ |
|||
bool get_attribute( const std::string_view& field_name, |
|||
std::string& value ) const |
|||
{ |
|||
for ( const auto& [first, second] : content ) { |
|||
if ( field_name == first ) { |
|||
value = second; |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
/**
|
|||
* @brief Add a new attribute. |
|||
* |
|||
* @param field The field name of the attribute. |
|||
* @param value The value of the attribute. |
|||
* @return Elf_Word The position of the new attribute. |
|||
*/ |
|||
Elf_Word add_attribute( const std::string& field, const std::string& value ) |
|||
{ |
|||
Elf_Word current_position = 0; |
|||
|
|||
if ( modinfo_section ) { |
|||
// Strings are addeded to the end of the current section data
|
|||
current_position = (Elf_Word)modinfo_section->get_size(); |
|||
|
|||
std::string attribute = field + "=" + value; |
|||
|
|||
modinfo_section->append_data( attribute + '\0' ); |
|||
content.emplace_back( field, value ); |
|||
} |
|||
|
|||
return current_position; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
private: |
|||
/**
|
|||
* @brief Process the section to extract attributes. |
|||
*/ |
|||
void process_section() |
|||
{ |
|||
const char* pdata = modinfo_section->get_data(); |
|||
if ( pdata ) { |
|||
ELFIO::Elf_Xword i = 0; |
|||
while ( i < modinfo_section->get_size() ) { |
|||
while ( i < modinfo_section->get_size() && !pdata[i] ) |
|||
i++; |
|||
if ( i < modinfo_section->get_size() ) { |
|||
std::string info = pdata + i; |
|||
size_t loc = info.find( '=' ); |
|||
content.emplace_back( info.substr( 0, loc ), |
|||
info.substr( loc + 1 ) ); |
|||
|
|||
i += info.length(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
private: |
|||
S* modinfo_section; ///< The section to be accessed.
|
|||
std::vector<std::pair<std::string, std::string>> |
|||
content; ///< The list of attributes.
|
|||
}; |
|||
|
|||
using modinfo_section_accessor = modinfo_section_accessor_template<section>; |
|||
using const_modinfo_section_accessor = |
|||
modinfo_section_accessor_template<const section>; |
|||
|
|||
} // namespace ELFIO
|
|||
|
|||
#endif // ELFIO_MODINFO_HPP
|
|||
@ -0,0 +1,208 @@ |
|||
/*
|
|||
Copyright (C) 2001-present by Serge Lamikhov-Center |
|||
|
|||
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. |
|||
*/ |
|||
|
|||
#ifndef ELFIO_NOTE_HPP |
|||
#define ELFIO_NOTE_HPP |
|||
|
|||
namespace ELFIO { |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// There are discrepancies in documentations. SCO documentation
|
|||
// (http://www.sco.com/developers/gabi/latest/ch5.pheader.html#note_section)
|
|||
// requires 8 byte entries alignment for 64-bit ELF file,
|
|||
// but Oracle's definition uses the same structure
|
|||
// for 32-bit and 64-bit formats.
|
|||
// (https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-18048.html)
|
|||
//
|
|||
// It looks like EM_X86_64 Linux implementation is similar to Oracle's
|
|||
// definition. Therefore, the same alignment works for both formats
|
|||
//------------------------------------------------------------------------------
|
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \class note_section_accessor_template
|
|||
//! \brief Class for accessing note section data
|
|||
template <class S, Elf_Xword ( S::*F_get_size )() const> |
|||
class note_section_accessor_template |
|||
{ |
|||
public: |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Constructor
|
|||
//! \param elf_file Reference to the ELF file
|
|||
//! \param section Pointer to the section
|
|||
explicit note_section_accessor_template( const elfio& elf_file, S* section ) |
|||
: elf_file( elf_file ), notes( section ) |
|||
{ |
|||
process_section(); |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the number of notes
|
|||
//! \return Number of notes
|
|||
Elf_Word get_notes_num() const |
|||
{ |
|||
return (Elf_Word)note_start_positions.size(); |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get a note
|
|||
//! \param index Index of the note
|
|||
//! \param type Type of the note
|
|||
//! \param name Name of the note
|
|||
//! \param desc Pointer to the descriptor
|
|||
//! \param descSize Size of the descriptor
|
|||
//! \return True if successful, false otherwise
|
|||
bool get_note( Elf_Word index, |
|||
Elf_Word& type, |
|||
std::string& name, |
|||
char*& desc, |
|||
Elf_Word& descSize ) const |
|||
{ |
|||
if ( index >= ( notes->*F_get_size )() ) { |
|||
return false; |
|||
} |
|||
|
|||
const char* pData = notes->get_data() + note_start_positions[index]; |
|||
int align = sizeof( Elf_Word ); |
|||
|
|||
const auto& convertor = elf_file.get_convertor(); |
|||
type = |
|||
( *convertor )( *(const Elf_Word*)( pData + 2 * (size_t)align ) ); |
|||
Elf_Word namesz = ( *convertor )( *(const Elf_Word*)( pData ) ); |
|||
descSize = |
|||
( *convertor )( *(const Elf_Word*)( pData + sizeof( namesz ) ) ); |
|||
|
|||
Elf_Xword max_name_size = |
|||
( notes->*F_get_size )() - note_start_positions[index]; |
|||
if ( namesz < 1 || namesz > max_name_size || |
|||
(Elf_Xword)namesz + descSize > max_name_size ) { |
|||
return false; |
|||
} |
|||
name.assign( pData + 3 * (size_t)align, namesz - 1 ); |
|||
if ( 0 == descSize ) { |
|||
desc = nullptr; |
|||
} |
|||
else { |
|||
desc = const_cast<char*>( pData + 3 * (size_t)align + |
|||
( ( namesz + align - 1 ) / align ) * |
|||
(size_t)align ); |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Add a note
|
|||
//! \param type Type of the note
|
|||
//! \param name Name of the note
|
|||
//! \param desc Pointer to the descriptor
|
|||
//! \param descSize Size of the descriptor
|
|||
void add_note( Elf_Word type, |
|||
const std::string& name, |
|||
const char* desc, |
|||
Elf_Word descSize ) |
|||
{ |
|||
const auto& convertor = elf_file.get_convertor(); |
|||
|
|||
int align = sizeof( Elf_Word ); |
|||
Elf_Word nameLen = (Elf_Word)name.size() + 1; |
|||
Elf_Word nameLenConv = ( *convertor )( nameLen ); |
|||
std::string buffer( reinterpret_cast<char*>( &nameLenConv ), align ); |
|||
Elf_Word descSizeConv = ( *convertor )( descSize ); |
|||
|
|||
buffer.append( reinterpret_cast<char*>( &descSizeConv ), align ); |
|||
type = ( *convertor )( type ); |
|||
buffer.append( reinterpret_cast<char*>( &type ), align ); |
|||
buffer.append( name ); |
|||
buffer.append( 1, '\x00' ); |
|||
const char pad[] = { '\0', '\0', '\0', '\0' }; |
|||
if ( nameLen % align != 0 ) { |
|||
buffer.append( pad, (size_t)align - nameLen % align ); |
|||
} |
|||
if ( desc != nullptr && descSize != 0 ) { |
|||
buffer.append( desc, descSize ); |
|||
if ( descSize % align != 0 ) { |
|||
buffer.append( pad, (size_t)align - descSize % align ); |
|||
} |
|||
} |
|||
|
|||
note_start_positions.emplace_back( ( notes->*F_get_size )() ); |
|||
notes->append_data( buffer ); |
|||
} |
|||
|
|||
private: |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Process the section to extract note start positions
|
|||
void process_section() |
|||
{ |
|||
const auto& convertor = elf_file.get_convertor(); |
|||
const char* data = notes->get_data(); |
|||
Elf_Xword size = ( notes->*F_get_size )(); |
|||
Elf_Xword current = 0; |
|||
|
|||
note_start_positions.clear(); |
|||
|
|||
// Is it empty?
|
|||
if ( nullptr == data || 0 == size ) { |
|||
return; |
|||
} |
|||
|
|||
Elf_Word align = sizeof( Elf_Word ); |
|||
while ( current + (Elf_Xword)3 * align <= size ) { |
|||
Elf_Word namesz = |
|||
( *convertor )( *(const Elf_Word*)( data + current ) ); |
|||
Elf_Word descsz = ( *convertor )( |
|||
*(const Elf_Word*)( data + current + sizeof( namesz ) ) ); |
|||
Elf_Word advance = |
|||
(Elf_Xword)3 * sizeof( Elf_Word ) + |
|||
( ( namesz + align - 1 ) / align ) * (Elf_Xword)align + |
|||
( ( descsz + align - 1 ) / align ) * (Elf_Xword)align; |
|||
if ( namesz < size && descsz < size && current + advance <= size ) { |
|||
note_start_positions.emplace_back( current ); |
|||
} |
|||
else { |
|||
break; |
|||
} |
|||
|
|||
current += advance; |
|||
} |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
private: |
|||
const elfio& elf_file; //!< Reference to the ELF file
|
|||
S* notes; //!< Pointer to the section or segment
|
|||
std::vector<Elf_Xword> |
|||
note_start_positions; //!< Vector of note start positions
|
|||
}; |
|||
|
|||
using note_section_accessor = |
|||
note_section_accessor_template<section, §ion::get_size>; |
|||
using const_note_section_accessor = |
|||
note_section_accessor_template<const section, §ion::get_size>; |
|||
using note_segment_accessor = |
|||
note_section_accessor_template<segment, &segment::get_file_size>; |
|||
using const_note_segment_accessor = |
|||
note_section_accessor_template<const segment, &segment::get_file_size>; |
|||
|
|||
} // namespace ELFIO
|
|||
|
|||
#endif // ELFIO_NOTE_HPP
|
|||
@ -0,0 +1,596 @@ |
|||
/*
|
|||
Copyright (C) 2001-present by Serge Lamikhov-Center |
|||
|
|||
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. |
|||
*/ |
|||
|
|||
#ifndef ELFIO_RELOCATION_HPP |
|||
#define ELFIO_RELOCATION_HPP |
|||
|
|||
namespace ELFIO { |
|||
|
|||
template <typename T> struct get_sym_and_type; |
|||
template <> struct get_sym_and_type<Elf32_Rel> |
|||
{ |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the symbol from the relocation info
|
|||
//! \param info Relocation info
|
|||
//! \return Symbol
|
|||
static int get_r_sym( Elf_Xword info ) |
|||
{ |
|||
return ELF32_R_SYM( (Elf_Word)info ); |
|||
} |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the type from the relocation info
|
|||
//! \param info Relocation info
|
|||
//! \return Type
|
|||
static int get_r_type( Elf_Xword info ) |
|||
{ |
|||
return ELF32_R_TYPE( (Elf_Word)info ); |
|||
} |
|||
}; |
|||
template <> struct get_sym_and_type<Elf32_Rela> |
|||
{ |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the symbol from the relocation info
|
|||
//! \param info Relocation info
|
|||
//! \return Symbol
|
|||
static int get_r_sym( Elf_Xword info ) |
|||
{ |
|||
return ELF32_R_SYM( (Elf_Word)info ); |
|||
} |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the type from the relocation info
|
|||
//! \param info Relocation info
|
|||
//! \return Type
|
|||
static int get_r_type( Elf_Xword info ) |
|||
{ |
|||
return ELF32_R_TYPE( (Elf_Word)info ); |
|||
} |
|||
}; |
|||
template <> struct get_sym_and_type<Elf64_Rel> |
|||
{ |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the symbol from the relocation info
|
|||
//! \param info Relocation info
|
|||
//! \return Symbol
|
|||
static int get_r_sym( Elf_Xword info ) { return ELF64_R_SYM( info ); } |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the type from the relocation info
|
|||
//! \param info Relocation info
|
|||
//! \return Type
|
|||
static int get_r_type( Elf_Xword info ) { return ELF64_R_TYPE( info ); } |
|||
}; |
|||
template <> struct get_sym_and_type<Elf64_Rela> |
|||
{ |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the symbol from the relocation info
|
|||
//! \param info Relocation info
|
|||
//! \return Symbol
|
|||
static int get_r_sym( Elf_Xword info ) { return ELF64_R_SYM( info ); } |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the type from the relocation info
|
|||
//! \param info Relocation info
|
|||
//! \return Type
|
|||
static int get_r_type( Elf_Xword info ) { return ELF64_R_TYPE( info ); } |
|||
}; |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \class relocation_section_accessor_template
|
|||
//! \brief Class for accessing relocation section data
|
|||
template <class S> class relocation_section_accessor_template |
|||
{ |
|||
public: |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Constructor
|
|||
//! \param elf_file Reference to the ELF file
|
|||
//! \param section Pointer to the section
|
|||
explicit relocation_section_accessor_template( const elfio& elf_file, |
|||
S* section ) |
|||
: elf_file( elf_file ), relocation_section( section ) |
|||
{ |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the number of entries
|
|||
//! \return Number of entries
|
|||
Elf_Xword get_entries_num() const |
|||
{ |
|||
Elf_Xword nRet = 0; |
|||
|
|||
if ( 0 != relocation_section->get_entry_size() ) { |
|||
nRet = relocation_section->get_size() / |
|||
relocation_section->get_entry_size(); |
|||
} |
|||
|
|||
return nRet; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get an entry
|
|||
//! \param index Index of the entry
|
|||
//! \param offset Offset of the entry
|
|||
//! \param symbol Symbol of the entry
|
|||
//! \param type Type of the entry
|
|||
//! \param addend Addend of the entry
|
|||
//! \return True if successful, false otherwise
|
|||
bool get_entry( Elf_Xword index, |
|||
Elf64_Addr& offset, |
|||
Elf_Word& symbol, |
|||
unsigned& type, |
|||
Elf_Sxword& addend ) const |
|||
{ |
|||
if ( index >= get_entries_num() ) { // Is index valid
|
|||
return false; |
|||
} |
|||
|
|||
if ( elf_file.get_class() == ELFCLASS32 ) { |
|||
if ( SHT_REL == relocation_section->get_type() ) { |
|||
return generic_get_entry_rel<Elf32_Rel>( index, offset, symbol, |
|||
type, addend ); |
|||
} |
|||
else if ( SHT_RELA == relocation_section->get_type() ) { |
|||
return generic_get_entry_rela<Elf32_Rela>( |
|||
index, offset, symbol, type, addend ); |
|||
} |
|||
} |
|||
else { |
|||
if ( SHT_REL == relocation_section->get_type() ) { |
|||
return generic_get_entry_rel<Elf64_Rel>( index, offset, symbol, |
|||
type, addend ); |
|||
} |
|||
else if ( SHT_RELA == relocation_section->get_type() ) { |
|||
return generic_get_entry_rela<Elf64_Rela>( |
|||
index, offset, symbol, type, addend ); |
|||
} |
|||
} |
|||
// Unknown relocation section type.
|
|||
return false; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get an entry with additional information
|
|||
//! \param index Index of the entry
|
|||
//! \param offset Offset of the entry
|
|||
//! \param symbolValue Value of the symbol
|
|||
//! \param symbolName Name of the symbol
|
|||
//! \param type Type of the entry
|
|||
//! \param addend Addend of the entry
|
|||
//! \param calcValue Calculated value
|
|||
//! \return True if successful, false otherwise
|
|||
bool get_entry( Elf_Xword index, |
|||
Elf64_Addr& offset, |
|||
Elf64_Addr& symbolValue, |
|||
std::string& symbolName, |
|||
unsigned& type, |
|||
Elf_Sxword& addend, |
|||
Elf_Sxword& calcValue ) const |
|||
{ |
|||
// Do regular job
|
|||
Elf_Word symbol = 0; |
|||
bool ret = get_entry( index, offset, symbol, type, addend ); |
|||
|
|||
// Find the symbol
|
|||
Elf_Xword size; |
|||
unsigned char bind; |
|||
unsigned char symbolType; |
|||
Elf_Half section; |
|||
unsigned char other; |
|||
|
|||
symbol_section_accessor symbols( |
|||
elf_file, elf_file.sections[get_symbol_table_index()] ); |
|||
ret = ret && symbols.get_symbol( symbol, symbolName, symbolValue, size, |
|||
bind, symbolType, section, other ); |
|||
|
|||
if ( ret ) { // Was it successful?
|
|||
switch ( type ) { |
|||
case R_386_NONE: // none
|
|||
calcValue = 0; |
|||
break; |
|||
case R_386_32: // S + A
|
|||
calcValue = symbolValue + addend; |
|||
break; |
|||
case R_386_PC32: // S + A - P
|
|||
calcValue = symbolValue + addend - offset; |
|||
break; |
|||
case R_386_GOT32: // G + A - P
|
|||
calcValue = 0; |
|||
break; |
|||
case R_386_PLT32: // L + A - P
|
|||
calcValue = 0; |
|||
break; |
|||
case R_386_COPY: // none
|
|||
calcValue = 0; |
|||
break; |
|||
case R_386_GLOB_DAT: // S
|
|||
case R_386_JMP_SLOT: // S
|
|||
calcValue = symbolValue; |
|||
break; |
|||
case R_386_RELATIVE: // B + A
|
|||
calcValue = addend; |
|||
break; |
|||
case R_386_GOTOFF: // S + A - GOT
|
|||
calcValue = 0; |
|||
break; |
|||
case R_386_GOTPC: // GOT + A - P
|
|||
calcValue = 0; |
|||
break; |
|||
default: // Not recognized symbol!
|
|||
calcValue = 0; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
return ret; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Set an entry
|
|||
//! \param index Index of the entry
|
|||
//! \param offset Offset of the entry
|
|||
//! \param symbol Symbol of the entry
|
|||
//! \param type Type of the entry
|
|||
//! \param addend Addend of the entry
|
|||
//! \return True if successful, false otherwise
|
|||
bool set_entry( Elf_Xword index, |
|||
Elf64_Addr offset, |
|||
Elf_Word symbol, |
|||
unsigned type, |
|||
Elf_Sxword addend ) |
|||
{ |
|||
if ( index >= get_entries_num() ) { // Is index valid
|
|||
return false; |
|||
} |
|||
|
|||
if ( elf_file.get_class() == ELFCLASS32 ) { |
|||
if ( SHT_REL == relocation_section->get_type() ) { |
|||
generic_set_entry_rel<Elf32_Rel>( index, offset, symbol, type, |
|||
addend ); |
|||
} |
|||
else if ( SHT_RELA == relocation_section->get_type() ) { |
|||
generic_set_entry_rela<Elf32_Rela>( index, offset, symbol, type, |
|||
addend ); |
|||
} |
|||
} |
|||
else { |
|||
if ( SHT_REL == relocation_section->get_type() ) { |
|||
generic_set_entry_rel<Elf64_Rel>( index, offset, symbol, type, |
|||
addend ); |
|||
} |
|||
else if ( SHT_RELA == relocation_section->get_type() ) { |
|||
generic_set_entry_rela<Elf64_Rela>( index, offset, symbol, type, |
|||
addend ); |
|||
} |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Add an entry
|
|||
//! \param offset Offset of the entry
|
|||
//! \param info Information of the entry
|
|||
void add_entry( Elf64_Addr offset, Elf_Xword info ) |
|||
{ |
|||
if ( elf_file.get_class() == ELFCLASS32 ) { |
|||
generic_add_entry<Elf32_Rel>( offset, info ); |
|||
} |
|||
else { |
|||
generic_add_entry<Elf64_Rel>( offset, info ); |
|||
} |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Add an entry
|
|||
//! \param offset Offset of the entry
|
|||
//! \param symbol Symbol of the entry
|
|||
//! \param type Type of the entry
|
|||
void add_entry( Elf64_Addr offset, Elf_Word symbol, unsigned type ) |
|||
{ |
|||
Elf_Xword info; |
|||
if ( elf_file.get_class() == ELFCLASS32 ) { |
|||
info = ELF32_R_INFO( (Elf_Xword)symbol, type ); |
|||
} |
|||
else { |
|||
info = ELF64_R_INFO( (Elf_Xword)symbol, type ); |
|||
} |
|||
|
|||
add_entry( offset, info ); |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Add an entry
|
|||
//! \param offset Offset of the entry
|
|||
//! \param info Information of the entry
|
|||
//! \param addend Addend of the entry
|
|||
void add_entry( Elf64_Addr offset, Elf_Xword info, Elf_Sxword addend ) |
|||
{ |
|||
if ( elf_file.get_class() == ELFCLASS32 ) { |
|||
generic_add_entry<Elf32_Rela>( offset, info, addend ); |
|||
} |
|||
else { |
|||
generic_add_entry<Elf64_Rela>( offset, info, addend ); |
|||
} |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Add an entry
|
|||
//! \param offset Offset of the entry
|
|||
//! \param symbol Symbol of the entry
|
|||
//! \param type Type of the entry
|
|||
//! \param addend Addend of the entry
|
|||
void add_entry( Elf64_Addr offset, |
|||
Elf_Word symbol, |
|||
unsigned type, |
|||
Elf_Sxword addend ) |
|||
{ |
|||
Elf_Xword info; |
|||
if ( elf_file.get_class() == ELFCLASS32 ) { |
|||
info = ELF32_R_INFO( (Elf_Xword)symbol, type ); |
|||
} |
|||
else { |
|||
info = ELF64_R_INFO( (Elf_Xword)symbol, type ); |
|||
} |
|||
|
|||
add_entry( offset, info, addend ); |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Add an entry with additional information
|
|||
//! \param str_writer String section accessor
|
|||
//! \param str String
|
|||
//! \param sym_writer Symbol section accessor
|
|||
//! \param value Value of the symbol
|
|||
//! \param size Size of the symbol
|
|||
//! \param sym_info Symbol information
|
|||
//! \param other Other information
|
|||
//! \param shndx Section index
|
|||
//! \param offset Offset of the entry
|
|||
//! \param type Type of the entry
|
|||
void add_entry( string_section_accessor str_writer, |
|||
const char* str, |
|||
symbol_section_accessor sym_writer, |
|||
Elf64_Addr value, |
|||
Elf_Word size, |
|||
unsigned char sym_info, |
|||
unsigned char other, |
|||
Elf_Half shndx, |
|||
Elf64_Addr offset, |
|||
unsigned type ) |
|||
{ |
|||
Elf_Word str_index = str_writer.add_string( str ); |
|||
Elf_Word sym_index = sym_writer.add_symbol( str_index, value, size, |
|||
sym_info, other, shndx ); |
|||
add_entry( offset, sym_index, type ); |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Swap symbols
|
|||
//! \param first First symbol
|
|||
//! \param second Second symbol
|
|||
void swap_symbols( Elf_Xword first, Elf_Xword second ) |
|||
{ |
|||
Elf64_Addr offset = 0; |
|||
Elf_Word symbol = 0; |
|||
unsigned rtype = 0; |
|||
Elf_Sxword addend = 0; |
|||
for ( Elf_Word i = 0; i < get_entries_num(); i++ ) { |
|||
get_entry( i, offset, symbol, rtype, addend ); |
|||
if ( symbol == first ) { |
|||
set_entry( i, offset, (Elf_Word)second, rtype, addend ); |
|||
} |
|||
if ( symbol == second ) { |
|||
set_entry( i, offset, (Elf_Word)first, rtype, addend ); |
|||
} |
|||
} |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
private: |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the symbol table index
|
|||
//! \return Symbol table index
|
|||
Elf_Half get_symbol_table_index() const |
|||
{ |
|||
return (Elf_Half)relocation_section->get_link(); |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get a generic entry for REL type
|
|||
//! \param index Index of the entry
|
|||
//! \param offset Offset of the entry
|
|||
//! \param symbol Symbol of the entry
|
|||
//! \param type Type of the entry
|
|||
//! \param addend Addend of the entry
|
|||
//! \return True if successful, false otherwise
|
|||
template <class T> |
|||
bool generic_get_entry_rel( Elf_Xword index, |
|||
Elf64_Addr& offset, |
|||
Elf_Word& symbol, |
|||
unsigned& type, |
|||
Elf_Sxword& addend ) const |
|||
{ |
|||
const auto& convertor = elf_file.get_convertor(); |
|||
|
|||
if ( relocation_section->get_entry_size() < sizeof( T ) ) { |
|||
return false; |
|||
} |
|||
const T* pEntry = reinterpret_cast<const T*>( |
|||
relocation_section->get_data() + |
|||
index * relocation_section->get_entry_size() ); |
|||
offset = ( *convertor )( pEntry->r_offset ); |
|||
Elf_Xword tmp = ( *convertor )( pEntry->r_info ); |
|||
symbol = get_sym_and_type<T>::get_r_sym( tmp ); |
|||
type = get_sym_and_type<T>::get_r_type( tmp ); |
|||
addend = 0; |
|||
return true; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get a generic entry for RELA type
|
|||
//! \param index Index of the entry
|
|||
//! \param offset Offset of the entry
|
|||
//! \param symbol Symbol of the entry
|
|||
//! \param type Type of the entry
|
|||
//! \param addend Addend of the entry
|
|||
//! \return True if successful, false otherwise
|
|||
template <class T> |
|||
bool generic_get_entry_rela( Elf_Xword index, |
|||
Elf64_Addr& offset, |
|||
Elf_Word& symbol, |
|||
unsigned& type, |
|||
Elf_Sxword& addend ) const |
|||
{ |
|||
const auto& convertor = elf_file.get_convertor(); |
|||
|
|||
if ( relocation_section->get_entry_size() < sizeof( T ) ) { |
|||
return false; |
|||
} |
|||
|
|||
const T* pEntry = reinterpret_cast<const T*>( |
|||
relocation_section->get_data() + |
|||
index * relocation_section->get_entry_size() ); |
|||
offset = ( *convertor )( pEntry->r_offset ); |
|||
Elf_Xword tmp = ( *convertor )( pEntry->r_info ); |
|||
symbol = get_sym_and_type<T>::get_r_sym( tmp ); |
|||
type = get_sym_and_type<T>::get_r_type( tmp ); |
|||
addend = ( *convertor )( pEntry->r_addend ); |
|||
return true; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Set a generic entry for REL type
|
|||
//! \param index Index of the entry
|
|||
//! \param offset Offset of the entry
|
|||
//! \param symbol Symbol of the entry
|
|||
//! \param type Type of the entry
|
|||
//! \param addend Addend of the entry
|
|||
template <class T> |
|||
void generic_set_entry_rel( Elf_Xword index, |
|||
Elf64_Addr offset, |
|||
Elf_Word symbol, |
|||
unsigned type, |
|||
Elf_Sxword ) |
|||
{ |
|||
const auto& convertor = elf_file.get_convertor(); |
|||
|
|||
T* pEntry = const_cast<T*>( reinterpret_cast<const T*>( |
|||
relocation_section->get_data() + |
|||
index * relocation_section->get_entry_size() ) ); |
|||
|
|||
if ( elf_file.get_class() == ELFCLASS32 ) { |
|||
pEntry->r_info = ELF32_R_INFO( (Elf_Xword)symbol, type ); |
|||
} |
|||
else { |
|||
pEntry->r_info = ELF64_R_INFO( (Elf_Xword)symbol, type ); |
|||
} |
|||
pEntry->r_offset = decltype( pEntry->r_offset )( offset ); |
|||
pEntry->r_offset = ( *convertor )( pEntry->r_offset ); |
|||
pEntry->r_info = ( *convertor )( pEntry->r_info ); |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Set a generic entry for RELA type
|
|||
//! \param index Index of the entry
|
|||
//! \param offset Offset of the entry
|
|||
//! \param symbol Symbol of the entry
|
|||
//! \param type Type of the entry
|
|||
//! \param addend Addend of the entry
|
|||
template <class T> |
|||
void generic_set_entry_rela( Elf_Xword index, |
|||
Elf64_Addr offset, |
|||
Elf_Word symbol, |
|||
unsigned type, |
|||
Elf_Sxword addend ) |
|||
{ |
|||
const auto& convertor = elf_file.get_convertor(); |
|||
|
|||
T* pEntry = const_cast<T*>( reinterpret_cast<const T*>( |
|||
relocation_section->get_data() + |
|||
index * relocation_section->get_entry_size() ) ); |
|||
|
|||
if ( elf_file.get_class() == ELFCLASS32 ) { |
|||
pEntry->r_info = ELF32_R_INFO( (Elf_Xword)symbol, type ); |
|||
} |
|||
else { |
|||
pEntry->r_info = ELF64_R_INFO( (Elf_Xword)symbol, type ); |
|||
} |
|||
pEntry->r_offset = decltype( pEntry->r_offset )( offset ); |
|||
pEntry->r_addend = decltype( pEntry->r_addend )( addend ); |
|||
pEntry->r_offset = ( *convertor )( pEntry->r_offset ); |
|||
pEntry->r_info = ( *convertor )( pEntry->r_info ); |
|||
pEntry->r_addend = ( *convertor )( pEntry->r_addend ); |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Add a generic entry for REL type
|
|||
//! \param offset Offset of the entry
|
|||
//! \param info Information of the entry
|
|||
template <class T> |
|||
void generic_add_entry( Elf64_Addr offset, Elf_Xword info ) |
|||
{ |
|||
const auto& convertor = elf_file.get_convertor(); |
|||
|
|||
T entry; |
|||
entry.r_offset = decltype( entry.r_offset )( offset ); |
|||
entry.r_info = decltype( entry.r_info )( info ); |
|||
entry.r_offset = ( *convertor )( entry.r_offset ); |
|||
entry.r_info = ( *convertor )( entry.r_info ); |
|||
|
|||
relocation_section->append_data( reinterpret_cast<char*>( &entry ), |
|||
sizeof( entry ) ); |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Add a generic entry for RELA type
|
|||
//! \param offset Offset of the entry
|
|||
//! \param info Information of the entry
|
|||
//! \param addend Addend of the entry
|
|||
template <class T> |
|||
void |
|||
generic_add_entry( Elf64_Addr offset, Elf_Xword info, Elf_Sxword addend ) |
|||
{ |
|||
const auto& convertor = elf_file.get_convertor(); |
|||
|
|||
T entry; |
|||
entry.r_offset = offset; |
|||
entry.r_info = info; |
|||
entry.r_addend = addend; |
|||
entry.r_offset = ( *convertor )( entry.r_offset ); |
|||
entry.r_info = ( *convertor )( entry.r_info ); |
|||
entry.r_addend = ( *convertor )( entry.r_addend ); |
|||
|
|||
relocation_section->append_data( reinterpret_cast<char*>( &entry ), |
|||
sizeof( entry ) ); |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
private: |
|||
const elfio& elf_file; |
|||
S* relocation_section = nullptr; |
|||
}; |
|||
|
|||
using relocation_section_accessor = |
|||
relocation_section_accessor_template<section>; |
|||
using const_relocation_section_accessor = |
|||
relocation_section_accessor_template<const section>; |
|||
|
|||
} // namespace ELFIO
|
|||
|
|||
#endif // ELFIO_RELOCATION_HPP
|
|||
@ -0,0 +1,611 @@ |
|||
/*
|
|||
Copyright (C) 2001-present by Serge Lamikhov-Center |
|||
|
|||
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. |
|||
*/ |
|||
|
|||
#ifndef ELFIO_SECTION_HPP |
|||
#define ELFIO_SECTION_HPP |
|||
|
|||
#include <string> |
|||
#include <iostream> |
|||
#include <new> |
|||
#include <limits> |
|||
|
|||
namespace ELFIO { |
|||
|
|||
/**
|
|||
* @class section |
|||
* @brief Represents a section in an ELF file. |
|||
*/ |
|||
class section |
|||
{ |
|||
friend class elfio; |
|||
|
|||
public: |
|||
virtual ~section() = default; |
|||
|
|||
ELFIO_GET_ACCESS_DECL( Elf_Half, index ); |
|||
ELFIO_GET_SET_ACCESS_DECL( std::string, name ); |
|||
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, type ); |
|||
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, flags ); |
|||
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, info ); |
|||
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, link ); |
|||
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, addr_align ); |
|||
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, entry_size ); |
|||
ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, address ); |
|||
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, size ); |
|||
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, name_string_offset ); |
|||
ELFIO_GET_ACCESS_DECL( Elf64_Off, offset ); |
|||
|
|||
/**
|
|||
* @brief Get the data of the section. |
|||
* @return Pointer to the data. |
|||
*/ |
|||
virtual const char* get_data() const = 0; |
|||
|
|||
/**
|
|||
* @brief Free the data of the section. |
|||
*/ |
|||
virtual void free_data() const = 0; |
|||
|
|||
/**
|
|||
* @brief Set the data of the section. |
|||
* @param raw_data Pointer to the raw data. |
|||
* @param size Size of the data. |
|||
*/ |
|||
virtual void set_data( const char* raw_data, Elf_Xword size ) = 0; |
|||
|
|||
/**
|
|||
* @brief Set the data of the section. |
|||
* @param data String containing the data. |
|||
*/ |
|||
virtual void set_data( const std::string& data ) = 0; |
|||
|
|||
/**
|
|||
* @brief Append data to the section. |
|||
* @param raw_data Pointer to the raw data. |
|||
* @param size Size of the data. |
|||
*/ |
|||
virtual void append_data( const char* raw_data, Elf_Xword size ) = 0; |
|||
|
|||
/**
|
|||
* @brief Append data to the section. |
|||
* @param data String containing the data. |
|||
*/ |
|||
virtual void append_data( const std::string& data ) = 0; |
|||
|
|||
/**
|
|||
* @brief Insert data into the section at a specific position. |
|||
* @param pos Position to insert the data. |
|||
* @param raw_data Pointer to the raw data. |
|||
* @param size Size of the data. |
|||
*/ |
|||
virtual void |
|||
insert_data( Elf_Xword pos, const char* raw_data, Elf_Xword size ) = 0; |
|||
|
|||
/**
|
|||
* @brief Insert data into the section at a specific position. |
|||
* @param pos Position to insert the data. |
|||
* @param data String containing the data. |
|||
*/ |
|||
virtual void insert_data( Elf_Xword pos, const std::string& data ) = 0; |
|||
|
|||
/**
|
|||
* @brief Get the size of the stream. |
|||
* @return Size of the stream. |
|||
*/ |
|||
virtual size_t get_stream_size() const = 0; |
|||
|
|||
/**
|
|||
* @brief Set the size of the stream. |
|||
* @param value Size of the stream. |
|||
*/ |
|||
virtual void set_stream_size( size_t value ) = 0; |
|||
|
|||
protected: |
|||
ELFIO_SET_ACCESS_DECL( Elf64_Off, offset ); |
|||
ELFIO_SET_ACCESS_DECL( Elf_Half, index ); |
|||
|
|||
/**
|
|||
* @brief Load the section from a stream. |
|||
* @param stream Input stream. |
|||
* @param header_offset Offset of the header. |
|||
* @param is_lazy Whether to load lazily. |
|||
* @return True if successful, false otherwise. |
|||
*/ |
|||
virtual bool load( std::istream& stream, |
|||
std::streampos header_offset, |
|||
bool is_lazy ) = 0; |
|||
|
|||
/**
|
|||
* @brief Save the section to a stream. |
|||
* @param stream Output stream. |
|||
* @param header_offset Offset of the header. |
|||
* @param data_offset Offset of the data. |
|||
*/ |
|||
virtual void save( std::ostream& stream, |
|||
std::streampos header_offset, |
|||
std::streampos data_offset ) = 0; |
|||
|
|||
/**
|
|||
* @brief Check if the address is initialized. |
|||
* @return True if initialized, false otherwise. |
|||
*/ |
|||
virtual bool is_address_initialized() const = 0; |
|||
}; |
|||
|
|||
/**
|
|||
* @class section_impl |
|||
* @brief Implementation of the section class. |
|||
* @tparam T Type of the section header. |
|||
*/ |
|||
template <class T> class section_impl : public section |
|||
{ |
|||
public: |
|||
/**
|
|||
* @brief Constructor. |
|||
* @param convertor Pointer to the endianness convertor. |
|||
* @param translator Pointer to the address translator. |
|||
* @param compression Shared pointer to the compression interface. |
|||
*/ |
|||
section_impl( std::shared_ptr<endianness_convertor> convertor, |
|||
std::shared_ptr<address_translator> translator, |
|||
std::shared_ptr<compression_interface> compression ) |
|||
: convertor( convertor ), translator( translator ), |
|||
compression( compression ) |
|||
{ |
|||
} |
|||
|
|||
// Section info functions
|
|||
ELFIO_GET_SET_ACCESS( Elf_Word, type, header.sh_type ); |
|||
ELFIO_GET_SET_ACCESS( Elf_Xword, flags, header.sh_flags ); |
|||
ELFIO_GET_SET_ACCESS( Elf_Xword, size, header.sh_size ); |
|||
ELFIO_GET_SET_ACCESS( Elf_Word, link, header.sh_link ); |
|||
ELFIO_GET_SET_ACCESS( Elf_Word, info, header.sh_info ); |
|||
ELFIO_GET_SET_ACCESS( Elf_Xword, addr_align, header.sh_addralign ); |
|||
ELFIO_GET_SET_ACCESS( Elf_Xword, entry_size, header.sh_entsize ); |
|||
ELFIO_GET_SET_ACCESS( Elf_Word, name_string_offset, header.sh_name ); |
|||
ELFIO_GET_ACCESS( Elf64_Addr, address, header.sh_addr ); |
|||
|
|||
/**
|
|||
* @brief Get the index of the section. |
|||
* @return Index of the section. |
|||
*/ |
|||
Elf_Half get_index() const override { return index; } |
|||
|
|||
/**
|
|||
* @brief Get the name of the section. |
|||
* @return Name of the section. |
|||
*/ |
|||
std::string get_name() const override { return name; } |
|||
|
|||
/**
|
|||
* @brief Set the name of the section. |
|||
* @param name_prm Name of the section. |
|||
*/ |
|||
void set_name( const std::string& name_prm ) override |
|||
{ |
|||
this->name = name_prm; |
|||
} |
|||
|
|||
/**
|
|||
* @brief Set the address of the section. |
|||
* @param value Address of the section. |
|||
*/ |
|||
void set_address( const Elf64_Addr& value ) override |
|||
{ |
|||
header.sh_addr = decltype( header.sh_addr )( value ); |
|||
header.sh_addr = ( *convertor )( header.sh_addr ); |
|||
is_address_set = true; |
|||
} |
|||
|
|||
/**
|
|||
* @brief Check if the address is initialized. |
|||
* @return True if initialized, false otherwise. |
|||
*/ |
|||
bool is_address_initialized() const override { return is_address_set; } |
|||
|
|||
/**
|
|||
* @brief Get the data of the section. |
|||
* @return Pointer to the data. |
|||
*/ |
|||
const char* get_data() const override |
|||
{ |
|||
// If data load failed, the stream is corrupt
|
|||
// When lazy loading, attempts to call get_data() on it after initial load are useless
|
|||
// When loading non-lazily, that load_data() will attempt to read data from
|
|||
// the stream specified on load() call, which might be freed by this point
|
|||
if ( !is_loaded && can_be_loaded ) { |
|||
bool res = load_data(); |
|||
|
|||
if ( !res ) { |
|||
can_be_loaded = false; |
|||
} |
|||
} |
|||
return data.get(); |
|||
} |
|||
|
|||
/**
|
|||
* @brief Free the data of the section. |
|||
*/ |
|||
void free_data() const override |
|||
{ |
|||
if ( is_lazy ) { |
|||
data.reset( nullptr ); |
|||
is_loaded = false; |
|||
} |
|||
} |
|||
|
|||
/**
|
|||
* @brief Set the data of the section. |
|||
* @param raw_data Pointer to the raw data. |
|||
* @param size Size of the data. |
|||
*/ |
|||
void set_data( const char* raw_data, Elf_Xword size ) override |
|||
{ |
|||
if ( get_type() != SHT_NOBITS ) { |
|||
data = std::unique_ptr<char[]>( |
|||
new ( std::nothrow ) char[(size_t)size] ); |
|||
if ( nullptr != data.get() && nullptr != raw_data ) { |
|||
data_size = size; |
|||
std::copy( raw_data, raw_data + size, data.get() ); |
|||
} |
|||
else { |
|||
data_size = 0; |
|||
} |
|||
} |
|||
|
|||
set_size( data_size ); |
|||
if ( translator->empty() ) { |
|||
set_stream_size( (size_t)data_size ); |
|||
} |
|||
} |
|||
|
|||
/**
|
|||
* @brief Set the data of the section. |
|||
* @param str_data String containing the data. |
|||
*/ |
|||
void set_data( const std::string& str_data ) override |
|||
{ |
|||
return set_data( str_data.c_str(), (Elf_Word)str_data.size() ); |
|||
} |
|||
|
|||
/**
|
|||
* @brief Append data to the section. |
|||
* @param raw_data Pointer to the raw data. |
|||
* @param size Size of the data. |
|||
*/ |
|||
void append_data( const char* raw_data, Elf_Xword size ) override |
|||
{ |
|||
insert_data( get_size(), raw_data, size ); |
|||
} |
|||
|
|||
/**
|
|||
* @brief Append data to the section. |
|||
* @param str_data String containing the data. |
|||
*/ |
|||
void append_data( const std::string& str_data ) override |
|||
{ |
|||
return append_data( str_data.c_str(), (Elf_Word)str_data.size() ); |
|||
} |
|||
|
|||
/**
|
|||
* @brief Insert data into the section at a specific position. |
|||
* @param pos Position to insert the data. |
|||
* @param raw_data Pointer to the raw data. |
|||
* @param size Size of the data. |
|||
*/ |
|||
void |
|||
insert_data( Elf_Xword pos, const char* raw_data, Elf_Xword size ) override |
|||
{ |
|||
if ( get_type() != SHT_NOBITS ) { |
|||
// Check for valid position
|
|||
if ( pos > get_size() ) { |
|||
return; // Invalid position
|
|||
} |
|||
|
|||
// Check for integer overflow in size calculation
|
|||
Elf_Xword new_size = get_size(); |
|||
if ( size > std::numeric_limits<Elf_Xword>::max() - new_size ) { |
|||
return; // Size would overflow
|
|||
} |
|||
new_size += size; |
|||
|
|||
if ( new_size <= data_size ) { |
|||
char* d = data.get(); |
|||
std::copy_backward( d + pos, d + get_size(), |
|||
d + get_size() + size ); |
|||
std::copy( raw_data, raw_data + size, d + pos ); |
|||
} |
|||
else { |
|||
// Calculate new size with overflow check
|
|||
Elf_Xword new_data_size = data_size; |
|||
if ( new_data_size > |
|||
std::numeric_limits<Elf_Xword>::max() / 2 ) { |
|||
return; // Multiplication would overflow
|
|||
} |
|||
new_data_size *= 2; |
|||
if ( size > |
|||
std::numeric_limits<Elf_Xword>::max() - new_data_size ) { |
|||
return; // Addition would overflow
|
|||
} |
|||
new_data_size += size; |
|||
|
|||
// Check if the size would overflow size_t
|
|||
if ( new_data_size > std::numeric_limits<size_t>::max() ) { |
|||
return; // Size would overflow size_t
|
|||
} |
|||
|
|||
std::unique_ptr<char[]> new_data( |
|||
new ( std::nothrow ) char[(size_t)new_data_size] ); |
|||
|
|||
if ( nullptr != new_data ) { |
|||
char* d = data.get(); |
|||
std::copy( d, d + pos, new_data.get() ); |
|||
std::copy( raw_data, raw_data + size, |
|||
new_data.get() + pos ); |
|||
std::copy( d + pos, d + get_size(), |
|||
new_data.get() + pos + size ); |
|||
data = std::move( new_data ); |
|||
data_size = new_data_size; |
|||
} |
|||
else { |
|||
return; // Allocation failed
|
|||
} |
|||
} |
|||
set_size( new_size ); |
|||
if ( translator->empty() ) { |
|||
set_stream_size( get_stream_size() + (size_t)size ); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/**
|
|||
* @brief Insert data into the section at a specific position. |
|||
* @param pos Position to insert the data. |
|||
* @param str_data String containing the data. |
|||
*/ |
|||
void insert_data( Elf_Xword pos, const std::string& str_data ) override |
|||
{ |
|||
return insert_data( pos, str_data.c_str(), (Elf_Word)str_data.size() ); |
|||
} |
|||
|
|||
/**
|
|||
* @brief Get the size of the stream. |
|||
* @return Size of the stream. |
|||
*/ |
|||
size_t get_stream_size() const override { return stream_size; } |
|||
|
|||
/**
|
|||
* @brief Set the size of the stream. |
|||
* @param value Size of the stream. |
|||
*/ |
|||
void set_stream_size( size_t value ) override { stream_size = value; } |
|||
|
|||
protected: |
|||
ELFIO_GET_SET_ACCESS( Elf64_Off, offset, header.sh_offset ); |
|||
|
|||
/**
|
|||
* @brief Set the index of the section. |
|||
* @param value Index of the section. |
|||
*/ |
|||
void set_index( const Elf_Half& value ) override { index = value; } |
|||
|
|||
/**
|
|||
* @brief Check if the section is compressed. |
|||
* @return True if compressed, false otherwise. |
|||
*/ |
|||
bool is_compressed() const |
|||
{ |
|||
return ( ( get_flags() & SHF_RPX_DEFLATE ) || |
|||
( get_flags() & SHF_COMPRESSED ) ) && |
|||
compression != nullptr; |
|||
} |
|||
|
|||
/**
|
|||
* @brief Load the section from a stream. |
|||
* @param stream Input stream. |
|||
* @param header_offset Offset of the header. |
|||
* @param is_lazy_ Whether to load lazily. |
|||
* @return True if successful, false otherwise. |
|||
*/ |
|||
bool load( std::istream& stream, |
|||
std::streampos header_offset, |
|||
bool is_lazy_ ) override |
|||
{ |
|||
pstream = &stream; |
|||
is_lazy = is_lazy_; |
|||
|
|||
if ( translator->empty() ) { |
|||
stream.seekg( 0, std::istream::end ); |
|||
set_stream_size( size_t( stream.tellg() ) ); |
|||
} |
|||
else { |
|||
set_stream_size( std::numeric_limits<size_t>::max() ); |
|||
} |
|||
|
|||
stream.seekg( ( *translator )[header_offset] ); |
|||
stream.read( reinterpret_cast<char*>( &header ), sizeof( header ) ); |
|||
|
|||
if ( !( is_lazy || is_loaded ) ) { |
|||
bool ret = get_data(); |
|||
|
|||
if ( is_compressed() ) { |
|||
Elf_Xword size = get_size(); |
|||
Elf_Xword uncompressed_size = 0; |
|||
auto decompressed_data = compression->inflate( |
|||
data.get(), convertor, size, uncompressed_size ); |
|||
if ( decompressed_data != nullptr ) { |
|||
set_size( uncompressed_size ); |
|||
data = std::move( decompressed_data ); |
|||
} |
|||
} |
|||
|
|||
return ret; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
/**
|
|||
* @brief Load the data of the section. |
|||
* @return True if successful, false otherwise. |
|||
*/ |
|||
bool load_data() const |
|||
{ |
|||
Elf_Xword sh_offset = |
|||
( *translator )[( *convertor )( header.sh_offset )]; |
|||
Elf_Xword size = get_size(); |
|||
|
|||
// Check for integer overflow in offset calculation
|
|||
if ( sh_offset > get_stream_size() ) { |
|||
return false; |
|||
} |
|||
|
|||
// Check for integer overflow in size calculation
|
|||
if ( size > get_stream_size() || |
|||
size > ( get_stream_size() - sh_offset ) ) { |
|||
return false; |
|||
} |
|||
|
|||
// Check if we need to load data
|
|||
if ( nullptr == data && SHT_NULL != get_type() && |
|||
SHT_NOBITS != get_type() ) { |
|||
// Check if size can be safely converted to size_t
|
|||
if ( size > std::numeric_limits<size_t>::max() - 1 ) { |
|||
return false; |
|||
} |
|||
|
|||
data.reset( new ( std::nothrow ) char[size_t( size ) + 1] ); |
|||
|
|||
if ( ( 0 != size ) && ( nullptr != data ) ) { |
|||
pstream->seekg( sh_offset ); |
|||
pstream->read( data.get(), size ); |
|||
if ( static_cast<Elf_Xword>( pstream->gcount() ) != size ) { |
|||
data.reset( nullptr ); |
|||
data_size = 0; |
|||
return false; |
|||
} |
|||
|
|||
data_size = size; |
|||
data.get()[size] = 0; // Safe now as we allocated size + 1
|
|||
} |
|||
else { |
|||
data_size = 0; |
|||
if ( size != 0 ) { |
|||
return false; // Failed to allocate required memory
|
|||
} |
|||
} |
|||
|
|||
is_loaded = true; |
|||
return true; |
|||
} |
|||
|
|||
// Data already loaded or doesn't need loading
|
|||
is_loaded = ( nullptr != data ) || ( SHT_NULL == get_type() ) || |
|||
( SHT_NOBITS == get_type() ); |
|||
return is_loaded; |
|||
} |
|||
|
|||
/**
|
|||
* @brief Save the section to a stream. |
|||
* @param stream Output stream. |
|||
* @param header_offset Offset of the header. |
|||
* @param data_offset Offset of the data. |
|||
*/ |
|||
void save( std::ostream& stream, |
|||
std::streampos header_offset, |
|||
std::streampos data_offset ) override |
|||
{ |
|||
if ( 0 != get_index() ) { |
|||
header.sh_offset = decltype( header.sh_offset )( data_offset ); |
|||
header.sh_offset = ( *convertor )( header.sh_offset ); |
|||
} |
|||
|
|||
save_header( stream, header_offset ); |
|||
if ( get_type() != SHT_NOBITS && get_type() != SHT_NULL && |
|||
get_size() != 0 && data != nullptr ) { |
|||
save_data( stream, data_offset ); |
|||
} |
|||
} |
|||
|
|||
private: |
|||
/**
|
|||
* @brief Save the header of the section to a stream. |
|||
* @param stream Output stream. |
|||
* @param header_offset Offset of the header. |
|||
*/ |
|||
void save_header( std::ostream& stream, std::streampos header_offset ) const |
|||
{ |
|||
adjust_stream_size( stream, header_offset ); |
|||
stream.write( reinterpret_cast<const char*>( &header ), |
|||
sizeof( header ) ); |
|||
} |
|||
|
|||
/**
|
|||
* @brief Save the data of the section to a stream. |
|||
* @param stream Output stream. |
|||
* @param data_offset Offset of the data. |
|||
*/ |
|||
void save_data( std::ostream& stream, std::streampos data_offset ) |
|||
{ |
|||
adjust_stream_size( stream, data_offset ); |
|||
|
|||
if ( ( ( get_flags() & SHF_COMPRESSED ) || |
|||
( get_flags() & SHF_RPX_DEFLATE ) ) && |
|||
compression != nullptr ) { |
|||
Elf_Xword decompressed_size = get_size(); |
|||
Elf_Xword compressed_size = 0; |
|||
auto compressed_ptr = compression->deflate( |
|||
data.get(), convertor, decompressed_size, compressed_size ); |
|||
stream.write( compressed_ptr.get(), compressed_size ); |
|||
} |
|||
else { |
|||
stream.write( get_data(), get_size() ); |
|||
} |
|||
} |
|||
|
|||
private: |
|||
mutable std::istream* pstream = |
|||
nullptr; /**< Pointer to the input stream. */ |
|||
T header = {}; /**< Section header. */ |
|||
Elf_Half index = 0; /**< Index of the section. */ |
|||
std::string name; /**< Name of the section. */ |
|||
mutable std::unique_ptr<char[]> data; /**< Pointer to the data. */ |
|||
mutable Elf_Xword data_size = 0; /**< Size of the data. */ |
|||
std::shared_ptr<endianness_convertor> convertor = |
|||
nullptr; /**< Pointer to the endianness convertor. */ |
|||
std::shared_ptr<address_translator> translator = |
|||
nullptr; /**< Pointer to the address translator. */ |
|||
std::shared_ptr<compression_interface> compression = |
|||
nullptr; /**< Shared pointer to the compression interface. */ |
|||
bool is_address_set = false; /**< Flag indicating if the address is set. */ |
|||
size_t stream_size = 0; /**< Size of the stream. */ |
|||
mutable bool is_lazy = |
|||
false; /**< Flag indicating if lazy loading is enabled. */ |
|||
mutable bool is_loaded = |
|||
false; /**< Flag indicating if the data is loaded. */ |
|||
mutable bool can_be_loaded = |
|||
true; /**< Flag indicating if the data can loaded. This is not the case if the section is corrupted. */ |
|||
}; |
|||
|
|||
} // namespace ELFIO
|
|||
|
|||
#endif // ELFIO_SECTION_HPP
|
|||
@ -0,0 +1,408 @@ |
|||
/*
|
|||
Copyright (C) 2001-present by Serge Lamikhov-Center |
|||
|
|||
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. |
|||
*/ |
|||
|
|||
#ifndef ELFIO_SEGMENT_HPP |
|||
#define ELFIO_SEGMENT_HPP |
|||
|
|||
|
|||
#include <iostream> |
|||
#include <vector> |
|||
#include <new> |
|||
#include <limits> |
|||
|
|||
|
|||
namespace ELFIO { |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \class segment
|
|||
//! \brief Class for accessing segment data
|
|||
class segment |
|||
{ |
|||
friend class elfio; |
|||
|
|||
public: |
|||
virtual ~segment() = default; |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the index of the segment
|
|||
//! \return Index of the segment
|
|||
ELFIO_GET_ACCESS_DECL( Elf_Half, index ); |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the type of the segment
|
|||
//! \return Type of the segment
|
|||
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, type ); |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the flags of the segment
|
|||
//! \return Flags of the segment
|
|||
ELFIO_GET_SET_ACCESS_DECL( Elf_Word, flags ); |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the alignment of the segment
|
|||
//! \return Alignment of the segment
|
|||
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, align ); |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the virtual address of the segment
|
|||
//! \return Virtual address of the segment
|
|||
ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, virtual_address ); |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the physical address of the segment
|
|||
//! \return Physical address of the segment
|
|||
ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, physical_address ); |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the file size of the segment
|
|||
//! \return File size of the segment
|
|||
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, file_size ); |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the memory size of the segment
|
|||
//! \return Memory size of the segment
|
|||
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, memory_size ); |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the offset of the segment
|
|||
//! \return Offset of the segment
|
|||
ELFIO_GET_ACCESS_DECL( Elf64_Off, offset ); |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the data of the segment
|
|||
//! \return Pointer to the data
|
|||
virtual const char* get_data() const = 0; |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Free the data of the segment
|
|||
virtual void free_data() const = 0; |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Add a section to the segment
|
|||
//! \param psec Pointer to the section
|
|||
//! \param addr_align Alignment of the section
|
|||
//! \return Index of the added section
|
|||
virtual Elf_Half add_section( section* psec, Elf_Xword addr_align ) = 0; |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Add a section index to the segment
|
|||
//! \param index Index of the section
|
|||
//! \param addr_align Alignment of the section
|
|||
//! \return Index of the added section
|
|||
virtual Elf_Half add_section_index( Elf_Half index, |
|||
Elf_Xword addr_align ) = 0; |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the number of sections in the segment
|
|||
//! \return Number of sections in the segment
|
|||
virtual Elf_Half get_sections_num() const = 0; |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the index of a section at a given position
|
|||
//! \param num Position of the section
|
|||
//! \return Index of the section
|
|||
virtual Elf_Half get_section_index_at( Elf_Half num ) const = 0; |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Check if the offset is initialized
|
|||
//! \return True if the offset is initialized, false otherwise
|
|||
virtual bool is_offset_initialized() const = 0; |
|||
|
|||
protected: |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Set the offset of the segment
|
|||
//! \param offset Offset of the segment
|
|||
ELFIO_SET_ACCESS_DECL( Elf64_Off, offset ); |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Set the index of the segment
|
|||
//! \param index Index of the segment
|
|||
ELFIO_SET_ACCESS_DECL( Elf_Half, index ); |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the sections of the segment
|
|||
//! \return Vector of section indices
|
|||
virtual const std::vector<Elf_Half>& get_sections() const = 0; |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Load the segment from a stream
|
|||
//! \param stream Input stream
|
|||
//! \param header_offset Offset of the segment header
|
|||
//! \param is_lazy Whether to load the segment lazily
|
|||
//! \return True if successful, false otherwise
|
|||
virtual bool load( std::istream& stream, |
|||
std::streampos header_offset, |
|||
bool is_lazy ) = 0; |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Save the segment to a stream
|
|||
//! \param stream Output stream
|
|||
//! \param header_offset Offset of the segment header
|
|||
//! \param data_offset Offset of the segment data
|
|||
virtual void save( std::ostream& stream, |
|||
std::streampos header_offset, |
|||
std::streampos data_offset ) = 0; |
|||
}; |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \class segment_impl
|
|||
//! \brief Implementation of the segment class
|
|||
template <class T> class segment_impl : public segment |
|||
{ |
|||
public: |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Constructor
|
|||
//! \param convertor Pointer to the endianness convertor
|
|||
//! \param translator Pointer to the address translator
|
|||
segment_impl( std::shared_ptr<endianness_convertor> convertor, |
|||
std::shared_ptr<address_translator> translator ) |
|||
: convertor( convertor ), translator( translator ) |
|||
{ |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// Section info functions
|
|||
ELFIO_GET_SET_ACCESS( Elf_Word, type, ph.p_type ); |
|||
ELFIO_GET_SET_ACCESS( Elf_Word, flags, ph.p_flags ); |
|||
ELFIO_GET_SET_ACCESS( Elf_Xword, align, ph.p_align ); |
|||
ELFIO_GET_SET_ACCESS( Elf64_Addr, virtual_address, ph.p_vaddr ); |
|||
ELFIO_GET_SET_ACCESS( Elf64_Addr, physical_address, ph.p_paddr ); |
|||
ELFIO_GET_SET_ACCESS( Elf_Xword, file_size, ph.p_filesz ); |
|||
ELFIO_GET_SET_ACCESS( Elf_Xword, memory_size, ph.p_memsz ); |
|||
ELFIO_GET_ACCESS( Elf64_Off, offset, ph.p_offset ); |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the index of the segment
|
|||
//! \return Index of the segment
|
|||
Elf_Half get_index() const override { return index; } |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the data of the segment
|
|||
//! \return Pointer to the data
|
|||
const char* get_data() const override |
|||
{ |
|||
if ( !is_loaded ) { |
|||
load_data(); |
|||
} |
|||
return data.get(); |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Free the data of the segment
|
|||
void free_data() const override |
|||
{ |
|||
if ( is_lazy ) { |
|||
data.reset( nullptr ); |
|||
is_loaded = false; |
|||
} |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Add a section index to the segment
|
|||
//! \param sec_index Index of the section
|
|||
//! \param addr_align Alignment of the section
|
|||
//! \return Index of the added section
|
|||
Elf_Half add_section_index( Elf_Half sec_index, |
|||
Elf_Xword addr_align ) override |
|||
{ |
|||
sections.emplace_back( sec_index ); |
|||
if ( addr_align > get_align() ) { |
|||
set_align( addr_align ); |
|||
} |
|||
|
|||
return (Elf_Half)sections.size(); |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Add a section to the segment
|
|||
//! \param psec Pointer to the section
|
|||
//! \param addr_align Alignment of the section
|
|||
//! \return Index of the added section
|
|||
Elf_Half add_section( section* psec, Elf_Xword addr_align ) override |
|||
{ |
|||
return add_section_index( psec->get_index(), addr_align ); |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the number of sections in the segment
|
|||
//! \return Number of sections in the segment
|
|||
Elf_Half get_sections_num() const override |
|||
{ |
|||
return (Elf_Half)sections.size(); |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the index of a section at a given position
|
|||
//! \param num Position of the section
|
|||
//! \return Index of the section
|
|||
Elf_Half get_section_index_at( Elf_Half num ) const override |
|||
{ |
|||
if ( num < sections.size() ) { |
|||
return sections[num]; |
|||
} |
|||
|
|||
return Elf_Half( -1 ); |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
protected: |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Set the offset of the segment
|
|||
//! \param value Offset of the segment
|
|||
void set_offset( const Elf64_Off& value ) override |
|||
{ |
|||
ph.p_offset = decltype( ph.p_offset )( value ); |
|||
ph.p_offset = ( *convertor )( ph.p_offset ); |
|||
is_offset_set = true; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Check if the offset is initialized
|
|||
//! \return True if the offset is initialized, false otherwise
|
|||
bool is_offset_initialized() const override { return is_offset_set; } |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the sections of the segment
|
|||
//! \return Vector of section indices
|
|||
const std::vector<Elf_Half>& get_sections() const override |
|||
{ |
|||
return sections; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Set the index of the segment
|
|||
//! \param value Index of the segment
|
|||
void set_index( const Elf_Half& value ) override { index = value; } |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Load the segment from a stream
|
|||
//! \param stream Input stream
|
|||
//! \param header_offset Offset of the segment header
|
|||
//! \param is_lazy_ Whether to load the segment lazily
|
|||
//! \return True if successful, false otherwise
|
|||
bool load( std::istream& stream, |
|||
std::streampos header_offset, |
|||
bool is_lazy_ ) override |
|||
{ |
|||
|
|||
pstream = &stream; |
|||
is_lazy = is_lazy_; |
|||
|
|||
if ( translator->empty() ) { |
|||
stream.seekg( 0, std::istream::end ); |
|||
set_stream_size( size_t( stream.tellg() ) ); |
|||
} |
|||
else { |
|||
set_stream_size( std::numeric_limits<size_t>::max() ); |
|||
} |
|||
|
|||
stream.seekg( ( *translator )[header_offset] ); |
|||
stream.read( reinterpret_cast<char*>( &ph ), sizeof( ph ) ); |
|||
|
|||
is_offset_set = true; |
|||
|
|||
if ( !( is_lazy || is_loaded ) ) { |
|||
return load_data(); |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Load the data of the segment
|
|||
//! \return True if successful, false otherwise
|
|||
bool load_data() const |
|||
{ |
|||
if ( PT_NULL == get_type() || 0 == get_file_size() ) { |
|||
return true; |
|||
} |
|||
|
|||
Elf_Xword p_offset = ( *translator )[( *convertor )( ph.p_offset )]; |
|||
Elf_Xword size = get_file_size(); |
|||
|
|||
// Check for integer overflow in offset calculation
|
|||
if ( p_offset > get_stream_size() ) { |
|||
data = nullptr; |
|||
return false; |
|||
} |
|||
|
|||
// Check for integer overflow in size calculation
|
|||
if ( size > get_stream_size() || |
|||
size > ( get_stream_size() - p_offset ) ) { |
|||
data = nullptr; |
|||
return false; |
|||
} |
|||
|
|||
// Check if size can be safely converted to size_t
|
|||
if ( size > std::numeric_limits<size_t>::max() - 1 ) { |
|||
data = nullptr; |
|||
return false; |
|||
} |
|||
|
|||
data.reset( new ( std::nothrow ) char[(size_t)size + 1] ); |
|||
|
|||
pstream->seekg( p_offset ); |
|||
if ( nullptr != data.get() && pstream->read( data.get(), size ) ) { |
|||
data.get()[size] = 0; |
|||
} |
|||
else { |
|||
data = nullptr; |
|||
return false; |
|||
} |
|||
|
|||
is_loaded = true; |
|||
|
|||
return true; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Save the segment to a stream
|
|||
//! \param stream Output stream
|
|||
//! \param header_offset Offset of the segment header
|
|||
//! \param data_offset Offset of the segment data
|
|||
void save( std::ostream& stream, |
|||
std::streampos header_offset, |
|||
std::streampos data_offset ) override |
|||
{ |
|||
ph.p_offset = decltype( ph.p_offset )( data_offset ); |
|||
ph.p_offset = ( *convertor )( ph.p_offset ); |
|||
adjust_stream_size( stream, header_offset ); |
|||
stream.write( reinterpret_cast<const char*>( &ph ), sizeof( ph ) ); |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the stream size
|
|||
//! \return Stream size
|
|||
size_t get_stream_size() const { return stream_size; } |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Set the stream size
|
|||
//! \param value Stream size
|
|||
void set_stream_size( size_t value ) { stream_size = value; } |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
private: |
|||
mutable std::istream* pstream = nullptr; //!< Pointer to the input stream
|
|||
T ph = {}; //!< Segment header
|
|||
Elf_Half index = 0; //!< Index of the segment
|
|||
mutable std::unique_ptr<char[]> data; //!< Pointer to the segment data
|
|||
std::vector<Elf_Half> sections; //!< Vector of section indices
|
|||
std::shared_ptr<endianness_convertor> convertor = |
|||
nullptr; //!< Pointer to the endianness convertor
|
|||
std::shared_ptr<address_translator> translator = |
|||
nullptr; //!< Pointer to the address translator
|
|||
size_t stream_size = 0; //!< Stream size
|
|||
bool is_offset_set = false; //!< Flag indicating if the offset is set
|
|||
mutable bool is_lazy = |
|||
false; //!< Flag indicating if the segment is loaded lazily
|
|||
mutable bool is_loaded = |
|||
false; //!< Flag indicating if the segment is loaded
|
|||
}; |
|||
|
|||
} // namespace ELFIO
|
|||
|
|||
#endif // ELFIO_SEGMENT_HPP
|
|||
@ -0,0 +1,143 @@ |
|||
/*
|
|||
Copyright (C) 2001-present by Serge Lamikhov-Center |
|||
|
|||
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. |
|||
*/ |
|||
|
|||
#ifndef ELFIO_STRINGS_HPP |
|||
#define ELFIO_STRINGS_HPP |
|||
|
|||
#include <cstdlib> |
|||
#include <cstring> |
|||
#include <string> |
|||
#include <limits> |
|||
|
|||
namespace ELFIO { |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \class string_section_accessor_template
|
|||
//! \brief Class for accessing string section data
|
|||
template <class S> class string_section_accessor_template |
|||
{ |
|||
public: |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Constructor
|
|||
//! \param section Pointer to the section
|
|||
explicit string_section_accessor_template( S* section ) |
|||
: string_section( section ) |
|||
{ |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get a string from the section
|
|||
//! \param index Index of the string
|
|||
//! \return Pointer to the string, or nullptr if not found
|
|||
const char* get_string( Elf_Word index ) const |
|||
{ |
|||
if ( string_section ) { |
|||
const char* data = string_section->get_data(); |
|||
size_t section_size = |
|||
static_cast<size_t>( string_section->get_size() ); |
|||
|
|||
// Check if index is within bounds
|
|||
if ( index >= section_size || nullptr == data ) { |
|||
return nullptr; |
|||
} |
|||
|
|||
// Check for integer overflow in size calculation
|
|||
size_t remaining_size = section_size - index; |
|||
if ( remaining_size > section_size ) { // Check for underflow
|
|||
return nullptr; |
|||
} |
|||
|
|||
// Use standard C++ functions to find string length
|
|||
const char* str = data + index; |
|||
const char* end = |
|||
(const char*)std::memchr( str, '\0', remaining_size ); |
|||
if ( end != nullptr && end < str + remaining_size ) { |
|||
return str; |
|||
} |
|||
} |
|||
|
|||
return nullptr; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Add a string to the section
|
|||
//! \param str Pointer to the string
|
|||
//! \return Index of the added string
|
|||
Elf_Word add_string( const char* str ) |
|||
{ |
|||
if ( !str ) { |
|||
return 0; // Return index of empty string for null input
|
|||
} |
|||
|
|||
Elf_Word current_position = 0; |
|||
|
|||
if ( string_section ) { |
|||
// Strings are added to the end of the current section data
|
|||
current_position = |
|||
static_cast<Elf_Word>( string_section->get_size() ); |
|||
|
|||
if ( current_position == 0 ) { |
|||
char empty_string = '\0'; |
|||
string_section->append_data( &empty_string, 1 ); |
|||
current_position++; |
|||
} |
|||
|
|||
// Calculate string length and check for overflow
|
|||
size_t str_len = std::strlen( str ); |
|||
if ( str_len > std::numeric_limits<Elf_Word>::max() - 1 ) { |
|||
return 0; // String too long
|
|||
} |
|||
|
|||
// Check if appending would overflow section size
|
|||
Elf_Word append_size = static_cast<Elf_Word>( str_len + 1 ); |
|||
if ( append_size > |
|||
std::numeric_limits<Elf_Word>::max() - current_position ) { |
|||
return 0; // Would overflow section size
|
|||
} |
|||
|
|||
string_section->append_data( str, append_size ); |
|||
} |
|||
|
|||
return current_position; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Add a string to the section
|
|||
//! \param str The string to add
|
|||
//! \return Index of the added string
|
|||
Elf_Word add_string( const std::string& str ) |
|||
{ |
|||
return add_string( str.c_str() ); |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
private: |
|||
S* string_section; //!< Pointer to the section
|
|||
}; |
|||
|
|||
using string_section_accessor = string_section_accessor_template<section>; |
|||
using const_string_section_accessor = |
|||
string_section_accessor_template<const section>; |
|||
|
|||
} // namespace ELFIO
|
|||
|
|||
#endif // ELFIO_STRINGS_HPP
|
|||
@ -0,0 +1,716 @@ |
|||
/*
|
|||
Copyright (C) 2001-present by Serge Lamikhov-Center |
|||
|
|||
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. |
|||
*/ |
|||
|
|||
#ifndef ELFIO_SYMBOLS_HPP |
|||
#define ELFIO_SYMBOLS_HPP |
|||
|
|||
namespace ELFIO { |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// @class symbol_section_accessor_template
|
|||
// @brief A template class for accessing symbol sections in an ELF file.
|
|||
//------------------------------------------------------------------------------
|
|||
template <class S> class symbol_section_accessor_template |
|||
{ |
|||
public: |
|||
//------------------------------------------------------------------------------
|
|||
// @brief Constructor
|
|||
// @param elf_file Reference to the ELF file
|
|||
// @param symbol_section Pointer to the symbol section
|
|||
//------------------------------------------------------------------------------
|
|||
explicit symbol_section_accessor_template( const elfio& elf_file, |
|||
S* symbol_section ) |
|||
: elf_file( elf_file ), symbol_section( symbol_section ) |
|||
{ |
|||
find_hash_section(); |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// @brief Get the number of symbols in the section
|
|||
// @return Number of symbols
|
|||
//------------------------------------------------------------------------------
|
|||
Elf_Xword get_symbols_num() const |
|||
{ |
|||
Elf_Xword nRet = 0; |
|||
|
|||
size_t minimum_symbol_size; |
|||
switch ( elf_file.get_class() ) { |
|||
case ELFCLASS32: |
|||
minimum_symbol_size = sizeof( Elf32_Sym ); |
|||
break; |
|||
case ELFCLASS64: |
|||
minimum_symbol_size = sizeof( Elf64_Sym ); |
|||
break; |
|||
default: |
|||
return nRet; |
|||
} |
|||
|
|||
if ( symbol_section->get_entry_size() >= minimum_symbol_size && |
|||
symbol_section->get_size() <= symbol_section->get_stream_size() ) { |
|||
nRet = |
|||
symbol_section->get_size() / symbol_section->get_entry_size(); |
|||
} |
|||
|
|||
return nRet; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// @brief Get the symbol at the specified index
|
|||
// @param index Index of the symbol
|
|||
// @param name Name of the symbol
|
|||
// @param value Value of the symbol
|
|||
// @param size Size of the symbol
|
|||
// @param bind Binding of the symbol
|
|||
// @param type Type of the symbol
|
|||
// @param section_index Section index of the symbol
|
|||
// @param other Other attributes of the symbol
|
|||
// @return True if the symbol is found, false otherwise
|
|||
//------------------------------------------------------------------------------
|
|||
bool get_symbol( Elf_Xword index, |
|||
std::string& name, |
|||
Elf64_Addr& value, |
|||
Elf_Xword& size, |
|||
unsigned char& bind, |
|||
unsigned char& type, |
|||
Elf_Half& section_index, |
|||
unsigned char& other ) const |
|||
{ |
|||
bool ret = false; |
|||
|
|||
if ( elf_file.get_class() == ELFCLASS32 ) { |
|||
ret = generic_get_symbol<Elf32_Sym>( index, name, value, size, bind, |
|||
type, section_index, other ); |
|||
} |
|||
else { |
|||
ret = generic_get_symbol<Elf64_Sym>( index, name, value, size, bind, |
|||
type, section_index, other ); |
|||
} |
|||
|
|||
return ret; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// @brief Get the symbol with the specified name
|
|||
// @param name Name of the symbol
|
|||
// @param value Value of the symbol
|
|||
// @param size Size of the symbol
|
|||
// @param bind Binding of the symbol
|
|||
// @param type Type of the symbol
|
|||
// @param section_index Section index of the symbol
|
|||
// @param other Other attributes of the symbol
|
|||
// @return True if the symbol is found, false otherwise
|
|||
//------------------------------------------------------------------------------
|
|||
bool get_symbol( const std::string& name, |
|||
Elf64_Addr& value, |
|||
Elf_Xword& size, |
|||
unsigned char& bind, |
|||
unsigned char& type, |
|||
Elf_Half& section_index, |
|||
unsigned char& other ) const |
|||
{ |
|||
bool ret = false; |
|||
|
|||
if ( 0 != get_hash_table_index() ) { |
|||
if ( hash_section->get_type() == SHT_HASH ) { |
|||
ret = hash_lookup( name, value, size, bind, type, section_index, |
|||
other ); |
|||
} |
|||
if ( hash_section->get_type() == SHT_GNU_HASH || |
|||
hash_section->get_type() == DT_GNU_HASH ) { |
|||
if ( elf_file.get_class() == ELFCLASS32 ) { |
|||
ret = gnu_hash_lookup<std::uint32_t>( |
|||
name, value, size, bind, type, section_index, other ); |
|||
} |
|||
else { |
|||
ret = gnu_hash_lookup<std::uint64_t>( |
|||
name, value, size, bind, type, section_index, other ); |
|||
} |
|||
} |
|||
} |
|||
|
|||
if ( !ret ) { |
|||
for ( Elf_Xword i = 0; !ret && i < get_symbols_num(); i++ ) { |
|||
std::string symbol_name; |
|||
if ( get_symbol( i, symbol_name, value, size, bind, type, |
|||
section_index, other ) && |
|||
( symbol_name == name ) ) { |
|||
ret = true; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return ret; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// @brief Get the symbol with the specified value
|
|||
// @param value Value of the symbol
|
|||
// @param name Name of the symbol
|
|||
// @param size Size of the symbol
|
|||
// @param bind Binding of the symbol
|
|||
// @param type Type of the symbol
|
|||
// @param section_index Section index of the symbol
|
|||
// @param other Other attributes of the symbol
|
|||
// @return True if the symbol is found, false otherwise
|
|||
//------------------------------------------------------------------------------
|
|||
bool get_symbol( const Elf64_Addr& value, |
|||
std::string& name, |
|||
Elf_Xword& size, |
|||
unsigned char& bind, |
|||
unsigned char& type, |
|||
Elf_Half& section_index, |
|||
unsigned char& other ) const |
|||
{ |
|||
|
|||
const auto& convertor = elf_file.get_convertor(); |
|||
|
|||
Elf_Xword idx = 0; |
|||
bool match = false; |
|||
Elf64_Addr v = 0; |
|||
|
|||
if ( elf_file.get_class() == ELFCLASS32 ) { |
|||
match = generic_search_symbols<Elf32_Sym>( |
|||
[&]( const Elf32_Sym* sym ) { |
|||
return ( *convertor )( sym->st_value ) == value; |
|||
}, |
|||
idx ); |
|||
} |
|||
else { |
|||
match = generic_search_symbols<Elf64_Sym>( |
|||
[&]( const Elf64_Sym* sym ) { |
|||
return ( *convertor )( sym->st_value ) == value; |
|||
}, |
|||
idx ); |
|||
} |
|||
|
|||
if ( match ) { |
|||
return get_symbol( idx, name, v, size, bind, type, section_index, |
|||
other ); |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// @brief Add a symbol to the section
|
|||
// @param name Name of the symbol
|
|||
// @param value Value of the symbol
|
|||
// @param size Size of the symbol
|
|||
// @param info Info of the symbol
|
|||
// @param other Other attributes of the symbol
|
|||
// @param shndx Section index of the symbol
|
|||
// @return Index of the added symbol
|
|||
//------------------------------------------------------------------------------
|
|||
Elf_Word add_symbol( Elf_Word name, |
|||
Elf64_Addr value, |
|||
Elf_Xword size, |
|||
unsigned char info, |
|||
unsigned char other, |
|||
Elf_Half shndx ) |
|||
{ |
|||
Elf_Word nRet; |
|||
|
|||
if ( symbol_section->get_size() == 0 ) { |
|||
if ( elf_file.get_class() == ELFCLASS32 ) { |
|||
nRet = generic_add_symbol<Elf32_Sym>( 0, 0, 0, 0, 0, 0 ); |
|||
} |
|||
else { |
|||
nRet = generic_add_symbol<Elf64_Sym>( 0, 0, 0, 0, 0, 0 ); |
|||
} |
|||
} |
|||
|
|||
if ( elf_file.get_class() == ELFCLASS32 ) { |
|||
nRet = generic_add_symbol<Elf32_Sym>( name, value, size, info, |
|||
other, shndx ); |
|||
} |
|||
else { |
|||
nRet = generic_add_symbol<Elf64_Sym>( name, value, size, info, |
|||
other, shndx ); |
|||
} |
|||
|
|||
return nRet; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// @brief Add a symbol to the section
|
|||
// @param name Name of the symbol
|
|||
// @param value Value of the symbol
|
|||
// @param size Size of the symbol
|
|||
// @param bind Binding of the symbol
|
|||
// @param type Type of the symbol
|
|||
// @param other Other attributes of the symbol
|
|||
// @param shndx Section index of the symbol
|
|||
// @return Index of the added symbol
|
|||
//------------------------------------------------------------------------------
|
|||
Elf_Word add_symbol( Elf_Word name, |
|||
Elf64_Addr value, |
|||
Elf_Xword size, |
|||
unsigned char bind, |
|||
unsigned char type, |
|||
unsigned char other, |
|||
Elf_Half shndx ) |
|||
{ |
|||
return add_symbol( name, value, size, ELF_ST_INFO( bind, type ), other, |
|||
shndx ); |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// @brief Add a symbol to the section
|
|||
// @param pStrWriter String section accessor
|
|||
// @param str Name of the symbol
|
|||
// @param value Value of the symbol
|
|||
// @param size Size of the symbol
|
|||
// @param info Info of the symbol
|
|||
// @param other Other attributes of the symbol
|
|||
// @param shndx Section index of the symbol
|
|||
// @return Index of the added symbol
|
|||
//------------------------------------------------------------------------------
|
|||
Elf_Word add_symbol( string_section_accessor& pStrWriter, |
|||
const char* str, |
|||
Elf64_Addr value, |
|||
Elf_Xword size, |
|||
unsigned char info, |
|||
unsigned char other, |
|||
Elf_Half shndx ) |
|||
{ |
|||
Elf_Word index = pStrWriter.add_string( str ); |
|||
return add_symbol( index, value, size, info, other, shndx ); |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// @brief Add a symbol to the section
|
|||
// @param pStrWriter String section accessor
|
|||
// @param str Name of the symbol
|
|||
// @param value Value of the symbol
|
|||
// @param size Size of the symbol
|
|||
// @param bind Binding of the symbol
|
|||
// @param type Type of the symbol
|
|||
// @param other Other attributes of the symbol
|
|||
// @param shndx Section index of the symbol
|
|||
// @return Index of the added symbol
|
|||
//------------------------------------------------------------------------------
|
|||
Elf_Word add_symbol( string_section_accessor& pStrWriter, |
|||
const char* str, |
|||
Elf64_Addr value, |
|||
Elf_Xword size, |
|||
unsigned char bind, |
|||
unsigned char type, |
|||
unsigned char other, |
|||
Elf_Half shndx ) |
|||
{ |
|||
return add_symbol( pStrWriter, str, value, size, |
|||
ELF_ST_INFO( bind, type ), other, shndx ); |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// @brief Arrange local symbols in the section
|
|||
// @param func Function to be called for each pair of symbols
|
|||
// @return Number of local symbols
|
|||
//------------------------------------------------------------------------------
|
|||
Elf_Xword arrange_local_symbols( |
|||
std::function<void( Elf_Xword first, Elf_Xword second )> func = |
|||
nullptr ) |
|||
{ |
|||
Elf_Xword nRet = 0; |
|||
|
|||
if ( elf_file.get_class() == ELFCLASS32 ) { |
|||
nRet = generic_arrange_local_symbols<Elf32_Sym>( func ); |
|||
} |
|||
else { |
|||
nRet = generic_arrange_local_symbols<Elf64_Sym>( func ); |
|||
} |
|||
|
|||
return nRet; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
private: |
|||
//------------------------------------------------------------------------------
|
|||
// @brief Find the hash section
|
|||
//------------------------------------------------------------------------------
|
|||
void find_hash_section() |
|||
{ |
|||
Elf_Half nSecNo = elf_file.sections.size(); |
|||
for ( Elf_Half i = 0; i < nSecNo; ++i ) { |
|||
const section* sec = elf_file.sections[i]; |
|||
if ( sec->get_link() == symbol_section->get_index() && |
|||
( sec->get_type() == SHT_HASH || |
|||
sec->get_type() == SHT_GNU_HASH || |
|||
sec->get_type() == DT_GNU_HASH ) ) { |
|||
hash_section = sec; |
|||
hash_section_index = i; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// @brief Get the index of the string table
|
|||
// @return Index of the string table
|
|||
//------------------------------------------------------------------------------
|
|||
Elf_Half get_string_table_index() const |
|||
{ |
|||
return (Elf_Half)symbol_section->get_link(); |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// @brief Get the index of the hash table
|
|||
// @return Index of the hash table
|
|||
//------------------------------------------------------------------------------
|
|||
Elf_Half get_hash_table_index() const { return hash_section_index; } |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// @brief Lookup a symbol in the hash table
|
|||
// @param name Name of the symbol
|
|||
// @param value Value of the symbol
|
|||
// @param size Size of the symbol
|
|||
// @param bind Binding of the symbol
|
|||
// @param type Type of the symbol
|
|||
// @param section_index Section index of the symbol
|
|||
// @param other Other attributes of the symbol
|
|||
// @return True if the symbol is found, false otherwise
|
|||
//------------------------------------------------------------------------------
|
|||
bool hash_lookup( const std::string& name, |
|||
Elf64_Addr& value, |
|||
Elf_Xword& size, |
|||
unsigned char& bind, |
|||
unsigned char& type, |
|||
Elf_Half& section_index, |
|||
unsigned char& other ) const |
|||
{ |
|||
bool ret = false; |
|||
const auto& convertor = elf_file.get_convertor(); |
|||
|
|||
Elf_Word nbucket = *(const Elf_Word*)hash_section->get_data(); |
|||
nbucket = ( *convertor )( nbucket ); |
|||
Elf_Word nchain = |
|||
*(const Elf_Word*)( hash_section->get_data() + sizeof( Elf_Word ) ); |
|||
nchain = ( *convertor )( nchain ); |
|||
Elf_Word val = elf_hash( (const unsigned char*)name.c_str() ); |
|||
Elf_Word y = |
|||
*(const Elf_Word*)( hash_section->get_data() + |
|||
( 2 + val % nbucket ) * sizeof( Elf_Word ) ); |
|||
y = ( *convertor )( y ); |
|||
std::string str; |
|||
get_symbol( y, str, value, size, bind, type, section_index, other ); |
|||
while ( str != name && STN_UNDEF != y && y < nchain ) { |
|||
y = *(const Elf_Word*)( hash_section->get_data() + |
|||
( 2 + nbucket + y ) * sizeof( Elf_Word ) ); |
|||
y = ( *convertor )( y ); |
|||
get_symbol( y, str, value, size, bind, type, section_index, other ); |
|||
} |
|||
|
|||
if ( str == name ) { |
|||
ret = true; |
|||
} |
|||
|
|||
return ret; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// @brief Lookup a symbol in the GNU hash table
|
|||
// @param name Name of the symbol
|
|||
// @param value Value of the symbol
|
|||
// @param size Size of the symbol
|
|||
// @param bind Binding of the symbol
|
|||
// @param type Type of the symbol
|
|||
// @param section_index Section index of the symbol
|
|||
// @param other Other attributes of the symbol
|
|||
// @return True if the symbol is found, false otherwise
|
|||
//------------------------------------------------------------------------------
|
|||
template <class T> |
|||
bool gnu_hash_lookup( const std::string& name, |
|||
Elf64_Addr& value, |
|||
Elf_Xword& size, |
|||
unsigned char& bind, |
|||
unsigned char& type, |
|||
Elf_Half& section_index, |
|||
unsigned char& other ) const |
|||
{ |
|||
bool ret = false; |
|||
const auto& convertor = elf_file.get_convertor(); |
|||
|
|||
std::uint32_t nbuckets = |
|||
*( (std::uint32_t*)hash_section->get_data() + 0 ); |
|||
std::uint32_t symoffset = |
|||
*( (std::uint32_t*)hash_section->get_data() + 1 ); |
|||
std::uint32_t bloom_size = |
|||
*( (std::uint32_t*)hash_section->get_data() + 2 ); |
|||
std::uint32_t bloom_shift = |
|||
*( (std::uint32_t*)hash_section->get_data() + 3 ); |
|||
nbuckets = ( *convertor )( nbuckets ); |
|||
symoffset = ( *convertor )( symoffset ); |
|||
bloom_size = ( *convertor )( bloom_size ); |
|||
bloom_shift = ( *convertor )( bloom_shift ); |
|||
|
|||
auto* bloom_filter = |
|||
(T*)( hash_section->get_data() + 4 * sizeof( std::uint32_t ) ); |
|||
|
|||
std::uint32_t hash = elf_gnu_hash( (const unsigned char*)name.c_str() ); |
|||
std::uint32_t bloom_index = ( hash / ( 8 * sizeof( T ) ) ) % bloom_size; |
|||
T bloom_bits = |
|||
( (T)1 << ( hash % ( 8 * sizeof( T ) ) ) ) | |
|||
( (T)1 << ( ( hash >> bloom_shift ) % ( 8 * sizeof( T ) ) ) ); |
|||
|
|||
if ( ( ( *convertor )( bloom_filter[bloom_index] ) & bloom_bits ) != |
|||
bloom_bits ) |
|||
return ret; |
|||
|
|||
std::uint32_t bucket = hash % nbuckets; |
|||
auto* buckets = (std::uint32_t*)( hash_section->get_data() + |
|||
4 * sizeof( std::uint32_t ) + |
|||
bloom_size * sizeof( T ) ); |
|||
auto* chains = (std::uint32_t*)( hash_section->get_data() + |
|||
4 * sizeof( std::uint32_t ) + |
|||
bloom_size * sizeof( T ) + |
|||
nbuckets * sizeof( std::uint32_t ) ); |
|||
|
|||
if ( ( *convertor )( buckets[bucket] ) >= symoffset ) { |
|||
std::uint32_t chain_index = |
|||
( *convertor )( buckets[bucket] ) - symoffset; |
|||
std::uint32_t chain_hash = ( *convertor )( chains[chain_index] ); |
|||
std::string symname; |
|||
|
|||
while ( true ) { |
|||
if ( ( chain_hash >> 1 ) == ( hash >> 1 ) && |
|||
get_symbol( chain_index + symoffset, symname, value, size, |
|||
bind, type, section_index, other ) && |
|||
( name == symname ) ) { |
|||
ret = true; |
|||
break; |
|||
} |
|||
|
|||
if ( chain_hash & 1 ) |
|||
break; |
|||
|
|||
chain_hash = ( *convertor )( chains[++chain_index] ); |
|||
} |
|||
} |
|||
|
|||
return ret; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// @brief Get the symbol at the specified index
|
|||
// @param index Index of the symbol
|
|||
// @return Pointer to the symbol
|
|||
//------------------------------------------------------------------------------
|
|||
template <class T> const T* generic_get_symbol_ptr( Elf_Xword index ) const |
|||
{ |
|||
if ( 0 != symbol_section->get_data() && index < get_symbols_num() ) { |
|||
if ( symbol_section->get_entry_size() < sizeof( T ) ) { |
|||
return nullptr; |
|||
} |
|||
const auto* pSym = reinterpret_cast<const T*>( |
|||
symbol_section->get_data() + |
|||
index * symbol_section->get_entry_size() ); |
|||
|
|||
return pSym; |
|||
} |
|||
|
|||
return nullptr; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// @brief Search for a symbol in the section
|
|||
// @param match Function to be called for each symbol
|
|||
// @param idx Index of the found symbol
|
|||
// @return True if the symbol is found, false otherwise
|
|||
//------------------------------------------------------------------------------
|
|||
template <class T> |
|||
bool generic_search_symbols( std::function<bool( const T* )> match, |
|||
Elf_Xword& idx ) const |
|||
{ |
|||
for ( Elf_Xword i = 0; i < get_symbols_num(); i++ ) { |
|||
const T* symPtr = generic_get_symbol_ptr<T>( i ); |
|||
|
|||
if ( symPtr == nullptr ) |
|||
return false; |
|||
|
|||
if ( match( symPtr ) ) { |
|||
idx = i; |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// @brief Get the symbol at the specified index
|
|||
// @param index Index of the symbol
|
|||
// @param name Name of the symbol
|
|||
// @param value Value of the symbol
|
|||
// @param size Size of the symbol
|
|||
// @param bind Binding of the symbol
|
|||
// @param type Type of the symbol
|
|||
// @param section_index Section index of the symbol
|
|||
// @param other Other attributes of the symbol
|
|||
// @return True if the symbol is found, false otherwise
|
|||
//------------------------------------------------------------------------------
|
|||
template <class T> |
|||
bool generic_get_symbol( Elf_Xword index, |
|||
std::string& name, |
|||
Elf64_Addr& value, |
|||
Elf_Xword& size, |
|||
unsigned char& bind, |
|||
unsigned char& type, |
|||
Elf_Half& section_index, |
|||
unsigned char& other ) const |
|||
{ |
|||
bool ret = false; |
|||
|
|||
if ( nullptr != symbol_section->get_data() && |
|||
index < get_symbols_num() ) { |
|||
const auto* pSym = reinterpret_cast<const T*>( |
|||
symbol_section->get_data() + |
|||
index * symbol_section->get_entry_size() ); |
|||
|
|||
const auto& convertor = elf_file.get_convertor(); |
|||
|
|||
section* string_section = |
|||
elf_file.sections[get_string_table_index()]; |
|||
string_section_accessor str_reader( string_section ); |
|||
const char* pStr = |
|||
str_reader.get_string( ( *convertor )( pSym->st_name ) ); |
|||
if ( nullptr != pStr ) { |
|||
name = pStr; |
|||
} |
|||
value = ( *convertor )( pSym->st_value ); |
|||
size = ( *convertor )( pSym->st_size ); |
|||
bind = ELF_ST_BIND( pSym->st_info ); |
|||
type = ELF_ST_TYPE( pSym->st_info ); |
|||
section_index = ( *convertor )( pSym->st_shndx ); |
|||
other = pSym->st_other; |
|||
|
|||
ret = true; |
|||
} |
|||
|
|||
return ret; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// @brief Add a symbol to the section
|
|||
// @param name Name of the symbol
|
|||
// @param value Value of the symbol
|
|||
// @param size Size of the symbol
|
|||
// @param info Info of the symbol
|
|||
// @param other Other attributes of the symbol
|
|||
// @param shndx Section index of the symbol
|
|||
// @return Index of the added symbol
|
|||
//------------------------------------------------------------------------------
|
|||
template <class T> |
|||
Elf_Word generic_add_symbol( Elf_Word name, |
|||
Elf64_Addr value, |
|||
Elf_Xword size, |
|||
unsigned char info, |
|||
unsigned char other, |
|||
Elf_Half shndx ) |
|||
{ |
|||
const auto& convertor = elf_file.get_convertor(); |
|||
|
|||
T entry; |
|||
entry.st_name = ( *convertor )( name ); |
|||
entry.st_value = decltype( entry.st_value )( value ); |
|||
entry.st_value = ( *convertor )( entry.st_value ); |
|||
entry.st_size = decltype( entry.st_size )( size ); |
|||
entry.st_size = ( *convertor )( entry.st_size ); |
|||
entry.st_info = ( *convertor )( info ); |
|||
entry.st_other = ( *convertor )( other ); |
|||
entry.st_shndx = ( *convertor )( shndx ); |
|||
|
|||
symbol_section->append_data( reinterpret_cast<char*>( &entry ), |
|||
sizeof( entry ) ); |
|||
|
|||
Elf_Word nRet = |
|||
Elf_Word( symbol_section->get_size() / sizeof( entry ) - 1 ); |
|||
|
|||
return nRet; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// @brief Arrange local symbols in the section
|
|||
// @param func Function to be called for each pair of symbols
|
|||
// @return Number of local symbols
|
|||
//------------------------------------------------------------------------------
|
|||
template <class T> |
|||
Elf_Xword generic_arrange_local_symbols( |
|||
std::function<void( Elf_Xword first, Elf_Xword second )> func ) |
|||
{ |
|||
const auto& convertor = elf_file.get_convertor(); |
|||
|
|||
Elf_Word first_not_local = |
|||
1; // Skip the first entry. It is always NOTYPE
|
|||
Elf_Xword current = 0; |
|||
Elf_Xword count = get_symbols_num(); |
|||
|
|||
while ( true ) { |
|||
T* p1 = nullptr; |
|||
T* p2 = nullptr; |
|||
|
|||
while ( first_not_local < count ) { |
|||
p1 = const_cast<T*>( |
|||
generic_get_symbol_ptr<T>( first_not_local ) ); |
|||
if ( ELF_ST_BIND( ( *convertor )( p1->st_info ) ) != STB_LOCAL ) |
|||
break; |
|||
++first_not_local; |
|||
} |
|||
|
|||
current = first_not_local + 1; |
|||
while ( current < count ) { |
|||
p2 = const_cast<T*>( generic_get_symbol_ptr<T>( current ) ); |
|||
if ( ELF_ST_BIND( ( *convertor )( p2->st_info ) ) == STB_LOCAL ) |
|||
break; |
|||
++current; |
|||
} |
|||
|
|||
if ( first_not_local < count && current < count ) { |
|||
if ( func ) |
|||
func( first_not_local, current ); |
|||
|
|||
std::swap( *p1, *p2 ); |
|||
} |
|||
else { |
|||
// Update 'info' field of the section
|
|||
symbol_section->set_info( first_not_local ); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
return first_not_local; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
private: |
|||
const elfio& elf_file; ///< Reference to the ELF file
|
|||
S* symbol_section; ///< Pointer to the symbol section
|
|||
Elf_Half hash_section_index{ 0 }; ///< Index of the hash section
|
|||
const section* hash_section{ nullptr }; ///< Pointer to the hash section
|
|||
}; |
|||
|
|||
using symbol_section_accessor = symbol_section_accessor_template<section>; |
|||
using const_symbol_section_accessor = |
|||
symbol_section_accessor_template<const section>; |
|||
|
|||
} // namespace ELFIO
|
|||
|
|||
#endif // ELFIO_SYMBOLS_HPP
|
|||
@ -0,0 +1,373 @@ |
|||
/*
|
|||
Copyright (C) 2001-present by Serge Lamikhov-Center |
|||
|
|||
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. |
|||
*/ |
|||
|
|||
#ifndef ELFIO_UTILS_HPP |
|||
#define ELFIO_UTILS_HPP |
|||
|
|||
#include <cstdint> |
|||
#include <ostream> |
|||
#include <cstring> |
|||
|
|||
#define ELFIO_GET_ACCESS_DECL( TYPE, NAME ) virtual TYPE get_##NAME() const = 0 |
|||
|
|||
#define ELFIO_SET_ACCESS_DECL( TYPE, NAME ) \ |
|||
virtual void set_##NAME( const TYPE& value ) = 0 |
|||
|
|||
#define ELFIO_GET_SET_ACCESS_DECL( TYPE, NAME ) \ |
|||
virtual TYPE get_##NAME() const = 0; \ |
|||
virtual void set_##NAME( const TYPE& value ) = 0 |
|||
|
|||
#define ELFIO_GET_ACCESS( TYPE, NAME, FIELD ) \ |
|||
TYPE get_##NAME() const override { return ( *convertor )( FIELD ); } |
|||
|
|||
#define ELFIO_SET_ACCESS( TYPE, NAME, FIELD ) \ |
|||
void set_##NAME( const TYPE& value ) override \ |
|||
{ \ |
|||
FIELD = decltype( FIELD )( value ); \ |
|||
FIELD = ( *convertor )( FIELD ); \ |
|||
} |
|||
#define ELFIO_GET_SET_ACCESS( TYPE, NAME, FIELD ) \ |
|||
TYPE get_##NAME() const override { return ( *convertor )( FIELD ); } \ |
|||
void set_##NAME( const TYPE& value ) override \ |
|||
{ \ |
|||
FIELD = decltype( FIELD )( value ); \ |
|||
FIELD = ( *convertor )( FIELD ); \ |
|||
} |
|||
|
|||
namespace ELFIO { |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \class endianness_convertor
|
|||
//! \brief Class for converting endianness of data
|
|||
class endianness_convertor |
|||
{ |
|||
public: |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Setup the endianness convertor
|
|||
//! \param elf_file_encoding The encoding of the ELF file
|
|||
void setup( unsigned char elf_file_encoding ) |
|||
{ |
|||
need_conversion = ( elf_file_encoding != get_host_encoding() ); |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Convert a 64-bit unsigned integer
|
|||
//! \param value The value to convert
|
|||
//! \return The converted value
|
|||
std::uint64_t operator()( std::uint64_t value ) const |
|||
{ |
|||
if ( !need_conversion ) { |
|||
return value; |
|||
} |
|||
value = ( ( value & 0x00000000000000FFuLL ) << 56 ) | |
|||
( ( value & 0x000000000000FF00uLL ) << 40 ) | |
|||
( ( value & 0x0000000000FF0000uLL ) << 24 ) | |
|||
( ( value & 0x00000000FF000000uLL ) << 8 ) | |
|||
( ( value & 0x000000FF00000000uLL ) >> 8 ) | |
|||
( ( value & 0x0000FF0000000000uLL ) >> 24 ) | |
|||
( ( value & 0x00FF000000000000uLL ) >> 40 ) | |
|||
( ( value & 0xFF00000000000000uLL ) >> 56 ); |
|||
|
|||
return value; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Convert a 64-bit signed integer
|
|||
//! \param value The value to convert
|
|||
//! \return The converted value
|
|||
std::int64_t operator()( std::int64_t value ) const |
|||
{ |
|||
if ( !need_conversion ) { |
|||
return value; |
|||
} |
|||
return ( std::int64_t )( *this )( (std::uint64_t)value ); |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Convert a 32-bit unsigned integer
|
|||
//! \param value The value to convert
|
|||
//! \return The converted value
|
|||
std::uint32_t operator()( std::uint32_t value ) const |
|||
{ |
|||
if ( !need_conversion ) { |
|||
return value; |
|||
} |
|||
value = |
|||
( ( value & 0x000000FF ) << 24 ) | ( ( value & 0x0000FF00 ) << 8 ) | |
|||
( ( value & 0x00FF0000 ) >> 8 ) | ( ( value & 0xFF000000 ) >> 24 ); |
|||
|
|||
return value; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Convert a 32-bit signed integer
|
|||
//! \param value The value to convert
|
|||
//! \return The converted value
|
|||
std::int32_t operator()( std::int32_t value ) const |
|||
{ |
|||
if ( !need_conversion ) { |
|||
return value; |
|||
} |
|||
return ( std::int32_t )( *this )( (std::uint32_t)value ); |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Convert a 16-bit unsigned integer
|
|||
//! \param value The value to convert
|
|||
//! \return The converted value
|
|||
std::uint16_t operator()( std::uint16_t value ) const |
|||
{ |
|||
if ( !need_conversion ) { |
|||
return value; |
|||
} |
|||
value = ( std::uint16_t )( ( value & 0x00FF ) << 8 ) | |
|||
( ( value & 0xFF00 ) >> 8 ); |
|||
|
|||
return value; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Convert a 16-bit signed integer
|
|||
//! \param value The value to convert
|
|||
//! \return The converted value
|
|||
std::int16_t operator()( std::int16_t value ) const |
|||
{ |
|||
if ( !need_conversion ) { |
|||
return value; |
|||
} |
|||
return ( std::int16_t )( *this )( (std::uint16_t)value ); |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Convert an 8-bit signed integer
|
|||
//! \param value The value to convert
|
|||
//! \return The converted value
|
|||
std::int8_t operator()( std::int8_t value ) const { return value; } |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Convert an 8-bit unsigned integer
|
|||
//! \param value The value to convert
|
|||
//! \return The converted value
|
|||
std::uint8_t operator()( std::uint8_t value ) const { return value; } |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
private: |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the host encoding
|
|||
//! \return The host encoding
|
|||
unsigned char get_host_encoding() const |
|||
{ |
|||
static const int tmp = 1; |
|||
if ( 1 == *reinterpret_cast<const char*>( &tmp ) ) { |
|||
return ELFDATA2LSB; |
|||
} |
|||
else { |
|||
return ELFDATA2MSB; |
|||
} |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
bool need_conversion = false; //!< Flag indicating if conversion is needed
|
|||
}; |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \struct address_translation
|
|||
//! \brief Structure for address translation
|
|||
struct address_translation |
|||
{ |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Constructor
|
|||
//! \param start The start address
|
|||
//! \param size The size of the address range
|
|||
//! \param mapped_to The mapped address
|
|||
address_translation( std::uint64_t start, |
|||
std::uint64_t size, |
|||
std::uint64_t mapped_to ) |
|||
: start( start ), size( size ), mapped_to( mapped_to ){}; |
|||
std::streampos start; //!< Start address
|
|||
std::streampos size; //!< Size of the address range
|
|||
std::streampos mapped_to; //!< Mapped address
|
|||
}; |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \class address_translator
|
|||
//! \brief Class for translating addresses
|
|||
class address_translator |
|||
{ |
|||
public: |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Set address translation
|
|||
//! \param addr_trans Vector of address translations
|
|||
void set_address_translation( std::vector<address_translation>& addr_trans ) |
|||
{ |
|||
addr_translations = addr_trans; |
|||
|
|||
std::sort( addr_translations.begin(), addr_translations.end(), |
|||
[]( const address_translation& a, |
|||
const address_translation& b ) -> bool { |
|||
return a.start < b.start; |
|||
} ); |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Translate an address
|
|||
//! \param value The address to translate
|
|||
//! \return The translated address
|
|||
std::streampos operator[]( std::streampos value ) const |
|||
{ |
|||
if ( addr_translations.empty() ) { |
|||
return value; |
|||
} |
|||
|
|||
for ( auto& t : addr_translations ) { |
|||
if ( ( t.start <= value ) && ( ( value - t.start ) < t.size ) ) { |
|||
return value - t.start + t.mapped_to; |
|||
} |
|||
} |
|||
|
|||
return value; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Check if the address translator is empty
|
|||
//! \return True if empty, false otherwise
|
|||
bool empty() const { return addr_translations.empty(); } |
|||
|
|||
private: |
|||
std::vector<address_translation> |
|||
addr_translations; //!< Vector of address translations
|
|||
}; |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Calculate the ELF hash of a name
|
|||
//! \param name The name to hash
|
|||
//! \return The ELF hash
|
|||
inline std::uint32_t elf_hash( const unsigned char* name ) |
|||
{ |
|||
std::uint32_t h = 0; |
|||
std::uint32_t g = 0; |
|||
while ( *name != '\0' ) { |
|||
h = ( h << 4 ) + *name++; |
|||
g = h & 0xf0000000; |
|||
if ( g != 0 ) |
|||
h ^= g >> 24; |
|||
h &= ~g; |
|||
} |
|||
return h; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Calculate the GNU hash of a name
|
|||
//! \param s The name to hash
|
|||
//! \return The GNU hash
|
|||
inline std::uint32_t elf_gnu_hash( const unsigned char* s ) |
|||
{ |
|||
std::uint32_t h = 0x1505; |
|||
for ( unsigned char c = *s; c != '\0'; c = *++s ) |
|||
h = ( h << 5 ) + h + c; |
|||
return h; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Convert a value to a hexadecimal string
|
|||
//! \param value The value to convert
|
|||
//! \return The hexadecimal string
|
|||
inline std::string to_hex_string( std::uint64_t value ) |
|||
{ |
|||
std::string str; |
|||
|
|||
while ( value ) { |
|||
if ( auto digit = value & 0xF; digit < 0xA ) { |
|||
str = char( '0' + digit ) + str; |
|||
} |
|||
else { |
|||
str = char( 'A' + digit - 0xA ) + str; |
|||
} |
|||
value >>= 4; |
|||
} |
|||
|
|||
return "0x" + str; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Adjust the size of a stream
|
|||
//! \param stream The stream to adjust
|
|||
//! \param offset The offset to adjust to
|
|||
inline void adjust_stream_size( std::ostream& stream, std::streamsize offset ) |
|||
{ |
|||
stream.seekp( 0, std::ios_base::end ); |
|||
if ( stream.tellp() < offset ) { |
|||
std::streamsize size = offset - stream.tellp(); |
|||
stream.write( std::string( size_t( size ), '\0' ).c_str(), size ); |
|||
} |
|||
stream.seekp( offset ); |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the length of a string with a maximum length
|
|||
//! \param s The string
|
|||
//! \param n The maximum length
|
|||
//! \return The length of the string
|
|||
inline static size_t strnlength( const char* s, size_t n ) |
|||
{ |
|||
auto found = (const char*)std::memchr( s, '\0', n ); |
|||
return found ? (size_t)( found - s ) : n; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \class compression_interface
|
|||
//! \brief Interface for compression and decompression
|
|||
class compression_interface |
|||
{ |
|||
public: |
|||
virtual ~compression_interface() = default; |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Decompress a compressed section
|
|||
//! \param data The buffer of compressed data
|
|||
//! \param convertor Pointer to an endianness convertor instance
|
|||
//! \param compressed_size The size of the compressed data buffer
|
|||
//! \param uncompressed_size Reference to a variable to store the decompressed buffer size
|
|||
//! \return A smart pointer to the decompressed data
|
|||
virtual std::unique_ptr<char[]> |
|||
inflate( const char* data, |
|||
std::shared_ptr<const endianness_convertor> convertor, |
|||
Elf_Xword compressed_size, |
|||
Elf_Xword& uncompressed_size ) const = 0; |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Compress a section
|
|||
//! \param data The buffer of uncompressed data
|
|||
//! \param convertor Pointer to an endianness convertor instance
|
|||
//! \param decompressed_size The size of the uncompressed data buffer
|
|||
//! \param compressed_size Reference to a variable to store the compressed buffer size
|
|||
//! \return A smart pointer to the compressed data
|
|||
virtual std::unique_ptr<char[]> |
|||
deflate( const char* data, |
|||
std::shared_ptr<const endianness_convertor> convertor, |
|||
Elf_Xword decompressed_size, |
|||
Elf_Xword& compressed_size ) const = 0; |
|||
}; |
|||
|
|||
} // namespace ELFIO
|
|||
|
|||
#endif // ELFIO_UTILS_HPP
|
|||
@ -0,0 +1,4 @@ |
|||
//------------------------------------------------------------------------------
|
|||
//! \def ELFIO_VERSION
|
|||
//! \brief Defines the version of the ELFIO library
|
|||
#define ELFIO_VERSION "3.14" |
|||
@ -0,0 +1,310 @@ |
|||
/*
|
|||
Copyright (C) 2001-present by Serge Lamikhov-Center |
|||
|
|||
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. |
|||
*/ |
|||
|
|||
#ifndef ELFIO_VERSYM_HPP |
|||
#define ELFIO_VERSYM_HPP |
|||
|
|||
namespace ELFIO { |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \class versym_section_accessor_template
|
|||
//! \brief Class for accessing version symbol section data
|
|||
template <class S> class versym_section_accessor_template |
|||
{ |
|||
public: |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Constructor
|
|||
//! \param section Pointer to the section
|
|||
explicit versym_section_accessor_template( S* section ) |
|||
: versym_section( section ) |
|||
{ |
|||
if ( section != nullptr ) { |
|||
entries_num = decltype( entries_num )( section->get_size() / |
|||
sizeof( Elf_Half ) ); |
|||
} |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the number of entries
|
|||
//! \return Number of entries
|
|||
Elf_Word get_entries_num() const |
|||
{ |
|||
if ( versym_section ) { |
|||
return entries_num; |
|||
} |
|||
return 0; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get an entry
|
|||
//! \param no Index of the entry
|
|||
//! \param value Value of the entry
|
|||
//! \return True if successful, false otherwise
|
|||
bool get_entry( Elf_Word no, Elf_Half& value ) const |
|||
{ |
|||
if ( versym_section && ( no < get_entries_num() ) ) { |
|||
value = ( (Elf_Half*)versym_section->get_data() )[no]; |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Modify an entry
|
|||
//! \param no Index of the entry
|
|||
//! \param value New value of the entry
|
|||
//! \return True if successful, false otherwise
|
|||
bool modify_entry( Elf_Word no, Elf_Half value ) |
|||
{ |
|||
if ( versym_section && ( no < get_entries_num() ) ) { |
|||
( (Elf_Half*)versym_section->get_data() )[no] = value; |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Add an entry
|
|||
//! \param value Value of the entry
|
|||
//! \return True if successful, false otherwise
|
|||
bool add_entry( Elf_Half value ) |
|||
{ |
|||
if ( !versym_section ) { |
|||
return false; |
|||
} |
|||
|
|||
versym_section->append_data( (const char*)&value, sizeof( Elf_Half ) ); |
|||
++entries_num; |
|||
|
|||
return true; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
private: |
|||
S* versym_section = nullptr; //!< Pointer to the section
|
|||
Elf_Word entries_num = 0; //!< Number of entries
|
|||
}; |
|||
|
|||
using versym_section_accessor = versym_section_accessor_template<section>; |
|||
using const_versym_section_accessor = |
|||
versym_section_accessor_template<const section>; |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \class versym_r_section_accessor_template
|
|||
//! \brief Class for accessing version requirement section data
|
|||
template <class S> class versym_r_section_accessor_template |
|||
{ |
|||
public: |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Constructor
|
|||
//! \param elf_file Reference to the ELF file
|
|||
//! \param versym_r_section Pointer to the version requirement section
|
|||
versym_r_section_accessor_template( const elfio& elf_file, |
|||
S* versym_r_section ) |
|||
: elf_file( elf_file ), versym_r_section( versym_r_section ), |
|||
entries_num( 0 ) |
|||
{ |
|||
// Find .dynamic section
|
|||
const section* dynamic_section = elf_file.sections[".dynamic"]; |
|||
|
|||
if ( dynamic_section == nullptr ) { |
|||
return; |
|||
} |
|||
|
|||
const_dynamic_section_accessor dynamic_section_acc( elf_file, |
|||
dynamic_section ); |
|||
Elf_Xword dyn_sec_num = dynamic_section_acc.get_entries_num(); |
|||
for ( Elf_Xword i = 0; i < dyn_sec_num; ++i ) { |
|||
Elf_Xword tag; |
|||
Elf_Xword value; |
|||
std::string str; |
|||
|
|||
if ( dynamic_section_acc.get_entry( i, tag, value, str ) && |
|||
tag == DT_VERNEEDNUM ) { |
|||
entries_num = (Elf_Word)value; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the number of entries
|
|||
//! \return Number of entries
|
|||
Elf_Word get_entries_num() const { return entries_num; } |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get an entry
|
|||
//! \param no Index of the entry
|
|||
//! \param version Version of the entry
|
|||
//! \param file_name File name of the entry
|
|||
//! \param hash Hash of the entry
|
|||
//! \param flags Flags of the entry
|
|||
//! \param other Other information of the entry
|
|||
//! \param dep_name Dependency name of the entry
|
|||
//! \return True if successful, false otherwise
|
|||
bool get_entry( Elf_Word no, |
|||
Elf_Half& version, |
|||
std::string& file_name, |
|||
Elf_Word& hash, |
|||
Elf_Half& flags, |
|||
Elf_Half& other, |
|||
std::string& dep_name ) const |
|||
{ |
|||
if ( versym_r_section == nullptr || ( no >= get_entries_num() ) ) { |
|||
return false; |
|||
} |
|||
|
|||
const_string_section_accessor string_section_acc( |
|||
elf_file.sections[versym_r_section->get_link()] ); |
|||
|
|||
Elfxx_Verneed* verneed = (Elfxx_Verneed*)versym_r_section->get_data(); |
|||
Elfxx_Vernaux* veraux = |
|||
(Elfxx_Vernaux*)( (char*)verneed + verneed->vn_aux ); |
|||
for ( Elf_Word i = 0; i < no; ++i ) { |
|||
verneed = (Elfxx_Verneed*)( (char*)verneed + verneed->vn_next ); |
|||
veraux = (Elfxx_Vernaux*)( (char*)verneed + verneed->vn_aux ); |
|||
} |
|||
|
|||
version = verneed->vn_version; |
|||
file_name = string_section_acc.get_string( verneed->vn_file ); |
|||
hash = veraux->vna_hash; |
|||
flags = veraux->vna_flags; |
|||
other = veraux->vna_other; |
|||
dep_name = string_section_acc.get_string( veraux->vna_name ); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
private: |
|||
const elfio& elf_file; |
|||
S* versym_r_section = |
|||
nullptr; //!< Pointer to the version requirement section
|
|||
Elf_Word entries_num = 0; //!< Number of entries
|
|||
}; |
|||
|
|||
using versym_r_section_accessor = versym_r_section_accessor_template<section>; |
|||
using const_versym_r_section_accessor = |
|||
versym_r_section_accessor_template<const section>; |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \class versym_d_section_accessor_template
|
|||
//! \brief Class for accessing version definition section data
|
|||
template <class S> class versym_d_section_accessor_template |
|||
{ |
|||
public: |
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Constructor
|
|||
//! \param elf_file Reference to the ELF file
|
|||
//! \param versym_d_section Pointer to the version definition section
|
|||
versym_d_section_accessor_template( const elfio& elf_file, |
|||
S* versym_d_section ) |
|||
: elf_file( elf_file ), versym_d_section( versym_d_section ), |
|||
entries_num( 0 ) |
|||
{ |
|||
// Find .dynamic section
|
|||
const section* dynamic_section = elf_file.sections[".dynamic"]; |
|||
|
|||
if ( dynamic_section == nullptr ) { |
|||
return; |
|||
} |
|||
|
|||
const_dynamic_section_accessor dynamic_section_acc( elf_file, |
|||
dynamic_section ); |
|||
Elf_Xword dyn_sec_num = dynamic_section_acc.get_entries_num(); |
|||
for ( Elf_Xword i = 0; i < dyn_sec_num; ++i ) { |
|||
Elf_Xword tag; |
|||
Elf_Xword value; |
|||
std::string str; |
|||
|
|||
if ( dynamic_section_acc.get_entry( i, tag, value, str ) && |
|||
tag == DT_VERDEFNUM ) { |
|||
entries_num = (Elf_Word)value; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get the number of entries
|
|||
//! \return Number of entries
|
|||
Elf_Word get_entries_num() const { return entries_num; } |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
//! \brief Get an entry
|
|||
//! \param no Index of the entry
|
|||
//! \param flags Flags of the entry
|
|||
//! \param version_index Version index of the entry
|
|||
//! \param hash Hash of the entry
|
|||
//! \param dep_name Dependency name of the entry
|
|||
//! \return True if successful, false otherwise
|
|||
bool get_entry( Elf_Word no, |
|||
Elf_Half& flags, |
|||
Elf_Half& version_index, |
|||
Elf_Word& hash, |
|||
std::string& dep_name ) const |
|||
{ |
|||
if ( versym_d_section == nullptr || ( no >= get_entries_num() ) ) { |
|||
return false; |
|||
} |
|||
|
|||
const_string_section_accessor string_section_acc( |
|||
elf_file.sections[versym_d_section->get_link()] ); |
|||
|
|||
Elfxx_Verdef* verdef = (Elfxx_Verdef*)versym_d_section->get_data(); |
|||
Elfxx_Verdaux* verdaux = |
|||
(Elfxx_Verdaux*)( (char*)verdef + verdef->vd_aux ); |
|||
for ( Elf_Word i = 0; i < no; ++i ) { |
|||
verdef = (Elfxx_Verdef*)( (char*)verdef + verdef->vd_next ); |
|||
verdaux = (Elfxx_Verdaux*)( (char*)verdef + verdef->vd_aux ); |
|||
} |
|||
|
|||
// verdef->vd_version should always be 1
|
|||
// see https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA.junk/symversion.html#VERDEFENTRIES
|
|||
// verdef->vd_cnt should always be 1.
|
|||
// see https://maskray.me/blog/2020-11-26-all-about-symbol-versioning
|
|||
|
|||
flags = verdef->vd_flags; |
|||
version_index = verdef->vd_ndx; |
|||
hash = verdef->vd_hash; |
|||
dep_name = string_section_acc.get_string( verdaux->vda_name ); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
private: |
|||
const elfio& elf_file; |
|||
S* versym_d_section = |
|||
nullptr; //!< Pointer to the version definition section
|
|||
Elf_Word entries_num = 0; //!< Number of entries
|
|||
}; |
|||
|
|||
using versym_d_section_accessor = versym_d_section_accessor_template<section>; |
|||
using const_versym_d_section_accessor = |
|||
versym_d_section_accessor_template<const section>; |
|||
|
|||
} // namespace ELFIO
|
|||
|
|||
#endif // ELFIO_VERSYM_HPP
|
|||
@ -0,0 +1,564 @@ |
|||
/* Routines for reading/writing Intel INHX8M and INHX32 files
|
|||
|
|||
Copyright 2002 Brandon Fosdick (BSD License) |
|||
*/ |
|||
|
|||
#include <fstream> |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include "intelhex.h" |
|||
#include <string> |
|||
|
|||
namespace intelhex |
|||
{ |
|||
|
|||
#define INH32M_HEADER ":020000040000FA" |
|||
|
|||
// Array access operator
|
|||
value_type& hex_data::operator[](address_type address) |
|||
{ |
|||
// Start at the end of the list and find the first (last) block with an address
|
|||
// less than addr
|
|||
reverse_iterator i = blocks.rbegin(); |
|||
while (i != blocks.rend()) |
|||
{ |
|||
if (i->first <= address) |
|||
{ |
|||
// Use the block if address is interior or adjacent to the block
|
|||
if ((address - i->first) <= i->second.size()) |
|||
return i->second[address - i->first]; |
|||
break; |
|||
} |
|||
++i; |
|||
} |
|||
return blocks[address][0]; |
|||
} |
|||
|
|||
// Return the value at address, or _fill if not set
|
|||
value_type hex_data::get(address_type address) |
|||
{ |
|||
// Start at the end of the list and find the first (last) block with an address
|
|||
// less than addr
|
|||
reverse_iterator i = blocks.rbegin(); |
|||
while (i != blocks.rend()) |
|||
{ |
|||
if (i->first <= address) |
|||
{ |
|||
// Use the block if address is interior to the block
|
|||
if ((address - i->first) < i->second.size()) |
|||
return i->second[address - i->first]; |
|||
break; |
|||
} |
|||
++i; |
|||
} |
|||
return _fill; |
|||
} |
|||
|
|||
// Set the value at address or create a new element using value
|
|||
void hex_data::set(address_type address, value_type value) |
|||
{ |
|||
if (value == fill()) // Handle fill values
|
|||
{ |
|||
erase(address); // If the address is already set, erase it
|
|||
return; |
|||
} |
|||
|
|||
// Start at the end of the list and find the first (last) block with an address
|
|||
// less than addr
|
|||
reverse_iterator i = blocks.rbegin(); |
|||
while (i != blocks.rend()) |
|||
{ |
|||
if (i->first <= address) |
|||
{ |
|||
// Use the block if address is interior or adjacent to the block
|
|||
const address_type index = address - i->first; |
|||
if (index < i->second.size()) |
|||
{ |
|||
i->second[index] = value; |
|||
return; |
|||
} |
|||
else if (index == i->second.size()) |
|||
{ |
|||
i->second.push_back(value); |
|||
return; |
|||
} |
|||
break; |
|||
} |
|||
++i; |
|||
} |
|||
blocks[address].push_back(value); // Otherwise create a new block
|
|||
} |
|||
|
|||
// Merge adjacent blocks
|
|||
void hex_data::compact() |
|||
{ |
|||
iterator previous = blocks.begin(); |
|||
iterator i = previous; |
|||
|
|||
for (++i; i != blocks.end(); ++i) |
|||
{ |
|||
if ((previous->first + previous->second.size()) == i->first) |
|||
{ |
|||
previous->second.insert(previous->second.end(), i->second.begin(), i->second.end()); |
|||
blocks.erase(i); |
|||
i = previous; |
|||
} |
|||
previous = i; |
|||
} |
|||
} |
|||
|
|||
// Delete all allocated memory
|
|||
void hex_data::clear() |
|||
{ |
|||
_fill = 0; |
|||
format = HEX_FORMAT_INHX8M; |
|||
linear_addr_rec = false; |
|||
segment_addr_rec = false; |
|||
blocks.clear(); |
|||
} |
|||
|
|||
// Erase a single element at the given address
|
|||
void hex_data::erase(address_type address) |
|||
{ |
|||
for (iterator i = blocks.begin(); i != blocks.end(); ++i) |
|||
{ |
|||
// The blocks are sorted, so if the byte to be deleted is
|
|||
// before the block it must be a blank address that's either
|
|||
// before the first block or after any previous blocks.
|
|||
if (address < i->first) |
|||
break; |
|||
// Ignore the block if address is past the end of the block
|
|||
const address_type ope = i->first + i->second.size(); |
|||
if (address >= ope) |
|||
continue; |
|||
// address is now guaranteed to be >= i->first and < ope
|
|||
// Copy trailing portion of the old block to a new block
|
|||
if ((ope - address) > 1) |
|||
{ |
|||
const address_type index = address - i->first + 1; |
|||
blocks[address + 1].assign(i->second.begin() + index, i->second.end()); |
|||
} |
|||
// Truncate or delete old block
|
|||
const address_type size = address - i->first; |
|||
if (size) |
|||
i->second.resize(size); |
|||
else |
|||
blocks.erase(i); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
// Erase [first, last]
|
|||
void hex_data::erase(address_type first, address_type last) |
|||
{ |
|||
if (first > last) |
|||
std::swap(first, last); |
|||
|
|||
for (iterator i = blocks.begin(); (i != blocks.end()) && (first <= last); ++i) |
|||
{ |
|||
const address_type ope = i->first + i->second.size(); |
|||
if (first >= ope) // Ignore all blocks with addresses < first
|
|||
continue; |
|||
// The blocks are sorted, so if the first byte to be deleted is
|
|||
// before the block it must be a blank address that's either
|
|||
// before the first block or after any previous blocks.
|
|||
if (first < i->first) |
|||
{ |
|||
if (last < i->first) // If the entire range is before the
|
|||
return; // block there's nothing left to do
|
|||
first = i->first; // Advance to the next non-blank address
|
|||
} |
|||
// first is now guaranteed to be >= i->first and < ope
|
|||
if (last < ope) // Entire range is interior
|
|||
{ |
|||
// Copy trailing portion of the old block to a new block
|
|||
if ((ope - last) > 1) |
|||
{ |
|||
const address_type index = last - i->first + 1; |
|||
blocks[last + 1].assign(i->second.begin() + index, i->second.end()); |
|||
} |
|||
// Truncate or delete old block
|
|||
const address_type size = first - i->first; |
|||
if (size) |
|||
i->second.resize(size); |
|||
else |
|||
blocks.erase(i); |
|||
return; |
|||
} |
|||
else // Truncate block
|
|||
{ |
|||
const address_type size = first - i->first; |
|||
if (size) |
|||
i->second.resize(size); |
|||
else |
|||
blocks.erase(i--); |
|||
first = ope; |
|||
} |
|||
} |
|||
} |
|||
|
|||
hex_data::size_type hex_data::size() |
|||
{ |
|||
size_type s = 0; |
|||
|
|||
for (iterator i = blocks.begin(); i != blocks.end(); ++i) |
|||
s += i->second.size(); |
|||
|
|||
return s; |
|||
} |
|||
|
|||
// Returns the number of populated elements with addresses less than addr
|
|||
hex_data::size_type hex_data::size_below_addr(address_type addr) |
|||
{ |
|||
size_type s = 0; |
|||
|
|||
for (iterator i = blocks.begin(); i != blocks.end(); ++i) |
|||
{ |
|||
if ((i->first + i->second.size()) < addr) |
|||
s += i->second.size(); |
|||
else if (i->first < addr) |
|||
s += addr - i->first; |
|||
} |
|||
|
|||
return s; |
|||
} |
|||
|
|||
// number of words in [lo, hi)
|
|||
hex_data::size_type hex_data::size_in_range(address_type lo, address_type hi) |
|||
{ |
|||
size_type s = 0; |
|||
|
|||
for (iterator i = blocks.begin(); i != blocks.end(); ++i) |
|||
{ |
|||
if (i->first < lo) |
|||
{ |
|||
const size_type a = i->first + i->second.size(); |
|||
if (a >= lo) |
|||
s += a - lo; |
|||
} |
|||
else |
|||
{ |
|||
if ((i->first + i->second.size()) < hi) |
|||
s += i->second.size(); |
|||
else if (i->first < hi) |
|||
s += hi - i->first; |
|||
} |
|||
} |
|||
|
|||
return s; |
|||
} |
|||
|
|||
// Return the max address of all of the set words with addresses less than or equal to hi
|
|||
address_type hex_data::max_addr_below(address_type hi) |
|||
{ |
|||
address_type s = 0; |
|||
|
|||
for (iterator i = blocks.begin(); i != blocks.end(); ++i) |
|||
{ |
|||
if (i->first <= hi) |
|||
{ |
|||
const address_type a = i->first + i->second.size() - 1; //Max address of this block
|
|||
if (a > s) |
|||
s = a; |
|||
} |
|||
} |
|||
if (s > hi) |
|||
return hi; |
|||
else |
|||
return s; |
|||
} |
|||
|
|||
// Lowest address
|
|||
address_type hex_data::min_address() const |
|||
{ |
|||
return blocks.begin()->first; |
|||
} |
|||
|
|||
// Highest address
|
|||
address_type hex_data::max_address() const |
|||
{ |
|||
return blocks.rbegin()->first + blocks.rbegin()->second.size() - 1; |
|||
} |
|||
|
|||
//Return true if an element exists at addr
|
|||
bool hex_data::is_set(address_type addr) |
|||
{ |
|||
// Start at the end of the list and find the first (last) block with an address
|
|||
// less than addr
|
|||
reverse_iterator i = blocks.rbegin(); |
|||
while ((i != blocks.rend()) && (i->first > addr)) |
|||
++i; |
|||
|
|||
if ((addr - i->first) >= i->second.size()) |
|||
return false; |
|||
else |
|||
return true; |
|||
} |
|||
|
|||
// Load from a file
|
|||
void hex_data::load(const std::string& path) |
|||
{ |
|||
std::ifstream f(path.c_str()); |
|||
read(f); |
|||
} |
|||
|
|||
// Convert a string from hex to binary and append it to a block
|
|||
uint8_t hex2binary(hex_data::data_container& to, std::string& from) |
|||
{ |
|||
value_type sum = 0, value; |
|||
uint8_t character; |
|||
bool first = true; |
|||
std::string::iterator i = from.begin(); |
|||
|
|||
while (i != from.end()) |
|||
{ |
|||
character = *i; |
|||
|
|||
if ((character >= '0') && (character <= '9')) |
|||
character -= '0'; |
|||
else if ((character >= 'A') && (character <= 'Z')) |
|||
character -= 'A' - 10; |
|||
else if ((character >= 'a') && (character <= 'z')) |
|||
character -= 'a' - 10; |
|||
else |
|||
break; // Bad character
|
|||
|
|||
if (first) |
|||
value = character << 4; |
|||
else |
|||
{ |
|||
value |= character; |
|||
to.push_back(value); |
|||
sum += value; |
|||
} |
|||
|
|||
first = !first; |
|||
++i; |
|||
} |
|||
|
|||
return sum; |
|||
} |
|||
|
|||
// Read data from an input stream
|
|||
void hex_data::read(std::istream& s) |
|||
{ |
|||
address_type address; |
|||
address_type extended_address(0); |
|||
std::string line; |
|||
data_container buffer; |
|||
|
|||
while ((s.get() == ':') && s.good()) |
|||
{ |
|||
getline(s, line); // Read the whole line
|
|||
if (line.size() <= 10) // Ignore truncated lines
|
|||
break; |
|||
buffer.clear(); |
|||
buffer.reserve(line.size() / 2); // Pre-allocate
|
|||
if (hex2binary(buffer, line)) // Ignore lines with bad checksums
|
|||
break; |
|||
|
|||
address = buffer[1]; |
|||
address = (address << 8) | buffer[2]; |
|||
unsigned length = buffer[0]; |
|||
const unsigned type = buffer[3]; |
|||
value_type* data = &buffer[4]; |
|||
|
|||
switch (type) |
|||
{ |
|||
case 0: //Data block
|
|||
{ |
|||
address += extended_address; |
|||
iterator i = blocks.begin(); |
|||
for (; i != blocks.end(); ++i) // Find a block that includes address
|
|||
{ |
|||
address_type num = 0; |
|||
// If the start of the new block is interior to an existing block...
|
|||
if ((i->first <= address) && ((i->first + i->second.size()) > address)) |
|||
{ |
|||
// Store the portion of the new block that overlaps the existing block
|
|||
const size_type index = address - i->first; |
|||
num = i->second.size() - index; |
|||
if (num > length) |
|||
num = length; |
|||
std::copy(data, data + num, &(i->second[index])); |
|||
} |
|||
// If the end of the new block is interior to an existing block...
|
|||
if ((address < i->first) && ((address + length) > i->first)) |
|||
{ |
|||
// Create a new block for the non-overlapping portion
|
|||
num = i->first - address; |
|||
if (num > length) |
|||
num = length; |
|||
blocks[address].assign(data, data + num); |
|||
} |
|||
length -= num; |
|||
address += num; |
|||
data += num; |
|||
// Bail out early if there's nothing left to do
|
|||
if (0 == length) |
|||
break; |
|||
} |
|||
// Handle any leftover bytes
|
|||
if (length) |
|||
blocks[address].assign(data, data + length); |
|||
break; |
|||
} |
|||
case 1: break; // Ignore EOF record
|
|||
case 2: // Segment address record (INHX32)
|
|||
if ((0 == address) && (2 == length)) |
|||
{ |
|||
extended_address = buffer[4]; |
|||
extended_address = (extended_address << 8) | buffer[5]; |
|||
extended_address <<= 4; |
|||
segment_addr_rec = true; |
|||
} |
|||
break; |
|||
case 4: // Linear address record (INHX32)
|
|||
if ((0 == address) && (2 == length)) |
|||
{ |
|||
extended_address = buffer[4]; |
|||
extended_address = (extended_address << 8) | buffer[5]; |
|||
extended_address <<= 16; |
|||
linear_addr_rec = true; |
|||
} |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Write all data to a file
|
|||
void hex_data::write(const char* path) |
|||
{ |
|||
std::ofstream ofs(path); |
|||
if (!ofs) // Bail out on bad files
|
|||
return; |
|||
write(ofs); |
|||
ofs.close(); |
|||
} |
|||
|
|||
// Write all data to an output stream
|
|||
void hex_data::write(std::ostream& os) |
|||
{ |
|||
uint8_t checksum; |
|||
uint16_t linear_address(0); |
|||
|
|||
if (!os) // Bail out on bad streams
|
|||
return; |
|||
|
|||
os.setf(std::ios::hex, std::ios::basefield); //Set the stream to ouput hex instead of decimal
|
|||
os.setf(std::ios::uppercase); //Use uppercase hex notation
|
|||
os.fill('0'); //Pad with zeroes
|
|||
|
|||
//If we already know that this is an INHX32M file, start with a segment address record
|
|||
// otherwise check all of the blocks just to make sure
|
|||
if (linear_addr_rec) |
|||
{ |
|||
os << INH32M_HEADER << std::endl; |
|||
} |
|||
else |
|||
{ |
|||
for (iterator i = blocks.begin(); i != blocks.end(); i++) |
|||
{ |
|||
if (i->first > 0xFFFF) //Check the upper 16 bits
|
|||
{ |
|||
linear_addr_rec = true; |
|||
os << INH32M_HEADER << std::endl; |
|||
break; //Only need to find one
|
|||
} |
|||
} |
|||
} |
|||
|
|||
for (iterator i = blocks.begin(); i != blocks.end(); i++) |
|||
{ |
|||
// Check upper 16 bits of the block address for non-zero,
|
|||
// which indicates that a segment address record is needed
|
|||
if (i->first > 0xFFFF) |
|||
{ |
|||
const uint16_t addr(i->first >> 16); |
|||
//Has a record for this segment already been emitted?
|
|||
if (addr != linear_address) |
|||
{ |
|||
//Emit a new segment address record
|
|||
os << ":02000004"; |
|||
os.width(4); |
|||
os << addr; //Address
|
|||
// Create a checksum for the linear address record
|
|||
checksum = 0x06 + addr + (addr >> 8); |
|||
checksum = 0x01 + ~checksum; |
|||
os.width(2); |
|||
// OSX (or maybe GCC), seems unable to handle uint8_t
|
|||
// arguments to a stream
|
|||
os << static_cast<uint16_t>(checksum); // Checksum byte
|
|||
os << std::endl; |
|||
linear_address = addr; |
|||
} |
|||
} |
|||
checksum = 0; |
|||
os << ':'; //Every line begins with ':'
|
|||
os.width(2); |
|||
os << i->second.size(); //Length
|
|||
checksum += i->second.size(); |
|||
os.width(4); |
|||
os << static_cast<uint16_t>(i->first); //Address
|
|||
checksum += static_cast<uint8_t>(i->first); // Low byte
|
|||
checksum += static_cast<uint8_t>(i->first >> 8); // High byte
|
|||
os << "00"; //Record type
|
|||
for (unsigned j = 0; j < i->second.size(); ++j) //Store the data bytes, LSB first, ASCII HEX
|
|||
{ |
|||
os.width(2); |
|||
// OSX (or maybe GCC), seems unable to handle uint8_t
|
|||
// arguments to a stream
|
|||
os << static_cast<uint16_t>(i->second[j]); |
|||
checksum += i->second[j]; |
|||
} |
|||
checksum = 0x01 + ~checksum; |
|||
os.width(2); |
|||
// OSX (or maybe GCC), seems unable to handle uint8_t arguments to a stream
|
|||
os << static_cast<uint16_t>(checksum); // Checksum byte
|
|||
os << std::endl; |
|||
} |
|||
os << ":00000001FF\n"; //EOF marker
|
|||
} |
|||
|
|||
// Make things pretty
|
|||
// Truncate blocks to a given length as needed
|
|||
void hex_data::tidy(hex_data::size_type length) |
|||
{ |
|||
for (iterator i = blocks.begin(); i != blocks.end(); i++) |
|||
{ |
|||
if (i->second.size() > length) //If the block is too long...
|
|||
{ |
|||
//Make an interator that points to the first element to copy out of i->second
|
|||
data_container::iterator k(i->second.begin()); |
|||
advance(k, length); |
|||
|
|||
// Assign the extra elements to a new block and truncate the original
|
|||
blocks[i->first + length].assign(k, i->second.end()); |
|||
i->second.erase(k, i->second.end()); |
|||
} |
|||
} |
|||
} |
|||
|
|||
//Compare two sets of hex data
|
|||
// Return true if every word in hex1 has a corresponding, and equivalent, word in hex2
|
|||
bool compare(hex_data& hex1, hex_data& hex2, value_type mask, address_type begin, address_type end) |
|||
{ |
|||
//Walk block list from hex1
|
|||
for (hex_data::iterator i = hex1.begin(); i != hex1.end(); ++i) |
|||
{ |
|||
//Walk the block
|
|||
address_type addr(i->first); |
|||
for (hex_data::data_container::iterator j = i->second.begin(); j != i->second.end(); ++j, ++addr) |
|||
{ |
|||
if ((addr < begin) || (addr > end)) |
|||
continue; |
|||
|
|||
//Compare both sides through the given mask
|
|||
if (((*j) & mask) != (hex2.get(addr) & mask)) |
|||
return false; |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,79 @@ |
|||
/* Routines for reading/writing Intel INHX8M and INHX32 files
|
|||
|
|||
Copyright 2002 Brandon Fosdick (BSD License) |
|||
*/ |
|||
|
|||
#ifndef INTELHEXH |
|||
#define INTELHEXH |
|||
|
|||
#include <iostream> |
|||
#include <map> |
|||
#include <vector> |
|||
|
|||
namespace intelhex |
|||
{ |
|||
|
|||
#define HEX_FORMAT_INHX8M 0x01 |
|||
#define HEX_FORMAT_INHX32 0x02 |
|||
|
|||
class hex_data; |
|||
typedef hex_data container; |
|||
typedef uint32_t address_type; |
|||
typedef uint8_t value_type; |
|||
|
|||
//The data set that results from parsing a hex file
|
|||
struct hex_data |
|||
{ |
|||
//Each line of the hex file generates a block of memory at a particular address
|
|||
typedef std::vector<value_type> data_container; //Element container
|
|||
typedef std::map<address_type, data_container> container; //List of data blocks
|
|||
|
|||
typedef container::iterator iterator; |
|||
typedef container::reverse_iterator reverse_iterator; |
|||
typedef data_container::size_type size_type; |
|||
private: |
|||
value_type _fill; // Value returned for unset addresses
|
|||
char format; //Format of the parsed file (necessary?)
|
|||
bool segment_addr_rec; // Uses/Has a segment address record
|
|||
bool linear_addr_rec; // Uses/Has a linear address record
|
|||
container blocks; // List of data blocks
|
|||
|
|||
public: |
|||
hex_data() : _fill(0), segment_addr_rec(false), linear_addr_rec(false) {} |
|||
hex_data(const std::string& s) : _fill(0), segment_addr_rec(false), linear_addr_rec(false) |
|||
{ |
|||
load(s); |
|||
} |
|||
iterator begin() { return blocks.begin(); } |
|||
iterator end() { return blocks.end(); } |
|||
|
|||
void compact(); // Merge adjacent blocks
|
|||
void clear(); //Delete everything
|
|||
void erase(address_type); // Erase a single element
|
|||
void erase(address_type first, address_type last); // Erase [first, last]
|
|||
value_type fill() { return _fill; } |
|||
void fill(value_type f) { _fill = f; } |
|||
size_type size(); |
|||
size_type size_below_addr(address_type); |
|||
size_type size_in_range(address_type, address_type); //number of words in [lo, hi)
|
|||
address_type max_addr_below(address_type); |
|||
|
|||
address_type min_address() const; // Lowest address
|
|||
address_type max_address() const; // Highest address
|
|||
|
|||
bool is_set(address_type); |
|||
|
|||
value_type& operator[](address_type); //Array access operator
|
|||
value_type get(address_type); // Return the value at address
|
|||
void set(address_type, value_type); // Set the value at address
|
|||
|
|||
void load(const std::string&); // Load from a file
|
|||
void read(std::istream&); // Read data from an input stream
|
|||
void write(const char*); //Save hex data to a hex file
|
|||
void write(std::ostream&); //Write all data to an output stream
|
|||
void tidy(size_type length); // Make things pretty
|
|||
}; |
|||
|
|||
bool compare(hex_data&, hex_data&, value_type, address_type, address_type); |
|||
} |
|||
#endif |
|||
Loading…
Reference in new issue