diff --git a/ext/GOTCHA/include/gotcha/gotcha.h b/ext/GOTCHA/include/gotcha/gotcha.h index 30018a238..118024506 100644 --- a/ext/GOTCHA/include/gotcha/gotcha.h +++ b/ext/GOTCHA/include/gotcha/gotcha.h @@ -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 */ /*! @@ -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 +#include +#include -#if defined(__cplusplus) +#if defined(__cplusplus) extern "C" { #endif @@ -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 @@ -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); /*! ****************************************************************************** @@ -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); /*! ****************************************************************************** @@ -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 diff --git a/ext/GOTCHA/include/gotcha/gotcha_config.h b/ext/GOTCHA/include/gotcha/gotcha_config.h new file mode 100644 index 000000000..782c12ea1 --- /dev/null +++ b/ext/GOTCHA/include/gotcha/gotcha_config.h @@ -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 */ diff --git a/ext/GOTCHA/include/gotcha/gotcha_types.h b/ext/GOTCHA/include/gotcha/gotcha_types.h index 5e247f757..76304f4a5 100644 --- a/ext/GOTCHA/include/gotcha/gotcha_types.h +++ b/ext/GOTCHA/include/gotcha/gotcha_types.h @@ -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 */ /*! ****************************************************************************** @@ -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 diff --git a/ext/GOTCHA/src/CMakeLists.txt b/ext/GOTCHA/src/CMakeLists.txt index 1132a4ca7..6c2e9ea24 100644 --- a/ext/GOTCHA/src/CMakeLists.txt +++ b/ext/GOTCHA/src/CMakeLists.txt @@ -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}) @@ -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 + $ + $) +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) diff --git a/ext/GOTCHA/src/elf_ops.c b/ext/GOTCHA/src/elf_ops.c index 93297e306..0b8afe0db 100644 --- a/ext/GOTCHA/src/elf_ops.c +++ b/ext/GOTCHA/src/elf_ops.c @@ -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 + +#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) { @@ -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)))); @@ -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) { @@ -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; } diff --git a/ext/GOTCHA/src/elf_ops.h b/ext/GOTCHA/src/elf_ops.h index 061b35fac..bc9b2bfed 100644 --- a/ext/GOTCHA/src/elf_ops.h +++ b/ext/GOTCHA/src/elf_ops.h @@ -3,14 +3,14 @@ This file is part of GOTCHA. For copyright information see the COPYRIGHT file in the top level directory, or at https://github.com/LLNL/gotcha/blob/master/COPYRIGHT This program is free software; you can redistribute it and/or modify it under -the terms of the GNU Lesser General Public License (as published by the Free Software -Foundation) version 2.1 dated February 1999. This program 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 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 +the terms of the GNU Lesser General Public License (as published by the Free +Software Foundation) version 2.1 dated February 1999. This program 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #if !defined(ELF_OPS_H_) @@ -18,8 +18,8 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include #include -#include "library_filters.h" +#include "library_filters.h" /*! ****************************************************************************** @@ -28,45 +28,53 @@ Place, Suite 330, Boston, MA 02111-1307 USA * \param sym The symbol you wish to check ****************************************************************************** */ -#define GOTCHA_CHECK_VISIBILITY(sym)((sym.st_size>0)) +#define GOTCHA_CHECK_VISIBILITY(sym) ((sym.st_size > 0)) /*! ****************************************************************************** * - * \fn signed long lookup_gnu_hash_symbol(const char *name, + * \fn signed long lookup_gnu_hash_symbol(const char *name, ElfW(Sym) *syms, - char *symnames, + ElfW(Half) *versym, + char *symnames, void *header); * - * \brief Looks up the index of a symbol in a symbol table given a symbol name + * \brief Looks up the index of a symbol in a symbol table given a symbol name * * \param name The name of the function to be looked up * \param syms The pointer to the symbol table + * \param versym The pointer to the symbol versioning table * \param symnames A pointer into the string table * \param header The parameters the underlying GNU Hash function will use * ****************************************************************************** */ -signed long lookup_gnu_hash_symbol(const char *name, ElfW(Sym) *syms, char *symnames, void *sheader); +signed long lookup_gnu_hash_symbol(const char *name, ElfW(Sym) * syms, + ElfW(Half) * versym, char *symnames, + void *sheader); /*! ****************************************************************************** * - * \fn signed long lookup_elf_hash_symbol(const char *name, + * \fn signed long lookup_elf_hash_symbol(const char *name, ElfW(Sym) *syms, - char *symnames, + ElfW(Half) *versym, + char *symnames, ElfW(Word) *header); * - * \brief Looks up the index of a symbol in a symbol table given a symbol name + * \brief Looks up the index of a symbol in a symbol table given a symbol name * * \param name The name of the function to be looked up * \param syms The pointer to the symbol table + * \param versym The pointer to the symbol versioning table * \param symnames A pointer into the string table * \param header The parameters the underlying ELF Hash function will use * ****************************************************************************** */ -signed long lookup_elf_hash_symbol(const char *name, ElfW(Sym) *syms, char *symnames, ElfW(Word) *header); +signed long lookup_elf_hash_symbol(const char *name, ElfW(Sym) * syms, + ElfW(Half) * versym, char *symnames, + ElfW(Word) * header); /*! ****************************************************************************** @@ -85,71 +93,108 @@ signed long lookup_elf_hash_symbol(const char *name, ElfW(Sym) *syms, char *symn * \param[out] gnu_hash * \param[out] got * \param[out] strtab + * \param[out] versym * ****************************************************************************** */ -#define INIT_DYNAMIC(lmap) \ - ElfW(Dyn) *dynsec = NULL, *dentry = NULL; \ - ElfW(Rela) *rela = NULL; \ - ElfW(Rel) *rel = NULL; \ - ElfW(Addr) jmprel = 0; \ - ElfW(Sym) *symtab = NULL; \ - ElfW(Addr) gnu_hash = 0x0, elf_hash = 0x0; \ - ElfW(Addr) got = 0x0; \ - char *strtab = NULL; \ - unsigned int rel_size = 0, rel_count = 0, is_rela = 0, i; \ - dynsec = lmap->l_ld; \ - if (!dynsec) \ - return -1; \ - for (dentry = dynsec; dentry->d_tag != DT_NULL; dentry++) { \ - switch (dentry->d_tag) { \ - case DT_PLTRELSZ: { \ - rel_size = (unsigned int) dentry->d_un.d_val; \ - break; \ - } \ - case DT_PLTGOT: { \ - got = dentry->d_un.d_ptr; \ - break; \ - } \ - case DT_HASH: { \ - elf_hash = dentry->d_un.d_val; \ - break; \ - } \ - case DT_STRTAB: { \ - strtab = (char *) dentry->d_un.d_ptr; \ - break; \ - } \ - case DT_SYMTAB: { \ - symtab = (ElfW(Sym) *) dentry->d_un.d_ptr; \ - break; \ - } \ - case DT_PLTREL: { \ - is_rela = (dentry->d_un.d_val == DT_RELA); \ - break; \ - } \ - case DT_JMPREL: { \ - jmprel = dentry->d_un.d_val; \ - break; \ - } \ - case DT_GNU_HASH: { \ - gnu_hash = dentry->d_un.d_val; \ - break; \ - } \ - } \ - } \ - rel_count = rel_size / (is_rela ? sizeof(ElfW(Rela)) : sizeof(ElfW(Rel))); \ - (void) rela; \ - (void) rel; \ - (void) jmprel; \ - (void) symtab; \ - (void) gnu_hash; \ - (void) elf_hash; \ - (void) got; \ - (void) strtab; \ - (void) rel_size; \ - (void) rel_count; \ - (void) is_rela; \ - (void) i; +#define INIT_DYNAMIC(lmap) \ + ElfW(Dyn) *dynsec = NULL, *dentry = NULL; \ + ElfW(Rela) *rela = NULL; \ + ElfW(Rel) *rel = NULL; \ + ElfW(Addr) jmprel = 0; \ + ElfW(Sym) *symtab = NULL; \ + ElfW(Addr) gnu_hash = 0x0, elf_hash = 0x0; \ + ElfW(Addr) got = 0x0; \ + ElfW(Half) *versym = NULL; \ + char *strtab = NULL; \ + unsigned int rel_size = 0, rel_count = 0, is_rela = 0, i; \ + unsigned int rela_size = 0, rela_count = 0, rela_esz = 1; \ + unsigned int jmprel_size = 0, jmprel_count = 0, rel_esz = 1; \ + dynsec = lmap->l_ld; \ + if (!dynsec) return -1; \ + for (dentry = dynsec; dentry->d_tag != DT_NULL; dentry++) { \ + switch (dentry->d_tag) { \ + case DT_REL: { \ + rel = (ElfW(Rel) *)dentry->d_un.d_ptr; \ + break; \ + } \ + case DT_RELSZ: { \ + rel_size = (unsigned int)dentry->d_un.d_val; \ + break; \ + } \ + case DT_RELENT: { \ + rel_esz = (unsigned int)dentry->d_un.d_val; \ + break; \ + } \ + case DT_RELA: { \ + rela = (ElfW(Rela) *)dentry->d_un.d_ptr; \ + break; \ + } \ + case DT_RELASZ: { \ + rela_size = (unsigned int)dentry->d_un.d_val; \ + break; \ + } \ + case DT_RELAENT: { \ + rela_esz = (unsigned int)dentry->d_un.d_val; \ + break; \ + } \ + case DT_PLTRELSZ: { \ + jmprel_size = (unsigned int)dentry->d_un.d_val; \ + break; \ + } \ + case DT_PLTGOT: { \ + got = dentry->d_un.d_ptr; \ + break; \ + } \ + case DT_HASH: { \ + elf_hash = dentry->d_un.d_val; \ + break; \ + } \ + case DT_STRTAB: { \ + strtab = (char *)dentry->d_un.d_ptr; \ + break; \ + } \ + case DT_SYMTAB: { \ + symtab = (ElfW(Sym) *)dentry->d_un.d_ptr; \ + break; \ + } \ + case DT_PLTREL: { \ + is_rela = (dentry->d_un.d_val == DT_RELA); \ + break; \ + } \ + case DT_JMPREL: { \ + jmprel = dentry->d_un.d_ptr; \ + break; \ + } \ + case DT_GNU_HASH: { \ + gnu_hash = dentry->d_un.d_val; \ + break; \ + } \ + case DT_VERSYM: { \ + versym = (ElfW(Half) *)dentry->d_un.d_ptr; \ + break; \ + } \ + } \ + } \ + jmprel_count = \ + jmprel_size / (is_rela ? sizeof(ElfW(Rela)) : sizeof(ElfW(Rel))); \ + if (rel) rel_count = rel_size / rel_esz; \ + if (rela) rela_count = rela_size / rela_esz; \ + (void)rela; \ + (void)jmprel_count; \ + (void)rela_count; \ + (void)rel; \ + (void)jmprel; \ + (void)symtab; \ + (void)gnu_hash; \ + (void)elf_hash; \ + (void)got; \ + (void)strtab; \ + (void)rel_size; \ + (void)rel_count; \ + (void)is_rela; \ + (void)versym; \ + (void)i; /*! ****************************************************************************** @@ -165,22 +210,22 @@ signed long lookup_elf_hash_symbol(const char *name, ElfW(Sym) *syms, char *symn * ****************************************************************************** */ -#define FOR_EACH_PLTREL_INT(relptr, op, ...) \ - for (i = 0; i < rel_count; i++) { \ - ElfW(Addr) offset = relptr[i].r_offset; \ - unsigned long symidx = R_SYM(relptr[i].r_info); \ - ElfW(Sym) *sym = symtab + symidx; \ - char *symname = strtab + sym->st_name; \ - op(sym, symname, offset, ## __VA_ARGS__); \ - } +#define FOR_EACH_PLTREL_INT(relptr, rel_count, op, ...) \ + for (i = 0; i < rel_count; i++) { \ + ElfW(Addr) offset = relptr[i].r_offset; \ + unsigned long symidx = R_SYM(relptr[i].r_info); \ + ElfW(Sym) *sym = symtab + symidx; \ + char *symname = strtab + sym->st_name; \ + op(sym, symname, offset, ##__VA_ARGS__); \ + } /*! ****************************************************************************** * * \def FOR_EACH_PLTREL(lmap, op, ...) * - * \brief This macro calls an operation on each relocation in the dynamic section - * associated with a link map entry + * \brief This macro calls an operation on each relocation in the dynamic + *section associated with a link map entry * * \param lmap The link map whose relocations you want processed * \param op The operation to be performed on each relocation @@ -188,19 +233,24 @@ signed long lookup_elf_hash_symbol(const char *name, ElfW(Sym) *syms, char *symn * ****************************************************************************** */ -#define FOR_EACH_PLTREL(lmap, op, ...) { \ - INIT_DYNAMIC(lmap) \ - ElfW(Addr) offset = lmap->l_addr; \ - (void) offset; \ - if (is_rela) { \ - rela = (ElfW(Rela) *) jmprel; \ - FOR_EACH_PLTREL_INT(rela, op, ## __VA_ARGS__); \ - } \ - else { \ - rel = (ElfW(Rel) *) jmprel; \ - FOR_EACH_PLTREL_INT(rel, op, ## __VA_ARGS__); \ - } \ - } - +#define FOR_EACH_PLTREL(lmap, op, ...) \ + { \ + INIT_DYNAMIC(lmap) \ + ElfW(Addr) offset = lmap->l_addr; \ + (void)offset; \ + if (is_rela) { \ + ElfW(Rela) *jmp_rela = (ElfW(Rela) *)jmprel; \ + FOR_EACH_PLTREL_INT(jmp_rela, jmprel_count, op, ##__VA_ARGS__); \ + if (rela) { \ + FOR_EACH_PLTREL_INT(rela, rela_count, op, ##__VA_ARGS__); \ + } \ + } else { \ + ElfW(Rel) *jmp_rel = (ElfW(Rel) *)jmprel; \ + FOR_EACH_PLTREL_INT(jmp_rel, jmprel_count, op, ##__VA_ARGS__); \ + if (rel) { \ + FOR_EACH_PLTREL_INT(rel, rel_count, op, ##__VA_ARGS__); \ + } \ + } \ + } #endif diff --git a/ext/GOTCHA/src/example/autotee/autotee.c b/ext/GOTCHA/src/example/autotee/autotee.c index 747f6fc81..248f528fb 100644 --- a/ext/GOTCHA/src/example/autotee/autotee.c +++ b/ext/GOTCHA/src/example/autotee/autotee.c @@ -10,29 +10,29 @@ 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 */ /** * autotee - - * Using gotcha, wrap the major IO writing routines with functions that + * Using gotcha, wrap the major IO writing routines with functions that * "tee" any stdout output to another file. Init by calling * init_autotee(filename) * finish by calling: * close_autotee() * * Note, this is a demonstration program for gotcha and does not handle - * cases like stdout's file descriptor being dup'd or more esoteric + * cases like stdout's file descriptor being dup'd or more esoteric * IO routines. **/ - -#include "gotcha/gotcha_types.h" -#include "gotcha/gotcha.h" -#include +#include #include #include -#include +#include + +#include "gotcha/gotcha.h" +#include "gotcha/gotcha_types.h" static int tee_fd = -1; static FILE *tee_FILE = NULL; @@ -44,7 +44,8 @@ static int vprintf_wrapper(const char *str, va_list args); static ssize_t write_wrapper(int fd, const void *buffer, size_t size); static int puts_wrapper(const char *str); static int fputs_wrapper(const char *str, FILE *f); -static int fwrite_wrapper(const void *ptr, size_t size, size_t nmemb, FILE *stream); +static int fwrite_wrapper(const void *ptr, size_t size, size_t nmemb, + FILE *stream); static gotcha_wrappee_handle_t orig_printf_handle; static gotcha_wrappee_handle_t orig_fprintf_handle; @@ -55,157 +56,139 @@ static gotcha_wrappee_handle_t orig_puts_handle; static gotcha_wrappee_handle_t orig_fputs_handle; static gotcha_wrappee_handle_t orig_fwrite_handle; - #define NUM_IOFUNCS 8 struct gotcha_binding_t iofuncs[] = { - { "printf", printf_wrapper, &orig_printf_handle }, - { "fprintf", fprintf_wrapper, &orig_fprintf_handle }, - { "vfprintf", vfprintf_wrapper, &orig_vfprintf_handle }, - { "vprintf", vprintf_wrapper, &orig_vprintf_handle }, - { "write", write_wrapper, &orig_write_handle }, - { "puts", puts_wrapper, &orig_puts_handle }, - { "fputs", fputs_wrapper, &orig_fputs_handle }, - { "fwrite", fwrite_wrapper, &orig_fwrite_handle } -}; - -int init_autotee(const char *teefile) -{ - enum gotcha_error_t result; - gotcha_set_priority("testing/whether/this/works", 1); - tee_FILE = fopen(teefile, "w"); - if (!tee_FILE) { - perror("Failed to open tee file"); - return -1; - } - tee_fd = fileno(tee_FILE); - - result = gotcha_wrap(iofuncs, NUM_IOFUNCS, "testing/whether"); - if (result != GOTCHA_SUCCESS) { - fprintf(stderr, "gotcha_wrap returned %d\n", (int) result); - return -1; - } - - return 0; + {"printf", printf_wrapper, &orig_printf_handle}, + {"fprintf", fprintf_wrapper, &orig_fprintf_handle}, + {"vfprintf", vfprintf_wrapper, &orig_vfprintf_handle}, + {"vprintf", vprintf_wrapper, &orig_vprintf_handle}, + {"write", write_wrapper, &orig_write_handle}, + {"puts", puts_wrapper, &orig_puts_handle}, + {"fputs", fputs_wrapper, &orig_fputs_handle}, + {"fwrite", fwrite_wrapper, &orig_fwrite_handle}}; + +int init_autotee(const char *teefile) { + enum gotcha_error_t result; + gotcha_set_priority("testing/whether/this/works", 1); + tee_FILE = fopen(teefile, "w"); + if (!tee_FILE) { + perror("Failed to open tee file"); + return -1; + } + tee_fd = fileno(tee_FILE); + + result = gotcha_wrap(iofuncs, NUM_IOFUNCS, "testing/whether"); + if (result != GOTCHA_SUCCESS) { + fprintf(stderr, "gotcha_wrap returned %d\n", (int)result); + return -1; + } + + return 0; } -int close_autotee() -{ - if (tee_FILE) { - fclose(tee_FILE); - tee_fd = -1; - } - return 0; +int close_autotee() { + if (tee_FILE) { + fclose(tee_FILE); + tee_fd = -1; + } + return 0; } -static int printf_wrapper(const char *format, ...) -{ - typeof(&vfprintf) orig_vfprintf = gotcha_get_wrappee(orig_vfprintf_handle); - typeof(&vprintf) orig_vprintf = gotcha_get_wrappee(orig_vprintf_handle); - int result; - va_list args, args2; - va_start(args, format); +static int printf_wrapper(const char *format, ...) { + typeof(&vfprintf) orig_vfprintf = gotcha_get_wrappee(orig_vfprintf_handle); + typeof(&vprintf) orig_vprintf = gotcha_get_wrappee(orig_vprintf_handle); + int result; + va_list args, args2; + va_start(args, format); - if (tee_FILE) { - va_copy(args2, args); - orig_vfprintf(tee_FILE, format, args2); - va_end(args2); - } + if (tee_FILE) { + va_copy(args2, args); + orig_vfprintf(tee_FILE, format, args2); + va_end(args2); + } - result = orig_vprintf(format, args); - va_end(args); + result = orig_vprintf(format, args); + va_end(args); - return result; + return result; } -static int fprintf_wrapper(FILE *stream, const char *format, ...) -{ - typeof(&vfprintf) orig_vfprintf = gotcha_get_wrappee(orig_vfprintf_handle); - int result; - va_list args, args2; - va_start(args, format); - - if (stream != stdout) { - result = orig_vfprintf(stream, format, args); - } - else { - if (tee_FILE) { - va_copy(args2, args); - orig_vfprintf(tee_FILE, format, args2); - va_end(args2); - } - result = orig_vfprintf(stdout, format, args); - } - - va_end(args); - return result; -} +static int fprintf_wrapper(FILE *stream, const char *format, ...) { + typeof(&vfprintf) orig_vfprintf = gotcha_get_wrappee(orig_vfprintf_handle); + int result; + va_list args, args2; + va_start(args, format); -static int vfprintf_wrapper(FILE *stream, const char *str, va_list args) -{ - typeof(&vfprintf) orig_vfprintf = gotcha_get_wrappee(orig_vfprintf_handle); - va_list args2; - if (stream != stdout) { - return orig_vfprintf(stream, str, args); - } - if (tee_FILE) { + if (stream != stdout) { + result = orig_vfprintf(stream, format, args); + } else { + if (tee_FILE) { va_copy(args2, args); - orig_vfprintf(tee_FILE, str, args2); + orig_vfprintf(tee_FILE, format, args2); va_end(args2); - } - return orig_vfprintf(stream, str, args); + } + result = orig_vfprintf(stdout, format, args); + } + + va_end(args); + return result; } -static int vprintf_wrapper(const char *str, va_list args) -{ - typeof(&vfprintf) orig_vfprintf = gotcha_get_wrappee(orig_vfprintf_handle); - typeof(&vprintf) orig_vprintf = gotcha_get_wrappee(orig_vprintf_handle); - va_list args2; - if (tee_FILE) { - va_copy(args2, args); - orig_vfprintf(tee_FILE, str, args2); - va_end(args2); - } - return orig_vprintf(str, args); +static int vfprintf_wrapper(FILE *stream, const char *str, va_list args) { + typeof(&vfprintf) orig_vfprintf = gotcha_get_wrappee(orig_vfprintf_handle); + va_list args2; + if (stream != stdout) { + return orig_vfprintf(stream, str, args); + } + if (tee_FILE) { + va_copy(args2, args); + orig_vfprintf(tee_FILE, str, args2); + va_end(args2); + } + return orig_vfprintf(stream, str, args); } -static ssize_t write_wrapper(int fd, const void *buffer, size_t size) -{ - typeof(&write) orig_write = gotcha_get_wrappee(orig_write_handle); - if (fd != 1) - return orig_write(fd, buffer, size); - - if (tee_fd != -1) - orig_write(tee_fd, buffer, size); - return orig_write(fd, buffer, size); +static int vprintf_wrapper(const char *str, va_list args) { + typeof(&vfprintf) orig_vfprintf = gotcha_get_wrappee(orig_vfprintf_handle); + typeof(&vprintf) orig_vprintf = gotcha_get_wrappee(orig_vprintf_handle); + va_list args2; + if (tee_FILE) { + va_copy(args2, args); + orig_vfprintf(tee_FILE, str, args2); + va_end(args2); + } + return orig_vprintf(str, args); +} + +static ssize_t write_wrapper(int fd, const void *buffer, size_t size) { + typeof(&write) orig_write = gotcha_get_wrappee(orig_write_handle); + if (fd != 1) return orig_write(fd, buffer, size); + + if (tee_fd != -1) orig_write(tee_fd, buffer, size); + return orig_write(fd, buffer, size); } -static int puts_wrapper(const char *str) -{ - typeof(&fputs) orig_fputs = gotcha_get_wrappee(orig_fputs_handle); - typeof(&puts) orig_puts = gotcha_get_wrappee(orig_puts_handle); - if (tee_FILE) { - orig_fputs(str, tee_FILE); - orig_fputs("\n", tee_FILE); - } - return orig_puts(str); +static int puts_wrapper(const char *str) { + typeof(&fputs) orig_fputs = gotcha_get_wrappee(orig_fputs_handle); + typeof(&puts) orig_puts = gotcha_get_wrappee(orig_puts_handle); + if (tee_FILE) { + orig_fputs(str, tee_FILE); + orig_fputs("\n", tee_FILE); + } + return orig_puts(str); } -static int fputs_wrapper(const char *str, FILE *f) -{ - typeof(&fputs) orig_fputs = gotcha_get_wrappee(orig_fputs_handle); - if (f != stdout) - return orig_fputs(str, f); - if (tee_FILE) - orig_fputs(str, tee_FILE); - return orig_fputs(str, f); +static int fputs_wrapper(const char *str, FILE *f) { + typeof(&fputs) orig_fputs = gotcha_get_wrappee(orig_fputs_handle); + if (f != stdout) return orig_fputs(str, f); + if (tee_FILE) orig_fputs(str, tee_FILE); + return orig_fputs(str, f); } -static int fwrite_wrapper(const void *ptr, size_t size, size_t nmemb, FILE *stream) -{ - typeof(&fwrite) orig_fwrite = gotcha_get_wrappee(orig_fwrite_handle); - if (stream != stdout) - return orig_fwrite(ptr, size, nmemb, stream); - if (tee_FILE) - orig_fwrite(ptr, size, nmemb, tee_FILE); - return orig_fwrite(ptr, size, nmemb, stream); +static int fwrite_wrapper(const void *ptr, size_t size, size_t nmemb, + FILE *stream) { + typeof(&fwrite) orig_fwrite = gotcha_get_wrappee(orig_fwrite_handle); + if (stream != stdout) return orig_fwrite(ptr, size, nmemb, stream); + if (tee_FILE) orig_fwrite(ptr, size, nmemb, tee_FILE); + return orig_fwrite(ptr, size, nmemb, stream); } diff --git a/ext/GOTCHA/src/example/autotee/test_autotee.c b/ext/GOTCHA/src/example/autotee/test_autotee.c index 704ebb82c..76ecef690 100644 --- a/ext/GOTCHA/src/example/autotee/test_autotee.c +++ b/ext/GOTCHA/src/example/autotee/test_autotee.c @@ -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 */ #include @@ -21,27 +21,28 @@ extern int close_autotee(); #define OUTPUT_FILE "tee.out" -int main() -{ - int result; - - printf("Every stdout print after this line should also appear in %s:\n", OUTPUT_FILE); - - result = init_autotee(OUTPUT_FILE); - if (result != 0) - return -1; - - printf("First line\n"); - printf("Second %s\n", "line"); - fprintf(stdout, "Third line\n"); - fprintf(stdout, "%s line\n", "Forth"); - puts("Fifth line"); - fputs("Sixth ", stdout); - fputs("line\n", stdout); - fwrite("Seventh line\n", 1, strlen("Seventh line\n"), stdout); - fprintf(stderr, "Eighth line is stderr and should not appear in in %s\n", OUTPUT_FILE); - close_autotee(); - printf("Ninth line is after close and should not appear in %s\n", OUTPUT_FILE); - - return 0; +int main() { + int result; + + printf("Every stdout print after this line should also appear in %s:\n", + OUTPUT_FILE); + + result = init_autotee(OUTPUT_FILE); + if (result != 0) return -1; + + printf("First line\n"); + printf("Second %s\n", "line"); + fprintf(stdout, "Third line\n"); + fprintf(stdout, "%s line\n", "Forth"); + puts("Fifth line"); + fputs("Sixth ", stdout); + fputs("line\n", stdout); + fwrite("Seventh line\n", 1, strlen("Seventh line\n"), stdout); + fprintf(stderr, "Eighth line is stderr and should not appear in in %s\n", + OUTPUT_FILE); + close_autotee(); + printf("Ninth line is after close and should not appear in %s\n", + OUTPUT_FILE); + + return 0; } diff --git a/ext/GOTCHA/src/example/minimal/sampleLib.c b/ext/GOTCHA/src/example/minimal/sampleLib.c index 03e8b98c2..19bc3ac15 100644 --- a/ext/GOTCHA/src/example/minimal/sampleLib.c +++ b/ext/GOTCHA/src/example/minimal/sampleLib.c @@ -10,53 +10,52 @@ 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 #include "sampleLib.h" -//We need a place to store the pointer to the function we've wrapped +#include + +// We need a place to store the pointer to the function we've wrapped gotcha_wrappee_handle_t origRetX_handle; /** - * We need to express our desired wrapping behavior to - * GOTCHA. For that we need three things: - * - * 1) The name of a symbol to wrap - * 2) The function we want to wrap it with - * 3) Some place to store the original function, if we wish - * to call it - * - * This variable bindings gets filled out with a list of three - * element structs containing those things. - * - * Note that the place to store the original function is passed - * by reference, this is required for us to be able to change it - */ + * We need to express our desired wrapping behavior to + * GOTCHA. For that we need three things: + * + * 1) The name of a symbol to wrap + * 2) The function we want to wrap it with + * 3) Some place to store the original function, if we wish + * to call it + * + * This variable bindings gets filled out with a list of three + * element structs containing those things. + * + * Note that the place to store the original function is passed + * by reference, this is required for us to be able to change it + */ struct gotcha_binding_t bindings[] = {{"retX", dogRetX, &origRetX_handle}}; // This is like a tool library's initialization function -int sample_init() -{ +int sample_init() { gotcha_wrap(bindings, 1, "gotcha_internal_sample_tool"); return 0; } /** - * In our example, this is the function we're wrapping. - * For convenience, it's in the same library, but this - * isn't a requirement imposed by GOTCHA - */ + * In our example, this is the function we're wrapping. + * For convenience, it's in the same library, but this + * isn't a requirement imposed by GOTCHA + */ int retX(int x) { return x; } -/** - * This is our wrapper function. All GOTCHA wrappers *must* - * reference dogs somewhere in the code. I didn't write the - * rules (yes I did) - */ -int dogRetX(int x) -{ +/** + * This is our wrapper function. All GOTCHA wrappers *must* + * reference dogs somewhere in the code. I didn't write the + * rules (yes I did) + */ +int dogRetX(int x) { typeof(&dogRetX) origRetX = gotcha_get_wrappee(origRetX_handle); printf("SO I FOR ONE THINK DOGS SHOULD RETURN %i\n", x); return origRetX ? origRetX(x) + 1 : 0; diff --git a/ext/GOTCHA/src/example/minimal/sampleLib.h b/ext/GOTCHA/src/example/minimal/sampleLib.h index aa229af5c..4a7a58ea2 100644 --- a/ext/GOTCHA/src/example/minimal/sampleLib.h +++ b/ext/GOTCHA/src/example/minimal/sampleLib.h @@ -3,14 +3,14 @@ This file is part of GOTCHA. For copyright information see the COPYRIGHT file in the top level directory, or at https://github.com/LLNL/gotcha/blob/master/COPYRIGHT This program is free software; you can redistribute it and/or modify it under -the terms of the GNU Lesser General Public License (as published by the Free Software -Foundation) version 2.1 dated February 1999. This program 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 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 +the terms of the GNU Lesser General Public License (as published by the Free +Software Foundation) version 2.1 dated February 1999. This program 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SAMPLE_LIB_H #define SAMPLE_LIB_H @@ -18,6 +18,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA int sample_init(); int retX(int x); int dogRetX(int x); -void* dog_malloc(int size); -void* mylloc(int size); +void *dog_malloc(int size); +void *mylloc(int size); #endif diff --git a/ext/GOTCHA/src/example/minimal/symbolLookup.c b/ext/GOTCHA/src/example/minimal/symbolLookup.c index ce8450dd6..82233fbb7 100644 --- a/ext/GOTCHA/src/example/minimal/symbolLookup.c +++ b/ext/GOTCHA/src/example/minimal/symbolLookup.c @@ -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 */ #include @@ -23,8 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "sampleLib.h" void dbg() {} -int main() -{ +int main() { sample_init(); int check_val = retX(9); assert(check_val == 10); diff --git a/ext/GOTCHA/src/gotcha.c b/ext/GOTCHA/src/gotcha.c index 8e9524d65..3d9db4561 100644 --- a/ext/GOTCHA/src/gotcha.c +++ b/ext/GOTCHA/src/gotcha.c @@ -10,263 +10,398 @@ 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 "translations.h" -#include "libc_wrappers.h" +#define _GNU_SOURCE #include "gotcha/gotcha.h" + +#include + +#include "elf_ops.h" #include "gotcha/gotcha_types.h" -#include "gotcha_utils.h" #include "gotcha_auxv.h" #include "gotcha_dl.h" -#include "elf_ops.h" +#include "gotcha_utils.h" +#include "libc_wrappers.h" #include "tool.h" +#include "translations.h" -static void writeAddress(void* write, void* value){ - *(void**)write = value; -} +static void writeAddress(void *write, void *value) { *(void **)write = value; } -static void** getBindingAddressPointer(struct gotcha_binding_t* in){ - return (void**)in->function_handle; +static void **getBindingAddressPointer(struct gotcha_binding_t *in) { + return (void **)in->function_handle; } -static void setBindingAddressPointer(struct gotcha_binding_t* in, void* value){ - void **target = getBindingAddressPointer(in); - debug_printf(3, "Updating binding address pointer at %p to %p\n", target, value); - writeAddress(target, value); +static void setBindingAddressPointer(struct gotcha_binding_t *in, void *value) { + void **target = getBindingAddressPointer(in); + debug_printf(3, "Updating binding address pointer at %p to %p\n", target, + value); + writeAddress(target, value); } -static void** getInternalBindingAddressPointer(struct internal_binding_t** in){ - return (void**)&((*in)->wrappee_pointer); +void **getInternalBindingAddressPointer(struct internal_binding_t **in) { + return (void **)&((*in)->wrappee_pointer); } -static void setInternalBindingAddressPointer(void** in, void* value){ - void** target = getInternalBindingAddressPointer((struct internal_binding_t**)in); - debug_printf(3, "Updating binding address pointer at %p to %p\n", target, value); +static void setInternalBindingAddressPointer(void **in, void *value) { + void **target = + getInternalBindingAddressPointer((struct internal_binding_t **)in); + debug_printf(3, "Updating binding address pointer at %p to %p\n", target, + value); writeAddress(target, value); } -int prepare_symbol(struct internal_binding_t *binding) -{ - int result; - struct link_map *lib; - struct gotcha_binding_t *user_binding = binding->user_binding; - - debug_printf(2, "Looking up exported symbols for %s\n", user_binding->name); - for (lib = _r_debug.r_map; lib != 0; lib = lib->l_next) { - struct library_t *int_library = get_library(lib); - if (!int_library) { - debug_printf(3, "Creating new library object for %s\n", LIB_NAME(lib)); - int_library = add_library(lib); - } - - if (is_vdso(lib)) { - debug_printf(2, "Skipping VDSO library at 0x%lx with name %s\n", - lib->l_addr, LIB_NAME(lib)); - continue; - } - debug_printf(2, "Searching for exported symbols in %s\n", LIB_NAME(lib)); - INIT_DYNAMIC(lib); - - if (!gnu_hash && !elf_hash) { - debug_printf(3, "Library %s does not export or import symbols\n", LIB_NAME(lib)); - continue; - } - result = -1; - if (gnu_hash) { - debug_printf(3, "Checking GNU hash for %s in %s\n", - user_binding->name, LIB_NAME(lib)); - result = lookup_gnu_hash_symbol(user_binding->name, symtab, strtab, - (struct gnu_hash_header *) gnu_hash); - } - if (elf_hash && result == -1) { - debug_printf(3, "Checking ELF hash for %s in %s\n", - user_binding->name, LIB_NAME(lib)); - result = lookup_elf_hash_symbol(user_binding->name, symtab, strtab, - (ElfW(Word) *)elf_hash); - } - if (result == -1) { - debug_printf(3, "%s not found in %s\n", - user_binding->name, LIB_NAME(lib)); - continue; - } - if (! GOTCHA_CHECK_VISIBILITY(symtab[result])) { - debug_printf(3, "Symbol %s found but not exported in %s\n", - user_binding->name, LIB_NAME(lib)); - continue; - } +long lookup_exported_symbol(const char *name, const struct link_map *lib, + void **symbol) { + long result; + if (is_vdso(lib)) { + debug_printf(2, "Skipping VDSO library at 0x%lx with name %s\n", + lib->l_addr, LIB_NAME(lib)); + return -1; + } + debug_printf(2, "Searching for exported symbols in %s\n", LIB_NAME(lib)); + INIT_DYNAMIC(lib); + + if (!gnu_hash && !elf_hash) { // GCOVR_EXCL_START + debug_printf(3, "Library %s does not export or import symbols\n", + LIB_NAME(lib)); + return -1; + } // GCOVR_EXCL_STOP + result = -1; + if (gnu_hash) { + debug_printf(3, "Checking GNU hash for %s in %s\n", name, LIB_NAME(lib)); + result = lookup_gnu_hash_symbol(name, symtab, versym, strtab, + (struct gnu_hash_header *)gnu_hash); + } + if (elf_hash && result == -1) { + debug_printf(3, "Checking ELF hash for %s in %s\n", name, LIB_NAME(lib)); + result = lookup_elf_hash_symbol(name, symtab, versym, strtab, + (ElfW(Word) *)elf_hash); + } + if (result == -1) { + debug_printf(3, "%s not found in %s\n", name, LIB_NAME(lib)); + return -1; + } + if (!GOTCHA_CHECK_VISIBILITY(symtab[result])) { // GCOVR_EXCL_START + debug_printf(3, "Symbol %s found but not exported in %s\n", name, + LIB_NAME(lib)); + return -1; + } // GCOVR_EXCL_STOP + + debug_printf(2, "Symbol %s found in %s at 0x%lx\n", name, LIB_NAME(lib), + symtab[result].st_value + lib->l_addr); + *symbol = (void *)(symtab[result].st_value + lib->l_addr); + return result; +} - debug_printf(2, "Symbol %s found in %s at 0x%lx\n", - user_binding->name, LIB_NAME(lib), - symtab[result].st_value + lib->l_addr); - setInternalBindingAddressPointer(user_binding->function_handle,(void *)(symtab[result].st_value + lib->l_addr)); +int prepare_symbol(struct internal_binding_t *binding) { + int result; + struct link_map *lib; + struct gotcha_binding_t *user_binding = binding->user_binding; + + debug_printf(2, "Looking up exported symbols for %s\n", user_binding->name); + for (lib = _r_debug.r_map; lib != 0; lib = lib->l_next) { + struct library_t *int_library = get_library(lib); + if (!int_library) { + debug_printf(3, "Creating new library object for %s\n", LIB_NAME(lib)); + int_library = add_library(lib); + } + void *symbol; + result = lookup_exported_symbol(user_binding->name, lib, &symbol); + if (result != -1) { + setInternalBindingAddressPointer(user_binding->function_handle, symbol); return 0; - } - debug_printf(1, "Symbol %s was found in program\n", user_binding->name); - return -1; + } + } + debug_printf(1, "Symbol %s was found in program\n", user_binding->name); + return -1; } -static void insert_at_head(struct internal_binding_t *binding, struct internal_binding_t *head) -{ - binding->next_binding = head; - setInternalBindingAddressPointer(binding->user_binding->function_handle, head->user_binding->wrapper_pointer); - removefrom_hashtable(&function_hash_table, (void*) binding->user_binding->name); - addto_hashtable(&function_hash_table, (void*)binding->user_binding->name, (void*)binding); +static void insert_at_head(struct internal_binding_t *binding, + struct internal_binding_t *head) { + binding->next_binding = head; + setInternalBindingAddressPointer(binding->user_binding->function_handle, + head->user_binding->wrapper_pointer); + removefrom_hashtable(&function_hash_table, + (void *)binding->user_binding->name); + addto_hashtable(&function_hash_table, (void *)binding->user_binding->name, + (void *)binding); } -static void insert_after_pos(struct internal_binding_t *binding, struct internal_binding_t *pos) -{ - setInternalBindingAddressPointer(binding->user_binding->function_handle, pos->wrappee_pointer); - setInternalBindingAddressPointer(pos->user_binding->function_handle, binding->user_binding->wrapper_pointer); - binding->next_binding = pos->next_binding; - pos->next_binding = binding; +static void insert_after_pos(struct internal_binding_t *binding, + struct internal_binding_t *pos) { + setInternalBindingAddressPointer(binding->user_binding->function_handle, + pos->wrappee_pointer); + setInternalBindingAddressPointer(pos->user_binding->function_handle, + binding->user_binding->wrapper_pointer); + binding->next_binding = pos->next_binding; + pos->next_binding = binding; } #define RWO_NOCHANGE 0 #define RWO_NEED_LOOKUP (1 << 0) #define RWO_NEED_BINDING (1 << 1) -static int rewrite_wrapper_orders(struct internal_binding_t* binding) -{ - const char* name = binding->user_binding->name; +static int rewrite_wrapper_orders(struct internal_binding_t *binding) { + const char *name = binding->user_binding->name; int insert_priority = get_priority(binding->associated_binding_table->tool); - - if(gotcha_strcmp(name,"main")==0){ - if(!main_wrapped){ + + if (gotcha_strcmp(name, "main") == 0) { + if (!main_wrapped) { debug_printf(2, "Wrapping main with Gotcha's internal wrappers"); main_wrapped = 1; - gotcha_wrap(libc_main_wrappers,1,"gotcha"); - gotcha_wrap(main_wrappers,1,"gotcha"); + gotcha_wrap(libc_main_wrappers, 1, "gotcha"); + gotcha_wrap(main_wrappers, 1, "gotcha"); } } - debug_printf(2, "gotcha_rewrite_wrapper_orders for binding %s in tool %s of priority %d\n", - name, binding->associated_binding_table->tool->tool_name, insert_priority); + debug_printf(2, + "gotcha_rewrite_wrapper_orders for binding %s in tool %s of " + "priority %d\n", + name, binding->associated_binding_table->tool->tool_name, + insert_priority); - struct internal_binding_t* head; + struct internal_binding_t *head; int hash_result; - hash_result = lookup_hashtable(&function_hash_table, (void*)name, (void**)&head); - if(hash_result != 0) { + hash_result = + lookup_hashtable(&function_hash_table, (void *)name, (void **)&head); + if (hash_result != 0) { debug_printf(2, "Adding new entry for %s to hash table\n", name); - addto_hashtable(&function_hash_table, (void *) name, (void *) binding); + addto_hashtable(&function_hash_table, (void *)name, (void *)binding); return (RWO_NEED_LOOKUP | RWO_NEED_BINDING); } int head_priority = get_priority(head->associated_binding_table->tool); - if (head_priority < insert_priority) { - debug_printf(2, "New binding priority %d is greater than head priority %d, adding to head\n", - insert_priority, head_priority); - insert_at_head(binding, head); - return RWO_NEED_BINDING; + if (head_priority < insert_priority) { + debug_printf(2, + "New binding priority %d is greater than head priority %d, " + "adding to head\n", + insert_priority, head_priority); + insert_at_head(binding, head); + return RWO_NEED_BINDING; } - struct internal_binding_t* cur; + struct internal_binding_t *cur; for (cur = head; cur->next_binding; cur = cur->next_binding) { - int next_priority = get_priority(cur->next_binding->associated_binding_table->tool); - debug_printf(3, "Comparing binding for new insertion %d to binding for tool %s at %d\n", - insert_priority, cur->next_binding->associated_binding_table->tool->tool_name, - next_priority); - if (next_priority < insert_priority) { - break; - } - if (cur->user_binding->wrapper_pointer == binding->user_binding->wrapper_pointer) { - debug_printf(3, "Tool is already inserted. Skipping binding rewrite\n"); - return RWO_NOCHANGE; - } + int next_priority = + get_priority(cur->next_binding->associated_binding_table->tool); + debug_printf( + 3, + "Comparing binding for new insertion %d to binding for tool %s at %d\n", + insert_priority, + cur->next_binding->associated_binding_table->tool->tool_name, + next_priority); + if (next_priority < insert_priority) { + break; + } + if (cur->user_binding->wrapper_pointer == + binding->user_binding->wrapper_pointer) { + debug_printf(3, "Tool is already inserted. Skipping binding rewrite\n"); + return RWO_NOCHANGE; + } } - debug_printf(2, "Inserting binding after tool %s\n", cur->associated_binding_table->tool->tool_name); + debug_printf(2, "Inserting binding after tool %s\n", + cur->associated_binding_table->tool->tool_name); insert_after_pos(binding, cur); return RWO_NOCHANGE; } -static int update_lib_bindings(ElfW(Sym) * symbol KNOWN_UNUSED, char *name, ElfW(Addr) offset, - struct link_map *lmap, hash_table_t *lookuptable) -{ +static int update_lib_bindings(ElfW(Sym) * symbol KNOWN_UNUSED, char *name, + ElfW(Addr) offset, struct link_map *lmap, + hash_table_t *lookuptable) { int result; struct internal_binding_t *internal_binding; void **got_address; - result = lookup_hashtable(lookuptable, name, (void **) &internal_binding); - if (result != 0) - return 0; - got_address = (void**) (lmap->l_addr + offset); + result = lookup_hashtable(lookuptable, name, (void **)&internal_binding); + if (result != 0) return -1; + got_address = (void **)(lmap->l_addr + offset); writeAddress(got_address, internal_binding->user_binding->wrapper_pointer); debug_printf(3, "Remapped call to %s at 0x%lx in %s to wrapper at 0x%p\n", - name, (lmap->l_addr + offset), LIB_NAME(lmap), - internal_binding->user_binding->wrapper_pointer); + name, (lmap->l_addr + offset), LIB_NAME(lmap), + internal_binding->user_binding->wrapper_pointer); return 0; } #ifndef MAX -#define MAX(a,b) (a>b?a:b) +#define MAX(a, b) (a > b ? a : b) #endif +/** + * structure used to pass lookup addr and return library address. + */ +struct Boundary { + const char *l_name; // input + ElfW(Addr) load_addr; // input + ElfW(Addr) start_addr; // output + ElfW(Addr) end_addr; // output + int found; +}; +int find_relro_boundary(struct dl_phdr_info *info, size_t size, void *data) { + struct Boundary *boundary = data; + int found = 0; + for (int i = 0; i < info->dlpi_phnum; ++i) { + if (info->dlpi_phdr[i].p_type == PT_LOAD) { + if (strcmp(boundary->l_name, info->dlpi_name) == 0 && + boundary->load_addr == info->dlpi_addr) { + found = 1; + break; + } + } + } + if (found) { + for (int i = 0; i < info->dlpi_phnum; ++i) { + if (info->dlpi_phdr[i].p_type == PT_GNU_RELRO) { + boundary->start_addr = boundary->load_addr + info->dlpi_phdr[i].p_vaddr; + boundary->end_addr = boundary->start_addr + info->dlpi_phdr[i].p_memsz; + boundary->found = 1; + return 1; + } + } + } + return 0; +} -static int mark_got_writable(struct link_map *lib) -{ - static unsigned int page_size = 0; - INIT_DYNAMIC(lib); - if (!got) - return 0; - - if (!page_size) - page_size = gotcha_getpagesize(); - - size_t protect_size = MAX(rel_size, page_size); - if(protect_size % page_size){ - protect_size += page_size - ((protect_size) %page_size); - } - ElfW(Addr) prot_address = BOUNDARY_BEFORE(got,(ElfW(Addr))page_size); - debug_printf(3, "Setting library %s GOT table from %p to +%lu to writeable\n", - LIB_NAME(lib), (void *) prot_address, protect_size); - int res = gotcha_mprotect((void*)prot_address,protect_size,PROT_READ | PROT_WRITE | PROT_EXEC ); - if(res == -1){ // mprotect returns -1 on an error - error_printf("GOTCHA attempted to mark the GOT table as writable and was unable to do so, " - "calls to wrapped functions may likely fail.\n"); - } - - return 0; +static int mark_got_writable(struct link_map *lib) { + static ElfW(Addr) page_size = 0; + INIT_DYNAMIC(lib); + if (!got) return 0; + + if (!page_size) page_size = gotcha_getpagesize(); + + ElfW(Addr) plt_got_size = MAX(rel_size, page_size); + if (plt_got_size % page_size) { // GCOVR_EXCL_START + plt_got_size += page_size - ((plt_got_size) % page_size); + } // GCOVR_EXCL_STOP + ElfW(Addr) plt_got_addr = BOUNDARY_BEFORE(got, (ElfW(Addr))page_size); + struct Boundary boundary; + boundary.l_name = lib->l_name; + boundary.load_addr = lib->l_addr; + boundary.found = 0; + dl_iterate_phdr(find_relro_boundary, &boundary); + int plt_got_written = 0; + if (boundary.found) { + ElfW(Addr) got_end = MAX(boundary.end_addr, page_size); + if (got_end % page_size) { + got_end += page_size - ((got_end) % page_size); // GCOVR_EXCL_LINE + } + ElfW(Addr) got_addr = + BOUNDARY_BEFORE(boundary.start_addr, (ElfW(Addr))page_size); + ElfW(Addr) got_size = got_end - got_addr; + /** + * The next two cases are to optimize mprotect calls to do both pages + * together if they align. We do not have such usecase yet and hence + * ignoring from coverage. + */ + if (got_addr == plt_got_addr + plt_got_size) { + // Haven't seen a library till now where got_addr > plt_got_addr + // GCOVR_EXCL_START + debug_printf(3, + "Setting library %s GOT and PLT table " + "from %p to +%lu to writeable\n", + LIB_NAME(lib), (void *)plt_got_addr, + plt_got_size + got_size); + int res = gotcha_mprotect((void *)plt_got_addr, plt_got_size + got_size, + PROT_READ | PROT_WRITE | PROT_EXEC); + // mprotect returns -1 on an error + if (res == -1) { + error_printf( + "GOTCHA attempted to mark both GOT and PLT GOT tables as writable " + "and was unable to do so, " + "calls to wrapped functions may likely fail.\n"); + } + plt_got_written = 1; + // GCOVR_EXCL_STOP + } else if (plt_got_addr == got_addr + got_size) { + // This is a more common case. + debug_printf(3, + "Setting library %s GOT and PLT table " + "from %p to +%lu to writeable\n", + LIB_NAME(lib), (void *)got_addr, plt_got_size + got_size); + int res = gotcha_mprotect((void *)got_addr, plt_got_size + got_size, + PROT_READ | PROT_WRITE | PROT_EXEC); + // mprotect returns -1 on an error + if (res == -1) { // GCOVR_EXCL_START + error_printf( + "GOTCHA attempted to mark both GOT and PLT GOT tables as writable " + "and was unable to do so, " + "calls to wrapped functions may likely fail.\n"); + } // GCOVR_EXCL_STOP + plt_got_written = 1; + } else { + debug_printf( + 3, "Setting library %s only GOT table from %p to +%lu to writeable\n", + LIB_NAME(lib), (void *)got_addr, got_size); + int res = gotcha_mprotect((void *)got_addr, got_size, + PROT_READ | PROT_WRITE | PROT_EXEC); + if (res == -1) { // GCOVR_EXCL_START + error_printf( + "GOTCHA attempted to mark the only GOT table as writable and was " + "unable to do so, " + "calls to wrapped functions may likely fail.\n"); + } // GCOVR_EXCL_STOP + } + } + if (!plt_got_written) { + debug_printf( + 3, + "Setting library %s only PLT GOT table from %p to +%lu to writeable\n", + LIB_NAME(lib), (void *)plt_got_addr, plt_got_size); + int res = gotcha_mprotect((void *)plt_got_addr, plt_got_size, + PROT_READ | PROT_WRITE | PROT_EXEC); + // mprotect returns -1 on an error + if (res == -1) { // GCOVR_EXCL_START + error_printf( + "GOTCHA attempted to mark the only PLT GOT table as writable and was " + "unable to do so, " + "calls to wrapped functions may likely fail.\n"); + } // GCOVR_EXCL_STOP + } + return 0; } -static int update_library_got(struct link_map *map, hash_table_t *bindingtable) -{ - struct library_t *lib = get_library(map); - if (!lib) { - debug_printf(3, "Creating new library object for %s\n", LIB_NAME(map)); - lib = add_library(map); - } +static int update_library_got(struct link_map *map, + hash_table_t *bindingtable) { + struct library_t *lib = get_library(map); + if (!lib) { + debug_printf(3, "Creating new library object for %s\n", LIB_NAME(map)); + lib = add_library(map); + } - if (!libraryFilterFunc(map)) { - debug_printf(3, "Skipping library %s due to libraryFilterFunc\n", LIB_NAME(map)); - return 0; - } + if (!libraryFilterFunc(map)) { + debug_printf(3, "Skipping library %s due to libraryFilterFunc\n", + LIB_NAME(map)); + return 0; + } - if (lib->generation == current_generation) { - debug_printf(2, "Library %s is already up-to-date. Skipping GOT rewriting\n", LIB_NAME(map)); - return 0; - } - - if (!(lib->flags & LIB_GOT_MARKED_WRITEABLE)) { - mark_got_writable(map); - lib->flags |= LIB_GOT_MARKED_WRITEABLE; - } + if (lib->generation == current_generation) { + debug_printf(2, + "Library %s is already up-to-date. Skipping GOT rewriting\n", + LIB_NAME(map)); + return 0; + } - FOR_EACH_PLTREL(map, update_lib_bindings, map, bindingtable); + if (!(lib->flags & LIB_GOT_MARKED_WRITEABLE)) { + mark_got_writable(map); + lib->flags |= LIB_GOT_MARKED_WRITEABLE; + } - lib->generation = current_generation; - return 0; + FOR_EACH_PLTREL(map, update_lib_bindings, map, bindingtable); + lib->generation = current_generation; + return 0; } -void update_all_library_gots(hash_table_t *bindings) -{ - struct link_map *lib_iter; - debug_printf(2, "Searching all callsites for %lu bindings\n", (unsigned long) bindings->entry_count); - for (lib_iter = _r_debug.r_map; lib_iter != 0; lib_iter = lib_iter->l_next) { - update_library_got(lib_iter, bindings); - } +void update_all_library_gots(hash_table_t *bindings) { + struct link_map *lib_iter; + debug_printf(2, "Searching all callsites for %lu bindings\n", + (unsigned long)bindings->entry_count); + for (lib_iter = _r_debug.r_map; lib_iter != 0; lib_iter = lib_iter->l_next) { + update_library_got(lib_iter, bindings); + } } -GOTCHA_EXPORT enum gotcha_error_t gotcha_wrap(struct gotcha_binding_t* user_bindings, int num_actions, const char* tool_name) -{ +GOTCHA_EXPORT enum gotcha_error_t gotcha_wrap( + struct gotcha_binding_t *user_bindings, int num_actions, + const char *tool_name) { int i, not_found = 0, new_bindings_count = 0; tool_t *tool; hash_table_t new_bindings; @@ -277,109 +412,126 @@ GOTCHA_EXPORT enum gotcha_error_t gotcha_wrap(struct gotcha_binding_t* user_bind tool_name, num_actions); if (debug_level >= 3) { for (i = 0; i < num_actions; i++) { - debug_bare_printf(3, "\t%d: %s will map to %p\n", i, user_bindings[i].name, - user_bindings[i].wrapper_pointer); + debug_bare_printf(3, "\t%d: %s will map to %p\n", i, + user_bindings[i].name, + user_bindings[i].wrapper_pointer); } } - debug_printf(3, "Initializing %d user binding entries to NULL\n", num_actions); + debug_printf(3, "Initializing %d user binding entries to NULL\n", + num_actions); for (i = 0; i < num_actions; i++) { setBindingAddressPointer(&user_bindings[i], NULL); } - if (!tool_name) - tool_name = "[UNSPECIFIED]"; + if (!tool_name) tool_name = "[UNSPECIFIED]"; tool = get_tool(tool_name); - if (!tool) - tool = create_tool(tool_name); + if (!tool) tool = create_tool(tool_name); if (!tool) { - error_printf("Failed to create tool %s\n", tool_name); - return GOTCHA_INTERNAL; + error_printf("Failed to create tool %s\n", tool_name); // GCOVR_EXCL_LINE + return GOTCHA_INTERNAL; // GCOVR_EXCL_LINE } current_generation++; - debug_printf(2, "Moved current_generation to %u in gotcha_wrap\n", current_generation); + debug_printf(2, "Moved current_generation to %u in gotcha_wrap\n", + current_generation); - debug_printf(2, "Creating internal binding data structures and adding binding to tool\n"); + debug_printf( + 2, + "Creating internal binding data structures and adding binding to tool\n"); binding_t *bindings = add_binding_to_tool(tool, user_bindings, num_actions); - if (!bindings) { - error_printf("Failed to create bindings for tool %s\n", tool_name); - return GOTCHA_INTERNAL; - } + if (!bindings) { // GCOVR_EXCL_START + error_printf("Failed to create bindings for tool %s\n", tool_name); + return GOTCHA_INTERNAL; + } // GCOVR_EXCL_STOP debug_printf(2, "Processing %d bindings\n", num_actions); for (i = 0; i < num_actions; i++) { - struct internal_binding_t *binding = bindings->internal_bindings + i; - - int result = rewrite_wrapper_orders(binding); - if (result & RWO_NEED_LOOKUP) { - debug_printf(2, "Symbol %s needs lookup operation\n", binding->user_binding->name); - int presult = prepare_symbol(binding); - if (presult == -1) { - debug_printf(2, "Stashing %s in notfound_binding table to re-lookup on dlopens\n", - binding->user_binding->name); - addto_hashtable(¬found_binding_table, (hash_key_t) binding->user_binding->name, (hash_data_t) binding); - not_found++; - } - } - if (result & RWO_NEED_BINDING) { - debug_printf(2, "Symbol %s needs binding from application\n", binding->user_binding->name); - if (!new_bindings_count) { - create_hashtable(&new_bindings, num_actions*2, (hash_func_t) strhash, (hash_cmp_t) gotcha_strcmp); - } - addto_hashtable(&new_bindings, (void *) binding->user_binding->name, (void *) binding); - new_bindings_count++; - } + struct internal_binding_t *binding = bindings->internal_bindings + i; + int result = rewrite_wrapper_orders(binding); + if (result & RWO_NEED_LOOKUP) { + debug_printf(2, "Symbol %s needs lookup operation\n", + binding->user_binding->name); + int presult = prepare_symbol(binding); + if (presult == -1) { + debug_printf( + 2, + "Stashing %s in notfound_binding table to re-lookup on dlopens\n", + binding->user_binding->name); + addto_hashtable(¬found_binding_table, + (hash_key_t)binding->user_binding->name, + (hash_data_t)binding); + not_found++; + } + } + if (result & RWO_NEED_BINDING) { + debug_printf(2, "Symbol %s needs binding from application\n", + binding->user_binding->name); + if (!new_bindings_count) { + create_hashtable(&new_bindings, num_actions * 2, (hash_func_t)strhash, + (hash_cmp_t)gotcha_strcmp); + } + addto_hashtable(&new_bindings, (void *)binding->user_binding->name, + (void *)binding); + new_bindings_count++; + } } - + if (new_bindings_count) { - update_all_library_gots(&new_bindings); - destroy_hashtable(&new_bindings); + update_all_library_gots(&new_bindings); + destroy_hashtable(&new_bindings); } if (not_found) { - debug_printf(1, "Could not find bindings for %d / %d functions\n", not_found, num_actions); - return GOTCHA_FUNCTION_NOT_FOUND; + debug_printf(1, "Could not find bindings for %d / %d functions\n", + not_found, num_actions); + return GOTCHA_FUNCTION_NOT_FOUND; } debug_printf(1, "Gotcha wrap completed successfully\n"); return GOTCHA_SUCCESS; } -static enum gotcha_error_t gotcha_configure_int(const char* tool_name, enum gotcha_config_key_t configuration_key , int value){ - tool_t * tool = get_tool(tool_name); - if(tool==NULL){ +static enum gotcha_error_t gotcha_configure_int( + const char *tool_name, enum gotcha_config_key_t configuration_key, + int value) { + tool_t *tool = get_tool(tool_name); + if (tool == NULL) { tool = create_tool(tool_name); } - if( configuration_key == GOTCHA_PRIORITY){ + if (configuration_key == GOTCHA_PRIORITY) { tool->config.priority = value; - } - else{ + } else { error_printf("Invalid property being configured on tool %s\n", tool_name); return GOTCHA_INTERNAL; } return GOTCHA_SUCCESS; } -GOTCHA_EXPORT enum gotcha_error_t gotcha_set_priority(const char* tool_name, int value){ +GOTCHA_EXPORT enum gotcha_error_t gotcha_set_priority(const char *tool_name, + int value) { gotcha_init(); - debug_printf(1, "User called gotcha_set_priority(%s, %d)\n", tool_name, value); - enum gotcha_error_t error_on_set = gotcha_configure_int(tool_name, GOTCHA_PRIORITY, value); - if(error_on_set != GOTCHA_SUCCESS) { - return error_on_set; + debug_printf(1, "User called gotcha_set_priority(%s, %d)\n", tool_name, + value); + enum gotcha_error_t error_on_set = + gotcha_configure_int(tool_name, GOTCHA_PRIORITY, value); + if (error_on_set != GOTCHA_SUCCESS) { + return error_on_set; // GCOVR_EXCL_LINE } - tool_t* tool_to_place = get_tool(tool_name); - if(!tool_to_place){ - tool_to_place = create_tool(tool_name); + tool_t *tool_to_place = get_tool(tool_name); + if (!tool_to_place) { // will not happen as gotcha_configure_init creats tool + // if not exists + tool_to_place = create_tool(tool_name); // GCOVR_EXCL_LINE } remove_tool_from_list(tool_to_place); reorder_tool(tool_to_place); return GOTCHA_SUCCESS; } -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) { gotcha_init(); return get_configuration_value(tool_name, GOTCHA_PRIORITY, priority); } -GOTCHA_EXPORT void* gotcha_get_wrappee(gotcha_wrappee_handle_t handle){ - return ((struct internal_binding_t*)handle)->wrappee_pointer; +GOTCHA_EXPORT void *gotcha_get_wrappee(gotcha_wrappee_handle_t handle) { + return ((struct internal_binding_t *)handle)->wrappee_pointer; } diff --git a/ext/GOTCHA/src/gotcha_auxv.c b/ext/GOTCHA/src/gotcha_auxv.c index 892eb31dd..9fe09841f 100644 --- a/ext/GOTCHA/src/gotcha_auxv.c +++ b/ext/GOTCHA/src/gotcha_auxv.c @@ -10,287 +10,259 @@ 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 "gotcha_auxv.h" -#include "gotcha_utils.h" -#include "libc_wrappers.h" #include +#include +#include #include #include -#include -#include -#include -#include #include -#include +#include #include +#include +#include +#include "gotcha_utils.h" +#include "libc_wrappers.h" static ElfW(Ehdr) *vdso_ehdr = NULL; static unsigned int auxv_pagesz = 0; - - -int parse_auxv_contents() -{ - char name[] = "/proc/self/auxv"; - int fd, done = 0; - char buffer[4096]; - ssize_t buffer_size = 4096, offset = 0, result; - ElfW(auxv_t) *auxv, *a; - static int parsed_auxv = 0; - - if (parsed_auxv) - return parsed_auxv == -1 ? parsed_auxv : 0; - parsed_auxv = 1; - - fd = gotcha_open(name, O_RDONLY); - if (fd == -1) { - parsed_auxv = -1; - return -1; - } - - do { - for (;;) { - result = gotcha_read(fd, buffer+offset, buffer_size-offset); - if (result == -1) { - if (errno == EINTR) - continue; - gotcha_close(fd); - parsed_auxv = -1; - return -1; - } - if (result == 0) { - gotcha_close(fd); - done = 1; - break; - } - if (offset == buffer_size) { - break; - } - offset += result; +#define BUFFER_LEN 4096 + +int parse_auxv_contents() { + char name[] = "/proc/self/auxv"; + int fd, done = 0; + char buffer[BUFFER_LEN]; + const ssize_t buffer_size = BUFFER_LEN; + ssize_t offset = 0, result; + ElfW(auxv_t) * auxv, *a; + static int parsed_auxv = 0; + + if (parsed_auxv) return parsed_auxv == -1 ? parsed_auxv : 0; + parsed_auxv = 1; + + fd = gotcha_open(name, O_RDONLY); + if (fd == -1) { + parsed_auxv = -1; // GCOVR_EXCL_LINE + return -1; // GCOVR_EXCL_LINE + } + + do { + for (;;) { + result = gotcha_read(fd, buffer + offset, buffer_size - offset); + if (result == -1) { + if (errno == EINTR) // GCOVR_EXCL_START + continue; + gotcha_close(fd); + parsed_auxv = -1; + return -1; + } // GCOVR_EXCL_STOP + if (result == 0) { + gotcha_close(fd); + done = 1; + break; } - - auxv = (ElfW(auxv_t) *) buffer; - for (a = auxv; a->a_type != AT_NULL; a++) { - if (a->a_type == AT_SYSINFO_EHDR) { - vdso_ehdr = (ElfW(Ehdr) *) a->a_un.a_val; - } - else if (a->a_type == AT_PAGESZ) { - auxv_pagesz = (int) a->a_un.a_val; - } + if (offset == buffer_size) { + break; // GCOVR_EXCL_LINE } - } while (!done); + offset += result; + } + + auxv = (ElfW(auxv_t) *)buffer; + for (a = auxv; a->a_type != AT_NULL; a++) { + if (a->a_type == AT_SYSINFO_EHDR) { + vdso_ehdr = (ElfW(Ehdr) *)a->a_un.a_val; + } else if (a->a_type == AT_PAGESZ) { + auxv_pagesz = (int)a->a_un.a_val; + } + } + } while (!done); - return 0; + return 0; } -struct link_map *get_vdso_from_auxv() -{ - struct link_map *m; - - ElfW(Phdr) *vdso_phdrs = NULL; - ElfW(Half) vdso_phdr_num, p; - // Initialization with zero added by Thomas Gruber to avoid warning - ElfW(Addr) vdso_dynamic = 0; +struct link_map *get_vdso_from_auxv() { + struct link_map *m; - parse_auxv_contents(); - if (!vdso_ehdr) - return NULL; + ElfW(Phdr) *vdso_phdrs = NULL; + ElfW(Half) vdso_phdr_num, p; + ElfW(Addr) vdso_dynamic = 0; - vdso_phdrs = (ElfW(Phdr) *) (vdso_ehdr->e_phoff + ((unsigned char *) vdso_ehdr)); - vdso_phdr_num = vdso_ehdr->e_phnum; + parse_auxv_contents(); + if (vdso_ehdr) { + vdso_phdrs = + (ElfW(Phdr) *)(vdso_ehdr->e_phoff + ((unsigned char *)vdso_ehdr)); + vdso_phdr_num = vdso_ehdr->e_phnum; - for (p = 0; p < vdso_phdr_num; p++) { + for (p = 0; p < vdso_phdr_num; p++) { if (vdso_phdrs[p].p_type == PT_DYNAMIC) { - vdso_dynamic = (ElfW(Addr)) vdso_phdrs[p].p_vaddr; + vdso_dynamic = (ElfW(Addr))vdso_phdrs[p].p_vaddr; } - } + } - for (m = _r_debug.r_map; m; m = m->l_next) { - if (m->l_addr + vdso_dynamic == (ElfW(Addr)) m->l_ld) { - return m; + for (m = _r_debug.r_map; m; m = m->l_next) { + if (m->l_addr + vdso_dynamic == (ElfW(Addr))m->l_ld) { + return m; } - } - return NULL; + } + } + return NULL; // GCOVR_EXCL_LINE } -unsigned int get_auxv_pagesize() -{ - int result; - result = parse_auxv_contents(); - if (result == -1) - return 0; - return auxv_pagesz; +unsigned int get_auxv_pagesize() { + int result; + result = parse_auxv_contents(); + return result == -1 ? 0 : auxv_pagesz; } -static char* vdso_aliases[] = { "linux-vdso.so", - "linux-gate.so", - NULL }; +static char *vdso_aliases[] = {"linux-vdso.so", "linux-gate.so", NULL}; -struct link_map *get_vdso_from_aliases() -{ - struct link_map *m; - char **aliases; - - for (m = _r_debug.r_map; m; m = m->l_next) { - for (aliases = vdso_aliases; *aliases; aliases++) { - if (m->l_name && gotcha_strcmp(m->l_name, *aliases) == 0) { - return m; - } - } - } - return NULL; -} +struct link_map *get_vdso_from_aliases() { + struct link_map *m; + char **aliases; -static int read_line(char *line, int size, int fd) -{ - int i; - for (i = 0; i < size - 1; i++) { - int result = gotcha_read(fd, line + i, 1); - if (result == -1 && errno == EINTR) - continue; - if (result == -1 || result == 0) { - line[i] = '\0'; - return -1; - } - if (line[i] == '\n') { - line[i + 1] = '\0'; - return 0; + for (m = _r_debug.r_map; m; m = m->l_next) { + for (aliases = vdso_aliases; *aliases; aliases++) { + if (m->l_name && gotcha_strcmp(m->l_name, *aliases) == 0) { + return m; // GCOVR_EXCL_LINE } - } - line[size-1] = '\0'; - return 0; + } + } + return NULL; } -static int read_hex(char *str, unsigned long *val) -{ - unsigned long local_val = 0, len = 0; - for (;;) { - if (*str >= '0' && *str <= '9') { - local_val = (local_val * 16) + (*str - '0'); - len++; - } - else if (*str >= 'a' && *str <= 'f') { - local_val = (local_val * 16) + (*str - 'a' + 10); - len++; - } - else if (*str >= 'A' && *str <= 'F') { - local_val = (local_val * 16) + (*str - 'A' + 10); - len++; - } - else { - *val = local_val; - return len; - } - str++; - } +static int read_line(char *line, int size, int fd) { + int i; + for (i = 0; i < size - 1; i++) { + int result = gotcha_read(fd, line + i, 1); + if (result == -1 && errno == EINTR) continue; // GCOVR_EXCL_LINE + if (result == -1 || result == 0) { + line[i] = '\0'; // GCOVR_EXCL_LINE + return -1; // GCOVR_EXCL_LINE + } + if (line[i] == '\n') { + line[i + 1] = '\0'; + return 0; + } + } + line[size - 1] = '\0'; // GCOVR_EXCL_LINE + return 0; // GCOVR_EXCL_LINE } -static int read_word(char *str, char *word, int word_size) -{ - int word_cur = 0; - int len = 0; - while (*str == ' ' || *str == '\t' || *str == '\n') { - str++; +static int read_hex(char *str, unsigned long *val) { + unsigned long local_val = 0, len = 0; + for (;;) { + if (*str >= '0' && *str <= '9') { + local_val = (local_val * 16) + (*str - '0'); len++; - } - if (*str == '\0') { - *word = '\0'; - return len; - } - while (*str != ' ' && *str != '\t' && *str != '\n' && *str != '\0') { - if (word && word_cur >= word_size) { - if (word_size > 0 && word) - word[word_size-1] = '\0'; - return word_cur; - } - if (word) - word[word_cur] = *str; - word_cur++; - str++; + } else if (*str >= 'a' && *str <= 'f') { + local_val = (local_val * 16) + (*str - 'a' + 10); len++; - } - if (word_cur >= word_size) - word_cur--; - if (word) - word[word_cur] = '\0'; - return len; + } else if (*str >= 'A' && *str <= 'F') { + local_val = (local_val * 16) + (*str - 'A' + 10); + len++; + } else { + *val = local_val; + return len; + } + str++; + } } -struct link_map *get_vdso_from_maps() -{ - int maps, hit_eof; - ElfW(Addr) addr_begin, addr_end, dynamic; - // Changed length of name and line to 4097 - char name[4097], line[4097], *line_pos; - struct link_map *m; - maps = gotcha_open("/proc/self/maps", O_RDONLY); - for (;;) { - // changed length input to 4096 - hit_eof = read_line(line, 4096, maps); - if (hit_eof) { - gotcha_close(maps); - return NULL; - } - line_pos = line; - line_pos += read_hex(line_pos, &addr_begin); - if (*line_pos != '-') - continue; - line_pos++; - line_pos += read_hex(line_pos, &addr_end); - line_pos += read_word(line_pos, NULL, 0); - line_pos += read_word(line_pos, NULL, 0); - line_pos += read_word(line_pos, NULL, 0); - line_pos += read_word(line_pos, NULL, 0); - line_pos += read_word(line_pos, name, sizeof(name)); - if (gotcha_strcmp(name, "[vdso]") == 0) { - gotcha_close(maps); - break; - } - } - - for (m = _r_debug.r_map; m; m = m->l_next) { - dynamic = (ElfW(Addr)) m->l_ld; - if (dynamic >= addr_begin && dynamic < addr_end) - return m; - } +static int read_word(char *str, char *word, int word_size) { + int word_cur = 0; + int len = 0; + while (*str == ' ' || *str == '\t' || *str == '\n') { + str++; + len++; + } + if (*str == '\0') { + *word = '\0'; + return len; + } + while (*str != ' ' && *str != '\t' && *str != '\n' && *str != '\0') { + if (word && word_cur >= word_size) { + if (word_size > 0 && word) // GCOVR_EXCL_START + word[word_size - 1] = '\0'; + return word_cur; + } // GCOVR_EXCL_STOP + if (word) word[word_cur] = *str; + word_cur++; + str++; + len++; + } + if (word_cur >= word_size) word_cur--; + if (word) word[word_cur] = '\0'; + return len; +} - return NULL; +struct link_map *get_vdso_from_maps() { + int maps, hit_eof; + ElfW(Addr) addr_begin, addr_end, dynamic; + char name[BUFFER_LEN], line[BUFFER_LEN], *line_pos; + struct link_map *m; + maps = gotcha_open("/proc/self/maps", O_RDONLY); + for (;;) { + hit_eof = read_line(line, BUFFER_LEN, maps); + if (hit_eof) { + gotcha_close(maps); // GCOVR_EXCL_LINE + return NULL; // GCOVR_EXCL_LINE + } + line_pos = line; + line_pos += read_hex(line_pos, &addr_begin); + if (*line_pos != '-') continue; // GCOVR_EXCL_LINE + line_pos++; + line_pos += read_hex(line_pos, &addr_end); + line_pos += read_word(line_pos, NULL, 0); + line_pos += read_word(line_pos, NULL, 0); + line_pos += read_word(line_pos, NULL, 0); + line_pos += read_word(line_pos, NULL, 0); + line_pos += read_word(line_pos, name, sizeof(name)); + if (gotcha_strcmp(name, "[vdso]") == 0) { + gotcha_close(maps); + break; + } + } + + for (m = _r_debug.r_map; m; m = m->l_next) { + dynamic = (ElfW(Addr))m->l_ld; + if (dynamic >= addr_begin && dynamic < addr_end) return m; + } + + return NULL; // GCOVR_EXCL_LINE } -int is_vdso(struct link_map *map) -{ - static int vdso_checked = 0; - static struct link_map *vdso = NULL; - struct link_map *result; +int is_vdso(const struct link_map *map) { + static int vdso_checked = 0; + static struct link_map *vdso = NULL; + struct link_map *result; - if (!map) - return 0; - if (vdso_checked) - return (map == vdso); - - vdso_checked = 1; - - result = get_vdso_from_aliases(); - if (result) { - vdso = result; - return (map == vdso); - } - - result = get_vdso_from_auxv(); - if (result) { - vdso = result; - return (map == vdso); - } - - result = get_vdso_from_maps(); - if (result) { - vdso = result; - return (map == vdso); - } - - return 0; -} + if (!map) return 0; + if (vdso_checked) return (map == vdso); + + vdso_checked = 1; + + result = get_vdso_from_aliases(); + if (result) { + vdso = result; // GCOVR_EXCL_LINE + return (map == vdso); // GCOVR_EXCL_LINE + } + + result = get_vdso_from_auxv(); + if (result) { + vdso = result; + return (map == vdso); + } + + result = get_vdso_from_maps(); // GCOVR_EXCL_START + if (result) { + vdso = result; + return (map == vdso); + } + + return 0; +} // GCOVR_EXCL_STOP diff --git a/ext/GOTCHA/src/gotcha_auxv.h b/ext/GOTCHA/src/gotcha_auxv.h index 576a018b2..44951c204 100644 --- a/ext/GOTCHA/src/gotcha_auxv.h +++ b/ext/GOTCHA/src/gotcha_auxv.h @@ -10,32 +10,30 @@ 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 */ #ifndef GOTCHA_AUXV_H #define GOTCHA_AUXV_H #include +#include +#include #include #include -#include -#include -#include -#include #include -#include +#include #include +#include +#include -int is_vdso(struct link_map *map); +int is_vdso(const struct link_map *map); unsigned int get_auxv_pagesize(); -//Do not use, exposed only for unit testing +// Do not use, exposed only for unit testing int parse_auxv_contents(); struct link_map *get_vdso_from_auxv(); struct link_map *get_vdso_from_aliases(); struct link_map *get_vdso_from_maps(); - - #endif diff --git a/ext/GOTCHA/src/gotcha_dl.c b/ext/GOTCHA/src/gotcha_dl.c index 7351a96bf..fe9308d6c 100644 --- a/ext/GOTCHA/src/gotcha_dl.c +++ b/ext/GOTCHA/src/gotcha_dl.c @@ -1,75 +1,190 @@ #define _GNU_SOURCE #include "gotcha_dl.h" -#include "tool.h" -#include "libc_wrappers.h" -#include "elf_ops.h" + #include -void* _dl_sym(void* handle, const char* name, void* where); +#include "elf_ops.h" +#include "libc_wrappers.h" +#include "tool.h" + +/** + * structure used to pass lookup addr and return library address. + */ +struct Addrs { + ElfW(Addr) lookup_addr; // input + struct link_map *lmap; // output + int found; +}; +/** + * This is a callback to get headers for each library. + * We check if the caller's virtual address is between base address and the + * virtual addr + memory size. Then we select the lmap based on base_addr and + * name + * + * @param info, information about headers + * @param size, size of headers + * @param data, data from caller + * @return + */ +int lib_header_callback(struct dl_phdr_info *info, size_t size, void *data) { + struct Addrs *addrs = data; + const char *name = NULL; + ElfW(Addr) load_address; + for (int i = 0; i < info->dlpi_phnum; ++i) { + if (info->dlpi_phdr[i].p_type == PT_LOAD) { + ElfW(Addr) base_addr = info->dlpi_addr; + ElfW(Addr) start_addr = base_addr + info->dlpi_phdr[i].p_vaddr; + ElfW(Addr) end_addr = start_addr + info->dlpi_phdr[i].p_memsz; + if (addrs->lookup_addr >= start_addr && addrs->lookup_addr < end_addr) { + name = info->dlpi_name; + load_address = info->dlpi_addr; + break; + } + } + } + if (name) { + struct link_map *current = addrs->lmap; + while (current) { + if (strcmp(current->l_name, name) == 0 && + load_address == current->l_addr) { + addrs->lmap = current; + addrs->found = 1; + return 1; + } + current = current->l_next; // GCOVR_EXCL_LINE + } + } + return 0; // GCOVR_EXCL_LINE +} + +/** + * Implement the logic of _dl_sym for supporting RTLD_NEXT + * 1. find the caller library using the program headers. + * 2. find the second library which has the symbol for RTLD_NEXT + * @param handle, handle for dl operation + * @param name, name of the symbol + * @param who, the virtual address of the caller + * @return link_map pointer + */ + +static struct link_map *gotchas_dlsym_rtld_next_lookup(const char *name, + void *who) { + ElfW(Addr) caller = (ElfW(Addr))who; + /* Iterative over the library headers and find the caller + * the address of the caller is set in addrs->library_laddr + **/ + struct Addrs addrs; + addrs.lookup_addr = caller; + addrs.lmap = _r_debug.r_map; + addrs.found = 0; + void *symbol; + dl_iterate_phdr(lib_header_callback, &addrs); + if (!addrs.found) { // GCOVR_EXCL_START + error_printf("RTLD_NEXT used in code not dynamically loaded"); + exit(127); + } // GCOVR_EXCL_STOP + struct link_map *handle = addrs.lmap->l_next; + while (handle) { + /* lookup symbol on the next-to-next lib which has symbol + * for RTLD_NEXT + **/ + long result = lookup_exported_symbol(name, handle, &symbol); + if (result != -1) { + return handle; + } else { + debug_printf(3, "Symbol %s not found in the library %s\n", name, + LIB_NAME(handle)); + } + handle = handle->l_next; + } + debug_printf(3, "Symbol %s not found in the libraries after caller\n", name); + return NULL; +} gotcha_wrappee_handle_t orig_dlopen_handle; gotcha_wrappee_handle_t orig_dlsym_handle; -static int per_binding(hash_key_t key, hash_data_t data, void *opaque KNOWN_UNUSED) -{ - int result; - struct internal_binding_t *binding = (struct internal_binding_t *) data; - - debug_printf(3, "Trying to re-bind %s from tool %s after dlopen\n", - binding->user_binding->name, binding->associated_binding_table->tool->tool_name); - - while (binding->next_binding) { - binding = binding->next_binding; - debug_printf(3, "Selecting new innermost version of binding %s from tool %s.\n", - binding->user_binding->name, binding->associated_binding_table->tool->tool_name); - } - - result = prepare_symbol(binding); - if (result == -1) { - debug_printf(3, "Still could not prepare binding %s after dlopen\n", binding->user_binding->name); - return 0; - } - - removefrom_hashtable(¬found_binding_table, key); - return 0; +static int per_binding(hash_key_t key, hash_data_t data, + void *opaque KNOWN_UNUSED) { + int result; + struct internal_binding_t *binding = (struct internal_binding_t *)data; + + debug_printf(3, "Trying to re-bind %s from tool %s after dlopen\n", + binding->user_binding->name, + binding->associated_binding_table->tool->tool_name); + + if (!binding->user_binding->name) return 0; + while (binding->next_binding) { + binding = binding->next_binding; // GCOVR_EXCL_START + debug_printf(3, + "Selecting new innermost version of binding %s from tool " + "%s.\n", // GCOVR_EXCL_LINE + binding->user_binding->name, + binding->associated_binding_table->tool->tool_name); + } // GCOVR_EXCL_STOP + + result = prepare_symbol(binding); + if (result == -1) { // GCOVR_EXCL_START + debug_printf(3, "Still could not prepare binding %s after dlopen\n", + binding->user_binding->name); + return 0; + } // GCOVR_EXCL_STOP + + removefrom_hashtable(¬found_binding_table, key); + return 0; } -static void* dlopen_wrapper(const char* filename, int flags) { - typeof(&dlopen_wrapper) orig_dlopen = gotcha_get_wrappee(orig_dlopen_handle); - void *handle; - debug_printf(1, "User called dlopen(%s, 0x%x)\n", filename, (unsigned int) flags); - handle = orig_dlopen(filename,flags); +static void *dlopen_wrapper(const char *filename, int flags) { + typeof(&dlopen_wrapper) orig_dlopen = gotcha_get_wrappee(orig_dlopen_handle); + void *handle; + debug_printf(1, "User called dlopen(%s, 0x%x)\n", filename, + (unsigned int)flags); + handle = orig_dlopen(filename, flags); + + debug_printf( + 2, "Searching new dlopened libraries for previously-not-found exports\n"); + foreach_hash_entry(¬found_binding_table, NULL, per_binding); - debug_printf(2, "Searching new dlopened libraries for previously-not-found exports\n"); - foreach_hash_entry(¬found_binding_table, NULL, per_binding); + debug_printf(2, "Updating GOT entries for new dlopened libraries\n"); + update_all_library_gots(&function_hash_table); - debug_printf(2, "Updating GOT entries for new dlopened libraries\n"); - update_all_library_gots(&function_hash_table); - - return handle; + return handle; } -static void* dlsym_wrapper(void* handle, const char* symbol_name){ +static void *dlsym_wrapper(void *handle, const char *symbol_name) { + typeof(&dlopen_wrapper) orig_dlopen = gotcha_get_wrappee(orig_dlopen_handle); typeof(&dlsym_wrapper) orig_dlsym = gotcha_get_wrappee(orig_dlsym_handle); struct internal_binding_t *binding; - int result; - - if(handle == RTLD_NEXT){ - return _dl_sym(RTLD_NEXT, symbol_name ,__builtin_return_address(0)); + debug_printf(1, "User called dlsym(%p, %s)\n", handle, symbol_name); + int result = lookup_hashtable(&function_hash_table, (hash_key_t)symbol_name, + (hash_data_t *)&binding); + void *val = orig_dlsym(handle, symbol_name); + if (result != -1) { + void **wrappee_ptr = getInternalBindingAddressPointer( + (struct internal_binding_t **)binding->user_binding->function_handle); + if (val == NULL || *wrappee_ptr == val) { + // if the wrapper is found and the wrappee is the function requested. + // This is needed in cases where we wrap a function F1 from library A and + // we dynamically load function F1 from library B. As name is same, we + // need to make sure the wrappee are the same as well + return binding->user_binding->wrapper_pointer; + } + } + if (handle == RTLD_NEXT) { + struct link_map *lib = gotchas_dlsym_rtld_next_lookup( + symbol_name, __builtin_return_address(0)); + if (lib) { + void *handle = orig_dlopen(lib->l_name, RTLD_NOW); + void *symbol = orig_dlsym(handle, symbol_name); + return symbol; + } + return NULL; + } else { + return val; } - - result = lookup_hashtable(&function_hash_table, (hash_key_t) symbol_name, (hash_data_t *) &binding); - if (result == -1) - return orig_dlsym(handle, symbol_name); - else - return binding->user_binding->wrapper_pointer; } struct gotcha_binding_t dl_binds[] = { - {"dlopen", dlopen_wrapper, &orig_dlopen_handle}, - {"dlsym", dlsym_wrapper, &orig_dlsym_handle} -}; -void handle_libdl(){ - gotcha_wrap(dl_binds, 2, "gotcha"); -} - + {"dlopen", dlopen_wrapper, &orig_dlopen_handle}, + {"dlsym", dlsym_wrapper, &orig_dlsym_handle}}; +void handle_libdl() { gotcha_wrap(dl_binds, 2, "gotcha"); } diff --git a/ext/GOTCHA/src/gotcha_dl.h b/ext/GOTCHA/src/gotcha_dl.h index a1117f448..252f5ae10 100644 --- a/ext/GOTCHA/src/gotcha_dl.h +++ b/ext/GOTCHA/src/gotcha_dl.h @@ -6,7 +6,10 @@ void handle_libdl(); extern void update_all_library_gots(hash_table_t *bindings); +extern long lookup_exported_symbol(const char *name, const struct link_map *lib, + void **symbol); extern int prepare_symbol(struct internal_binding_t *binding); +extern void **getInternalBindingAddressPointer(struct internal_binding_t **in); extern gotcha_wrappee_handle_t orig_dlopen_handle; extern gotcha_wrappee_handle_t orig_dlsym_handle; diff --git a/ext/GOTCHA/src/gotcha_utils.c b/ext/GOTCHA/src/gotcha_utils.c index 1f43f38fb..92f710986 100644 --- a/ext/GOTCHA/src/gotcha_utils.c +++ b/ext/GOTCHA/src/gotcha_utils.c @@ -10,39 +10,39 @@ 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 "gotcha_utils.h" -#include "gotcha_dl.h" -#include "tool.h" -#include "libc_wrappers.h" + +#include + #include "elf_ops.h" #include "gotcha/gotcha.h" -#include +#include "gotcha_dl.h" #include "hash.h" +#include "libc_wrappers.h" +#include "tool.h" int debug_level; -static void debug_init() -{ - static int debug_initialized = 0; - - char *debug_str; - if (debug_initialized) { - return; - } - debug_initialized = 1; - - debug_str = gotcha_getenv(GOTCHA_DEBUG_ENV); - if (!debug_str) { - return; - } - - debug_level = gotcha_atoi(debug_str); - if (debug_level <= 0) - debug_level = 1; - - debug_printf(0, "Gotcha debug initialized at level %d\n", debug_level); +static void debug_init() { + static int debug_initialized = 0; + + char *debug_str; + if (debug_initialized) { + return; // GCOVR_EXCL_LINE + } + debug_initialized = 1; + + debug_str = gotcha_getenv(GOTCHA_DEBUG_ENV); + if (!debug_str) { + return; + } + + debug_level = gotcha_atoi(debug_str); + if (debug_level <= 0) debug_level = 1; // GCOVR_EXCL_LINE + + debug_printf(0, "Gotcha debug initialized at level %d\n", debug_level); } hash_table_t function_hash_table; @@ -52,73 +52,65 @@ static hash_table_t library_table; static library_t *library_list = NULL; unsigned int current_generation; -static hash_hashvalue_t link_map_hash(struct link_map *map) -{ - hash_hashvalue_t hashval = (hash_hashvalue_t) ((unsigned long) map); - hashval ^= strhash(LIB_NAME(map)); - return hashval; +static hash_hashvalue_t link_map_hash(struct link_map *map) { + hash_hashvalue_t hashval = (hash_hashvalue_t)((unsigned long)map); + hashval ^= strhash(LIB_NAME(map)); + return hashval; } -static int link_map_cmp(struct link_map *a, struct link_map *b) -{ - return ((unsigned long) a) < ((unsigned long) b); +static int link_map_cmp(struct link_map *a, struct link_map *b) { + return ((unsigned long)a) < ((unsigned long)b); } static void setup_hash_tables() { - create_hashtable(&library_table, 128, (hash_func_t) link_map_hash, (hash_cmp_t) link_map_cmp); - create_hashtable(&function_hash_table, 4096, (hash_func_t) strhash, (hash_cmp_t) gotcha_strcmp); - create_hashtable(¬found_binding_table, 128, (hash_func_t) strhash, (hash_cmp_t) gotcha_strcmp); + create_hashtable(&library_table, 128, (hash_func_t)link_map_hash, + (hash_cmp_t)link_map_cmp); + create_hashtable(&function_hash_table, 4096, (hash_func_t)strhash, + (hash_cmp_t)gotcha_strcmp); + create_hashtable(¬found_binding_table, 128, (hash_func_t)strhash, + (hash_cmp_t)gotcha_strcmp); } -struct library_t *get_library(struct link_map *map) -{ - library_t *lib; - int result; - result = lookup_hashtable(&library_table, (hash_key_t) map, (hash_data_t *) &lib); - if (result == -1) - return NULL; - return lib; +struct library_t *get_library(struct link_map *map) { + library_t *lib; + int result; + result = + lookup_hashtable(&library_table, (hash_key_t)map, (hash_data_t *)&lib); + if (result == -1) return NULL; + return lib; } -struct library_t *add_library(struct link_map *map) -{ - library_t *newlib = gotcha_malloc(sizeof(library_t)); - newlib->map = map; - newlib->flags = 0; - newlib->generation = 0; - newlib->next = library_list; - newlib->prev = NULL; - if (library_list) - library_list->prev = newlib; - library_list = newlib; - addto_hashtable(&library_table, (hash_key_t) map, (hash_data_t) newlib); - return newlib; +struct library_t *add_library(struct link_map *map) { + library_t *newlib = gotcha_malloc(sizeof(library_t)); + newlib->map = map; + newlib->flags = 0; + newlib->generation = 0; + newlib->next = library_list; + newlib->prev = NULL; + if (library_list) library_list->prev = newlib; + library_list = newlib; + addto_hashtable(&library_table, (hash_key_t)map, (hash_data_t)newlib); + return newlib; } -void remove_library(struct link_map *map) -{ - library_t *lib = get_library(map); - if (!lib) - return; - if (lib->prev) - lib->prev->next = lib->next; - if (lib->next) - lib->next->prev = lib->prev; - if (lib == library_list) - library_list = library_list->next; - removefrom_hashtable(&library_table, (hash_key_t) map); - memset(lib, 0, sizeof(library_t)); - gotcha_free(lib); +void remove_library(struct link_map *map) { + library_t *lib = get_library(map); + if (!lib) return; + if (lib->prev) lib->prev->next = lib->next; + if (lib->next) lib->next->prev = lib->prev; + if (lib == library_list) library_list = library_list->next; + removefrom_hashtable(&library_table, (hash_key_t)map); + memset(lib, 0, sizeof(library_t)); + gotcha_free(lib); } -void gotcha_init(){ - static int gotcha_initialized = 0; - if(gotcha_initialized){ - return; - } - gotcha_initialized = 1; - debug_init(); - setup_hash_tables(); - handle_libdl(); +void gotcha_init() { + static int gotcha_initialized = 0; + if (gotcha_initialized) { + return; + } + gotcha_initialized = 1; + debug_init(); + setup_hash_tables(); + handle_libdl(); } - diff --git a/ext/GOTCHA/src/gotcha_utils.h b/ext/GOTCHA/src/gotcha_utils.h index 85aada986..f0e88bf12 100644 --- a/ext/GOTCHA/src/gotcha_utils.h +++ b/ext/GOTCHA/src/gotcha_utils.h @@ -3,14 +3,14 @@ This file is part of GOTCHA. For copyright information see the COPYRIGHT file in the top level directory, or at https://github.com/LLNL/gotcha/blob/master/COPYRIGHT This program is free software; you can redistribute it and/or modify it under -the terms of the GNU Lesser General Public License (as published by the Free Software -Foundation) version 2.1 dated February 1999. This program 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 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 +the terms of the GNU Lesser General Public License (as published by the Free +Software Foundation) version 2.1 dated February 1999. This program 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! @@ -26,12 +26,13 @@ Place, Suite 330, Boston, MA 02111-1307 USA #ifndef GOTCHA_UTILS_H #define GOTCHA_UTILS_H #include + #include "gotcha/gotcha_types.h" #include "hash.h" // TODO: remove these includes -#include -#include #include +#include +#include // END TODO #include #include @@ -44,36 +45,35 @@ extern int debug_level; void gotcha_init(); extern hash_table_t function_hash_table; extern hash_table_t notfound_binding_table; -#define debug_bare_printf(lvl, format, ...) \ - do { \ - if (debug_level >= lvl) { \ - gotcha_dbg_printf(format, ## __VA_ARGS__); \ - } \ - } while (0); +#define debug_bare_printf(lvl, format, ...) \ + do { \ + if (debug_level >= lvl) { \ + gotcha_dbg_printf(format, ##__VA_ARGS__); \ + } \ + } while (0); -#define SHORT_FILE__ ((strrchr(__FILE__, '/') ? : __FILE__ - 1) + 1) +#define SHORT_FILE__ ((strrchr(__FILE__, '/') ?: __FILE__ - 1) + 1) -#define debug_printf(lvl, format, ...) \ - do { \ - if (debug_level >= lvl) { \ - gotcha_dbg_printf("[%d/%d][%s:%u] - " format, \ - gotcha_gettid(), gotcha_getpid(), \ - SHORT_FILE__, __LINE__, \ - ## __VA_ARGS__); \ - } \ - } while (0); +#define debug_printf(lvl, format, ...) \ + do { \ + if (debug_level >= lvl) { \ + gotcha_dbg_printf("[%d/%d][%s:%u] - " format, gotcha_gettid(), \ + gotcha_getpid(), SHORT_FILE__, __LINE__, \ + ##__VA_ARGS__); \ + } \ + } while (0); -#define error_printf(format, ...) \ -do { \ - if (debug_level) { \ - gotcha_dbg_printf("ERROR [%d/%d][%s:%u] - " format, \ - gotcha_gettid(), gotcha_getpid(), \ - SHORT_FILE__, __LINE__, \ - ## __VA_ARGS__); \ - } \ - } while (0); +#define error_printf(format, ...) \ + do { \ + if (debug_level) { \ + gotcha_dbg_printf("ERROR [%d/%d][%s:%u] - " format, gotcha_gettid(), \ + gotcha_getpid(), SHORT_FILE__, __LINE__, \ + ##__VA_ARGS__); \ + } \ + } while (0); -#define LIB_NAME(X) (!X->l_name ? "[NULL]" : (!*X->l_name ? "[EMPTY]" : X->l_name)) +#define LIB_NAME(X) \ + (!X->l_name ? "[NULL]" : (!*X->l_name ? "[EMPTY]" : X->l_name)) /*! ****************************************************************************** @@ -97,7 +97,6 @@ do { \ ****************************************************************************** */ #define BOUNDARY_BEFORE(ptr, pagesize) \ - (ElfW(Addr))(((ElfW(Addr))ptr) &(-pagesize)) - + (ElfW(Addr))(((ElfW(Addr))ptr) & (-pagesize)) #endif diff --git a/ext/GOTCHA/src/hash.c b/ext/GOTCHA/src/hash.c index 8a631310b..29e27b048 100644 --- a/ext/GOTCHA/src/hash.c +++ b/ext/GOTCHA/src/hash.c @@ -10,235 +10,212 @@ 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 "libc_wrappers.h" #include "hash.h" +#include "libc_wrappers.h" + #define EMPTY 0 #define TOMBSTONE 1 #define INUSE 2 struct hash_entry_t { - hash_key_t key; - hash_data_t data; - hash_hashvalue_t hash_value; - struct hash_entry_t *next; - struct hash_entry_t *prev; - uint32_t status; + hash_key_t key; + hash_data_t data; + hash_hashvalue_t hash_value; + struct hash_entry_t *next; + struct hash_entry_t *prev; + uint32_t status; }; typedef struct hash_entry_t hash_entry_t; -int create_hashtable(hash_table_t *table, size_t initial_size, hash_func_t hashfunc, - hash_cmp_t keycmp) -{ - hash_entry_t *newtable; - int entries_per_page; - - entries_per_page = gotcha_getpagesize() / sizeof(hash_entry_t); - if (initial_size % entries_per_page) - initial_size += entries_per_page - (initial_size % entries_per_page); - - newtable = (hash_entry_t *) gotcha_malloc(initial_size * sizeof(hash_entry_t)); - if (!newtable) - return -1; - gotcha_memset(newtable, 0, initial_size * sizeof(hash_entry_t)); - - table->table_size = initial_size; - table->entry_count = 0; - table->hashfunc = hashfunc; - table->keycmp = keycmp; - table->table = newtable; - table->head = NULL; - - return 0; +int create_hashtable(hash_table_t *table, size_t initial_size, + hash_func_t hashfunc, hash_cmp_t keycmp) { + hash_entry_t *newtable; + int entries_per_page; + + entries_per_page = gotcha_getpagesize() / sizeof(hash_entry_t); + if (initial_size % entries_per_page) + initial_size += entries_per_page - (initial_size % entries_per_page); + + newtable = (hash_entry_t *)gotcha_malloc(initial_size * sizeof(hash_entry_t)); + if (!newtable) return -1; // GCOVR_EXCL_LINE + gotcha_memset(newtable, 0, initial_size * sizeof(hash_entry_t)); + + table->table_size = initial_size; + table->entry_count = 0; + table->hashfunc = hashfunc; + table->keycmp = keycmp; + table->table = newtable; + table->head = NULL; + + return 0; } -static hash_entry_t *insert(hash_table_t *table, hash_key_t key, hash_data_t data, hash_hashvalue_t value) -{ - unsigned long index = (unsigned long)value % table->table_size; - unsigned long startindex = index; - - hash_entry_t *entry = NULL; - do { - entry = table->table + index; - if (entry->status == EMPTY || entry->status == TOMBSTONE) { - entry->key = key; - entry->data = data; - entry->hash_value = value; - entry->status = INUSE; - break; - } - index++; - if (index == table->table_size) - index = 0; - } while (index != startindex); - - if (!entry) - return NULL; - - entry->next = table->head; - entry->prev = NULL; - if (table->head) - table->head->prev = entry; - table->head = entry; - table->entry_count++; - - return entry; +static hash_entry_t *insert(hash_table_t *table, hash_key_t key, + hash_data_t data, hash_hashvalue_t value) { + unsigned long index = (unsigned long)value % table->table_size; + unsigned long startindex = index; + + hash_entry_t *entry = NULL; + do { + entry = table->table + index; + if (entry->status == EMPTY || entry->status == TOMBSTONE) { + entry->key = key; + entry->data = data; + entry->hash_value = value; + entry->status = INUSE; + break; + } + index++; + if (index == table->table_size) index = 0; + } while (index != startindex); + + if (!entry) return NULL; // GCOVR_EXCL_LINE this is unreachable code. + + entry->next = table->head; + entry->prev = NULL; + if (table->head) table->head->prev = entry; + table->head = entry; + table->entry_count++; + + return entry; } -int grow_hashtable(hash_table_t *table, size_t new_size) -{ - hash_table_t newtable; - hash_entry_t *result; - size_t i; - - newtable.table_size = new_size; - newtable.entry_count = 0; - newtable.hashfunc = table->hashfunc; - newtable.keycmp = table->keycmp; - newtable.table = (hash_entry_t *) gotcha_malloc(new_size * sizeof(hash_entry_t)); - newtable.head = NULL; - gotcha_memset(newtable.table, 0, new_size * sizeof(hash_entry_t)); - - for (i = 0; i < table->table_size; i++) { - if (table->table[i].status == EMPTY || table->table[i].status == TOMBSTONE) - continue; - result = insert(&newtable, table->table[i].key, table->table[i].data, - table->table[i].hash_value); - if (!result) { - return -1; - } - } - - destroy_hashtable(table); - *table = newtable; - return 0; +int grow_hashtable(hash_table_t *table, size_t new_size) { + hash_table_t newtable; + hash_entry_t *result; + size_t i; + + newtable.table_size = new_size; + newtable.entry_count = 0; + newtable.hashfunc = table->hashfunc; + newtable.keycmp = table->keycmp; + newtable.table = + (hash_entry_t *)gotcha_malloc(new_size * sizeof(hash_entry_t)); + newtable.head = NULL; + gotcha_memset(newtable.table, 0, new_size * sizeof(hash_entry_t)); + + for (i = 0; i < table->table_size; i++) { + if (table->table[i].status == EMPTY || table->table[i].status == TOMBSTONE) + continue; + result = insert(&newtable, table->table[i].key, table->table[i].data, + table->table[i].hash_value); + if (!result) { + return -1; // GCOVR_EXCL_LINE this is unreachable code + } + } + + destroy_hashtable(table); + *table = newtable; + return 0; } -int destroy_hashtable(hash_table_t *table) -{ - gotcha_free(table->table); - table->table_size = 0; - table->entry_count = 0; - table->hashfunc = NULL; - table->keycmp = NULL; - table->table = NULL; - table->head = NULL; - return 0; +int destroy_hashtable(hash_table_t *table) { + gotcha_free(table->table); + table->table_size = 0; + table->entry_count = 0; + table->hashfunc = NULL; + table->keycmp = NULL; + table->table = NULL; + table->head = NULL; + return 0; } -static int lookup(hash_table_t *table, hash_key_t key, hash_entry_t **entry) -{ - size_t index, startindex; - hash_hashvalue_t hashval; - - hashval = table->hashfunc(key); - index = hashval % table->table_size; - startindex = index; - - for (;;) { - hash_entry_t *cur = table->table + index; - if ((cur->status == INUSE) && - (cur->hash_value == hashval) && - (table->keycmp(cur->key, key) == 0)) { - *entry = cur; - return 0; - } - - if (cur->status == EMPTY) - return -1; - index++; - if (index == table->table_size) - index = 0; - if (index == startindex) - return -1; - } +static int lookup(hash_table_t *table, hash_key_t key, hash_entry_t **entry) { + size_t index, startindex; + hash_hashvalue_t hashval; + + hashval = table->hashfunc(key); + index = hashval % table->table_size; + startindex = index; + + for (;;) { + hash_entry_t *cur = table->table + index; + if ((cur->status == INUSE) && (cur->hash_value == hashval) && + (table->keycmp(cur->key, key) == 0)) { + *entry = cur; + return 0; + } + + if (cur->status == EMPTY) return -1; + index++; + if (index == table->table_size) index = 0; // GCOVR_EXCL_LINE + if (index == startindex) return -1; // GCOVR_EXCL_LINE + } } -int lookup_hashtable(hash_table_t *table, hash_key_t key, hash_data_t *data) -{ - hash_entry_t *entry; - int result; +int lookup_hashtable(hash_table_t *table, hash_key_t key, hash_data_t *data) { + hash_entry_t *entry; + int result; - result = lookup(table, key, &entry); - if (result == -1) - return -1; - *data = entry->data; - return 0; + result = lookup(table, key, &entry); + if (result == -1) return -1; + *data = entry->data; + return 0; } -int addto_hashtable(hash_table_t *table, hash_key_t key, hash_data_t data) -{ - size_t newsize; - int result; - hash_hashvalue_t val; - hash_entry_t *entry; - - newsize = table->table_size; - while (table->entry_count > newsize/2) - newsize *= 2; - if (newsize != table->table_size) { - result = grow_hashtable(table, newsize); - if (result == -1) - return -1; - } - - val = table->hashfunc(key); - entry = insert(table, key, data, val); - if (!entry) - return -1; - - return 0; +int addto_hashtable(hash_table_t *table, hash_key_t key, hash_data_t data) { + size_t newsize; + int result; + hash_hashvalue_t val; + hash_entry_t *entry; + + newsize = table->table_size; + while (table->entry_count > newsize / 2) newsize *= 2; + if (newsize != table->table_size) { + result = grow_hashtable(table, newsize); + if (result == -1) return -1; // GCOVR_EXCL_LINE unreachable code + } + + val = table->hashfunc(key); + entry = insert(table, key, data, val); + if (!entry) return -1; // GCOVR_EXCL_LINE unreachable code + + return 0; } -int removefrom_hashtable(hash_table_t *table, hash_key_t key) -{ - hash_entry_t *entry; - int result; - - result = lookup(table, key, &entry); - if (result == -1) - return -1; - - entry->key = NULL; - entry->data = NULL; - entry->hash_value = 0; - entry->status = TOMBSTONE; - if (entry->next) - entry->next->prev = entry->prev; - if (entry->prev) - entry->prev->next = entry->next; - if (table->head == entry) - table->head = entry->next; - //Do not set entry->next to NULL, which would break the iterate & delete - //idiom used under dlopen_wrapper. - - table->entry_count--; - return 0; +int removefrom_hashtable(hash_table_t *table, hash_key_t key) { + hash_entry_t *entry; + int result; + + result = lookup(table, key, &entry); + if (result == -1) return -1; + + entry->key = NULL; + entry->data = NULL; + entry->hash_value = 0; + entry->status = TOMBSTONE; + if (entry->next) entry->next->prev = entry->prev; + if (entry->prev) entry->prev->next = entry->next; + if (table->head == entry) table->head = entry->next; + // Do not set entry->next to NULL, which would break the iterate & delete + // idiom used under dlopen_wrapper. + + table->entry_count--; + return 0; } -int foreach_hash_entry(hash_table_t *table, void *opaque, int (*cb)(hash_key_t key, hash_data_t data, void *opaque)) -{ - int result; - struct hash_entry_t *i; - for (i = table->head; i != NULL; i = i->next) { - result = cb(i->key, i->data, opaque); - if (result != 0) - return result; - } - return 0; +int foreach_hash_entry(hash_table_t *table, void *opaque, + int (*cb)(hash_key_t key, hash_data_t data, + void *opaque)) { + int result; + struct hash_entry_t *i; + for (i = table->head; i != NULL; i = i->next) { + result = cb(i->key, i->data, opaque); + if (result != 0) return result; // GCOVR_EXCL_LINE + } + return 0; } -hash_hashvalue_t strhash(const char *str) -{ - unsigned long hash = 5381; - int c; +hash_hashvalue_t strhash(const char *str) { + unsigned long hash = 5381; + int c; - while ((c = *str++)) - hash = hash * 33 + c; + while ((c = *str++)) hash = hash * 33 + c; - return (hash_hashvalue_t) hash; + return (hash_hashvalue_t)hash; } diff --git a/ext/GOTCHA/src/hash.h b/ext/GOTCHA/src/hash.h index 5ac11a7e9..4f846d42d 100644 --- a/ext/GOTCHA/src/hash.h +++ b/ext/GOTCHA/src/hash.h @@ -10,34 +10,33 @@ 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 */ #if !defined(HASH_H_) #define HASH_H_ -#include #include +#include -typedef void* hash_key_t; -typedef void* hash_data_t; +typedef void *hash_key_t; +typedef void *hash_data_t; typedef int hash_hashvalue_t; typedef hash_hashvalue_t (*hash_func_t)(hash_data_t data); typedef int (*hash_cmp_t)(hash_key_t a, hash_key_t b); struct hash_entry_t; -typedef struct -{ - size_t table_size; - size_t entry_count; - hash_func_t hashfunc; - hash_cmp_t keycmp; - struct hash_entry_t *table; - struct hash_entry_t *head; +typedef struct { + size_t table_size; + size_t entry_count; + hash_func_t hashfunc; + hash_cmp_t keycmp; + struct hash_entry_t *table; + struct hash_entry_t *head; } hash_table_t; -int create_hashtable(hash_table_t *table, size_t initial_size, hash_func_t func, +int create_hashtable(hash_table_t *table, size_t initial_size, hash_func_t func, hash_cmp_t keycmp); int grow_hashtable(hash_table_t *table, size_t new_size); int destroy_hashtable(hash_table_t *table); @@ -45,7 +44,9 @@ int destroy_hashtable(hash_table_t *table); int lookup_hashtable(hash_table_t *table, hash_key_t key, hash_data_t *data); int addto_hashtable(hash_table_t *table, hash_key_t key, hash_data_t data); int removefrom_hashtable(hash_table_t *table, hash_key_t key); -int foreach_hash_entry(hash_table_t *table, void *opaque, int (*cb)(hash_key_t key, hash_data_t data, void *opaque)); +int foreach_hash_entry(hash_table_t *table, void *opaque, + int (*cb)(hash_key_t key, hash_data_t data, + void *opaque)); hash_hashvalue_t strhash(const char *str); diff --git a/ext/GOTCHA/src/libc_wrappers.c b/ext/GOTCHA/src/libc_wrappers.c index 3e53f6d0c..30608e1bb 100644 --- a/ext/GOTCHA/src/libc_wrappers.c +++ b/ext/GOTCHA/src/libc_wrappers.c @@ -10,153 +10,135 @@ 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 */ #define _GNU_SOURCE #define BUILDING_LIBC_WRAPPERS -#include +#include "libc_wrappers.h" + +#include +#include +#include #include #include -#include +#include +#include #include #include -#include -#include -#include -#include -#include "libc_wrappers.h" #include "gotcha_auxv.h" typedef struct malloc_header_t { - size_t size; + size_t size; } malloc_header_t; typedef struct malloc_link_t { - malloc_header_t header; - struct malloc_link_t *next; + malloc_header_t header; + struct malloc_link_t *next; } malloc_link_t; #define MIN_SIZE (sizeof(malloc_link_t) - sizeof(malloc_header_t)) -#define MIN_BLOCK_SIZE (1024*32) +#define MIN_BLOCK_SIZE (1024 * 32) static malloc_link_t *free_list = NULL; -static void split_allocation(malloc_link_t *allocation, size_t new_size) -{ - size_t orig_size = allocation->header.size; - malloc_link_t *newalloc; +static void split_allocation(malloc_link_t *allocation, size_t new_size) { + size_t orig_size = allocation->header.size; + malloc_link_t *newalloc; - if (orig_size - new_size <= sizeof(malloc_link_t)) - return; + if (orig_size - new_size <= sizeof(malloc_link_t)) return; - allocation->header.size = new_size; - newalloc = (malloc_link_t *) (((unsigned char *) &allocation->next) + new_size); - newalloc->header.size = (orig_size - new_size) - sizeof(malloc_header_t); - newalloc->next = free_list; - free_list = newalloc; + allocation->header.size = new_size; + newalloc = (malloc_link_t *)(((unsigned char *)&allocation->next) + new_size); + newalloc->header.size = (orig_size - new_size) - sizeof(malloc_header_t); + newalloc->next = free_list; + free_list = newalloc; } -void *gotcha_malloc(size_t size) -{ - malloc_link_t *cur, *prev, *newalloc; - // Initialization of best_fit_prev to NULL added by Thomas Gruber to avoid - // warnings - malloc_link_t *best_fit = NULL, *best_fit_prev = NULL; - // Initialization of best_fit_diff to SIZE_MAX added by Thomas Gruber to - // avoid warnings - ssize_t best_fit_diff = SIZE_MAX, diff, block_size; - void *result; - - if (size < MIN_SIZE) - size = MIN_SIZE; - if (size % 8) - size += 8 - (size % 8); - - //Find the tightest fit allocation in the free list - for (prev = NULL, cur = free_list; cur; cur = cur->next) { - diff = cur->header.size - size; - if (diff >= 0 && (!best_fit || diff < best_fit_diff)) { - best_fit = cur; - best_fit_prev = prev; - best_fit_diff = diff; - if (!diff) - break; - } - prev = cur; - } +void *gotcha_malloc(size_t size) { + malloc_link_t *cur, *prev, *newalloc; + malloc_link_t *best_fit = NULL, *best_fit_prev; + ssize_t best_fit_diff = SIZE_MAX, diff, block_size; + void *result; + + if (size < MIN_SIZE) size = MIN_SIZE; + if (size % 8) size += 8 - (size % 8); + + // Find the tightest fit allocation in the free list + for (prev = NULL, cur = free_list; cur; cur = cur->next) { + diff = cur->header.size - size; + if (diff >= 0 && (!best_fit || diff < best_fit_diff)) { + best_fit = cur; + best_fit_prev = prev; + best_fit_diff = diff; + if (!diff) break; + } + prev = cur; + } - //Removes the best fit from the free list, split if needed, and return - if (best_fit) { - if (best_fit_prev) - best_fit_prev->next = best_fit->next; - else - free_list = best_fit->next; - split_allocation(best_fit, size); - return (void *) &best_fit->next; - } - - //Create a new allocation area - if (size + sizeof(malloc_header_t) > MIN_BLOCK_SIZE) { - block_size = size + sizeof(malloc_header_t); - diff = block_size % gotcha_getpagesize(); - if (diff) - block_size += gotcha_getpagesize() - diff; - } - else { - block_size = MIN_BLOCK_SIZE; - } - - result = gotcha_mmap(NULL, block_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - if (result == MAP_FAILED) - return NULL; - newalloc = (malloc_link_t *) result; - newalloc->header.size = block_size - sizeof(malloc_header_t); - split_allocation(newalloc, size); - return (void *) &newalloc->next; + // Removes the best fit from the free list, split if needed, and return + if (best_fit) { + if (best_fit_prev) + best_fit_prev->next = best_fit->next; + else + free_list = best_fit->next; + split_allocation(best_fit, size); + return (void *)&best_fit->next; + } + + // Create a new allocation area + if (size + sizeof(malloc_header_t) > MIN_BLOCK_SIZE) { + block_size = size + sizeof(malloc_header_t); + diff = block_size % gotcha_getpagesize(); + if (diff) block_size += gotcha_getpagesize() - diff; + } else { + block_size = MIN_BLOCK_SIZE; + } + + result = gotcha_mmap(NULL, block_size, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (result == MAP_FAILED) return NULL; // GCOVR_EXCL_LINE + newalloc = (malloc_link_t *)result; + newalloc->header.size = block_size - sizeof(malloc_header_t); + split_allocation(newalloc, size); + return (void *)&newalloc->next; } -void *gotcha_realloc(void* buffer, size_t size) -{ - void *newbuffer; - malloc_link_t *alloc; +void *gotcha_realloc(void *buffer, size_t size) { + void *newbuffer; + malloc_link_t *alloc; - alloc = (malloc_link_t *) (((malloc_header_t *) buffer) - 1); + alloc = (malloc_link_t *)(((malloc_header_t *)buffer) - 1); - if (size <= alloc->header.size) - return buffer; + if (size <= alloc->header.size) return buffer; - newbuffer = gotcha_malloc(size); - if (!newbuffer) - return NULL; - gotcha_memcpy(newbuffer, buffer, alloc->header.size); + newbuffer = gotcha_malloc(size); + if (!newbuffer) return NULL; // GCOVR_EXCL_LINE + gotcha_memcpy(newbuffer, buffer, alloc->header.size); - gotcha_free(buffer); + gotcha_free(buffer); - return newbuffer; + return newbuffer; } -void gotcha_free(void *buffer) -{ - malloc_link_t *alloc; - alloc = (malloc_link_t *) (((malloc_header_t *) buffer) - 1); +void gotcha_free(void *buffer) { + malloc_link_t *alloc; + alloc = (malloc_link_t *)(((malloc_header_t *)buffer) - 1); - alloc->next = free_list; - free_list = alloc; + alloc->next = free_list; + free_list = alloc; } -void gotcha_memcpy(void *dest, void *src, size_t size) -{ - size_t i; - for (i = 0; i < size; i++) { - ((unsigned char *) dest)[i] = ((unsigned char *) src)[i]; - } +void gotcha_memcpy(void *dest, void *src, size_t size) { + size_t i; + for (i = 0; i < size; i++) { + ((unsigned char *)dest)[i] = ((unsigned char *)src)[i]; + } } -int gotcha_strncmp(const char *in_one, const char *in_two, int max_length) -{ +int gotcha_strncmp(const char *in_one, const char *in_two, int max_length) { int i = 0; for (; i < max_length; i++) { if (in_one[i] == '\0') { @@ -169,8 +151,7 @@ int gotcha_strncmp(const char *in_one, const char *in_two, int max_length) return 0; } -int gotcha_strcmp(const char *in_one, const char *in_two) -{ +int gotcha_strcmp(const char *in_one, const char *in_two) { int i = 0; for (;; i++) { if (in_one[i] == '\0') { @@ -182,402 +163,373 @@ int gotcha_strcmp(const char *in_one, const char *in_two) } } -char *gotcha_strstr(const char *searchIn, const char *searchFor) -{ - int i, j; - if (!searchFor[0]) - return NULL; - - for (i = 0; searchIn[i]; i++) { - if (searchIn[i] != searchFor[0]) - continue; - for (j = 1; ; j++) { - if (!searchFor[j]) - return (char*)(searchFor + i); - if (!searchIn[i+j]) - return NULL; - if (searchFor[j] != searchIn[i+j]) - break; - } - } - return NULL; -} +char *gotcha_strstr(const char *searchIn, const char *searchFor) { + int i, j; + if (!searchFor[0]) return NULL; // GCOVR_EXCL_LINE -ssize_t gotcha_write(int fd, const void *buf, size_t count) -{ - return syscall(SYS_write, fd, buf, count); + for (i = 0; searchIn[i]; i++) { + if (searchIn[i] != searchFor[0]) continue; + for (j = 1;; j++) { + if (!searchFor[j]) return (char *)(searchFor + i); + if (!searchIn[i + j]) return NULL; + if (searchFor[j] != searchIn[i + j]) break; + } + } + return NULL; } -size_t gotcha_strlen(const char *s) -{ - size_t i; - for (i = 0; s[i]; i++); - return i; +ssize_t gotcha_write(int fd, const void *buf, size_t count) { + return syscall(SYS_write, fd, buf, count); } -size_t gotcha_strnlen(const char *s, size_t max_length) -{ - size_t i; - for (i = 0; s[i] && i= strlen) - return -1; - - str[len] = '\0'; - val = num; - for (i = 1; i <= len; i++) { - - str[len - i] = (val % 16 <= 9) ? ('0' + val % 16) : (base_char + (val % 16 - 10)); - val = val / 16; - } - return len; +size_t gotcha_strnlen(const char *s, size_t max_length) { + size_t i; + for (i = 0; s[i] && i < max_length; i++) + ; + return i; } -static int ulong_to_str(unsigned long num, char *str, int strlen) -{ - int len, i; - unsigned long val; - - if (num == 0) { - if (strlen < 2) - return -1; - str[0] = '0'; - str[1] = '\0'; - return 1; - } - - for (len = 0, val = num; val; val = val / 10, len++); - if (len + 1 >= strlen) - return -1; - - str[len] = '\0'; - val = num; - for (i = 1; i <= len; i++) { - str[len - i] = '0' + val % 10; - val = val / 10; - } - return len; +static int ulong_to_hexstr(unsigned long num, char *str, int strlen, + int uppercase) { + int len, i; + unsigned long val; + char base_char = uppercase ? 'A' : 'a'; + + if (num == 0) { + if (strlen < 2) return -1; // GCOVR_EXCL_LINE + str[0] = '0'; + str[1] = '\0'; + return 1; + } + + for (len = 0, val = num; val; val = val / 16, len++) + ; + if (len + 1 >= strlen) return -1; // GCOVR_EXCL_LINE + + str[len] = '\0'; + val = num; + for (i = 1; i <= len; i++) { + str[len - i] = + (val % 16 <= 9) ? ('0' + val % 16) : (base_char + (val % 16 - 10)); + val = val / 16; + } + return len; } -static int slong_to_str(signed long num, char *str, int strlen) -{ - int result; - if (num >= 0) - return ulong_to_str((unsigned long) num, str, strlen); - - result = ulong_to_str((unsigned long) (num * -1), str+1, strlen-1); - if (result == -1) - return -1; - str[0] = '-'; - return result + 1; +static int ulong_to_str(unsigned long num, char *str, int strlen) { + int len, i; + unsigned long val; + + if (num == 0) { + if (strlen < 2) return -1; // GCOVR_EXCL_LINE + str[0] = '0'; + str[1] = '\0'; + return 1; + } + + for (len = 0, val = num; val; val = val / 10, len++) + ; + if (len + 1 >= strlen) return -1; // GCOVR_EXCL_LINE + + str[len] = '\0'; + val = num; + for (i = 1; i <= len; i++) { + str[len - i] = '0' + val % 10; + val = val / 10; + } + return len; } -void gotcha_assert_fail(const char *s, const char *file, unsigned int line, const char *function) -{ - char linestr[64]; - int result; - - result = ulong_to_str(line, linestr, sizeof(linestr)-1); - if (result == -1) - linestr[0] = '\0'; - - gotcha_write(2, file, gotcha_strlen(file)); - gotcha_write(2, ":", 1); - gotcha_write(2, linestr, gotcha_strlen(linestr)); - gotcha_write(2, ": ", 2); - gotcha_write(2, function, gotcha_strlen(function)); - gotcha_write(2, ": Assertion `", 13); - gotcha_write(2, s, gotcha_strlen(s)); - gotcha_write(2, "' failed.\n", 10); - syscall(SYS_kill, gotcha_getpid(), SIGABRT); +static int slong_to_str(signed long num, char *str, int strlen) { + int result; + if (num >= 0) return ulong_to_str((unsigned long)num, str, strlen); + + result = ulong_to_str((unsigned long)(num * -1), str + 1, strlen - 1); + if (result == -1) return -1; // GCOVR_EXCL_LINE + str[0] = '-'; + return result + 1; } +// GCOVR_EXCL_START +void gotcha_assert_fail(const char *s, const char *file, unsigned int line, + const char *function) { + char linestr[64]; + int result; + + result = ulong_to_str(line, linestr, sizeof(linestr) - 1); + if (result == -1) linestr[0] = '\0'; + + gotcha_write(2, file, gotcha_strlen(file)); + gotcha_write(2, ":", 1); + gotcha_write(2, linestr, gotcha_strlen(linestr)); + gotcha_write(2, ": ", 2); + gotcha_write(2, function, gotcha_strlen(function)); + gotcha_write(2, ": Assertion `", 13); + gotcha_write(2, s, gotcha_strlen(s)); + gotcha_write(2, "' failed.\n", 10); + syscall(SYS_kill, gotcha_getpid(), SIGABRT); +} +// GCOVR_EXCL_STOP extern char **__environ; -char *gotcha_getenv(const char *name) -{ - char **s; - int name_len; - - name_len = gotcha_strlen(name); - for (s = __environ; *s; s++) { - if (gotcha_strncmp(name, *s, name_len) != 0) - continue; - if ((*s)[name_len] != '=') - continue; - return (*s) + name_len + 1; - } - return NULL; +char *gotcha_getenv(const char *name) { + char **s; + int name_len; + + name_len = gotcha_strlen(name); + for (s = __environ; *s; s++) { + if (gotcha_strncmp(name, *s, name_len) != 0) continue; + if ((*s)[name_len] != '=') continue; // GCOVR_EXCL_LINE + return (*s) + name_len + 1; + } + return NULL; // GCOVR_EXCL_LINE } -pid_t gotcha_getpid() -{ - return syscall(SYS_getpid); -} +pid_t gotcha_getpid() { return syscall(SYS_getpid); } -pid_t gotcha_gettid() -{ - return syscall(SYS_gettid); -} +pid_t gotcha_gettid() { return syscall(SYS_gettid); } -unsigned int gotcha_getpagesize() -{ - static unsigned int pagesz = 0; - if (pagesz) - return pagesz; +unsigned int gotcha_getpagesize() { + static unsigned int pagesz = 0; + if (pagesz) return pagesz; - pagesz = get_auxv_pagesize(); - if (!pagesz) - pagesz = 4096; - return pagesz; + pagesz = get_auxv_pagesize(); + if (!pagesz) pagesz = 4096; // GCOVR_EXCL_LINE + return pagesz; } -int gotcha_open(const char *pathname, int flags, ...) -{ - mode_t mode; - va_list args; - long result; - - va_start(args, flags); - if (flags & O_CREAT) { - mode = va_arg(args, mode_t); - } - else { - mode = 0; - } - va_end(args); - - result = syscall(SYS_open, pathname, flags, mode); - if (result >= 0) - return (int) result; - - return -1; +int gotcha_open(const char *pathname, int flags, ...) { + mode_t mode; + va_list args; + long result; + + va_start(args, flags); + if (flags & O_CREAT) { + mode = va_arg(args, mode_t); // GCOVR_EXCL_LINE + } else { + mode = 0; + } + va_end(args); + +#if defined(SYS_open) + result = syscall(SYS_open, pathname, flags, mode); +#else + result = syscall(SYS_openat, AT_FDCWD, pathname, flags, mode); +#endif + + if (result >= 0) return (int)result; + + return -1; // GCOVR_EXCL_LINE } -void *gotcha_mmap(void *addr, size_t length, int prot, int flags, - int fd, off_t offset) -{ - long result; +void *gotcha_mmap(void *addr, size_t length, int prot, int flags, int fd, + off_t offset) { + long result; - result = syscall(SYS_mmap, addr, length, prot, flags, fd, offset); - return (void *) result; + result = syscall(SYS_mmap, addr, length, prot, flags, fd, offset); + return (void *)result; } -int gotcha_atoi(const char *nptr) -{ - int neg = 1, len, val = 0, mult = 1; - const char *cur; +int gotcha_atoi(const char *nptr) { + int neg = 1, len, val = 0, mult = 1; + const char *cur; - while (*nptr == '-') { - neg = neg * -1; - nptr++; - } + while (*nptr == '-') { + neg = neg * -1; + nptr++; + } - for (len = 0; nptr[len] >= '0' && nptr[len] <= '9'; len++); + for (len = 0; nptr[len] >= '0' && nptr[len] <= '9'; len++) + ; - for (cur = nptr + len - 1; cur != nptr-1; cur--) { - val += mult * (*cur - '0'); - mult *= 10; - } + for (cur = nptr + len - 1; cur != nptr - 1; cur--) { + val += mult * (*cur - '0'); + mult *= 10; + } - return val * neg; + return val * neg; } -int gotcha_close(int fd) -{ - return syscall(SYS_close, fd); -} +int gotcha_close(int fd) { return syscall(SYS_close, fd); } -int gotcha_mprotect(void *addr, size_t len, int prot) -{ - return syscall(SYS_mprotect, addr, len, prot); +int gotcha_mprotect(void *addr, size_t len, int prot) { + return syscall(SYS_mprotect, addr, len, prot); } -ssize_t gotcha_read(int fd, void *buf, size_t count) -{ - return syscall(SYS_read, fd, buf, count); +ssize_t gotcha_read(int fd, void *buf, size_t count) { + return syscall(SYS_read, fd, buf, count); } -static const char *add_to_buffer(const char *str, int fd, int *pos, char *buffer, - int buffer_size, int *num_printed, int print_percent) -{ - for (; *str && (print_percent || *str != '%'); str++) { - if (*pos >= buffer_size) { - gotcha_write(fd, buffer, buffer_size); - *num_printed += buffer_size; - *pos = 0; - } - else { - buffer[*pos] = *str; - } - *pos = *pos + 1; - } - return str; +static const char *add_to_buffer(const char *str, int fd, int *pos, + char *buffer, int buffer_size, + int *num_printed, int print_percent) { + for (; *str && (print_percent || *str != '%'); str++) { + if (*pos >= buffer_size) { // GCOVR_EXCL_START + gotcha_write(fd, buffer, buffer_size); + *num_printed += buffer_size; + *pos = 0; + } // GCOVR_EXCL_STOP + else { + buffer[*pos] = *str; + } + *pos = *pos + 1; + } + return str; } -int gotcha_int_printf(int fd, const char *format, ...) -{ -#define inc(S) do { S++; if (*(S) == '\0') goto done; } while(0) - va_list args; - const char *str = format; - int buffer_pos = 0; - int char_width, short_width, long_width, long_long_width, size_width; - int num_printed = 0; - char buffer[4096]; - - va_start(args, format); - while (*str) { - str = add_to_buffer(str, fd, &buffer_pos, buffer, sizeof(buffer), &num_printed, 0); - if (!*str) break; - - gotcha_assert(*str == '%'); +int gotcha_int_printf(int fd, const char *format, ...) { +#define inc(S) \ + do { \ + S++; \ + if (*(S) == '\0') goto done; \ + } while (0) + va_list args; + const char *str = format; + int buffer_pos = 0; + int char_width, short_width, long_width, long_long_width, size_width; + int num_printed = 0; + char buffer[4096]; + + va_start(args, format); + while (*str) { + str = add_to_buffer(str, fd, &buffer_pos, buffer, sizeof(buffer), + &num_printed, 0); + if (!*str) break; + + gotcha_assert(*str == '%'); + inc(str); + + char_width = short_width = long_width = long_long_width = size_width = 0; + if (*str == 'h' && *(str + 1) == 'h') { + char_width = 1; inc(str); + inc(str); + } else if (*str == 'h') { + short_width = 1; + inc(str); + } else if (*str == 'l' && *(str + 1) == 'l') { + long_long_width = 1; + inc(str); + inc(str); + } else if (*str == 'l') { + long_width = 1; + inc(str); + } else if (*str == 'z') { + size_width = 1; + inc(str); + } - char_width = short_width = long_width = long_long_width = size_width = 0; - if (*str == 'h' && *(str+1) == 'h') { - char_width = 1; - inc(str); - inc(str); - } - else if (*str == 'h') { - short_width = 1; - inc(str); - } - else if (*str == 'l' && *(str+1) == 'l') { - long_long_width = 1; - inc(str); - inc(str); - } - else if (*str == 'l') { - long_width = 1; - inc(str); - } - else if (*str == 'z') { - size_width = 1; - inc(str); - } - - if (*str == 'd' || *str == 'i') { - signed long val; - char numstr[64]; - if (char_width) - val = (signed long) (signed char) va_arg(args, signed int); - else if (short_width) - val = (signed long) (signed short) va_arg(args, signed int); - else if (long_width) - val = (signed long) va_arg(args, signed long); - else if (long_long_width) - val = (signed long) va_arg(args, signed long long); - else if (size_width) - val = (signed long) va_arg(args, ssize_t); - else - val = (signed long) va_arg(args, signed int); - slong_to_str(val, numstr, 64); - add_to_buffer(numstr, fd, &buffer_pos, buffer, sizeof(buffer), &num_printed, 1); - } - else if (*str == 'u') { - unsigned long val; - char numstr[64]; - if (char_width) - val = (unsigned long) (unsigned char) va_arg(args, unsigned int); - else if (short_width) - val = (unsigned long) (unsigned short) va_arg(args, unsigned int); - else if (long_width) - val = (unsigned long) va_arg(args, unsigned long); - else if (long_long_width) - val = (unsigned long) va_arg(args, unsigned long long); - else if (size_width) - val = (unsigned long) va_arg(args, ssize_t); - else - val = (unsigned long) va_arg(args, unsigned int); - ulong_to_str(val, numstr, 64); - add_to_buffer(numstr, fd, &buffer_pos, buffer, sizeof(buffer), &num_printed, 1); - } - else if (*str == 'x' || *str == 'X' || *str == 'p') { - unsigned long val; - char numstr[64]; - if (*str != 'p') { - if (char_width) - val = (unsigned long) (unsigned char) va_arg(args, unsigned int); - else if (short_width) - val = (unsigned long) (unsigned short) va_arg(args, unsigned int); - else if (long_width) - val = (unsigned long) va_arg(args, unsigned long); - else if (long_long_width) - val = (unsigned long) va_arg(args, unsigned long long); - else if (size_width) - val = (unsigned long) va_arg(args, ssize_t); - else - val = (unsigned long) va_arg(args, unsigned int); - } - else { - val = (unsigned long) va_arg(args, void *); - add_to_buffer("0x", fd, &buffer_pos, buffer, sizeof(buffer), &num_printed, 1); - } - ulong_to_hexstr(val, numstr, 64, (*str == 'X')); - add_to_buffer(numstr, fd, &buffer_pos, buffer, sizeof(buffer), &num_printed, 1); - } - else if (*str == 'c') { - char cbuf[2]; - cbuf[0] = (unsigned char) va_arg(args, unsigned int); - cbuf[1] = '\0'; - add_to_buffer(cbuf, fd, &buffer_pos, buffer, sizeof(buffer), &num_printed, 1); - } - else if (*str == 's') { - char *s = (char *) va_arg(args, char *); - add_to_buffer(s, fd, &buffer_pos, buffer, sizeof(buffer), &num_printed, 1); - } - else if (*str == '%') { - add_to_buffer("%", fd, &buffer_pos, buffer, sizeof(buffer), &num_printed, 1); - } - else { - char s[3]; - s[0] = '%'; - s[1] = *str; - s[2] = '\0'; - add_to_buffer(s, fd, &buffer_pos, buffer, sizeof(buffer), &num_printed, 1); + if (*str == 'd' || *str == 'i') { + signed long val; + char numstr[64]; + if (char_width) + val = (signed long)(signed char)va_arg(args, signed int); + else if (short_width) + val = (signed long)(signed short)va_arg(args, signed int); + else if (long_width) + val = (signed long)va_arg(args, signed long); + else if (long_long_width) + val = (signed long)va_arg(args, signed long long); + else if (size_width) + val = (signed long)va_arg(args, ssize_t); + else + val = (signed long)va_arg(args, signed int); + slong_to_str(val, numstr, 64); + add_to_buffer(numstr, fd, &buffer_pos, buffer, sizeof(buffer), + &num_printed, 1); + } else if (*str == 'u') { + unsigned long val; + char numstr[64]; + if (char_width) + val = (unsigned long)(unsigned char)va_arg(args, unsigned int); + else if (short_width) + val = (unsigned long)(unsigned short)va_arg(args, unsigned int); + else if (long_width) + val = (unsigned long)va_arg(args, unsigned long); + else if (long_long_width) + val = (unsigned long)va_arg(args, unsigned long long); + else if (size_width) + val = (unsigned long)va_arg(args, ssize_t); + else + val = (unsigned long)va_arg(args, unsigned int); + ulong_to_str(val, numstr, 64); + add_to_buffer(numstr, fd, &buffer_pos, buffer, sizeof(buffer), + &num_printed, 1); + } else if (*str == 'x' || *str == 'X' || *str == 'p') { + unsigned long val; + char numstr[64]; + if (*str != 'p') { + if (char_width) + val = (unsigned long)(unsigned char)va_arg(args, unsigned int); + else if (short_width) + val = (unsigned long)(unsigned short)va_arg(args, unsigned int); + else if (long_width) + val = (unsigned long)va_arg(args, unsigned long); + else if (long_long_width) + val = (unsigned long)va_arg(args, unsigned long long); + else if (size_width) + val = (unsigned long)va_arg(args, ssize_t); + else + val = (unsigned long)va_arg(args, unsigned int); + } else { + val = (unsigned long)va_arg(args, void *); + add_to_buffer("0x", fd, &buffer_pos, buffer, sizeof(buffer), + &num_printed, 1); } - inc(str); - } + ulong_to_hexstr(val, numstr, 64, (*str == 'X')); + add_to_buffer(numstr, fd, &buffer_pos, buffer, sizeof(buffer), + &num_printed, 1); + } else if (*str == 'c') { + char cbuf[2]; + cbuf[0] = (unsigned char)va_arg(args, unsigned int); + cbuf[1] = '\0'; + add_to_buffer(cbuf, fd, &buffer_pos, buffer, sizeof(buffer), &num_printed, + 1); + } else if (*str == 's') { + char *s = (char *)va_arg(args, char *); + add_to_buffer(s, fd, &buffer_pos, buffer, sizeof(buffer), &num_printed, + 1); + } else if (*str == '%') { + add_to_buffer("%", fd, &buffer_pos, buffer, sizeof(buffer), &num_printed, + 1); + } else { + char s[3]; + s[0] = '%'; + s[1] = *str; + s[2] = '\0'; + add_to_buffer(s, fd, &buffer_pos, buffer, sizeof(buffer), &num_printed, + 1); + } + inc(str); + } - done: - gotcha_write(fd, buffer, buffer_pos); - num_printed += buffer_pos; - va_end(args); - return num_printed; +done: // GCOVR_EXCL_LINE + gotcha_write(fd, buffer, buffer_pos); + num_printed += buffer_pos; + va_end(args); + return num_printed; } -void *gotcha_memset(void *s, int c, size_t n) -{ - size_t i; - unsigned char byte = (unsigned char) c; - for (i = 0; i < n; i++) { - ((unsigned char *) s)[i] = byte; - } - return s; +void *gotcha_memset(void *s, int c, size_t n) { + size_t i; + unsigned char byte = (unsigned char)c; + for (i = 0; i < n; i++) { + ((unsigned char *)s)[i] = byte; + } + return s; } -char* gotcha_strncat(char* dest, const char* src, size_t n){ - char* dest_begin = dest; +char *gotcha_strncat(char *dest, const char *src, size_t n) { + char *dest_begin = dest; dest = dest + gotcha_strlen(dest); size_t dest_stop = gotcha_strnlen(src, n); dest[dest_stop] = '\0'; - gotcha_memcpy(dest, (void *) src, n); + gotcha_memcpy(dest, (void *)src, n); return dest_begin; } diff --git a/ext/GOTCHA/src/libc_wrappers.h b/ext/GOTCHA/src/libc_wrappers.h index d3b19b163..535af2ca0 100644 --- a/ext/GOTCHA/src/libc_wrappers.h +++ b/ext/GOTCHA/src/libc_wrappers.h @@ -10,18 +10,18 @@ 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 */ #if !defined(LIBC_WRAPPERS_H_) #define LIBC_WRAPPERS_H_ +#include #include #include -#include +#include #include #include -#include #ifndef FORCE_NO_LIBC #define GOTCHA_USE_LIBC @@ -29,67 +29,68 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #if defined(GOTCHA_USE_LIBC) && !defined(BUILDING_LIBC_WRAPPERS) -#define gotcha_malloc malloc -#define gotcha_realloc realloc -#define gotcha_free free -#define gotcha_memcpy memcpy -#define gotcha_strncmp strncmp -#define gotcha_strstr strstr -#define gotcha_assert assert -#define gotcha_strcmp strcmp -#define gotcha_getenv getenv -#define gotcha_getpid getpid -#define gotcha_getpagesize getpagesize -#define gotcha_open open -#define gotcha_mmap mmap -#define gotcha_atoi atoi -#define gotcha_close close -#define gotcha_mprotect mprotect -#define gotcha_read read -#define gotcha_memset memset -#define gotcha_write write -#define gotcha_strlen strlen -#define gotcha_strnlen strnlen -#define gotcha_strtok strtok -#define gotcha_strncat strncat +#define gotcha_malloc malloc +#define gotcha_realloc realloc +#define gotcha_free free +#define gotcha_memcpy memcpy +#define gotcha_strncmp strncmp +#define gotcha_strstr strstr +#define gotcha_assert assert +#define gotcha_strcmp strcmp +#define gotcha_getenv getenv +#define gotcha_getpid getpid +#define gotcha_getpagesize getpagesize +#define gotcha_open open +#define gotcha_mmap mmap +#define gotcha_atoi atoi +#define gotcha_close close +#define gotcha_mprotect mprotect +#define gotcha_read read +#define gotcha_memset memset +#define gotcha_write write +#define gotcha_strlen strlen +#define gotcha_strnlen strnlen +#define gotcha_strtok strtok +#define gotcha_strncat strncat #define gotcha_dbg_printf(A, ...) fprintf(stderr, A, ##__VA_ARGS__) -pid_t gotcha_gettid(); //No libc gettid, always use gotcha version +pid_t gotcha_gettid(); // No libc gettid, always use gotcha version #else void *gotcha_malloc(size_t size); -void *gotcha_realloc(void* buffer, size_t size); -void gotcha_free(void* free_me); -void gotcha_memcpy(void* dest, void* src, size_t size); -int gotcha_strncmp(const char* in_one, const char* in_two, int max_length); -char *gotcha_strstr(const char* searchIn,const char* searchFor); -int gotcha_strcmp(const char* in_one, const char* in_two); +void *gotcha_realloc(void *buffer, size_t size); +void gotcha_free(void *free_me); +void gotcha_memcpy(void *dest, void *src, size_t size); +int gotcha_strncmp(const char *in_one, const char *in_two, int max_length); +char *gotcha_strstr(const char *searchIn, const char *searchFor); +int gotcha_strcmp(const char *in_one, const char *in_two); char *gotcha_getenv(const char *env); pid_t gotcha_getpid(); pid_t gotcha_gettid(); unsigned int gotcha_getpagesize(); int gotcha_open(const char *pathname, int flags, ...); -void *gotcha_mmap(void *addr, size_t length, int prot, int flags, - int fd, off_t offset); +void *gotcha_mmap(void *addr, size_t length, int prot, int flags, int fd, + off_t offset); int gotcha_atoi(const char *nptr); int gotcha_close(int fd); int gotcha_mprotect(void *addr, size_t len, int prot); ssize_t gotcha_read(int fd, void *buf, size_t count); ssize_t gotcha_write(int fd, const void *buf, size_t count); -void gotcha_assert_fail(const char *s, const char *file, unsigned int line, const char *function); +void gotcha_assert_fail(const char *s, const char *file, unsigned int line, + const char *function); void *gotcha_memset(void *s, int c, size_t n); -size_t gotcha_strlen(const char* str); -size_t gotcha_strnlen(const char* str, size_t max_length); -char* gotcha_strncat(char* dest, const char* src, size_t n); -char* gotcha_strtok(char* dest, const char* src, size_t n); +size_t gotcha_strlen(const char *str); +size_t gotcha_strnlen(const char *str, size_t max_length); +char *gotcha_strncat(char *dest, const char *src, size_t n); +char *gotcha_strtok(char *dest, const char *src, size_t n); -#define gotcha_dbg_printf(FORMAT, ...) gotcha_int_printf(2, FORMAT, ##__VA_ARGS__) +#define gotcha_dbg_printf(FORMAT, ...) \ + gotcha_int_printf(2, FORMAT, ##__VA_ARGS__) -#define gotcha_assert(A) \ - do { \ - if (! (A) ) \ - gotcha_assert_fail("" #A, __FILE__, __LINE__, __func__); \ - } while (0); +#define gotcha_assert(A) \ + do { \ + if (!(A)) gotcha_assert_fail("" #A, __FILE__, __LINE__, __func__); \ + } while (0); #endif diff --git a/ext/GOTCHA/src/library_filters.c b/ext/GOTCHA/src/library_filters.c index 028b53808..90b5c2e81 100644 --- a/ext/GOTCHA/src/library_filters.c +++ b/ext/GOTCHA/src/library_filters.c @@ -10,38 +10,36 @@ 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 "library_filters.h" + +#include "gotcha/gotcha.h" #include "libc_wrappers.h" -static const char* filter; -int (*libraryFilterFunc)(struct link_map*) = alwaysTrue; +static const char *filter; +int (*libraryFilterFunc)(struct link_map *) = alwaysTrue; -int alwaysTrue(struct link_map* candidate KNOWN_UNUSED){ - return 1; -} +int alwaysTrue(struct link_map *candidate KNOWN_UNUSED) { return 1; } -int trueIfNameMatches(struct link_map* target){ - int match = (filter) && (target) && (gotcha_strstr(target->l_name, filter) != 0); +int trueIfNameMatches(struct link_map *target) { + int match = + (filter) && (target) && (gotcha_strstr(target->l_name, filter) != 0); return match; } -int trueIfLast(struct link_map* target){ +int trueIfLast(struct link_map *target) { int ret = (target->l_next) ? 0 : 1; return ret; } -void onlyFilterLast(){ - setLibraryFilterFunc(trueIfLast); -} -void setLibraryFilterFunc(int(*new_func)(struct link_map*)){ +void gotcha_only_filter_last() { gotcha_set_library_filter_func(trueIfLast); } +void gotcha_set_library_filter_func(int (*new_func)(struct link_map *)) { libraryFilterFunc = new_func; } -void restoreLibraryFilterFunc(){ - setLibraryFilterFunc(alwaysTrue); +void gotcha_restore_library_filter_func() { + gotcha_set_library_filter_func(alwaysTrue); } -void filterLibrariesByName(const char* nameFilter){ +void gotcha_filter_libraries_by_name(const char *nameFilter) { filter = nameFilter; - setLibraryFilterFunc(trueIfNameMatches); + gotcha_set_library_filter_func(trueIfNameMatches); } - diff --git a/ext/GOTCHA/src/library_filters.h b/ext/GOTCHA/src/library_filters.h index 34dea03bd..3db57ace4 100644 --- a/ext/GOTCHA/src/library_filters.h +++ b/ext/GOTCHA/src/library_filters.h @@ -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 */ // TODO: Determine whether this interface should stay on in this form @@ -18,15 +18,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #ifndef GOTCHA_LIBRARY_FILTERS_H #define GOTCHA_LIBRARY_FILTERS_H #include + #include "gotcha_utils.h" -int alwaysTrue(struct link_map* candidate KNOWN_UNUSED); -extern int (*libraryFilterFunc)(struct link_map*); +int alwaysTrue(struct link_map *candidate KNOWN_UNUSED); +extern int (*libraryFilterFunc)(struct link_map *); -int trueIfNameMatches(struct link_map* target); -int trueIfLast(struct link_map* target); -void filterLibrariesByName(const char* nameFilter); -void onlyFilterLast(); -void setLibraryFilterFunc(int(*new_func)(struct link_map*)); -void restoreLibraryFilterFunc(); +int trueIfNameMatches(struct link_map *target); +int trueIfLast(struct link_map *target); #endif diff --git a/ext/GOTCHA/src/tool.c b/ext/GOTCHA/src/tool.c index 1f43b5eb7..8202a703d 100644 --- a/ext/GOTCHA/src/tool.c +++ b/ext/GOTCHA/src/tool.c @@ -10,189 +10,186 @@ 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 "tool.h" -#include "libc_wrappers.h" + #include "gotcha_utils.h" +#include "libc_wrappers.h" static tool_t *tools = NULL; static binding_t *all_bindings = NULL; -tool_t* get_tool_list(){ - return tools; -} +tool_t *get_tool_list() { return tools; } -int tool_equal(tool_t* t1, tool_t* t2){ - return gotcha_strcmp(t1->tool_name,t2->tool_name); +int tool_equal(tool_t *t1, tool_t *t2) { + return gotcha_strcmp(t1->tool_name, t2->tool_name); } -void remove_tool_from_list(struct tool_t* target){ - if(!tools){ - return; - } - if(!tool_equal(tools,target)){ - tools = tools->next_tool; - return; - } - struct tool_t *cur = tools; - while( (cur!=NULL) && (cur->next_tool != NULL) && (tool_equal(cur->next_tool,target))){ - cur = cur->next_tool; - } - if(!tool_equal(cur->next_tool,target)){ - cur->next_tool = target->next_tool; - } +void remove_tool_from_list(struct tool_t *target) { + if (!tools) { + return; // GCOVR_EXCL_LINE + } + if (!tool_equal(tools, target)) { + tools = tools->next_tool; + return; + } + struct tool_t *cur = tools; + while ((cur != NULL) && (cur->next_tool != NULL) && + (tool_equal(cur->next_tool, target))) { + cur = cur->next_tool; + } + if (!tool_equal(cur->next_tool, target)) { + cur->next_tool = target->next_tool; + } } -void reorder_tool(tool_t* new_tool) { +void reorder_tool(tool_t *new_tool) { int new_priority = new_tool->config.priority; - if(tools==NULL || tools->config.priority >= new_priority ){ - new_tool->next_tool = tools; - tools = new_tool; - } - else{ - struct tool_t *cur = tools; - while((cur->next_tool != NULL) && cur->next_tool->config.priority < new_priority){ - cur = cur->next_tool; - } - new_tool->next_tool = cur->next_tool; - cur->next_tool = new_tool; + if (tools == NULL || tools->config.priority >= new_priority) { + new_tool->next_tool = tools; + tools = new_tool; + } else { + struct tool_t *cur = tools; + while ((cur->next_tool != NULL) && + cur->next_tool->config.priority < new_priority) { + cur = cur->next_tool; + } + new_tool->next_tool = cur->next_tool; + cur->next_tool = new_tool; } } -tool_t *create_tool(const char *tool_name) -{ - debug_printf(1, "Found no existing tool with name %s\n",tool_name); - // TODO: ensure free - tool_t *newtool = (tool_t *) gotcha_malloc(sizeof(tool_t)); - if (!newtool) { - error_printf("Failed to malloc tool %s\n", tool_name); - return NULL; - } - newtool->tool_name = tool_name; - newtool->binding = NULL; - //newtool->next_tool = tools; - newtool->config = get_default_configuration(); - reorder_tool(newtool); - newtool->parent_tool = NULL; - create_hashtable(&newtool->child_tools, 24, - (hash_func_t) strhash, (hash_cmp_t) gotcha_strcmp); - //tools = newtool; - debug_printf(1, "Created new tool %s\n", tool_name); - return newtool; +tool_t *create_tool(const char *tool_name) { + debug_printf(1, "Found no existing tool with name %s\n", tool_name); + // TODO: ensure free + tool_t *newtool = (tool_t *)gotcha_malloc(sizeof(tool_t)); + if (!newtool) { + error_printf("Failed to malloc tool %s\n", tool_name); // GCOVR_EXCL_LINE + return NULL; // GCOVR_EXCL_LINE + } + newtool->tool_name = tool_name; + newtool->binding = NULL; + // newtool->next_tool = tools; + newtool->config = get_default_configuration(); + reorder_tool(newtool); + newtool->parent_tool = NULL; + create_hashtable(&newtool->child_tools, 24, (hash_func_t)strhash, + (hash_cmp_t)gotcha_strcmp); + // tools = newtool; + debug_printf(1, "Created new tool %s\n", tool_name); + return newtool; } -tool_t *get_tool(const char *tool_name) -{ - tool_t *t; - for (t = tools; t; t = t->next_tool) { - if (gotcha_strcmp(tool_name, t->tool_name) == 0) { - return t; - } - } - return NULL; +tool_t *get_tool(const char *tool_name) { + tool_t *t; + for (t = tools; t; t = t->next_tool) { + if (gotcha_strcmp(tool_name, t->tool_name) == 0) { + return t; + } + } + return NULL; } -binding_t *add_binding_to_tool(tool_t *tool, struct gotcha_binding_t *user_binding, int user_binding_size) -{ - binding_t *newbinding; - int result, i; - newbinding = (binding_t *) gotcha_malloc(sizeof(binding_t)); - newbinding->tool = tool; - struct internal_binding_t* internal_bindings = (struct internal_binding_t*)gotcha_malloc(sizeof(struct internal_binding_t)*user_binding_size); - for(i=0;iinternal_bindings = internal_bindings; - newbinding->internal_bindings_size = user_binding_size; - result = create_hashtable(&newbinding->binding_hash, user_binding_size * 2, - (hash_func_t) strhash, (hash_cmp_t) gotcha_strcmp); - if (result != 0) { - error_printf("Could not create hash table for %s\n", tool->tool_name); - goto error; // error is a label which frees allocated resources and returns NULL - } - - for (i = 0; i < user_binding_size; i++) { - result = addto_hashtable(&newbinding->binding_hash, (void *) user_binding[i].name, - (void *) (internal_bindings + i)); - if (result != 0) { - error_printf("Could not add hash entry for %s to table for tool %s\n", - user_binding[i].name, tool->tool_name); - goto error; // error is a label which frees allocated resources and returns NULL - } - } +binding_t *add_binding_to_tool(tool_t *tool, + struct gotcha_binding_t *user_binding, + int user_binding_size) { + binding_t *newbinding; + int result, i; + newbinding = (binding_t *)gotcha_malloc(sizeof(binding_t)); + newbinding->tool = tool; + struct internal_binding_t *internal_bindings = + (struct internal_binding_t *)gotcha_malloc( + sizeof(struct internal_binding_t) * user_binding_size); + for (i = 0; i < user_binding_size; i++) { + internal_bindings[i].next_binding = NULL; + internal_bindings[i].user_binding = &user_binding[i]; + *(user_binding[i].function_handle) = &internal_bindings[i]; + internal_bindings[i].associated_binding_table = newbinding; + } + newbinding->internal_bindings = internal_bindings; + newbinding->internal_bindings_size = user_binding_size; + result = create_hashtable(&newbinding->binding_hash, user_binding_size * 2, + (hash_func_t)strhash, (hash_cmp_t)gotcha_strcmp); + if (result != 0) { // GCOVR_EXCL_START + error_printf("Could not create hash table for %s\n", tool->tool_name); + goto error; // error is a label which frees allocated resources and returns + } // GCOVR_EXCL_STOP + + for (i = 0; i < user_binding_size; i++) { + result = + addto_hashtable(&newbinding->binding_hash, (void *)user_binding[i].name, + (void *)(internal_bindings + i)); + if (result != 0) { // GCOVR_EXCL_START + error_printf("Could not add hash entry for %s to table for tool %s\n", + user_binding[i].name, tool->tool_name); + goto error; // error is a label which frees allocated resources and + // returns NULL + } // GCOVR_EXCL_STOP + } - newbinding->next_tool_binding = tool->binding; - tool->binding = newbinding; + newbinding->next_tool_binding = tool->binding; + tool->binding = newbinding; - newbinding->next_binding = all_bindings; - all_bindings = newbinding; + newbinding->next_binding = all_bindings; + all_bindings = newbinding; - debug_printf(2, "Created new binding table of size %d for tool %s\n", user_binding_size, tool->tool_name); - return newbinding; + debug_printf(2, "Created new binding table of size %d for tool %s\n", + user_binding_size, tool->tool_name); + return newbinding; - error: - if (newbinding) - gotcha_free(newbinding); - return NULL; -} +error: // GCOVR_EXCL_START + if (newbinding) gotcha_free(newbinding); + return NULL; +} // GCOVR_EXCL_STOP -binding_t *get_bindings() -{ - return all_bindings; -} +binding_t *get_bindings() { return all_bindings; } -binding_t *get_tool_bindings(tool_t *tool) -{ - return tool->binding; -} +binding_t *get_tool_bindings(tool_t *tool) { return tool->binding; } -struct gotcha_configuration_t get_default_configuration(){ +struct gotcha_configuration_t get_default_configuration() { struct gotcha_configuration_t result; result.priority = UNSET_PRIORITY; return result; } -enum gotcha_error_t get_default_configuration_value(enum gotcha_config_key_t key, void* data){ +enum gotcha_error_t get_default_configuration_value( + enum gotcha_config_key_t key, void *data) { struct gotcha_configuration_t config = get_default_configuration(); - if(key==GOTCHA_PRIORITY){ - *((int*)(data)) = config.priority; + if (key == GOTCHA_PRIORITY) { + *((int *)(data)) = config.priority; } return GOTCHA_SUCCESS; - } -enum gotcha_error_t get_configuration_value(const char* tool_name, enum gotcha_config_key_t key, void* location_to_store_result){ - struct tool_t* tool = get_tool(tool_name); - if(tool==NULL){ - error_printf("Property being examined for nonexistent tool %s\n", tool_name); - return GOTCHA_INVALID_TOOL; +enum gotcha_error_t get_configuration_value(const char *tool_name, + enum gotcha_config_key_t key, + void *location_to_store_result) { + struct tool_t *tool = get_tool(tool_name); + if (tool == NULL) { + error_printf("Property being examined for nonexistent tool %s\n", + tool_name); + return GOTCHA_INVALID_TOOL; } get_default_configuration_value(key, location_to_store_result); int found_valid_value = 0; - while( (tool!=NULL) && !(found_valid_value) ){ + while ((tool != NULL) && !(found_valid_value)) { struct gotcha_configuration_t config = tool->config; - if(key==GOTCHA_PRIORITY){ + if (key == GOTCHA_PRIORITY) { int current_priority = config.priority; - if(current_priority!=UNSET_PRIORITY){ - *((int*)(location_to_store_result)) = config.priority; + if (current_priority != UNSET_PRIORITY) { + *((int *)(location_to_store_result)) = config.priority; found_valid_value = 1; return GOTCHA_SUCCESS; } - } - else{ + } else { error_printf("Invalid property being configured on tool %s\n", tool_name); return GOTCHA_INTERNAL; } tool = tool->parent_tool; } - return GOTCHA_SUCCESS; + return GOTCHA_SUCCESS; } -int get_priority(tool_t *tool) -{ - return tool->config.priority; -} +int get_priority(tool_t *tool) { return tool->config.priority; } diff --git a/ext/GOTCHA/src/tool.h b/ext/GOTCHA/src/tool.h index 3fc1daeed..8c7e9b36a 100644 --- a/ext/GOTCHA/src/tool.h +++ b/ext/GOTCHA/src/tool.h @@ -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 */ #if !defined(TOOL_H_) @@ -24,9 +24,7 @@ struct tool_t; #define UNSET_PRIORITY (-1) -enum gotcha_config_key_t { - GOTCHA_PRIORITY -}; +enum gotcha_config_key_t { GOTCHA_PRIORITY }; /** * A structure representing how a given tool's bindings are configured @@ -39,19 +37,19 @@ struct gotcha_configuration_t { * A per-library structure **/ #define LIB_GOT_MARKED_WRITEABLE (1 << 0) -#define LIB_PRESENT (1 << 1) +#define LIB_PRESENT (1 << 1) typedef struct library_t { - struct link_map *map; - struct library_t *next; - struct library_t *prev; - unsigned int generation; - int flags; + struct link_map *map; + struct library_t *next; + struct library_t *prev; + unsigned int generation; + int flags; } library_t; struct library_t *get_library(struct link_map *map); struct library_t *add_library(struct link_map *map); void remove_library(struct link_map *map); extern unsigned int current_generation; - + /** * The internal structure that matches the external gotcha_binding_t. * In addition to the data specified in the gotcha_binding_t, we add: @@ -59,12 +57,12 @@ extern unsigned int current_generation; * - a linked-list pointer to the next binding table **/ typedef struct binding_t { - struct tool_t *tool; - struct internal_binding_t *internal_bindings; - int internal_bindings_size; - hash_table_t binding_hash; - struct binding_t *next_tool_binding; - struct binding_t *next_binding; + struct tool_t *tool; + struct internal_binding_t *internal_bindings; + int internal_bindings_size; + hash_table_t binding_hash; + struct binding_t *next_tool_binding; + struct binding_t *next_binding; } binding_t; /** @@ -72,35 +70,39 @@ typedef struct binding_t { * tools this will become more important. **/ typedef struct tool_t { - const char *tool_name; - binding_t *binding; - struct tool_t *next_tool; - struct gotcha_configuration_t config; - hash_table_t child_tools; - struct tool_t * parent_tool; + const char *tool_name; + binding_t *binding; + struct tool_t *next_tool; + struct gotcha_configuration_t config; + hash_table_t child_tools; + struct tool_t *parent_tool; } tool_t; struct internal_binding_t { - struct binding_t* associated_binding_table; - struct gotcha_binding_t* user_binding; - struct internal_binding_t* next_binding; - void* wrappee_pointer; + struct binding_t *associated_binding_table; + struct gotcha_binding_t *user_binding; + struct internal_binding_t *next_binding; + void *wrappee_pointer; }; tool_t *create_tool(const char *tool_name); tool_t *get_tool(const char *tool_name); tool_t *get_tool_list(); -void reorder_tool(tool_t* new_tool); -void remove_tool_from_list(struct tool_t* target); +void reorder_tool(tool_t *new_tool); +void remove_tool_from_list(struct tool_t *target); void print_tools(); -binding_t *add_binding_to_tool(tool_t *tool, struct gotcha_binding_t *user_binding, int user_binding_size); +binding_t *add_binding_to_tool(tool_t *tool, + struct gotcha_binding_t *user_binding, + int user_binding_size); binding_t *get_bindings(); binding_t *get_tool_bindings(tool_t *tool); struct gotcha_configuration_t get_default_configuration(); -enum gotcha_error_t get_configuration_value(const char* tool_name, enum gotcha_config_key_t key, void* location_to_store_result); +enum gotcha_error_t get_configuration_value(const char *tool_name, + enum gotcha_config_key_t key, + void *location_to_store_result); int get_priority(tool_t *tool); -int tool_equal(tool_t* tool_1, tool_t* tool_2); +int tool_equal(tool_t *tool_1, tool_t *tool_2); #endif diff --git a/ext/GOTCHA/src/translations.c b/ext/GOTCHA/src/translations.c index ff88e3fc6..6325f8a98 100644 --- a/ext/GOTCHA/src/translations.c +++ b/ext/GOTCHA/src/translations.c @@ -10,29 +10,43 @@ 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 #include "translations.h" + +#include + #include "gotcha_utils.h" int main_wrapped; gotcha_wrappee_handle_t gotcha_internal_libc_main_wrappee_handle; gotcha_wrappee_handle_t gotcha_internal_main_wrappee_handle; - -int gotcha_internal_main(int argc, char** argv, char** envp){ - main_t underlying_main = gotcha_get_wrappee(gotcha_internal_main_wrappee_handle); +/** + * This function is excluded from coverage as this is only required for our + * wrapper to call main. + */ +// GCOV_EXCL_START +int gotcha_internal_main(int argc, char **argv, char **envp) { + main_t underlying_main = + gotcha_get_wrappee(gotcha_internal_main_wrappee_handle); return underlying_main(argc, argv, envp); } -int gotcha_internal_libc_start_main(int (*main_arg)(int, char**, char**) KNOWN_UNUSED, int argc, char** argv, void (*init)(), void (*fini)(), void (*rtld_fini)(), void* stack_end){ - libc_start_main_t underlying_libc_main = gotcha_get_wrappee(gotcha_internal_libc_main_wrappee_handle); - main_t underlying_main = gotcha_get_wrappee(gotcha_internal_main_wrappee_handle); - return underlying_libc_main(underlying_main, argc, argv, init, fini, rtld_fini, stack_end); +// GCOV_EXCL_STOP +int gotcha_internal_libc_start_main(int (*main_arg)(int, char **, char **) + KNOWN_UNUSED, + int argc, char **argv, void (*init)(), + void (*fini)(), void (*rtld_fini)(), + void *stack_end) { + libc_start_main_t underlying_libc_main = + gotcha_get_wrappee(gotcha_internal_libc_main_wrappee_handle); + main_t underlying_main = + gotcha_get_wrappee(gotcha_internal_main_wrappee_handle); + return underlying_libc_main(underlying_main, argc, argv, init, fini, + rtld_fini, stack_end); } struct gotcha_binding_t libc_main_wrappers[] = { - {"__libc_start_main", gotcha_internal_libc_start_main, &gotcha_internal_libc_main_wrappee_handle} -}; + {"__libc_start_main", gotcha_internal_libc_start_main, + &gotcha_internal_libc_main_wrappee_handle}}; struct gotcha_binding_t main_wrappers[] = { - {"main", gotcha_internal_main, &gotcha_internal_main_wrappee_handle} -}; + {"main", gotcha_internal_main, &gotcha_internal_main_wrappee_handle}}; diff --git a/ext/GOTCHA/src/translations.h b/ext/GOTCHA/src/translations.h index faa0b25cb..775aa57db 100644 --- a/ext/GOTCHA/src/translations.h +++ b/ext/GOTCHA/src/translations.h @@ -10,10 +10,10 @@ 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 */ -/** - * This file contains utilities for cases where users say something (wrap main) +/** + * This file contains utilities for cases where users say something (wrap main) * that doesn't work, but can be translated to something that does work */ #ifndef GOTCHA_SRC_TRANSLATIONS_H @@ -21,15 +21,18 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include /** "int main" wrapping handling */ -typedef int (*libc_start_main_t) (int (*)(int, char**, char**), int, char**, void (*)(), void (*)(), void (*)(), void*); -typedef int (*main_t) (int argc, char** argv, char** envp); +typedef int (*libc_start_main_t)(int (*)(int, char **, char **), int, char **, + void (*)(), void (*)(), void (*)(), void *); +typedef int (*main_t)(int argc, char **argv, char **envp); extern int main_wrapped; extern gotcha_wrappee_handle_t gotcha_internal_libc_main_wrappee_handle; extern gotcha_wrappee_handle_t gotcha_internal_main_wrappee_handle; -int gotcha_internal_main(int argc, char** argv, char** envp); -int gotcha_internal_libc_start_main (int (*)(int, char**, char**), int, char**, void (*)(), void (*)(), void (*)(), void*); +int gotcha_internal_main(int argc, char **argv, char **envp); +int gotcha_internal_libc_start_main(int (*)(int, char **, char **), int, + char **, void (*)(), void (*)(), void (*)(), + void *); extern struct gotcha_binding_t libc_main_wrappers[]; extern struct gotcha_binding_t main_wrappers[];