Skip to content

Commit

Permalink
Update GOTCHA
Browse files Browse the repository at this point in the history
  • Loading branch information
TomTheBear committed Sep 17, 2024
1 parent 9f1481c commit 20a99d2
Show file tree
Hide file tree
Showing 28 changed files with 2,231 additions and 1,959 deletions.
45 changes: 29 additions & 16 deletions ext/GOTCHA/include/gotcha/gotcha.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ without even the IMPLIED WARRANTY OF MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the terms and conditions of the GNU Lesser General Public License
for more details. You should have received a copy of the GNU Lesser General
Public License along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

/*!
Expand All @@ -22,17 +22,19 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* The intended use pattern is as follows
*
* TODO ON-INTERFACE-SOLID: document the interface
* usage
* TODO ON-INTERFACE-SOLID: document the
*interface usage
*
******************************************************************************
*/
#ifndef GOTCHA_H
#define GOTCHA_H

#include "gotcha/gotcha_types.h"
#include <gotcha/gotcha_config.h>
#include <gotcha/gotcha_types.h>
#include <link.h>

#if defined(__cplusplus)
#if defined(__cplusplus)
extern "C" {
#endif

Expand All @@ -44,19 +46,20 @@ extern "C" {
* \param name The name of the function you want to get a pointer to
* \param ret_type The return type of the function you want a pointer to
* \param ... A comma separated list of the types of the parameters
* to the function you're getting a pointer to
* to the function you're getting a pointer to
******************************************************************************
*/

#define GOTCHA_MAKE_FUNCTION_PTR(name, ret_type, ...) ret_type(*name)(__VA_ARGS__)
#define GOTCHA_MAKE_FUNCTION_PTR(name, ret_type, ...) \
ret_type (*name)(__VA_ARGS__)

#define GOTCHA_EXPORT __attribute__((__visibility__("default")))

/*!
******************************************************************************
*
* \fn enum gotcha_error_t gotcha_wrap(struct gotcha_binding_t* bindings,
* void** wrappers, void*** originals,
* \fn enum gotcha_error_t gotcha_wrap(struct gotcha_binding_t* bindings,
* void** wrappers, void*** originals,
* int num_actions);
*
* \brief Makes GOTCHA wrap the functions picked in gotcha_prepare_symbols
Expand All @@ -69,8 +72,9 @@ extern "C" {
******************************************************************************
*/

GOTCHA_EXPORT enum gotcha_error_t gotcha_wrap(struct gotcha_binding_t* bindings, int num_actions, const char* tool_name);

GOTCHA_EXPORT enum gotcha_error_t gotcha_wrap(struct gotcha_binding_t *bindings,
int num_actions,
const char *tool_name);

/*!
******************************************************************************
Expand All @@ -87,7 +91,8 @@ GOTCHA_EXPORT enum gotcha_error_t gotcha_wrap(struct gotcha_binding_t* bindings,
*
******************************************************************************
*/
GOTCHA_EXPORT enum gotcha_error_t gotcha_set_priority(const char* tool_name, int priority);
GOTCHA_EXPORT enum gotcha_error_t gotcha_set_priority(const char *tool_name,
int priority);

/*!
******************************************************************************
Expand All @@ -103,22 +108,30 @@ GOTCHA_EXPORT enum gotcha_error_t gotcha_set_priority(const char* tool_name, int
*
******************************************************************************
*/
GOTCHA_EXPORT enum gotcha_error_t gotcha_get_priority(const char* tool_name, int *priority);
GOTCHA_EXPORT enum gotcha_error_t gotcha_get_priority(const char *tool_name,
int *priority);

/*!
******************************************************************************
*
* \fn enum void* gotcha_get_wrappee(gotcha_wrappee_handle_t)
*
* \brief Given a GOTCHA wrapper's handle, returns the wrapped function for it to call
* \brief Given a GOTCHA wrapper's handle, returns the wrapped function for it
*to call
*
* \param handle The wrappee handle to return the function pointer for
*
******************************************************************************
*/
GOTCHA_EXPORT void* gotcha_get_wrappee(gotcha_wrappee_handle_t handle);
GOTCHA_EXPORT void *gotcha_get_wrappee(gotcha_wrappee_handle_t handle);

GOTCHA_EXPORT void gotcha_filter_libraries_by_name(const char *nameFilter);
GOTCHA_EXPORT void gotcha_only_filter_last();
GOTCHA_EXPORT void gotcha_set_library_filter_func(
int (*new_func)(struct link_map *));
GOTCHA_EXPORT void gotcha_restore_library_filter_func();

#if defined(__cplusplus)
#if defined(__cplusplus)
}
#endif

Expand Down
10 changes: 10 additions & 0 deletions ext/GOTCHA/include/gotcha/gotcha_config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#ifndef GOTCHA_CONFIG_H
#define GOTCHA_CONFIG_H

#define GOTCHA_GET_VERSION(MAJOR, MINOR, PATCH) (MAJOR * 100000 + MINOR * 100 + PATCH)
#define GOTCHA_VERSION (GOTCHA_GET_VERSION (1, 0, 7))
#define GOTCHA_VERSION_MAJOR (GOTCHA_VERSION / 100000)
#define GOTCHA_VERSION_MINOR ((GOTCHA_VERSION / 100) % 1000)
#define GOTCHA_VERSION_PATCH (GOTCHA_VERSION % 100)

#endif /* GOTCHA_CONFIG_H */
28 changes: 15 additions & 13 deletions ext/GOTCHA/include/gotcha/gotcha_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ without even the IMPLIED WARRANTY OF MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the terms and conditions of the GNU Lesser General Public License
for more details. You should have received a copy of the GNU Lesser General
Public License along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*!
******************************************************************************
Expand All @@ -24,33 +24,35 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#ifndef GOTCHA_TYPES_H
#define GOTCHA_TYPES_H

#if defined(__cplusplus)
#if defined(__cplusplus)
extern "C" {
#endif

typedef void* gotcha_wrappee_handle_t;
typedef void *gotcha_wrappee_handle_t;

/*!
* The representation of a Gotcha action
* as it passes through the pipeline
*/
typedef struct gotcha_binding_t {
const char* name; //!< The name of the function being wrapped
void* wrapper_pointer; //!< A pointer to the wrapper function
gotcha_wrappee_handle_t* function_handle; //!< A pointer to the function being wrapped
}gotcha_binding_t;
const char *name; //!< The name of the function being wrapped
void *wrapper_pointer; //!< A pointer to the wrapper function
gotcha_wrappee_handle_t
*function_handle; //!< A pointer to the function being wrapped
} gotcha_binding_t;

/*!
* The representation of an error (or success) of a Gotcha action
*/
typedef enum gotcha_error_t {
GOTCHA_SUCCESS = 0, //!< The call succeeded
GOTCHA_FUNCTION_NOT_FOUND, //!< The call looked up a function which could not be found
GOTCHA_INTERNAL, //!< Internal gotcha error
GOTCHA_INVALID_TOOL //!< Invalid tool name
}gotcha_error_t;
GOTCHA_SUCCESS = 0, //!< The call succeeded
GOTCHA_FUNCTION_NOT_FOUND, //!< The call looked up a function which could not
//!< be found
GOTCHA_INTERNAL, //!< Internal gotcha error
GOTCHA_INVALID_TOOL //!< Invalid tool name
} gotcha_error_t;

