Merge branch 'develop'
commit
76cd637755
@ -1,4 +1,3 @@
|
||||
[submodule "modules/ImGui/src"]
|
||||
path = modules/ImGui/src
|
||||
url = https://github.com/ocornut/imgui.git
|
||||
branch = tables
|
||||
url = https://github.com/flightlessmango/imgui.git
|
||||
|
@ -0,0 +1,198 @@
|
||||
/**
|
||||
* \file src/elfhacks.h
|
||||
* \brief elfhacks application interface
|
||||
* \author Pyry Haulos <pyry.haulos@gmail.com>
|
||||
* \date 2007-2008
|
||||
*/
|
||||
|
||||
/* elfhacks.h -- Various ELF run-time hacks
|
||||
version 0.4.1, March 9th, 2008
|
||||
|
||||
Copyright (C) 2007-2008 Pyry Haulos
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Pyry Haulos <pyry.haulos@gmail.com>
|
||||
*/
|
||||
|
||||
#include <elf.h>
|
||||
#include <link.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define __PUBLIC __attribute__ ((visibility ("default")))
|
||||
|
||||
#ifdef __x86_64__
|
||||
# define __elf64
|
||||
#endif
|
||||
#ifdef __i386__
|
||||
# define __elf32
|
||||
#endif
|
||||
|
||||
#ifdef __elf64
|
||||
# define ELFW_R_SYM ELF64_R_SYM
|
||||
# define ElfW_Sword Elf64_Sxword
|
||||
#else
|
||||
# ifdef __elf32
|
||||
# define ELFW_R_SYM ELF32_R_SYM
|
||||
# define ElfW_Sword Elf32_Sword
|
||||
# else
|
||||
# error neither __elf32 nor __elf64 is defined
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \defgroup elfhacks elfhacks
|
||||
* Elfhacks is a collection of functions that aim for retvieving
|
||||
* or modifying progam's dynamic linking information at run-time.
|
||||
* \{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief elfhacks program object
|
||||
*/
|
||||
typedef struct {
|
||||
/** file name */
|
||||
const char *name;
|
||||
/** base address in memory */
|
||||
ElfW(Addr) addr;
|
||||
/** program headers */
|
||||
const ElfW(Phdr) *phdr;
|
||||
/** number of program headers */
|
||||
ElfW(Half) phnum;
|
||||
/** .dynamic */
|
||||
ElfW(Dyn) *dynamic;
|
||||
/** .symtab */
|
||||
ElfW(Sym) *symtab;
|
||||
/** .strtab */
|
||||
const char *strtab;
|
||||
/** symbol hash table (DT_HASH) */
|
||||
ElfW(Word) *hash;
|
||||
/** symbol hash table (DT_GNU_HASH) */
|
||||
Elf32_Word *gnu_hash;
|
||||
} eh_obj_t;
|
||||
|
||||
/**
|
||||
* \brief elfhacks symbol
|
||||
*/
|
||||
typedef struct {
|
||||
/** symbol name */
|
||||
const char *name;
|
||||
/** corresponding ElfW(Sym) */
|
||||
ElfW(Sym) *sym;
|
||||
/** elfhacks object this symbol is associated to */
|
||||
eh_obj_t *obj;
|
||||
} eh_sym_t;
|
||||
|
||||
/**
|
||||
* \brief elfhacks relocation
|
||||
*/
|
||||
typedef struct {
|
||||
/** symbol this relocation is associated to */
|
||||
eh_sym_t *sym;
|
||||
/** corresponding ElfW(Rel) (NULL if this is Rela) */
|
||||
ElfW(Rel) *rel;
|
||||
/** corresponding ElfW(Rela) (NULL if this is Rel) */
|
||||
ElfW(Rela) *rela;
|
||||
/** elfhacks program object */
|
||||
eh_obj_t *obj;
|
||||
} eh_rel_t;
|
||||
|
||||
/**
|
||||
* \brief Iterate objects callback
|
||||
*/
|
||||
typedef int (*eh_iterate_obj_callback_func)(eh_obj_t *obj, void *arg);
|
||||
/**
|
||||
* \brief Iterate symbols callback
|
||||
*/
|
||||
typedef int (*eh_iterate_sym_callback_func)(eh_sym_t *sym, void *arg);
|
||||
/**
|
||||
* \brief Iterate relocations callback
|
||||
*/
|
||||
typedef int (*eh_iterate_rel_callback_func)(eh_rel_t *rel, void *arg);
|
||||
|
||||
/**
|
||||
* \brief Initializes eh_obj_t for given soname
|
||||
*
|
||||
* Matching is done using fnmatch() so wildcards and other standard
|
||||
* filename metacharacters and expressions work.
|
||||
*
|
||||
* If soname is NULL, this function returns the main program object.
|
||||
* \param obj elfhacks object
|
||||
* \param soname object's soname (see /proc/pid/maps) or NULL for main
|
||||
* \return 0 on success otherwise a positive error code
|
||||
*/
|
||||
__PUBLIC int eh_find_obj(eh_obj_t *obj, const char *soname);
|
||||
|
||||
/**
|
||||
* \brief Walk through list of objects
|
||||
* \param callback callback function
|
||||
* \param arg argument passed to callback function
|
||||
* \return 0 on success otherwise an error code
|
||||
*/
|
||||
__PUBLIC int eh_iterate_obj(eh_iterate_obj_callback_func callback, void *arg);
|
||||
|
||||
/**
|
||||
* \brief Finds symbol in object's .dynsym and retrvieves its value.
|
||||
* \param obj elfhacks program object
|
||||
* \param name symbol to find
|
||||
* \param to returned value
|
||||
* \return 0 on success otherwise a positive error code
|
||||
*/
|
||||
__PUBLIC int eh_find_sym(eh_obj_t *obj, const char *name, void **to);
|
||||
|
||||
/**
|
||||
* \brief Walk through list of symbols in object
|
||||
* \param obj elfhacks program object
|
||||
* \param callback callback function
|
||||
* \param arg argument passed to callback function
|
||||
* \return 0 on success otherwise an error code
|
||||
*/
|
||||
__PUBLIC int eh_iterate_sym(eh_obj_t *obj, eh_iterate_sym_callback_func callback, void *arg);
|
||||
|
||||
/**
|
||||
* \brief Iterates through object's .rel.plt and .rela.plt and sets every
|
||||
* occurrence of some symbol to the specified value.
|
||||
* \param obj elfhacks program object
|
||||
* \param sym symbol to replace
|
||||
* \param val new value
|
||||
* \return 0 on success otherwise a positive error code
|
||||
*/
|
||||
__PUBLIC int eh_set_rel(eh_obj_t *obj, const char *sym, void *val);
|
||||
|
||||
/**
|
||||
* \brief Walk through object's .rel.plt and .rela.plt
|
||||
* \param obj elfhacks program object
|
||||
* \param callback callback function
|
||||
* \param arg argument passed to callback function
|
||||
*/
|
||||
__PUBLIC int eh_iterate_rel(eh_obj_t *obj, eh_iterate_rel_callback_func callback, void *arg);
|
||||
|
||||
/**
|
||||
* \brief Destroy eh_obj_t object.
|
||||
* \param obj elfhacks program object
|
||||
* \return 0 on success otherwise a positive error code
|
||||
*/
|
||||
__PUBLIC int eh_destroy_obj(eh_obj_t *obj);
|
||||
|
||||
/** \} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -1 +1 @@
|
||||
Subproject commit e628122da006c0e9f7e695592765696d8253cf6f
|
||||
Subproject commit 96a2c4619b0c8009f684556683b2e1b6408bb0dc
|
@ -1,5 +1,2 @@
|
||||
#include <unordered_map>
|
||||
|
||||
extern std::unordered_map<std::string,std::string> options;
|
||||
|
||||
void parseConfigFile(void);
|
||||
#include "overlay_params.h"
|
||||
void parseConfigFile(overlay_params& p);
|
@ -0,0 +1,606 @@
|
||||
/**
|
||||
* \file src/elfhacks.c
|
||||
* \brief various ELF run-time hacks
|
||||
* \author Pyry Haulos <pyry.haulos@gmail.com>
|
||||
* \date 2007-2008
|
||||
* For conditions of distribution and use, see copyright notice in elfhacks.h
|
||||
*/
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <elf.h>
|
||||
#include <link.h>
|
||||
#include <fnmatch.h>
|
||||
#include "elfhacks.h"
|
||||
|
||||
/**
|
||||
* \addtogroup elfhacks
|
||||
* \{
|
||||
*/
|
||||
|
||||
struct eh_iterate_callback_args {
|
||||
eh_iterate_obj_callback_func callback;
|
||||
void *arg;
|
||||
};
|
||||
|
||||
int eh_check_addr(eh_obj_t *obj, const void *addr);
|
||||
int eh_find_callback(struct dl_phdr_info *info, size_t size, void *argptr);
|
||||
int eh_find_next_dyn(eh_obj_t *obj, ElfW_Sword tag, int i, ElfW(Dyn) **next);
|
||||
int eh_init_obj(eh_obj_t *obj);
|
||||
|
||||
int eh_set_rela_plt(eh_obj_t *obj, int p, const char *sym, void *val);
|
||||
int eh_set_rel_plt(eh_obj_t *obj, int p, const char *sym, void *val);
|
||||
|
||||
int eh_iterate_rela_plt(eh_obj_t *obj, int p, eh_iterate_rel_callback_func callback, void *arg);
|
||||
int eh_iterate_rel_plt(eh_obj_t *obj, int p, eh_iterate_rel_callback_func callback, void *arg);
|
||||
|
||||
int eh_find_sym_hash(eh_obj_t *obj, const char *name, eh_sym_t *sym);
|
||||
int eh_find_sym_gnu_hash(eh_obj_t *obj, const char *name, eh_sym_t *sym);
|
||||
|
||||
ElfW(Word) eh_hash_elf(const char *name);
|
||||
Elf32_Word eh_hash_gnu(const char *name);
|
||||
|
||||
int eh_find_callback(struct dl_phdr_info *info, size_t size, void *argptr)
|
||||
{
|
||||
eh_obj_t *find = (eh_obj_t *) argptr;
|
||||
|
||||
if (find->name == NULL) {
|
||||
if (strcmp(info->dlpi_name, ""))
|
||||
return 0;
|
||||
} else if (fnmatch(find->name, info->dlpi_name, 0))
|
||||
return 0;
|
||||
|
||||
if (find->name == NULL) /* TODO readlink? */
|
||||
find->name = "/proc/self/exe";
|
||||
else
|
||||
find->name = info->dlpi_name;
|
||||
find->addr = info->dlpi_addr;
|
||||
|
||||
/* segment headers */
|
||||
find->phdr = info->dlpi_phdr;
|
||||
find->phnum = info->dlpi_phnum;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int eh_iterate_callback(struct dl_phdr_info *info, size_t size, void *argptr)
|
||||
{
|
||||
struct eh_iterate_callback_args *args = (eh_iterate_callback_args *)argptr;
|
||||
eh_obj_t obj;
|
||||
int ret = 0;
|
||||
|
||||
/* eh_init_obj needs phdr and phnum */
|
||||
obj.phdr = info->dlpi_phdr;
|
||||
obj.phnum = info->dlpi_phnum;
|
||||
obj.addr = info->dlpi_addr;
|
||||
obj.name = info->dlpi_name;
|
||||
|
||||
if ((ret = eh_init_obj(&obj))) {
|
||||
if (ret == ENOTSUP) /* just skip */
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((ret = args->callback(&obj, args->arg)))
|
||||
return ret;
|
||||
|
||||
if ((ret = eh_destroy_obj(&obj)))
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int eh_iterate_obj(eh_iterate_obj_callback_func callback, void *arg)
|
||||
{
|
||||
int ret;
|
||||
struct eh_iterate_callback_args args;
|
||||
|
||||
args.callback = callback;
|
||||
args.arg = arg;
|
||||
|
||||
if ((ret = dl_iterate_phdr(eh_iterate_callback, &args)))
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int eh_find_obj(eh_obj_t *obj, const char *soname)
|
||||
{
|
||||
/* This function uses glibc-specific dl_iterate_phdr().
|
||||
Another way could be parsing /proc/self/exe or using
|
||||
pmap() on Solaris or *BSD */
|
||||
obj->phdr = NULL;
|
||||
obj->name = soname;
|
||||
dl_iterate_phdr(eh_find_callback, obj);
|
||||
|
||||
if (!obj->phdr)
|
||||
return EAGAIN;
|
||||
|
||||
return eh_init_obj(obj);
|
||||
}
|
||||
|
||||
int eh_check_addr(eh_obj_t *obj, const void *addr)
|
||||
{
|
||||
/*
|
||||
Check that given address is inside program's
|
||||
memory maps. PT_LOAD program headers tell us
|
||||
where program has been loaded into.
|
||||
*/
|
||||
int p;
|
||||
for (p = 0; p < obj->phnum; p++) {
|
||||
if (obj->phdr[p].p_type == PT_LOAD) {
|
||||
if (((ElfW(Addr)) addr < obj->phdr[p].p_memsz + obj->phdr[p].p_vaddr + obj->addr) &&
|
||||
((ElfW(Addr)) addr >= obj->phdr[p].p_vaddr + obj->addr))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
int eh_init_obj(eh_obj_t *obj)
|
||||
{
|
||||
/*
|
||||
ELF spec says in section header documentation, that:
|
||||
"An object file may have only one dynamic section."
|
||||
|
||||
Let's assume it means that object has only one PT_DYNAMIC
|
||||
as well.
|
||||
*/
|
||||
int p;
|
||||
obj->dynamic = NULL;
|
||||
for (p = 0; p < obj->phnum; p++) {
|
||||
if (obj->phdr[p].p_type == PT_DYNAMIC) {
|
||||
if (obj->dynamic)
|
||||
return ENOTSUP;
|
||||
|
||||
obj->dynamic = (ElfW(Dyn) *) (obj->phdr[p].p_vaddr + obj->addr);
|
||||
}
|
||||
}
|
||||
|
||||
if (!obj->dynamic)
|
||||
return ENOTSUP;
|
||||
|
||||
/*
|
||||
ELF spec says that program is allowed to have more than one
|
||||
.strtab but does not describe how string table indexes translate
|
||||
to multiple string tables.
|
||||
|
||||
And spec says that only one SHT_HASH is allowed, does it mean that
|
||||
obj has only one DT_HASH?
|
||||
|
||||
About .symtab it does not mention anything about if multiple
|
||||
symbol tables are allowed or not.
|
||||
|
||||
Maybe st_shndx is the key here?
|
||||
*/
|
||||
obj->strtab = NULL;
|
||||
obj->hash = NULL;
|
||||
obj->gnu_hash = NULL;
|
||||
obj->symtab = NULL;
|
||||
p = 0;
|
||||
while (obj->dynamic[p].d_tag != DT_NULL) {
|
||||
if (obj->dynamic[p].d_tag == DT_STRTAB) {
|
||||
if (obj->strtab)
|
||||
return ENOTSUP;
|
||||
|
||||
obj->strtab = (const char *) obj->dynamic[p].d_un.d_ptr;
|
||||
} else if (obj->dynamic[p].d_tag == DT_HASH) {
|
||||
if (obj->hash)
|
||||
return ENOTSUP;
|
||||
|
||||
obj->hash = (ElfW(Word) *) obj->dynamic[p].d_un.d_ptr;
|
||||
} else if (obj->dynamic[p].d_tag == DT_GNU_HASH) {
|
||||
if (obj->gnu_hash)
|
||||
return ENOTSUP;
|
||||
|
||||
obj->gnu_hash = (Elf32_Word *) obj->dynamic[p].d_un.d_ptr;
|
||||
} else if (obj->dynamic[p].d_tag == DT_SYMTAB) {
|
||||
if (obj->symtab)
|
||||
return ENOTSUP;
|
||||
|
||||
obj->symtab = (ElfW(Sym) *) obj->dynamic[p].d_un.d_ptr;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
/* This is here to catch b0rken headers (vdso) */
|
||||
if ((eh_check_addr(obj, (const void *) obj->strtab)) |
|
||||
(eh_check_addr(obj, (const void *) obj->symtab)))
|
||||
return ENOTSUP;
|
||||
|
||||
if (obj->hash) {
|
||||
/* DT_HASH found */
|
||||
if (eh_check_addr(obj, (void *) obj->hash))
|
||||
obj->hash = NULL;
|
||||
} else if (obj->gnu_hash) {
|
||||
/* DT_GNU_HASH found */
|
||||
if (eh_check_addr(obj, (void *) obj->gnu_hash))
|
||||
obj->gnu_hash = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int eh_find_sym(eh_obj_t *obj, const char *name, void **to)
|
||||
{
|
||||
eh_sym_t sym;
|
||||
|
||||
/* DT_GNU_HASH is faster ;) */
|
||||
if (obj->gnu_hash) {
|
||||
if (!eh_find_sym_gnu_hash(obj, name, &sym)) {
|
||||
*to = (void *) (sym.sym->st_value + obj->addr);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* maybe it is in DT_HASH or DT_GNU_HASH is not present */
|
||||
if (obj->hash) {
|
||||
if (!eh_find_sym_hash(obj, name, &sym)) {
|
||||
*to = (void *) (sym.sym->st_value + obj->addr);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return EAGAIN;
|
||||
}
|
||||
|
||||
ElfW(Word) eh_hash_elf(const char *name)
|
||||
{
|
||||
ElfW(Word) tmp, hash = 0;
|
||||
const unsigned char *uname = (const unsigned char *) name;
|
||||
int c;
|
||||
|
||||
while ((c = *uname++) != '\0') {
|
||||
hash = (hash << 4) + c;
|
||||
if ((tmp = (hash & 0xf0000000)) != 0) {
|
||||
hash ^= tmp >> 24;
|
||||
hash ^= tmp;
|
||||
}
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
int eh_find_sym_hash(eh_obj_t *obj, const char *name, eh_sym_t *sym)
|
||||
{
|
||||
ElfW(Word) hash, *chain;
|
||||
ElfW(Sym) *esym;
|
||||
unsigned int bucket_idx, idx;
|
||||
|
||||
if (!obj->hash)
|
||||
return ENOTSUP;
|
||||
|
||||
if (obj->hash[0] == 0)
|
||||
return EAGAIN;
|
||||
|
||||
hash = eh_hash_elf(name);
|
||||
/*
|
||||
First item in DT_HASH is nbucket, second is nchain.
|
||||
hash % nbucket gives us our bucket index.
|
||||
*/
|
||||
bucket_idx = obj->hash[2 + (hash % obj->hash[0])];
|
||||
chain = &obj->hash[2 + obj->hash[0] + bucket_idx];
|
||||
|
||||
idx = 0;
|
||||
sym->sym = NULL;
|
||||
|
||||
/* we have to check symtab[bucket_idx] first */
|
||||
esym = &obj->symtab[bucket_idx];
|
||||
if (esym->st_name) {
|
||||
if (!strcmp(&obj->strtab[esym->st_name], name))
|
||||
sym->sym = esym;
|
||||
}
|
||||
|
||||
while ((sym->sym == NULL) &&
|
||||
(chain[idx] != STN_UNDEF)) {
|
||||
esym = &obj->symtab[chain[idx]];
|
||||
|
||||
if (esym->st_name) {
|
||||
if (!strcmp(&obj->strtab[esym->st_name], name))
|
||||
sym->sym = esym;
|
||||
}
|
||||
|
||||
idx++;
|
||||
}
|
||||
|
||||
/* symbol not found */
|
||||
if (sym->sym == NULL)
|
||||
return EAGAIN;
|
||||
|
||||
sym->obj = obj;
|
||||
sym->name = &obj->strtab[sym->sym->st_name];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Elf32_Word eh_hash_gnu(const char *name)
|
||||
{
|
||||
Elf32_Word hash = 5381;
|
||||
const unsigned char *uname = (const unsigned char *) name;
|
||||
int c;
|
||||
|
||||
while ((c = *uname++) != '\0')
|
||||
hash = (hash << 5) + hash + c;
|
||||
|
||||
return hash & 0xffffffff;
|
||||
}
|
||||
|
||||
int eh_find_sym_gnu_hash(eh_obj_t *obj, const char *name, eh_sym_t *sym)
|
||||
{
|
||||
Elf32_Word *buckets, *chain_zero, *hasharr;
|
||||
ElfW(Addr) *bitmask, bitmask_word;
|
||||
Elf32_Word symbias, bitmask_nwords, bucket,
|
||||
nbuckets, bitmask_idxbits, shift;
|
||||
Elf32_Word hash, hashbit1, hashbit2;
|
||||
ElfW(Sym) *esym;
|
||||
|
||||
if (!obj->gnu_hash)
|
||||
return ENOTSUP;
|
||||
|
||||
if (obj->gnu_hash[0] == 0)
|
||||
return EAGAIN;
|
||||
|
||||
sym->sym = NULL;
|
||||
|
||||
/*
|
||||
Initialize our hash table stuff
|
||||
|
||||
DT_GNU_HASH is(?):
|
||||
[nbuckets] [symbias] [bitmask_nwords] [shift]
|
||||
[bitmask_nwords * ElfW(Addr)] <- bitmask
|
||||
[nbuckets * Elf32_Word] <- buckets
|
||||
...chains? - symbias...
|
||||
*/
|
||||
nbuckets = obj->gnu_hash[0];
|
||||
symbias = obj->gnu_hash[1];
|
||||
bitmask_nwords = obj->gnu_hash[2]; /* must be power of two */
|
||||
bitmask_idxbits = bitmask_nwords - 1;
|
||||
shift = obj->gnu_hash[3];
|
||||
bitmask = (ElfW(Addr) *) &obj->gnu_hash[4];
|
||||
buckets = &obj->gnu_hash[4 + (__ELF_NATIVE_CLASS / 32) * bitmask_nwords];
|
||||
chain_zero = &buckets[nbuckets] - symbias;
|
||||
|
||||
/* hash our symbol */
|
||||
hash = eh_hash_gnu(name);
|
||||
|
||||
/* bitmask stuff... no idea really :D */
|
||||
bitmask_word = bitmask[(hash / __ELF_NATIVE_CLASS) & bitmask_idxbits];
|
||||
hashbit1 = hash & (__ELF_NATIVE_CLASS - 1);
|
||||
hashbit2 = (hash >> shift) & (__ELF_NATIVE_CLASS - 1);
|
||||
|
||||
/* wtf this does actually? */
|
||||
if (!((bitmask_word >> hashbit1) & (bitmask_word >> hashbit2) & 1))
|
||||
return EAGAIN;
|
||||
|
||||
/* locate bucket */
|
||||
bucket = buckets[hash % nbuckets];
|
||||
if (bucket == 0)
|
||||
return EAGAIN;
|
||||
|
||||
/* and find match in chain */
|
||||
hasharr = &chain_zero[bucket];
|
||||
do {
|
||||
if (((*hasharr ^ hash) >> 1) == 0) {
|
||||
/* hash matches, but does the name? */
|
||||
esym = &obj->symtab[hasharr - chain_zero];
|
||||
if (esym->st_name) {
|
||||
if (!strcmp(&obj->strtab[esym->st_name], name)) {
|
||||
sym->sym = esym;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while ((*hasharr++ & 1u) == 0);
|
||||
|
||||
/* symbol not found */
|
||||
if (sym->sym == NULL)
|
||||
return EAGAIN;
|
||||
|
||||
sym->obj = obj;
|
||||
sym->name = &obj->strtab[sym->sym->st_name];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int eh_iterate_sym(eh_obj_t *obj, eh_iterate_sym_callback_func callback, void *arg)
|
||||
{
|
||||
return ENOTSUP;
|
||||
}
|
||||
|
||||
int eh_find_next_dyn(eh_obj_t *obj, ElfW_Sword tag, int i, ElfW(Dyn) **next)
|
||||
{
|
||||
/* first from i + 1 to end, then from start to i - 1 */
|
||||
int p;
|
||||
*next = NULL;
|
||||
|
||||
p = i + 1;
|
||||
while (obj->dynamic[p].d_tag != DT_NULL) {
|
||||
if (obj->dynamic[p].d_tag == tag) {
|
||||
*next = &obj->dynamic[p];
|
||||
return 0;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
p = 0;
|
||||
while ((obj->dynamic[i].d_tag != DT_NULL) && (p < i)) {
|
||||
if (obj->dynamic[p].d_tag == tag) {
|
||||
*next = &obj->dynamic[p];
|
||||
return 0;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
return EAGAIN;
|
||||
}
|
||||
|
||||
int eh_set_rela_plt(eh_obj_t *obj, int p, const char *sym, void *val)
|
||||
{
|
||||
ElfW(Rela) *rela = (ElfW(Rela) *) obj->dynamic[p].d_un.d_ptr;
|
||||
ElfW(Dyn) *relasize;
|
||||
unsigned int i;
|
||||
|
||||
/* DT_PLTRELSZ contains PLT relocs size in bytes */
|
||||
if (eh_find_next_dyn(obj, DT_PLTRELSZ, p, &relasize))
|
||||
return EINVAL; /* b0rken elf :/ */
|
||||
|
||||
for (i = 0; i < relasize->d_un.d_val / sizeof(ElfW(Rela)); i++) {
|
||||
if (!obj->symtab[ELFW_R_SYM(rela[i].r_info)].st_name)
|
||||
continue;
|
||||
|
||||
if (!strcmp(&obj->strtab[obj->symtab[ELFW_R_SYM(rela[i].r_info)].st_name], sym))
|
||||
*((void **) (rela[i].r_offset + obj->addr)) = val;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int eh_set_rel_plt(eh_obj_t *obj, int p, const char *sym, void *val)
|
||||
{
|
||||
ElfW(Rel) *rel = (ElfW(Rel) *) obj->dynamic[p].d_un.d_ptr;
|
||||
ElfW(Dyn) *relsize;
|
||||
unsigned int i;
|
||||
|
||||
if (eh_find_next_dyn(obj, DT_PLTRELSZ, p, &relsize))
|
||||
return EINVAL; /* b0rken elf :/ */
|
||||
|
||||
for (i = 0; i < relsize->d_un.d_val / sizeof(ElfW(Rel)); i++) {
|
||||
if (!obj->symtab[ELFW_R_SYM(rel[i].r_info)].st_name)
|
||||
continue;
|
||||
|
||||
if (!strcmp(&obj->strtab[obj->symtab[ELFW_R_SYM(rel[i].r_info)].st_name], sym))
|
||||
*((void **) (rel[i].r_offset + obj->addr)) = val;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int eh_set_rel(eh_obj_t *obj, const char *sym, void *val)
|
||||
{
|
||||
/*
|
||||
Elf spec states that object is allowed to have multiple
|
||||
.rel.plt and .rela.plt tables, so we will support 'em - here.
|
||||
*/
|
||||
ElfW(Dyn) *pltrel;
|
||||
int ret, p = 0;
|
||||
|
||||
while (obj->dynamic[p].d_tag != DT_NULL) {
|
||||
/* DT_JMPREL contains .rel.plt or .rela.plt */
|
||||
if (obj->dynamic[p].d_tag == DT_JMPREL) {
|
||||
/* DT_PLTREL tells if it is Rela or Rel */
|
||||
eh_find_next_dyn(obj, DT_PLTREL, p, &pltrel);
|
||||
|
||||
if (pltrel->d_un.d_val == DT_RELA) {
|
||||
if ((ret = eh_set_rela_plt(obj, p, sym, val)))
|
||||
return ret;
|
||||
} else if (pltrel->d_un.d_val == DT_REL) {
|
||||
if ((ret = eh_set_rel_plt(obj, p, sym, val)))
|
||||
return ret;
|
||||
} else
|
||||
return EINVAL;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int eh_iterate_rela_plt(eh_obj_t *obj, int p, eh_iterate_rel_callback_func callback, void *arg)
|
||||
{
|
||||
ElfW(Rela) *rela = (ElfW(Rela) *) obj->dynamic[p].d_un.d_ptr;
|
||||
ElfW(Dyn) *relasize;
|
||||
eh_rel_t rel;
|
||||
eh_sym_t sym;
|
||||
unsigned int i, ret;
|
||||
|
||||
rel.sym = &sym;
|
||||
rel.rel = NULL;
|
||||
rel.obj = obj;
|
||||
|
||||
if (eh_find_next_dyn(obj, DT_PLTRELSZ, p, &relasize))
|
||||
return EINVAL;
|
||||
|
||||
for (i = 0; i < relasize->d_un.d_val / sizeof(ElfW(Rela)); i++) {
|
||||
rel.rela = &rela[i];
|
||||
sym.sym = &obj->symtab[ELFW_R_SYM(rel.rela->r_info)];
|
||||
if (sym.sym->st_name)
|
||||
sym.name = &obj->strtab[sym.sym->st_name];
|
||||
else
|
||||
sym.name = NULL;
|
||||
|
||||
if ((ret = callback(&rel, arg)))
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int eh_iterate_rel_plt(eh_obj_t *obj, int p, eh_iterate_rel_callback_func callback, void *arg)
|
||||
{
|
||||
ElfW(Rel) *relp = (ElfW(Rel) *) obj->dynamic[p].d_un.d_ptr;
|
||||
ElfW(Dyn) *relsize;
|
||||
eh_rel_t rel;
|
||||
eh_sym_t sym;
|
||||
unsigned int i, ret;
|
||||
|
||||
rel.sym = &sym;
|
||||
rel.rela = NULL;
|
||||
rel.obj = obj;
|
||||
|
||||
if (eh_find_next_dyn(obj, DT_PLTRELSZ, p, &relsize))
|
||||
return EINVAL;
|
||||
|
||||
for (i = 0; i < relsize->d_un.d_val / sizeof(ElfW(Rel)); i++) {
|
||||
rel.rel = &relp[i];
|
||||
sym.sym = &obj->symtab[ELFW_R_SYM(rel.rel->r_info)];
|
||||
if (sym.sym->st_name)
|
||||
sym.name = &obj->strtab[sym.sym->st_name];
|
||||
else
|
||||
sym.name = NULL;
|
||||
|
||||
if ((ret = callback(&rel, arg)))
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int eh_iterate_rel(eh_obj_t *obj, eh_iterate_rel_callback_func callback, void *arg)
|
||||
{
|
||||
ElfW(Dyn) *pltrel;
|
||||
int ret, p = 0;
|
||||
|
||||
while (obj->dynamic[p].d_tag != DT_NULL) {
|
||||
if (obj->dynamic[p].d_tag == DT_JMPREL) {
|
||||
eh_find_next_dyn(obj, DT_PLTREL, p, &pltrel);
|
||||
|
||||
if (pltrel->d_un.d_val == DT_RELA) {
|
||||
if ((ret = eh_iterate_rela_plt(obj, p, callback, arg)))
|
||||
return ret;
|
||||
} else if (pltrel->d_un.d_val == DT_REL) {
|
||||
if ((ret = eh_iterate_rel_plt(obj, p, callback, arg)))
|
||||
return ret;
|
||||
} else
|
||||
return EINVAL;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int eh_destroy_obj(eh_obj_t *obj)
|
||||
{
|
||||
obj->phdr = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** \} */
|
@ -1,18 +1,83 @@
|
||||
#include "real_dlsym.h"
|
||||
/**
|
||||
* \author Pyry Haulos <pyry.haulos@gmail.com>
|
||||
* \date 2007-2008
|
||||
* For conditions of distribution and use, see copyright notice in elfhacks.h
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <dlfcn.h>
|
||||
#include "real_dlsym.h"
|
||||
#include "elfhacks.h"
|
||||
|
||||
extern "C" void* __libc_dlsym( void* handle, const char* name );
|
||||
void *(*__dlopen)(const char *, int) = nullptr;
|
||||
void *(*__dlsym)(void *, const char *) = nullptr;
|
||||
static bool print_dlopen = getenv("MANGOHUD_DEBUG_DLOPEN") != nullptr;
|
||||
static bool print_dlsym = getenv("MANGOHUD_DEBUG_DLSYM") != nullptr;
|
||||
|
||||
void* real_dlsym( void* handle, const char* name )
|
||||
void get_real_functions()
|
||||
{
|
||||
static void *(*the_real_dlsym)( void*, const char* );
|
||||
eh_obj_t libdl;
|
||||
|
||||
if (eh_find_obj(&libdl, "*libdl.so*")) {
|
||||
fprintf(stderr, "can't get libdl.so\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (eh_find_sym(&libdl, "dlopen", (void **) &__dlopen)) {
|
||||
fprintf(stderr, "can't get dlopen()\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!the_real_dlsym) {
|
||||
void* libdl = dlopen( "libdl.so", RTLD_NOW | RTLD_LOCAL );
|
||||
the_real_dlsym = reinterpret_cast<decltype(the_real_dlsym)> (__libc_dlsym( libdl, "dlsym" ));
|
||||
if (eh_find_sym(&libdl, "dlsym", (void **) &__dlsym)) {
|
||||
fprintf(stderr, "can't get dlsym()\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return the_real_dlsym( handle, name );
|
||||
eh_destroy_obj(&libdl);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief dlopen() wrapper, just passes calls to real dlopen()
|
||||
* and writes information to standard output
|
||||
*/
|
||||
void *real_dlopen(const char *filename, int flag)
|
||||
{
|
||||
if (__dlopen == nullptr)
|
||||
get_real_functions();
|
||||
|
||||
void *result = __dlopen(filename, flag);
|
||||
|
||||
if (print_dlopen) {
|
||||
printf("dlopen(%s, ", filename);
|
||||
const char *fmt = "%s";
|
||||
#define FLAG(test) if (flag & test) { printf(fmt, #test); fmt = "|%s"; }
|
||||
FLAG(RTLD_LAZY)
|
||||
FLAG(RTLD_NOW)
|
||||
FLAG(RTLD_GLOBAL)
|
||||
FLAG(RTLD_LOCAL)
|
||||
FLAG(RTLD_NODELETE)
|
||||
FLAG(RTLD_NOLOAD)
|
||||
FLAG(RTLD_DEEPBIND)
|
||||
#undef FLAG
|
||||
printf(") = %p\n", result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief dlsym() wrapper, passes calls to real dlsym() and
|
||||
* writes information to standard output
|
||||
*/
|
||||
void *real_dlsym(void *handle, const char *symbol)
|
||||
{
|
||||
if (__dlsym == nullptr)
|
||||
get_real_functions();
|
||||
|
||||
void *result = __dlsym(handle, symbol);
|
||||
|
||||
if (print_dlsym)
|
||||
printf("dlsym(%p, %s) = %p\n", handle, symbol, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -1,22 +1,4 @@
|
||||
/*
|
||||
Copyright (C) 2016-2017 Björn Spindel
|
||||
|
||||
This file is part of libstrangle.
|
||||
|
||||
libstrangle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
libstrangle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with libstrangle. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
void *real_dlopen(const char *filename, int flag);
|
||||
void* real_dlsym( void*, const char* );
|
||||
|
@ -1,18 +1,18 @@
|
||||
#include <X11/Xlib.h>
|
||||
#include <iostream>
|
||||
#include "X11/keysym.h"
|
||||
#include "mesa/util/os_time.h"
|
||||
#include <functional>
|
||||
|
||||
double elapsedF2, elapsedF12, elapsedReloadCfg;
|
||||
uint64_t last_f2_press, last_f12_press, reload_cfg_press;
|
||||
pthread_t f2;
|
||||
char *displayid = getenv("DISPLAY");
|
||||
Display *dpy = XOpenDisplay(displayid);
|
||||
std::unique_ptr<Display, std::function<void(Display*)>> dpy(XOpenDisplay(displayid), [](Display* d) { XCloseDisplay(d); });
|
||||
|
||||
bool key_is_pressed(KeySym ks) {
|
||||
char keys_return[32];
|
||||
XQueryKeymap(dpy, keys_return);
|
||||
KeyCode kc2 = XKeysymToKeycode(dpy, ks);
|
||||
XQueryKeymap(dpy.get(), keys_return);
|
||||
KeyCode kc2 = XKeysymToKeycode(dpy.get(), ks);
|
||||
bool isPressed = !!(keys_return[kc2 >> 3] & (1 << (kc2 & 7)));
|
||||
return isPressed;
|
||||
}
|
||||
|
@ -0,0 +1,35 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/inotify.h>
|
||||
#include "config.h"
|
||||
#include "notify.h"
|
||||
|
||||
pthread_t fileChange;
|
||||
|
||||
#define EVENT_SIZE ( sizeof (struct inotify_event) )
|
||||
#define EVENT_BUF_LEN ( 1024 * ( EVENT_SIZE + 16 ) )
|
||||
|
||||
void *fileChanged(void *params_void){
|
||||
notify_thread *nt = reinterpret_cast<notify_thread *>(params_void);
|
||||
int length, i = 0;
|
||||
int fd;
|
||||
int wd;
|
||||
char buffer[EVENT_BUF_LEN];
|
||||
fd = inotify_init();
|
||||
wd = inotify_add_watch( fd, nt->params->config_file_path.c_str(), IN_MODIFY);
|
||||
while (!nt->quit) {
|
||||
length = read( fd, buffer, EVENT_BUF_LEN );
|
||||
while (i < length) {
|
||||
struct inotify_event *event =
|
||||
(struct inotify_event *) &buffer[i];
|
||||
i += EVENT_SIZE + event->len;
|
||||
if (event->mask & IN_MODIFY) {
|
||||
std::lock_guard<std::mutex> lk(nt->mutex);
|
||||
parse_overlay_config(nt->params, getenv("MANGOHUD_CONFIG"));
|
||||
}
|
||||
}
|
||||
i = 0;
|
||||
printf("File Changed\n");
|
||||
}
|
||||
return NULL;
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include "overlay_params.h"
|
||||
|
||||
struct notify_thread
|
||||
{
|
||||
overlay_params *params = nullptr;
|
||||
bool quit = false;
|
||||
std::mutex mutex;
|
||||
};
|
||||
|
||||
extern pthread_t fileChange;
|
||||
extern void *fileChanged(void *params_void);
|
Loading…
Reference in New Issue