feat add dispatcher
This commit is contained in:
6
3party/libelfin/elf/.gitignore
vendored
Normal file
6
3party/libelfin/elf/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
*.o
|
||||
to_string.cc
|
||||
libelf++.a
|
||||
libelf++.so
|
||||
libelf++.so.*
|
||||
libelf++.pc
|
||||
109
3party/libelfin/elf/common.hh
Normal file
109
3party/libelfin/elf/common.hh
Normal file
@@ -0,0 +1,109 @@
|
||||
// Copyright (c) 2013 Austin T. Clements. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#ifndef _ELFPP_COMMON_HH_
|
||||
#define _ELFPP_COMMON_HH_
|
||||
|
||||
#define ELFPP_BEGIN_NAMESPACE namespace elf {
|
||||
#define ELFPP_END_NAMESPACE }
|
||||
#define ELFPP_BEGIN_INTERNAL namespace internal {
|
||||
#define ELFPP_END_INTERNAL }
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
ELFPP_BEGIN_NAMESPACE
|
||||
|
||||
/**
|
||||
* A byte ordering.
|
||||
*/
|
||||
enum class byte_order
|
||||
{
|
||||
native,
|
||||
lsb,
|
||||
msb
|
||||
};
|
||||
|
||||
/**
|
||||
* Return either byte_order::lsb or byte_order::msb. If the argument
|
||||
* is byte_order::native, it will be resolved to whatever the native
|
||||
* byte order is.
|
||||
*/
|
||||
static inline byte_order
|
||||
resolve_order(byte_order o)
|
||||
{
|
||||
static const union
|
||||
{
|
||||
int i;
|
||||
char c[sizeof(int)];
|
||||
} test = {1};
|
||||
|
||||
if (o == byte_order::native)
|
||||
return test.c[0] == 1 ? byte_order::lsb : byte_order::msb;
|
||||
return o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return v converted from one byte order to another.
|
||||
*/
|
||||
template<typename T>
|
||||
T
|
||||
swizzle(T v, byte_order from, byte_order to)
|
||||
{
|
||||
static_assert(sizeof(T) == 1 ||
|
||||
sizeof(T) == 2 ||
|
||||
sizeof(T) == 4 ||
|
||||
sizeof(T) == 8,
|
||||
"cannot swizzle type");
|
||||
|
||||
from = resolve_order(from);
|
||||
to = resolve_order(to);
|
||||
|
||||
if (from == to)
|
||||
return v;
|
||||
|
||||
switch (sizeof(T)) {
|
||||
case 1:
|
||||
return v;
|
||||
case 2: {
|
||||
std::uint16_t x = (std::uint16_t)v;
|
||||
return (T)(((x&0xFF) << 8) | (x >> 8));
|
||||
}
|
||||
case 4:
|
||||
return (T)__builtin_bswap32((std::uint32_t)v);
|
||||
case 8:
|
||||
return (T)__builtin_bswap64((std::uint64_t)v);
|
||||
}
|
||||
}
|
||||
|
||||
ELFPP_BEGIN_INTERNAL
|
||||
|
||||
/**
|
||||
* OrderPick selects between Native, LSB, and MSB based on ord.
|
||||
*/
|
||||
template<byte_order ord, typename Native, typename LSB, typename MSB>
|
||||
struct OrderPick;
|
||||
|
||||
template<typename Native, typename LSB, typename MSB>
|
||||
struct OrderPick<byte_order::native, Native, LSB, MSB>
|
||||
{
|
||||
typedef Native T;
|
||||
};
|
||||
|
||||
template<typename Native, typename LSB, typename MSB>
|
||||
struct OrderPick<byte_order::lsb, Native, LSB, MSB>
|
||||
{
|
||||
typedef LSB T;
|
||||
};
|
||||
|
||||
template<typename Native, typename LSB, typename MSB>
|
||||
struct OrderPick<byte_order::msb, Native, LSB, MSB>
|
||||
{
|
||||
typedef MSB T;
|
||||
};
|
||||
|
||||
ELFPP_END_INTERNAL
|
||||
|
||||
ELFPP_END_NAMESPACE
|
||||
|
||||
#endif
|
||||
574
3party/libelfin/elf/data.hh
Normal file
574
3party/libelfin/elf/data.hh
Normal file
@@ -0,0 +1,574 @@
|
||||
// Copyright (c) 2013 Austin T. Clements. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#ifndef _ELFPP_DATA_HH_
|
||||
#define _ELFPP_DATA_HH_
|
||||
|
||||
#include "common.hh"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
ELFPP_BEGIN_NAMESPACE
|
||||
|
||||
// Object file classes (ELF64 table 3)
|
||||
enum class elfclass : unsigned char
|
||||
{
|
||||
_32 = 1, // 32-bit objects
|
||||
_64 = 2, // 64-bit objects
|
||||
};
|
||||
|
||||
std::string
|
||||
to_string(elfclass v);
|
||||
|
||||
// Common basic data types
|
||||
struct ElfTypes
|
||||
{
|
||||
typedef std::uint16_t Half;
|
||||
typedef std::uint32_t Word;
|
||||
typedef std::int32_t Sword;
|
||||
};
|
||||
|
||||
struct Elf32 : public ElfTypes
|
||||
{
|
||||
// ELF class
|
||||
static const elfclass cls = elfclass::_32;
|
||||
|
||||
// Basic data types (ELF32 figure 1-2)
|
||||
typedef std::uint32_t Addr;
|
||||
typedef std::uint32_t Off;
|
||||
|
||||
// Predicated types
|
||||
typedef Word Word32_Xword64;
|
||||
|
||||
template<typename t32, typename t64>
|
||||
struct pick
|
||||
{
|
||||
typedef t32 t;
|
||||
};
|
||||
};
|
||||
|
||||
struct Elf64 : ElfTypes
|
||||
{
|
||||
// ELF class
|
||||
static const elfclass cls = elfclass::_64;
|
||||
|
||||
// Basic data types (ELF64 table 1)
|
||||
typedef std::uint64_t Addr;
|
||||
typedef std::uint64_t Off;
|
||||
typedef std::uint64_t Xword;
|
||||
typedef std::int64_t Sxword;
|
||||
|
||||
// Predicated types
|
||||
typedef Xword Word32_Xword64;
|
||||
|
||||
template<typename t32, typename t64>
|
||||
struct pick
|
||||
{
|
||||
typedef t64 t;
|
||||
};
|
||||
};
|
||||
|
||||
// Data encodings (ELF64 table 4)
|
||||
enum class elfdata : unsigned char
|
||||
{
|
||||
lsb = 1,
|
||||
msb = 2,
|
||||
};
|
||||
|
||||
std::string
|
||||
to_string(elfdata v);
|
||||
|
||||
// Operating system and ABI identifiers (ELF64 table 5)
|
||||
enum class elfosabi : unsigned char
|
||||
{
|
||||
sysv = 0,
|
||||
hpux = 1,
|
||||
standalone = 255,
|
||||
};
|
||||
|
||||
std::string
|
||||
to_string(elfosabi v);
|
||||
|
||||
// Object file types (ELF64 table 6)
|
||||
enum class et : ElfTypes::Half
|
||||
{
|
||||
none = 0, // No file type
|
||||
rel = 1, // Relocatable object file
|
||||
exec = 2, // Executable file
|
||||
dyn = 3, // Shared object file
|
||||
core = 4, // Core file
|
||||
loos = 0xfe00, // Environment-specific use
|
||||
hios = 0xfeff,
|
||||
loproc = 0xff00, // Processor-specific use
|
||||
hiproc = 0xffff,
|
||||
};
|
||||
|
||||
std::string
|
||||
to_string(et v);
|
||||
|
||||
// ELF header (ELF32 figure 1-3, ELF64 figure 2)
|
||||
template<typename E = Elf64, byte_order Order = byte_order::native>
|
||||
struct Ehdr
|
||||
{
|
||||
typedef E types;
|
||||
static const byte_order order = Order;
|
||||
|
||||
// ELF identification
|
||||
unsigned char ei_magic[4];
|
||||
elfclass ei_class;
|
||||
elfdata ei_data;
|
||||
unsigned char ei_version;
|
||||
elfosabi ei_osabi;
|
||||
unsigned char ei_abiversion;
|
||||
unsigned char ei_pad[7];
|
||||
|
||||
et type; // Object file type
|
||||
typename E::Half machine; // Machine type
|
||||
typename E::Word version; // Object file version
|
||||
typename E::Addr entry; // Entry point address
|
||||
typename E::Off phoff; // Program header offset
|
||||
typename E::Off shoff; // Section header offset
|
||||
typename E::Word flags; // Processor-specific flags
|
||||
typename E::Half ehsize; // ELF header size
|
||||
typename E::Half phentsize; // Size of program header entry
|
||||
typename E::Half phnum; // Number of program header entries
|
||||
typename E::Half shentsize; // Size of section header entry
|
||||
typename E::Half shnum; // Number of section header entries
|
||||
typename E::Half shstrndx; // Section name string table index
|
||||
|
||||
template<typename E2>
|
||||
void from(const E2 &o)
|
||||
{
|
||||
std::memcpy(ei_magic, o.ei_magic, sizeof(ei_magic));
|
||||
ei_class = swizzle(o.ei_class, o.order, order);
|
||||
ei_data = swizzle(o.ei_data, o.order, order);
|
||||
ei_version = swizzle(o.ei_version, o.order, order);
|
||||
ei_osabi = swizzle(o.ei_osabi, o.order, order);
|
||||
ei_abiversion = swizzle(o.ei_abiversion, o.order, order);
|
||||
std::memcpy(ei_pad, o.ei_pad, sizeof(ei_pad));
|
||||
|
||||
type = swizzle(o.type, o.order, order);
|
||||
machine = swizzle(o.machine, o.order, order);
|
||||
version = swizzle(o.version, o.order, order);
|
||||
entry = swizzle(o.entry, o.order, order);
|
||||
phoff = swizzle(o.phoff, o.order, order);
|
||||
shoff = swizzle(o.shoff, o.order, order);
|
||||
flags = swizzle(o.flags, o.order, order);
|
||||
ehsize = swizzle(o.ehsize, o.order, order);
|
||||
phentsize = swizzle(o.phentsize, o.order, order);
|
||||
phnum = swizzle(o.phnum, o.order, order);
|
||||
shentsize = swizzle(o.shentsize, o.order, order);
|
||||
shnum = swizzle(o.shnum, o.order, order);
|
||||
shstrndx = swizzle(o.shstrndx, o.order, order);
|
||||
}
|
||||
};
|
||||
|
||||
// Special section indices (ELF32 figure 1-7, ELF64 table 7)
|
||||
//
|
||||
// This is an integer with a few special values, so this is a regular
|
||||
// enum, rather than a type-safe enum. However, this is declared in a
|
||||
// namespace and then used to avoid polluting the elf:: namespace.
|
||||
namespace enums {
|
||||
enum shn : ElfTypes::Half // This is a Word in Shdr and Half in Sym.
|
||||
{
|
||||
undef = 0, // Undefined or meaningless
|
||||
|
||||
loproc = 0xff00, // Processor-specific use
|
||||
hiproc = 0xff1f,
|
||||
loos = 0xff20, // Environment-specific use
|
||||
hios = 0xff3f,
|
||||
|
||||
abs = 0xfff1, // Reference is an absolute value
|
||||
common = 0xfff2, // Symbol declared as a common block
|
||||
};
|
||||
|
||||
std::string
|
||||
to_string(shn v);
|
||||
}
|
||||
|
||||
using enums::shn;
|
||||
|
||||
// Section types (ELF64 table 8)
|
||||
enum class sht : ElfTypes::Word
|
||||
{
|
||||
null = 0, // Marks an unseen section header
|
||||
progbits = 1, // Contains information defined by the program
|
||||
symtab = 2, // Contains a linker symbol table
|
||||
strtab = 3, // Contains a string table
|
||||
rela = 4, // Contains "Rela" type relocation entries
|
||||
hash = 5, // Contains a symbol hash table
|
||||
dynamic = 6, // Contains dynamic linking tables
|
||||
note = 7, // Contains note information
|
||||
nobits = 8, // Contains uninitialized space;
|
||||
// does not occupy any space in the file
|
||||
rel = 9, // Contains "Rel" type relocation entries
|
||||
shlib = 10, // Reserved
|
||||
dynsym = 11, // Contains a dynamic loader symbol table
|
||||
loos = 0x60000000, // Environment-specific use
|
||||
hios = 0x6FFFFFFF,
|
||||
loproc = 0x70000000, // Processor-specific use
|
||||
hiproc = 0x7FFFFFFF,
|
||||
};
|
||||
|
||||
std::string
|
||||
to_string(sht v);
|
||||
|
||||
// Section attributes (ELF64 table 9). Note: This is an Elf32_Word in
|
||||
// ELF32. We use the larger ELF64 type for the canonical
|
||||
// representation and switch it out for a plain Elf32_Word in the
|
||||
// ELF32 format.
|
||||
enum class shf : Elf64::Xword
|
||||
{
|
||||
write = 0x1, // Section contains writable data
|
||||
alloc = 0x2, // Section is allocated in memory image of program
|
||||
execinstr = 0x4, // Section contains executable instructions
|
||||
maskos = 0x0F000000, // Environment-specific use
|
||||
maskproc = 0xF0000000, // Processor-specific use
|
||||
};
|
||||
|
||||
std::string
|
||||
to_string(shf v);
|
||||
|
||||
static inline constexpr shf operator&(shf a, shf b)
|
||||
{
|
||||
return (shf)((std::uint64_t)a & (std::uint64_t)b);
|
||||
}
|
||||
|
||||
static inline constexpr shf operator|(shf a, shf b)
|
||||
{
|
||||
return (shf)((std::uint64_t)a | (std::uint64_t)b);
|
||||
}
|
||||
|
||||
static inline constexpr shf operator^(shf a, shf b)
|
||||
{
|
||||
return (shf)((std::uint64_t)a ^ (std::uint64_t)b);
|
||||
}
|
||||
|
||||
static inline constexpr shf operator~(shf a)
|
||||
{
|
||||
return (shf)~((std::uint64_t)a);
|
||||
}
|
||||
|
||||
static inline shf& operator&=(shf &a, shf b)
|
||||
{
|
||||
a = a & b;
|
||||
return a;
|
||||
}
|
||||
|
||||
static inline shf& operator|=(shf &a, shf b)
|
||||
{
|
||||
a = a | b;
|
||||
return a;
|
||||
}
|
||||
|
||||
static inline shf& operator^=(shf &a, shf b)
|
||||
{
|
||||
a = a ^ b;
|
||||
return a;
|
||||
}
|
||||
|
||||
// Section header (ELF32 figure 1-8, ELF64 figure 3)
|
||||
template<typename E = Elf64, byte_order Order = byte_order::native>
|
||||
struct Shdr
|
||||
{
|
||||
typedef E types;
|
||||
static const byte_order order = Order;
|
||||
// Section numbers are half-words in some structures and full
|
||||
// words in others. Here we declare a local shn type that is
|
||||
// elf::shn for the native byte order, but the full word for
|
||||
// specific encoding byte orders.
|
||||
typedef typename internal::OrderPick<Order, elf::shn, typename E::Word, typename E::Word>::T shn;
|
||||
|
||||
typename E::Word name; // Section name
|
||||
sht type; // Section type
|
||||
typename E::template pick<typename E::Word, shf>::t flags; // Section attributes
|
||||
typename E::Addr addr; // Virtual address in memory
|
||||
typename E::Off offset; // Offset in file
|
||||
typename E::Word32_Xword64 size; // Size of section
|
||||
shn link; // Link to other section
|
||||
typename E::Word info; // Miscellaneous information
|
||||
typename E::Word32_Xword64 addralign; // Address alignment boundary
|
||||
typename E::Word32_Xword64 entsize; // Size of entries, if section has table
|
||||
|
||||
template<typename E2>
|
||||
void from(const E2 &o)
|
||||
{
|
||||
name = swizzle(o.name, o.order, order);
|
||||
type = swizzle(o.type, o.order, order);
|
||||
flags = (decltype(flags))swizzle(o.flags, o.order, order);
|
||||
addr = swizzle(o.addr, o.order, order);
|
||||
offset = swizzle(o.offset, o.order, order);
|
||||
size = swizzle(o.size, o.order, order);
|
||||
link = (decltype(link))swizzle((typename E::Word)o.link, o.order, order);
|
||||
info = swizzle(o.info, o.order, order);
|
||||
addralign = swizzle(o.addralign, o.order, order);
|
||||
entsize = swizzle(o.entsize, o.order, order);
|
||||
}
|
||||
};
|
||||
|
||||
// Segment types (ELF64 table 16)
|
||||
enum class pt : ElfTypes::Word
|
||||
{
|
||||
null = 0, // Unused entry
|
||||
load = 1, // Loadable segment
|
||||
dynamic = 2, // Dynamic linking tables
|
||||
interp = 3, // Program interpreter path name
|
||||
note = 4, // Note sections
|
||||
shlib = 5, // Reserved
|
||||
phdr = 6, // Program header table
|
||||
loos = 0x60000000, // Environment-specific use
|
||||
hios = 0x6FFFFFFF,
|
||||
loproc = 0x70000000, // Processor-specific use
|
||||
hiproc = 0x7FFFFFFF,
|
||||
};
|
||||
|
||||
std::string
|
||||
to_string(pt v);
|
||||
|
||||
// Segment attributes
|
||||
enum class pf : ElfTypes::Word
|
||||
{
|
||||
x = 0x1, // Execute permission
|
||||
w = 0x2, // Write permission
|
||||
r = 0x4, // Read permission
|
||||
maskos = 0x00FF0000, // Environment-specific use
|
||||
maskproc = 0xFF000000, // Processor-specific use
|
||||
};
|
||||
|
||||
std::string
|
||||
to_string(pf v);
|
||||
|
||||
static inline constexpr pf operator&(pf a, pf b)
|
||||
{
|
||||
return (pf)((std::uint64_t)a & (std::uint64_t)b);
|
||||
}
|
||||
|
||||
static inline constexpr pf operator|(pf a, pf b)
|
||||
{
|
||||
return (pf)((std::uint64_t)a | (std::uint64_t)b);
|
||||
}
|
||||
|
||||
static inline constexpr pf operator^(pf a, pf b)
|
||||
{
|
||||
return (pf)((std::uint64_t)a ^ (std::uint64_t)b);
|
||||
}
|
||||
|
||||
static inline constexpr pf operator~(pf a)
|
||||
{
|
||||
return (pf)~((std::uint64_t)a);
|
||||
}
|
||||
|
||||
static inline pf& operator&=(pf &a, pf b)
|
||||
{
|
||||
a = a & b;
|
||||
return a;
|
||||
}
|
||||
|
||||
static inline pf& operator|=(pf &a, pf b)
|
||||
{
|
||||
a = a | b;
|
||||
return a;
|
||||
}
|
||||
|
||||
static inline pf& operator^=(pf &a, pf b)
|
||||
{
|
||||
a = a ^ b;
|
||||
return a;
|
||||
}
|
||||
|
||||
// Program header (ELF32 figure 2-1, ELF64 figure 6)
|
||||
template<typename E = Elf64, byte_order Order = byte_order::native>
|
||||
struct Phdr;
|
||||
|
||||
template<byte_order Order>
|
||||
struct Phdr<Elf32, Order>
|
||||
{
|
||||
typedef Elf32 types;
|
||||
static const byte_order order = Order;
|
||||
|
||||
pt type; // Type of segment
|
||||
Elf32::Off offset; // Offset in file
|
||||
Elf32::Addr vaddr; // Virtual address in memory
|
||||
Elf32::Addr paddr; // Reserved
|
||||
Elf32::Word filesz; // Size of segment in file
|
||||
Elf32::Word memsz; // Size of segment in memory
|
||||
pf flags; // Segment attributes
|
||||
Elf32::Word align; // Alignment of segment
|
||||
|
||||
template<typename E2>
|
||||
void from(const E2 &o)
|
||||
{
|
||||
type = swizzle(o.type, o.order, order);
|
||||
offset = swizzle(o.offset, o.order, order);
|
||||
vaddr = swizzle(o.vaddr, o.order, order);
|
||||
paddr = swizzle(o.paddr, o.order, order);
|
||||
filesz = swizzle(o.filesz, o.order, order);
|
||||
memsz = swizzle(o.memsz, o.order, order);
|
||||
flags = swizzle(o.flags, o.order, order);
|
||||
align = swizzle(o.align, o.order, order);
|
||||
}
|
||||
};
|
||||
|
||||
template<byte_order Order>
|
||||
struct Phdr<Elf64, Order>
|
||||
{
|
||||
typedef Elf64 types;
|
||||
static const byte_order order = Order;
|
||||
|
||||
pt type; // Type of segment
|
||||
pf flags; // Segment attributes
|
||||
Elf64::Off offset; // Offset in file
|
||||
Elf64::Addr vaddr; // Virtual address in memory
|
||||
Elf64::Addr paddr; // Reserved
|
||||
Elf64::Xword filesz; // Size of segment in file
|
||||
Elf64::Xword memsz; // Size of segment in memory
|
||||
Elf64::Xword align; // Alignment of segment
|
||||
|
||||
template<typename E2>
|
||||
void from(const E2 &o)
|
||||
{
|
||||
type = swizzle(o.type, o.order, order);
|
||||
offset = swizzle(o.offset, o.order, order);
|
||||
vaddr = swizzle(o.vaddr, o.order, order);
|
||||
paddr = swizzle(o.paddr, o.order, order);
|
||||
filesz = swizzle(o.filesz, o.order, order);
|
||||
memsz = swizzle(o.memsz, o.order, order);
|
||||
flags = swizzle(o.flags, o.order, order);
|
||||
align = swizzle(o.align, o.order, order);
|
||||
}
|
||||
};
|
||||
|
||||
// Symbol bindings (ELF32 figure 1-16, ELF64 table 14)
|
||||
enum class stb : unsigned char
|
||||
{
|
||||
local = 0, // Not visible outside the object file
|
||||
global = 1, // Global symbol
|
||||
weak = 2, // Global scope, but with lower
|
||||
// precedence than global symbols
|
||||
loos = 10, // Environment-specific use
|
||||
hios = 12,
|
||||
loproc = 13, // Processor-specific use
|
||||
hiproc = 15,
|
||||
};
|
||||
|
||||
std::string
|
||||
to_string(stb v);
|
||||
|
||||
// Symbol types (ELF32 figure 1-17, ELF64 table 15)
|
||||
enum class stt : unsigned char
|
||||
{
|
||||
notype = 0, // No type (e.g., absolute symbol)
|
||||
object = 1, // Data object
|
||||
func = 2, // Function entry point
|
||||
section = 3, // Symbol is associated with a section
|
||||
file = 4, // Source file associated with the
|
||||
// object file
|
||||
loos = 10, // Environment-specific use
|
||||
hios = 12,
|
||||
loproc = 13, // Processor-specific use
|
||||
hiproc = 15,
|
||||
};
|
||||
|
||||
std::string
|
||||
to_string(stt v);
|
||||
|
||||
// Symbol table (ELF32 figure 1-15, ELF64 figure 4)
|
||||
template<typename E = Elf64, byte_order Order = byte_order::native>
|
||||
struct Sym;
|
||||
|
||||
template<byte_order Order>
|
||||
struct Sym<Elf32, Order>
|
||||
{
|
||||
typedef Elf32 types;
|
||||
static const byte_order order = Order;
|
||||
|
||||
Elf32::Word name; // Symbol name (strtab offset)
|
||||
Elf32::Addr value; // Symbol value (address)
|
||||
Elf32::Word size; // Size of object
|
||||
unsigned char info; // Type and binding attributes
|
||||
unsigned char other; // Reserved
|
||||
shn shnxd; // Section table index
|
||||
|
||||
template<typename E2>
|
||||
void from(const E2 &o)
|
||||
{
|
||||
name = swizzle(o.name, o.order, order);
|
||||
value = swizzle(o.value, o.order, order);
|
||||
size = swizzle(o.size, o.order, order);
|
||||
info = o.info;
|
||||
other = o.other;
|
||||
shnxd = swizzle(o.shnxd, o.order, order);
|
||||
}
|
||||
|
||||
stb binding() const
|
||||
{
|
||||
return (stb)(info >> 4);
|
||||
}
|
||||
|
||||
void set_binding(stb v)
|
||||
{
|
||||
info = (info & 0x0F) | ((unsigned char)v << 4);
|
||||
}
|
||||
|
||||
stt type() const
|
||||
{
|
||||
return (stt)(info & 0xF);
|
||||
}
|
||||
|
||||
void set_type(stt v)
|
||||
{
|
||||
info = (info & 0xF0) | (unsigned char)v;
|
||||
}
|
||||
};
|
||||
|
||||
template<byte_order Order>
|
||||
struct Sym<Elf64, Order>
|
||||
{
|
||||
typedef Elf64 types;
|
||||
static const byte_order order = Order;
|
||||
|
||||
Elf64::Word name; // Symbol name (strtab offset)
|
||||
unsigned char info; // Type and binding attributes
|
||||
unsigned char other; // Reserved
|
||||
shn shnxd; // Section table index
|
||||
Elf64::Addr value; // Symbol value (address)
|
||||
Elf64::Xword size; // Size of object
|
||||
|
||||
template<typename E2>
|
||||
void from(const E2 &o)
|
||||
{
|
||||
name = swizzle(o.name, o.order, order);
|
||||
value = swizzle(o.value, o.order, order);
|
||||
size = swizzle(o.size, o.order, order);
|
||||
info = o.info;
|
||||
other = o.other;
|
||||
shnxd = swizzle(o.shnxd, o.order, order);
|
||||
}
|
||||
|
||||
stb binding() const
|
||||
{
|
||||
return (stb)(info >> 4);
|
||||
}
|
||||
|
||||
void set_binding(stb v)
|
||||
{
|
||||
info = (info & 0xF) | ((unsigned char)v << 4);
|
||||
}
|
||||
|
||||
stt type() const
|
||||
{
|
||||
return (stt)(info & 0xF);
|
||||
}
|
||||
|
||||
void set_type(stt v)
|
||||
{
|
||||
info = (info & 0xF0) | (unsigned char)v;
|
||||
}
|
||||
};
|
||||
|
||||
ELFPP_END_NAMESPACE
|
||||
|
||||
#endif
|
||||
454
3party/libelfin/elf/elf++.hh
Normal file
454
3party/libelfin/elf/elf++.hh
Normal file
@@ -0,0 +1,454 @@
|
||||
// Copyright (c) 2013 Austin T. Clements. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#ifndef _ELFPP_HH_
|
||||
#define _ELFPP_HH_
|
||||
|
||||
#include "common.hh"
|
||||
#include "data.hh"
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
ELFPP_BEGIN_NAMESPACE
|
||||
|
||||
class elf;
|
||||
class loader;
|
||||
class section;
|
||||
class strtab;
|
||||
class symtab;
|
||||
class segment;
|
||||
// XXX Audit for binary compatibility
|
||||
|
||||
// XXX Segments, other section types
|
||||
|
||||
/**
|
||||
* An exception indicating malformed ELF data.
|
||||
*/
|
||||
class format_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit format_error(const std::string &what_arg)
|
||||
: std::runtime_error(what_arg) { }
|
||||
explicit format_error(const char *what_arg)
|
||||
: std::runtime_error(what_arg) { }
|
||||
};
|
||||
|
||||
/**
|
||||
* An ELF file.
|
||||
*
|
||||
* This class is internally reference counted and efficiently
|
||||
* copyable.
|
||||
*
|
||||
* Raw pointers to ELF data returned by any method of this object or
|
||||
* any object derived from this object point directly into loaded
|
||||
* section data. Hence, callers must ensure that the loader passed to
|
||||
* this file remains live as long as any such pointer is in use.
|
||||
* Keeping any object that can return such a pointer live is
|
||||
* sufficient to keep the loader live.
|
||||
*/
|
||||
class elf
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Construct an ELF file that is backed by data read from the
|
||||
* given loader.
|
||||
*/
|
||||
explicit elf(const std::shared_ptr<loader> &l);
|
||||
|
||||
/**
|
||||
* Construct an ELF file that is initially not valid. Calling
|
||||
* methods other than operator= and valid on this results in
|
||||
* undefined behavior.
|
||||
*/
|
||||
elf() = default;
|
||||
elf(const elf &o) = default;
|
||||
elf(elf &&o) = default;
|
||||
|
||||
elf& operator=(const elf &o) = default;
|
||||
|
||||
bool valid() const
|
||||
{
|
||||
return !!m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ELF file header in canonical form (ELF64 in
|
||||
* native byte order).
|
||||
*/
|
||||
const Ehdr<> &get_hdr() const;
|
||||
|
||||
/**
|
||||
* Return the loader used by this file.
|
||||
*/
|
||||
std::shared_ptr<loader> get_loader() const;
|
||||
|
||||
/**
|
||||
* Return the segments in this file.
|
||||
*/
|
||||
const std::vector<segment> &segments() const;
|
||||
|
||||
/**
|
||||
* Return the segment at the given index. If no such segment
|
||||
* is found, return an invalid segment.
|
||||
*/
|
||||
const segment &get_segment(unsigned index) const;
|
||||
|
||||
/**
|
||||
* Return the sections in this file.
|
||||
*/
|
||||
const std::vector<section> §ions() const;
|
||||
|
||||
/**
|
||||
* Return the section with the specified name. If no such
|
||||
* section is found, return an invalid section.
|
||||
*/
|
||||
const section &get_section(const std::string &name) const;
|
||||
|
||||
/**
|
||||
* Return the section at the given index. If no such section
|
||||
* is found, return an invalid section.
|
||||
*/
|
||||
const section &get_section(unsigned index) const;
|
||||
|
||||
private:
|
||||
struct impl;
|
||||
std::shared_ptr<impl> m;
|
||||
};
|
||||
|
||||
/**
|
||||
* An interface for loading sections of an ELF file.
|
||||
*/
|
||||
class loader
|
||||
{
|
||||
public:
|
||||
virtual ~loader() { }
|
||||
|
||||
/**
|
||||
* Load the requested file section into memory and return a
|
||||
* pointer to the beginning of it. This memory must remain
|
||||
* valid and unchanged until the loader is destroyed. If the
|
||||
* loader cannot satisfy the full request for any reason
|
||||
* (including a premature EOF), it must throw an exception.
|
||||
*/
|
||||
virtual const void *load(off_t offset, size_t size) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* An mmap-based loader that maps requested sections on demand. This
|
||||
* will close fd when done, so the caller should dup the file
|
||||
* descriptor if it intends to continue using it.
|
||||
*/
|
||||
std::shared_ptr<loader> create_mmap_loader(int fd);
|
||||
|
||||
/**
|
||||
* An exception indicating that a section is not of the requested type.
|
||||
*/
|
||||
class section_type_mismatch : public std::logic_error
|
||||
{
|
||||
public:
|
||||
explicit section_type_mismatch(const std::string &what_arg)
|
||||
: std::logic_error(what_arg) { }
|
||||
explicit section_type_mismatch(const char *what_arg)
|
||||
: std::logic_error(what_arg) { }
|
||||
};
|
||||
|
||||
/**
|
||||
* An ELF segment.
|
||||
*
|
||||
* This class is internally reference counted and efficiently
|
||||
* copyable.
|
||||
*/
|
||||
class segment
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Construct a segment that is initially not valid. Calling
|
||||
* methods other than operator= and valid on this results in
|
||||
* undefined behavior.
|
||||
*/
|
||||
segment() { }
|
||||
|
||||
segment(const elf &f, const void *hdr);
|
||||
segment(const segment &o) = default;
|
||||
segment(segment &&o) = default;
|
||||
|
||||
/**
|
||||
* Return true if this segment is valid and corresponds to a
|
||||
* segment in the ELF file.
|
||||
*/
|
||||
bool valid() const
|
||||
{
|
||||
return !!m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ELF section header in canonical form (ELF64 in
|
||||
* native byte order).
|
||||
*/
|
||||
const Phdr<> &get_hdr() const;
|
||||
|
||||
/**
|
||||
* Return this segment's data. The returned buffer will
|
||||
* be file_size() bytes long.
|
||||
*/
|
||||
const void *data() const;
|
||||
|
||||
/**
|
||||
* Return the on disk size of this segment in bytes.
|
||||
*/
|
||||
size_t file_size() const;
|
||||
|
||||
/**
|
||||
* Return the in-memory size of this segment in bytes.
|
||||
* Bytes between file_size() and mem_size() are implicitly zeroes.
|
||||
*/
|
||||
size_t mem_size() const;
|
||||
|
||||
private:
|
||||
struct impl;
|
||||
std::shared_ptr<impl> m;
|
||||
};
|
||||
|
||||
/**
|
||||
* An ELF section.
|
||||
*
|
||||
* This class is internally reference counted and efficiently
|
||||
* copyable.
|
||||
*/
|
||||
class section
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Construct a section that is initially not valid. Calling
|
||||
* methods other than operator= and valid on this results in
|
||||
* undefined behavior.
|
||||
*/
|
||||
section() { }
|
||||
|
||||
section(const elf &f, const void *hdr);
|
||||
section(const section &o) = default;
|
||||
section(section &&o) = default;
|
||||
|
||||
/**
|
||||
* Return true if this section is valid and corresponds to a
|
||||
* section in the ELF file.
|
||||
*/
|
||||
bool valid() const
|
||||
{
|
||||
return !!m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ELF section header in canonical form (ELF64 in
|
||||
* native byte order).
|
||||
*/
|
||||
const Shdr<> &get_hdr() const;
|
||||
|
||||
/**
|
||||
* Return this section's name.
|
||||
*/
|
||||
const char *get_name(size_t *len_out) const;
|
||||
/**
|
||||
* Return this section's name. The returned string copies its
|
||||
* data, so loader liveness requirements don't apply.
|
||||
*/
|
||||
std::string get_name() const;
|
||||
|
||||
/**
|
||||
* Return this section's data. If this is a NOBITS section,
|
||||
* return nullptr.
|
||||
*/
|
||||
const void *data() const;
|
||||
/**
|
||||
* Return the size of this section in bytes.
|
||||
*/
|
||||
size_t size() const;
|
||||
|
||||
/**
|
||||
* Return this section as a strtab. Throws
|
||||
* section_type_mismatch if this section is not a string
|
||||
* table.
|
||||
*/
|
||||
strtab as_strtab() const;
|
||||
|
||||
/**
|
||||
* Return this section as a symtab. Throws
|
||||
* section_type_mismatch if this section is not a symbol
|
||||
* table.
|
||||
*/
|
||||
symtab as_symtab() const;
|
||||
|
||||
private:
|
||||
struct impl;
|
||||
std::shared_ptr<impl> m;
|
||||
};
|
||||
|
||||
/**
|
||||
* A string table.
|
||||
*
|
||||
* This class is internally reference counted and efficiently
|
||||
* copyable.
|
||||
*/
|
||||
class strtab
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Construct a strtab that is initially not valid. Calling
|
||||
* methods other than operator= and valid on this results in
|
||||
* undefined behavior.
|
||||
*/
|
||||
strtab() = default;
|
||||
strtab(elf f, const void *data, size_t size);
|
||||
|
||||
bool valid() const
|
||||
{
|
||||
return !!m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the string at the given offset in this string table.
|
||||
* If the offset is out of bounds, throws std::range_error.
|
||||
* This is very efficient since the returned pointer points
|
||||
* directly into the loaded section, though this still
|
||||
* verifies that the returned string is NUL-terminated.
|
||||
*/
|
||||
const char *get(Elf64::Off offset, size_t *len_out) const;
|
||||
/**
|
||||
* Return the string at the given offset in this string table.
|
||||
*/
|
||||
std::string get(Elf64::Off offset) const;
|
||||
|
||||
private:
|
||||
struct impl;
|
||||
std::shared_ptr<impl> m;
|
||||
};
|
||||
|
||||
/**
|
||||
* A symbol from a symbol table.
|
||||
*/
|
||||
class sym
|
||||
{
|
||||
const strtab strs;
|
||||
Sym<> data;
|
||||
|
||||
public:
|
||||
sym(elf f, const void *data, strtab strs);
|
||||
|
||||
/**
|
||||
* Return this symbol's raw data.
|
||||
*/
|
||||
const Sym<> &get_data() const
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return this symbol's name.
|
||||
*
|
||||
* This returns a pointer into the string table and, as such,
|
||||
* is very efficient. If len_out is non-nullptr, *len_out
|
||||
* will be set the length of the returned string.
|
||||
*/
|
||||
const char *get_name(size_t *len_out) const;
|
||||
|
||||
/**
|
||||
* Return this symbol's name as a string.
|
||||
*/
|
||||
std::string get_name() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* A symbol table.
|
||||
*
|
||||
* This class is internally reference counted and efficiently
|
||||
* copyable.
|
||||
*/
|
||||
class symtab
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Construct a symtab that is initially not valid. Calling
|
||||
* methods other than operator= and valid on this results in
|
||||
* undefined behavior.
|
||||
*/
|
||||
symtab() = default;
|
||||
symtab(elf f, const void *data, size_t size, strtab strs);
|
||||
|
||||
bool valid() const
|
||||
{
|
||||
return !!m;
|
||||
}
|
||||
|
||||
class iterator
|
||||
{
|
||||
const elf f;
|
||||
const strtab strs;
|
||||
const char *pos;
|
||||
size_t stride;
|
||||
|
||||
iterator(const symtab &tab, const char *pos);
|
||||
friend class symtab;
|
||||
|
||||
public:
|
||||
sym operator*() const
|
||||
{
|
||||
return sym(f, pos, strs);
|
||||
}
|
||||
|
||||
iterator& operator++()
|
||||
{
|
||||
return *this += 1;
|
||||
}
|
||||
|
||||
iterator operator++(int)
|
||||
{
|
||||
iterator cur(*this);
|
||||
*this += 1;
|
||||
return cur;
|
||||
}
|
||||
|
||||
iterator& operator+=(std::ptrdiff_t x)
|
||||
{
|
||||
pos += x * stride;
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator& operator-=(std::ptrdiff_t x)
|
||||
{
|
||||
pos -= x * stride;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(iterator &o) const
|
||||
{
|
||||
return pos == o.pos;
|
||||
}
|
||||
|
||||
bool operator!=(iterator &o) const
|
||||
{
|
||||
return pos != o.pos;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return an iterator to the first symbol.
|
||||
*/
|
||||
iterator begin() const;
|
||||
|
||||
/**
|
||||
* Return an iterator just past the last symbol.
|
||||
*/
|
||||
iterator end() const;
|
||||
|
||||
private:
|
||||
struct impl;
|
||||
std::shared_ptr<impl> m;
|
||||
};
|
||||
|
||||
ELFPP_END_NAMESPACE
|
||||
|
||||
#endif
|
||||
403
3party/libelfin/elf/elf.cc
Normal file
403
3party/libelfin/elf/elf.cc
Normal file
@@ -0,0 +1,403 @@
|
||||
// Copyright (c) 2013 Austin T. Clements. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "elf++.hh"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
using namespace std;
|
||||
|
||||
ELFPP_BEGIN_NAMESPACE
|
||||
|
||||
template<template<typename E, byte_order Order> class Hdr>
|
||||
void canon_hdr(Hdr<Elf64, byte_order::native> *out, const void *data,
|
||||
elfclass ei_class, elfdata ei_data)
|
||||
{
|
||||
switch (ei_class) {
|
||||
case elfclass::_32:
|
||||
switch (ei_data) {
|
||||
case elfdata::lsb:
|
||||
out->from(*(Hdr<Elf32, byte_order::lsb>*)data);
|
||||
break;
|
||||
case elfdata::msb:
|
||||
out->from(*(Hdr<Elf32, byte_order::msb>*)data);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case elfclass::_64:
|
||||
switch (ei_data) {
|
||||
case elfdata::lsb:
|
||||
out->from(*(Hdr<Elf64, byte_order::lsb>*)data);
|
||||
break;
|
||||
case elfdata::msb:
|
||||
out->from(*(Hdr<Elf64, byte_order::msb>*)data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// class elf
|
||||
//
|
||||
|
||||
struct elf::impl
|
||||
{
|
||||
impl(const shared_ptr<loader> &l)
|
||||
: l(l) { }
|
||||
|
||||
const shared_ptr<loader> l;
|
||||
Ehdr<> hdr;
|
||||
vector<section> sections;
|
||||
vector<segment> segments;
|
||||
|
||||
section invalid_section;
|
||||
segment invalid_segment;
|
||||
};
|
||||
|
||||
elf::elf(const std::shared_ptr<loader> &l)
|
||||
: m(make_shared<impl>(l))
|
||||
{
|
||||
// Read the first six bytes to check the magic number, ELF
|
||||
// class, and byte order.
|
||||
struct core_hdr
|
||||
{
|
||||
char ei_magic[4];
|
||||
elfclass ei_class;
|
||||
elfdata ei_data;
|
||||
unsigned char ei_version;
|
||||
} *core_hdr = (struct core_hdr*)l->load(0, sizeof *core_hdr);
|
||||
|
||||
// Check basic header
|
||||
if (strncmp(core_hdr->ei_magic, "\x7f" "ELF", 4) != 0)
|
||||
throw format_error("bad ELF magic number");
|
||||
if (core_hdr->ei_version != 1)
|
||||
throw format_error("unknown ELF version");
|
||||
if (core_hdr->ei_class != elfclass::_32 &&
|
||||
core_hdr->ei_class != elfclass::_64)
|
||||
throw format_error("bad ELF class");
|
||||
if (core_hdr->ei_data != elfdata::lsb &&
|
||||
core_hdr->ei_data != elfdata::msb)
|
||||
throw format_error("bad ELF data order");
|
||||
|
||||
// Read in the real header and canonicalize it
|
||||
size_t hdr_size = (core_hdr->ei_class == elfclass::_32 ?
|
||||
sizeof(Ehdr<Elf32>) : sizeof(Ehdr<Elf64>));
|
||||
const void *hdr = l->load(0, hdr_size);
|
||||
canon_hdr(&m->hdr, hdr, core_hdr->ei_class, core_hdr->ei_data);
|
||||
|
||||
// More checks
|
||||
if (m->hdr.version != 1)
|
||||
throw format_error("bad section ELF version");
|
||||
if (m->hdr.shnum && m->hdr.shstrndx >= m->hdr.shnum)
|
||||
throw format_error("bad section name string table index");
|
||||
|
||||
// Load segments
|
||||
const void *seg_data = l->load(m->hdr.phoff,
|
||||
m->hdr.phentsize * m->hdr.phnum);
|
||||
for (unsigned i = 0; i < m->hdr.phnum; i++) {
|
||||
const void *seg = ((const char*)seg_data) + i * m->hdr.phentsize;
|
||||
m->segments.push_back(segment(*this, seg));
|
||||
}
|
||||
|
||||
// Load sections
|
||||
const void *sec_data = l->load(m->hdr.shoff,
|
||||
m->hdr.shentsize * m->hdr.shnum);
|
||||
for (unsigned i = 0; i < m->hdr.shnum; i++) {
|
||||
const void *sec = ((const char*)sec_data) + i * m->hdr.shentsize;
|
||||
// XXX Circular reference. Maybe this should be
|
||||
// constructed on the fly? Canonicalizing the header
|
||||
// isn't super-cheap.
|
||||
m->sections.push_back(section(*this, sec));
|
||||
}
|
||||
}
|
||||
|
||||
const Ehdr<> &
|
||||
elf::get_hdr() const
|
||||
{
|
||||
return m->hdr;
|
||||
}
|
||||
|
||||
shared_ptr<loader>
|
||||
elf::get_loader() const
|
||||
{
|
||||
return m->l;
|
||||
}
|
||||
|
||||
const std::vector<section> &
|
||||
elf::sections() const
|
||||
{
|
||||
return m->sections;
|
||||
}
|
||||
|
||||
const std::vector<segment> &
|
||||
elf::segments() const
|
||||
{
|
||||
return m->segments;
|
||||
}
|
||||
|
||||
const section &
|
||||
elf::get_section(const std::string &name) const
|
||||
{
|
||||
for (auto &sec : sections())
|
||||
if (name == sec.get_name(nullptr))
|
||||
return sec;
|
||||
return m->invalid_section;
|
||||
}
|
||||
|
||||
const section &
|
||||
elf::get_section(unsigned index) const
|
||||
{
|
||||
if (index >= sections().size())
|
||||
return m->invalid_section;
|
||||
return sections().at(index);
|
||||
}
|
||||
|
||||
const segment&
|
||||
elf::get_segment(unsigned index) const
|
||||
{
|
||||
if (index >= segments().size())
|
||||
return m->invalid_segment;
|
||||
return segments().at(index);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// class segment
|
||||
//
|
||||
|
||||
struct segment::impl {
|
||||
impl(const elf &f)
|
||||
: f(f), data(nullptr) { }
|
||||
|
||||
const elf f;
|
||||
Phdr<> hdr;
|
||||
const void *data;
|
||||
};
|
||||
|
||||
segment::segment(const elf &f, const void *hdr)
|
||||
: m(make_shared<impl>(f)) {
|
||||
canon_hdr(&m->hdr, hdr, f.get_hdr().ei_class, f.get_hdr().ei_data);
|
||||
}
|
||||
|
||||
const Phdr<> &
|
||||
segment::get_hdr() const {
|
||||
return m->hdr;
|
||||
}
|
||||
|
||||
const void *
|
||||
segment::data() const {
|
||||
if (!m->data)
|
||||
m->data = m->f.get_loader()->load(m->hdr.offset,
|
||||
m->hdr.filesz);
|
||||
return m->data;
|
||||
}
|
||||
|
||||
size_t
|
||||
segment::file_size() const {
|
||||
return m->hdr.filesz;
|
||||
}
|
||||
|
||||
size_t
|
||||
segment::mem_size() const {
|
||||
return m->hdr.memsz;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// class section
|
||||
//
|
||||
|
||||
std::string
|
||||
enums::to_string(shn v)
|
||||
{
|
||||
if (v == shn::undef)
|
||||
return "undef";
|
||||
if (v == shn::abs)
|
||||
return "abs";
|
||||
if (v == shn::common)
|
||||
return "common";
|
||||
return std::to_string(v);
|
||||
}
|
||||
|
||||
struct section::impl
|
||||
{
|
||||
impl(const elf &f)
|
||||
: f(f), name(nullptr), data(nullptr) { }
|
||||
|
||||
const elf f;
|
||||
Shdr<> hdr;
|
||||
const char *name;
|
||||
size_t name_len;
|
||||
const void *data;
|
||||
};
|
||||
|
||||
section::section(const elf &f, const void *hdr)
|
||||
: m(make_shared<impl>(f))
|
||||
{
|
||||
canon_hdr(&m->hdr, hdr, f.get_hdr().ei_class, f.get_hdr().ei_data);
|
||||
}
|
||||
|
||||
const Shdr<> &
|
||||
section::get_hdr() const
|
||||
{
|
||||
return m->hdr;
|
||||
}
|
||||
|
||||
const char *
|
||||
section::get_name(size_t *len_out) const
|
||||
{
|
||||
// XXX Should the section name strtab be cached?
|
||||
if (!m->name)
|
||||
m->name = m->f.get_section(m->f.get_hdr().shstrndx)
|
||||
.as_strtab().get(m->hdr.name, &m->name_len);
|
||||
if (len_out)
|
||||
*len_out = m->name_len;
|
||||
return m->name;
|
||||
}
|
||||
|
||||
string
|
||||
section::get_name() const
|
||||
{
|
||||
return get_name(nullptr);
|
||||
}
|
||||
|
||||
const void *
|
||||
section::data() const
|
||||
{
|
||||
if (m->hdr.type == sht::nobits)
|
||||
return nullptr;
|
||||
if (!m->data)
|
||||
m->data = m->f.get_loader()->load(m->hdr.offset, m->hdr.size);
|
||||
return m->data;
|
||||
}
|
||||
|
||||
size_t
|
||||
section::size() const
|
||||
{
|
||||
return m->hdr.size;
|
||||
}
|
||||
|
||||
strtab
|
||||
section::as_strtab() const
|
||||
{
|
||||
if (m->hdr.type != sht::strtab)
|
||||
throw section_type_mismatch("cannot use section as strtab");
|
||||
return strtab(m->f, data(), size());
|
||||
}
|
||||
|
||||
symtab
|
||||
section::as_symtab() const
|
||||
{
|
||||
if (m->hdr.type != sht::symtab && m->hdr.type != sht::dynsym)
|
||||
throw section_type_mismatch("cannot use section as symtab");
|
||||
return symtab(m->f, data(), size(),
|
||||
m->f.get_section(get_hdr().link).as_strtab());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// class strtab
|
||||
//
|
||||
|
||||
struct strtab::impl
|
||||
{
|
||||
impl(const elf &f, const char *data, const char *end)
|
||||
: f(f), data(data), end(end) { }
|
||||
|
||||
const elf f;
|
||||
const char *data, *end;
|
||||
};
|
||||
|
||||
strtab::strtab(elf f, const void *data, size_t size)
|
||||
: m(make_shared<impl>(f, (const char*)data, (const char *)data + size))
|
||||
{
|
||||
}
|
||||
|
||||
const char *
|
||||
strtab::get(Elf64::Off offset, size_t *len_out) const
|
||||
{
|
||||
const char *start = m->data + offset;
|
||||
|
||||
if (start >= m->end)
|
||||
throw range_error("string offset " + std::to_string(offset) + " exceeds section size");
|
||||
|
||||
// Find the null terminator
|
||||
const char *p = start;
|
||||
while (p < m->end && *p)
|
||||
p++;
|
||||
if (p == m->end)
|
||||
throw format_error("unterminated string");
|
||||
|
||||
if (len_out)
|
||||
*len_out = p - start;
|
||||
return start;
|
||||
}
|
||||
|
||||
std::string
|
||||
strtab::get(Elf64::Off offset) const
|
||||
{
|
||||
return get(offset, nullptr);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// class sym
|
||||
//
|
||||
|
||||
sym::sym(elf f, const void *data, strtab strs)
|
||||
: strs(strs)
|
||||
{
|
||||
canon_hdr(&this->data, data, f.get_hdr().ei_class, f.get_hdr().ei_data);
|
||||
}
|
||||
|
||||
const char *
|
||||
sym::get_name(size_t *len_out) const
|
||||
{
|
||||
return strs.get(get_data().name, len_out);
|
||||
}
|
||||
|
||||
std::string
|
||||
sym::get_name() const
|
||||
{
|
||||
return strs.get(get_data().name);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// class symtab
|
||||
//
|
||||
|
||||
struct symtab::impl
|
||||
{
|
||||
impl(const elf &f, const char *data, const char *end, strtab strs)
|
||||
: f(f), data(data), end(end), strs(strs) { }
|
||||
|
||||
const elf f;
|
||||
const char *data, *end;
|
||||
const strtab strs;
|
||||
};
|
||||
|
||||
symtab::symtab(elf f, const void *data, size_t size, strtab strs)
|
||||
: m(make_shared<impl>(f, (const char*)data, (const char *)data + size,
|
||||
strs))
|
||||
{
|
||||
}
|
||||
|
||||
symtab::iterator::iterator(const symtab &tab, const char *pos)
|
||||
: f(tab.m->f), strs(tab.m->strs), pos(pos)
|
||||
{
|
||||
if (f.get_hdr().ei_class == elfclass::_32)
|
||||
stride = sizeof(Sym<Elf32>);
|
||||
else
|
||||
stride = sizeof(Sym<Elf64>);
|
||||
}
|
||||
|
||||
symtab::iterator
|
||||
symtab::begin() const
|
||||
{
|
||||
return iterator(*this, m->data);
|
||||
}
|
||||
|
||||
symtab::iterator
|
||||
symtab::end() const
|
||||
{
|
||||
return iterator(*this, m->end);
|
||||
}
|
||||
|
||||
ELFPP_END_NAMESPACE
|
||||
163
3party/libelfin/elf/enum-print.py
Normal file
163
3party/libelfin/elf/enum-print.py
Normal file
@@ -0,0 +1,163 @@
|
||||
# Copyright (c) 2013 Austin T. Clements. All rights reserved.
|
||||
# Use of this source code is governed by an MIT license
|
||||
# that can be found in the LICENSE file.
|
||||
|
||||
import sys, re
|
||||
from optparse import OptionParser
|
||||
|
||||
def read_toks():
|
||||
data = sys.stdin.read()
|
||||
while data:
|
||||
data = data.lstrip()
|
||||
if data.startswith("//") or data.startswith("#"):
|
||||
data = data.split("\n",1)[1]
|
||||
elif data.startswith("/*"):
|
||||
data = data.split("*/",1)[1]
|
||||
elif data.startswith("\"") or data.startswith("'"):
|
||||
c = data[0]
|
||||
m = re.match(r'%s([^\\%s]|\\.)*%s' % (c,c,c), data)
|
||||
yield m.group(0)
|
||||
data = data[m.end():]
|
||||
else:
|
||||
m = re.match(r"[_a-zA-Z0-9]+|[{}();]|[^_a-zA-Z0-9 \n\t\f]+", data)
|
||||
yield m.group(0)
|
||||
data = data[m.end():]
|
||||
|
||||
enums = {}
|
||||
|
||||
def do_top_level(toks, ns=[]):
|
||||
while toks:
|
||||
tok = toks.pop(0)
|
||||
if tok == "enum" and toks[0] == "class":
|
||||
toks.pop(0)
|
||||
name = toks.pop(0)
|
||||
# Get to the first token in the body
|
||||
while toks.pop(0) != "{":
|
||||
pass
|
||||
# Consume body and close brace
|
||||
do_enum_body("::".join(ns + [name]), toks)
|
||||
elif tok == "class":
|
||||
name = do_qname(toks)
|
||||
# Find the class body, if there is one
|
||||
while toks[0] != "{" and toks[0] != ";":
|
||||
toks.pop(0)
|
||||
# Enter the class's namespace
|
||||
if toks[0] == "{":
|
||||
toks.pop(0)
|
||||
do_top_level(toks, ns + [name])
|
||||
elif tok == "{":
|
||||
# Enter an unknown namespace
|
||||
do_top_level(toks, ns + [None])
|
||||
elif tok == "}":
|
||||
# Exit the namespace
|
||||
assert len(ns)
|
||||
return
|
||||
elif not ns and tok == "string" and toks[:2] == ["to_string", "("]:
|
||||
# Get the argument type and name
|
||||
toks.pop(0)
|
||||
toks.pop(0)
|
||||
typ = do_qname(toks)
|
||||
if typ not in enums:
|
||||
continue
|
||||
arg = toks.pop(0)
|
||||
assert toks[0] == ")"
|
||||
|
||||
if typ in options.mask:
|
||||
make_to_string_mask(typ, arg)
|
||||
else:
|
||||
make_to_string(typ, arg)
|
||||
|
||||
def fmt_value(typ, key):
|
||||
if options.no_type:
|
||||
val = key
|
||||
else:
|
||||
val = "%s%s%s" % (typ, options.separator, key)
|
||||
if options.strip_underscore:
|
||||
val = val.strip("_")
|
||||
return val
|
||||
|
||||
def expr_remainder(typ, arg):
|
||||
if options.hex:
|
||||
return "\"(%s)0x\" + to_hex((int)%s)" % (typ, arg)
|
||||
else:
|
||||
return "\"(%s)\" + std::to_string((int)%s)" % (typ, arg)
|
||||
|
||||
def make_to_string(typ, arg):
|
||||
print("std::string")
|
||||
print("to_string(%s %s)" % (typ, arg))
|
||||
print("{")
|
||||
print(" switch (%s) {" % arg)
|
||||
for key in enums[typ]:
|
||||
if key in options.exclude:
|
||||
print(" case %s::%s: break;" % (typ, key))
|
||||
continue
|
||||
print(" case %s::%s: return \"%s\";" % \
|
||||
(typ, key, fmt_value(typ, key)))
|
||||
print(" }")
|
||||
print(" return %s;" % expr_remainder(typ, arg))
|
||||
print("}")
|
||||
print()
|
||||
|
||||
def make_to_string_mask(typ, arg):
|
||||
print("std::string")
|
||||
print("to_string(%s %s)" % (typ, arg))
|
||||
print("{")
|
||||
print(" std::string res;")
|
||||
for key in enums[typ]:
|
||||
if key in options.exclude:
|
||||
continue
|
||||
print(" if ((%s & %s::%s) == %s::%s) { res += \"%s|\"; %s &= ~%s::%s; }" % \
|
||||
(arg, typ, key, typ, key, fmt_value(typ, key), arg, typ, key))
|
||||
print(" if (res.empty() || %s != (%s)0) res += %s;" % \
|
||||
(arg, typ, expr_remainder(typ, arg)))
|
||||
print(" else res.pop_back();")
|
||||
print(" return res;")
|
||||
print("}")
|
||||
print()
|
||||
|
||||
def do_enum_body(name, toks):
|
||||
keys = []
|
||||
while True:
|
||||
key = toks.pop(0)
|
||||
if key == "}":
|
||||
assert toks.pop(0) == ";"
|
||||
enums[name] = keys
|
||||
return
|
||||
keys.append(key)
|
||||
if toks[0] == "=":
|
||||
toks.pop(0)
|
||||
toks.pop(0)
|
||||
if toks[0] == ",":
|
||||
toks.pop(0)
|
||||
else:
|
||||
assert toks[0] == "}"
|
||||
|
||||
def do_qname(toks):
|
||||
# Get a nested-name-specifier followed by an identifier
|
||||
res = []
|
||||
while True:
|
||||
res.append(toks.pop(0))
|
||||
if toks[0] != "::":
|
||||
return "::".join(res)
|
||||
toks.pop(0)
|
||||
|
||||
parser = OptionParser()
|
||||
parser.add_option("-x", "--exclude", dest="exclude", action="append",
|
||||
help="exclude FIELD", metavar="FIELD", default=[])
|
||||
parser.add_option("-u", "--strip-underscore", dest="strip_underscore",
|
||||
action="store_true",
|
||||
help="strip leading and trailing underscores")
|
||||
parser.add_option("-s", "--separator", dest="separator",
|
||||
help="use SEP between type and field", metavar="SEP",
|
||||
default="::")
|
||||
parser.add_option("--hex", dest="hex", action="store_true",
|
||||
help="return unknown values in hex", default=False)
|
||||
parser.add_option("--no-type", dest="no_type", action="store_true",
|
||||
help="omit type")
|
||||
parser.add_option("--mask", dest="mask", action="append",
|
||||
help="treat TYPE as a bit-mask", metavar="TYPE", default=[])
|
||||
(options, args) = parser.parse_args()
|
||||
if args:
|
||||
parser.error("expected 0 arguments")
|
||||
|
||||
do_top_level(list(read_toks()))
|
||||
60
3party/libelfin/elf/mmap_loader.cc
Normal file
60
3party/libelfin/elf/mmap_loader.cc
Normal file
@@ -0,0 +1,60 @@
|
||||
// Copyright (c) 2013 Austin T. Clements. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "elf++.hh"
|
||||
|
||||
#include <system_error>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
ELFPP_BEGIN_NAMESPACE
|
||||
|
||||
class mmap_loader : public loader
|
||||
{
|
||||
void *base;
|
||||
size_t lim;
|
||||
|
||||
public:
|
||||
mmap_loader(int fd)
|
||||
{
|
||||
off_t end = lseek(fd, 0, SEEK_END);
|
||||
if (end == (off_t)-1)
|
||||
throw system_error(errno, system_category(),
|
||||
"finding file length");
|
||||
lim = end;
|
||||
|
||||
base = mmap(nullptr, lim, PROT_READ, MAP_SHARED, fd, 0);
|
||||
if (base == MAP_FAILED)
|
||||
throw system_error(errno, system_category(),
|
||||
"mmap'ing file");
|
||||
close(fd);
|
||||
}
|
||||
|
||||
~mmap_loader()
|
||||
{
|
||||
munmap(base, lim);
|
||||
}
|
||||
|
||||
const void *load(off_t offset, size_t size)
|
||||
{
|
||||
if (offset + size > lim)
|
||||
throw range_error("offset exceeds file size");
|
||||
return (const char*)base + offset;
|
||||
}
|
||||
};
|
||||
|
||||
std::shared_ptr<loader>
|
||||
create_mmap_loader(int fd)
|
||||
{
|
||||
return make_shared<mmap_loader>(fd);
|
||||
}
|
||||
|
||||
ELFPP_END_NAMESPACE
|
||||
34
3party/libelfin/elf/to_hex.hh
Normal file
34
3party/libelfin/elf/to_hex.hh
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2013 Austin T. Clements. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#ifndef _ELFPP_TO_HEX_HH_
|
||||
#define _ELFPP_TO_HEX_HH_
|
||||
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
template<typename T>
|
||||
std::string
|
||||
to_hex(T v)
|
||||
{
|
||||
static_assert(std::is_integral<T>::value,
|
||||
"to_hex applied to non-integral type");
|
||||
if (v == 0)
|
||||
return std::string("0");
|
||||
char buf[sizeof(T)*2 + 1];
|
||||
char *pos = &buf[sizeof(buf)-1];
|
||||
*pos-- = '\0';
|
||||
while (v && pos >= buf) {
|
||||
int digit = v & 0xf;
|
||||
if (digit < 10)
|
||||
*pos = '0' + digit;
|
||||
else
|
||||
*pos = 'a' + (digit - 10);
|
||||
pos--;
|
||||
v >>= 4;
|
||||
}
|
||||
return std::string(pos + 1);
|
||||
}
|
||||
|
||||
#endif // _ELFPP_TO_HEX_HH_
|
||||
Reference in New Issue
Block a user