#if defined(__cplusplus)
#if defined(__cplusplus)
}
#endif

Expand Down
44 changes: 25 additions & 19 deletions ext/GOTCHA/src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
include(GNUInstallDirs)
set(GOTCHA_SOURCES
gotcha_utils.c
gotcha.c
gotcha_auxv.c
libc_wrappers.c
elf_ops.c
hash.c
tool.c
library_filters.c
gotcha_dl.c
translations.c
gotcha_utils.c
gotcha.c
gotcha_auxv.c
libc_wrappers.c
elf_ops.c
hash.c
tool.c
library_filters.c
gotcha_dl.c
translations.c
)

add_library(gotcha SHARED ${GOTCHA_SOURCES})
Expand All @@ -18,19 +18,25 @@ add_library(gotcha SHARED ${GOTCHA_SOURCES})
set_target_properties(gotcha PROPERTIES SOVERSION ${LIBTOOL_INTERFACE})
set_target_properties(gotcha PROPERTIES VERSION "${LIBTOOL_INTERFACE}.${LIBTOOL_REVISION}.${LIBTOOL_AGE}")
set_target_properties(gotcha PROPERTIES COMPILE_FLAGS "-fvisibility=${DEFAULT_SYMBOL_VISIBILITY}")
if (GOTCHA_ENABLE_WARNING_ERROR)
set_target_properties(gotcha PROPERTIES COMPILE_FLAGS "-Wall -Werror")
endif ()
set_target_properties(gotcha PROPERTIES LINK_FLAGS "-fvisibility=${DEFAULT_SYMBOL_VISIBILITY}")
if(GOTCHA_ENABLE_TESTS)
add_library(gotcha_no_libc SHARED ${GOTCHA_SOURCES})
set_target_properties(gotcha_no_libc PROPERTIES SOVERSION ${LIBTOOL_INTERFACE})
set_target_properties(gotcha_no_libc PROPERTIES VERSION "${LIBTOOL_INTERFACE}.${LIBTOOL_REVISION}.${LIBTOOL_AGE}")
set_target_properties(gotcha_no_libc PROPERTIES COMPILE_DEFINITIONS "FORCE_NO_LIBC")
set_target_properties(gotcha_no_libc PROPERTIES COMPILE_FLAGS "-fvisibility=${DEFAULT_SYMBOL_VISIBILITY}")
set_target_properties(gotcha_no_libc PROPERTIES LINK_FLAGS "-fvisibility=${DEFAULT_SYMBOL_VISIBILITY}")
endif()
target_include_directories(gotcha PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include>)
if (GOTCHA_ENABLE_TESTS)
add_library(gotcha_no_libc SHARED ${GOTCHA_SOURCES})
set_target_properties(gotcha_no_libc PROPERTIES SOVERSION ${LIBTOOL_INTERFACE})
set_target_properties(gotcha_no_libc PROPERTIES VERSION "${LIBTOOL_INTERFACE}.${LIBTOOL_REVISION}.${LIBTOOL_AGE}")
set_target_properties(gotcha_no_libc PROPERTIES COMPILE_DEFINITIONS "FORCE_NO_LIBC")
set_target_properties(gotcha_no_libc PROPERTIES COMPILE_FLAGS "-fvisibility=${DEFAULT_SYMBOL_VISIBILITY}")
set_target_properties(gotcha_no_libc PROPERTIES LINK_FLAGS "-fvisibility=${DEFAULT_SYMBOL_VISIBILITY}")
endif ()

