feat add dispatcher

This commit is contained in:
tqcq
2024-04-07 02:42:12 +00:00
parent 7807eecc08
commit cc7d131d95
32 changed files with 7240 additions and 133 deletions

6
3party/libelfin/elf/.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
*.o
to_string.cc
libelf++.a
libelf++.so
libelf++.so.*
libelf++.pc

View 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
View 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

View 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> &sections() 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
View 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

View 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()))

View 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

View 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_