include_directories(${CMAKE_CURRENT_SOURCE_DIR})

install(TARGETS gotcha EXPORT gotcha-targets DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(TARGETS gotcha EXPORT gotcha-targets DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(EXPORT gotcha-targets DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/gotcha)

add_subdirectory(example)
62 changes: 49 additions & 13 deletions ext/GOTCHA/src/elf_ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,20 @@ without even the IMPLIED WARRANTY OF MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the terms and conditions of the GNU Lesser General Public License
for more details. You should have received a copy of the GNU Lesser General
Public License along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "elf_ops.h"
#include "libc_wrappers.h"

#include <elf.h>

#include "libc_wrappers.h"
struct gnu_hash_header {
uint32_t nbuckets; //!< The number of buckets to hash symbols into
uint32_t symndx; //!< Index of the first symbol accessible via hashtable in the symbol table
uint32_t maskwords; //!< Number of words in the hash table's bloom filter
uint32_t shift2; //!< The bloom filter's shift count
uint32_t nbuckets; //!< The number of buckets to hash symbols into
uint32_t symndx; //!< Index of the first symbol accessible via hashtable in
//!< the symbol table
uint32_t maskwords; //!< Number of words in the hash table's bloom filter
uint32_t shift2; //!< The bloom filter's shift count
};

static uint32_t gnu_hash_func(const char *str) {
Expand All @@ -31,13 +34,26 @@ static uint32_t gnu_hash_func(const char *str) {
return hash;
}

/* Symbol versioning
*
* https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA.junk/symversion.html
*
* versym[symidx] does only provides an index into the ElfW(Verdef) array
* (DT_VERDEF/SHT_GNU_verdef) and is not the version itself, but SHT_GNU_verdef
* is sorted in ascending order and the entries have a parent relation, thus a
* higher index should always be a higher version. As we only search for the
* latest symbol/highest version it is sufficient to compare the index.
*/

signed long lookup_gnu_hash_symbol(const char *name, ElfW(Sym) * syms,
char *symnames,
ElfW(Half) * versym, char *symnames,
void *sheader) {
uint32_t *buckets, *vals;
uint32_t hash_val;
uint32_t cur_sym, cur_sym_hashval;
struct gnu_hash_header *header = (struct gnu_hash_header *) (sheader);
signed long latest_sym = -1;
ElfW(Half) latest_sym_ver = 0;
struct gnu_hash_header *header = (struct gnu_hash_header *)(sheader);

buckets = (uint32_t *)(((unsigned char *)(header + 1)) +
(header->maskwords * sizeof(ElfW(Addr))));
Expand All @@ -54,13 +70,22 @@ signed long lookup_gnu_hash_symbol(const char *name, ElfW(Sym) * syms,
cur_sym_hashval = vals[cur_sym - header->symndx];
if (((cur_sym_hashval & ~1) == hash_val) &&
(gotcha_strcmp(name, symnames + syms[cur_sym].st_name) == 0)) {
return (signed long)cur_sym;
if (!versym) {
return (signed long)cur_sym;
}

if ((versym[cur_sym] & 0x7fff) > latest_sym_ver) {
latest_sym = (signed long)cur_sym;
latest_sym_ver = versym[cur_sym] & 0x7fff;
}
}
if (cur_sym_hashval & 1) {
return -1;
break;
}
cur_sym++;
}

return latest_sym;
}

static unsigned long elf_hash(const unsigned char *name) {
Expand All @@ -76,19 +101,30 @@ static unsigned long elf_hash(const unsigned char *name) {
}

signed long lookup_elf_hash_symbol(const char *name, ElfW(Sym) * syms,
char *symnames, ElfW(Word) * header) {
ElfW(Half) * versym, char *symnames,
ElfW(Word) * header) {
ElfW(Word) *nbucket = header + 0;
ElfW(Word) *buckets = header + 2;
ElfW(Word) *chains = buckets + *nbucket;
signed long latest_sym = -1;
ElfW(Half) latest_sym_ver = 0;

unsigned int x = elf_hash((const unsigned char *)name);
signed long y = (signed long)buckets[x % *nbucket];
while (y != STN_UNDEF) {
if (gotcha_strcmp(name, symnames + syms[y].st_name) == 0) {
return y;
if (!versym) {
// in general all libs would have version but it is a guard condition.
return y; // GCOVR_EXCL_LINE
}

if ((versym[y] & 0x7fff) > latest_sym_ver) {
latest_sym = y;
latest_sym_ver = versym[y] & 0x7fff;
}
}
y = chains[y];
}

return -1;
return latest_sym;
}
Loading

0 comments on commit 20a99d2

Please sign in to comment.