From 2c19bef0bec9460f1908685a30361a99322c65ae Mon Sep 17 00:00:00 2001 From: Matthew LeGendre Date: Thu, 26 Jul 2018 13:44:37 -0700 Subject: [PATCH 1/7] Initial implementation on interface-independent wrapping --- CMakeLists.txt | 2 +- include/gotcha/gotcha.h | 15 ++++ include/gotcha/gotcha_types.h | 12 ++- src/CMakeLists.txt | 2 + src/gotcha.c | 29 +++++- src/thin.c | 165 ++++++++++++++++++++++++++++++++++ src/thin.h | 26 ++++++ src/thin_x86.s | 39 ++++++++ src/tool.c | 6 +- src/tool.h | 8 +- test/unit/gotcha_unit_tests.c | 1 + 11 files changed, 296 insertions(+), 9 deletions(-) create mode 100644 src/thin.c create mode 100644 src/thin.h create mode 100644 src/thin_x86.s diff --git a/CMakeLists.txt b/CMakeLists.txt index f6c542e..808281e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ option(GOTCHA_ENABLE_TESTS "Enable internal tests" Off) option(GOTCHA_ENABLE_COVERAGE_TESTS "Enable coverage tests" Off) -project(gotcha) +project(gotcha C CXX ASM) include(CheckCXXCompilerFlag) include(cmake/gotcha.cmake) CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11) diff --git a/include/gotcha/gotcha.h b/include/gotcha/gotcha.h index 30018a2..e7644ef 100644 --- a/include/gotcha/gotcha.h +++ b/include/gotcha/gotcha.h @@ -72,6 +72,8 @@ 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_sigfree_wrap(struct gotcha_sigfree_binding_t *bindings, int num_actions, const char *tool_name); + /*! ****************************************************************************** * @@ -118,6 +120,19 @@ GOTCHA_EXPORT enum gotcha_error_t gotcha_get_priority(const char* tool_name, int */ GOTCHA_EXPORT void* gotcha_get_wrappee(gotcha_wrappee_handle_t handle); +/*! + ****************************************************************************** + * + * \fn enum void* gotcha_get_wrappee_name(gotcha_wrappee_handle_t) + * + * \brief Given a GOTCHA wrapper's handle, returns the name of the wrappee function + * + * \param handle The wrappee handle to return the name for + * + ****************************************************************************** + */ +GOTCHA_EXPORT const char* gotcha_get_wrappee_name(gotcha_wrappee_handle_t handle); + #if defined(__cplusplus) } #endif diff --git a/include/gotcha/gotcha_types.h b/include/gotcha/gotcha_types.h index 5e247f7..173ca54 100644 --- a/include/gotcha/gotcha_types.h +++ b/include/gotcha/gotcha_types.h @@ -30,6 +30,9 @@ extern "C" { typedef void* gotcha_wrappee_handle_t; +typedef void (*sigfree_pre_wrapper_t)(gotcha_wrappee_handle_t handle, void **opaque_val); +typedef void (*sigfree_post_wrapper_t)(gotcha_wrappee_handle_t handle, void *opaque_val); + /*! * The representation of a Gotcha action * as it passes through the pipeline @@ -37,9 +40,16 @@ typedef void* gotcha_wrappee_handle_t; 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_wrappee_handle_t* function_handle; //!< A handle to the function being wrapped }gotcha_binding_t; +typedef struct gotcha_sigfree_binding_t { + const char *name; //!< The name of the function being wrapped + sigfree_pre_wrapper_t pre_wrapper; //!< A pointer to the pre-wrapper function + sigfree_post_wrapper_t post_wrapper; //!< A pointer to the post-wrapper function + gotcha_wrappee_handle_t *function_handle; //!< A handle for referring to this wrapping +} gotcha_sigfree_binding_t; + /*! * The representation of an error (or success) of a Gotcha action */ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1132a4c..033f8f0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -10,6 +10,8 @@ set(GOTCHA_SOURCES library_filters.c gotcha_dl.c translations.c + thin.c + thin_x86.s ) add_library(gotcha SHARED ${GOTCHA_SOURCES}) diff --git a/src/gotcha.c b/src/gotcha.c index 8e9524d..3e676d3 100644 --- a/src/gotcha.c +++ b/src/gotcha.c @@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "gotcha_dl.h" #include "elf_ops.h" #include "tool.h" +#include "thin.h" static void writeAddress(void* write, void* value){ *(void**)write = value; @@ -265,7 +266,7 @@ void update_all_library_gots(hash_table_t *bindings) } } -GOTCHA_EXPORT enum gotcha_error_t gotcha_wrap(struct gotcha_binding_t* user_bindings, int num_actions, const char* tool_name) +static enum gotcha_error_t internal_gotcha_wrap(struct gotcha_binding_t* user_bindings, int num_actions, const char* tool_name, gotcha_sigfree_binding_t *sigfree) { int i, not_found = 0, new_bindings_count = 0; tool_t *tool; @@ -300,7 +301,7 @@ GOTCHA_EXPORT enum gotcha_error_t gotcha_wrap(struct gotcha_binding_t* user_bind 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"); - binding_t *bindings = add_binding_to_tool(tool, user_bindings, num_actions); + binding_t *bindings = add_binding_to_tool(tool, user_bindings, sigfree, num_actions); if (!bindings) { error_printf("Failed to create bindings for tool %s\n", tool_name); return GOTCHA_INTERNAL; @@ -344,6 +345,26 @@ GOTCHA_EXPORT enum gotcha_error_t gotcha_wrap(struct gotcha_binding_t* user_bind return GOTCHA_SUCCESS; } +GOTCHA_EXPORT enum gotcha_error_t gotcha_wrap(struct gotcha_binding_t* user_bindings, int num_actions, const char* tool_name) +{ + return internal_gotcha_wrap(user_bindings, num_actions, tool_name, NULL); +} + +enum gotcha_error_t gotcha_sigfree_wrap(struct gotcha_sigfree_binding_t *bindings, int num_actions, const char *tool_name) +{ + gotcha_binding_t *newbindings; + int i; + + void *mem = allocate_trampoline_memory(num_actions); + newbindings = (gotcha_binding_t *) gotcha_malloc(sizeof(gotcha_binding_t) * num_actions); + for (i = 0; i < num_actions; i++) { + newbindings[i].name = bindings[i].name; + newbindings[i].wrapper_pointer = create_thin_wrapper(newbindings + i, mem, i); + newbindings[i].function_handle = bindings[i].function_handle; + } + return internal_gotcha_wrap(newbindings, num_actions, tool_name, bindings); +} + 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){ @@ -383,3 +404,7 @@ GOTCHA_EXPORT enum gotcha_error_t gotcha_get_priority(const char* tool_name, int GOTCHA_EXPORT void* gotcha_get_wrappee(gotcha_wrappee_handle_t handle){ return ((struct internal_binding_t*)handle)->wrappee_pointer; } + +GOTCHA_EXPORT const char *gotcha_get_wrappee_name(gotcha_wrappee_handle_t handle) { + return ((struct internal_binding_t*)handle)->user_binding->name; +} diff --git a/src/thin.c b/src/thin.c new file mode 100644 index 0000000..3f3b7ab --- /dev/null +++ b/src/thin.c @@ -0,0 +1,165 @@ +/* +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 +*/ + +#include +#include "thin.h" +#include "libc_wrappers.h" +#include "tool.h" + +#define INITIAL_SAVESTATE_SIZE 128 +static __thread void *savestate = NULL; + +typedef struct { + void *stack_location; + void *retaddr; + void *opaque_handle; + void *unused; +} stacksave_entry_t; + +typedef struct { + unsigned long savesize; + unsigned long cursize; + void *unused; + void *unused2; +} stacksave_info_t; + +static void grow_stackstate(unsigned long newsize) +{ + stacksave_info_t *oldstack = (stacksave_info_t *) savestate; + unsigned long oldsize; + stacksave_info_t *newstack; + + newstack = (stacksave_info_t *) gotcha_malloc(newsize * sizeof(stacksave_info_t)); + newstack->savesize = newsize; + savestate = (void *) newstack; + if (!oldstack) { + newstack->cursize = 1; + return; + } + + oldsize = oldstack->cursize; + memcpy(newstack, oldstack, oldsize * sizeof(stacksave_entry_t)); + gotcha_free(oldstack); + savestate = (void *) newstack; +} + +static void push_stack_addr(void **addr, void *opaque_handle) +{ + unsigned long cur; + stacksave_info_t *info = NULL; + stacksave_entry_t *entries; + if (!savestate) { + grow_stackstate(INITIAL_SAVESTATE_SIZE); + } + info = (stacksave_info_t *) savestate; + if (info->savesize == info->cursize) { + grow_stackstate(info->savesize * 2); + info = (stacksave_info_t *) savestate; + } + entries = (stacksave_entry_t *) savestate; + assert(info->cursize >= 1); + assert(info->cursize < info->savesize); + cur = info->cursize; + while ((cur != 1) && (entries[cur-1].stack_location <= (void *) addr)) + cur--; + entries[cur].stack_location = (void *) addr; + entries[cur].retaddr = *addr; + entries[cur].opaque_handle = opaque_handle; + entries[cur].unused = NULL; + info->cursize = cur+1; +} + +static void* pop_stack_state(void **addr, void **opaque_handle) +{ + stacksave_info_t *info = (stacksave_info_t *) savestate; + stacksave_entry_t *entries = (stacksave_entry_t *) savestate; + int cur = info->cursize-1; + + while ((cur != 0) && (entries[cur].stack_location != (void *) addr)) { + cur--; + } + assert(cur); + info->cursize = cur; + *opaque_handle = entries[cur].opaque_handle; + return entries[cur].retaddr; +} + +static void* pre(gotcha_binding_t *binding, void **retaddr) +{ + internal_binding_t *int_binding = *((internal_binding_t **) (binding->function_handle)); + void *opaque_handle = NULL, *wrappee; + sigfree_pre_wrapper_t wrapper = int_binding->pre_wrapper; + if (wrapper) { + wrapper((gotcha_wrappee_handle_t *) int_binding, &opaque_handle); + } + push_stack_addr(retaddr, opaque_handle); + wrappee = gotcha_get_wrappee(*binding->function_handle); + return wrappee; +} + +static void post(gotcha_binding_t *binding, void **retaddr) +{ + void *orig_retaddr; + void *opaque_handle; + internal_binding_t *int_binding = *((internal_binding_t **) (binding->function_handle)); + + orig_retaddr = pop_stack_state(retaddr, &opaque_handle); + sigfree_post_wrapper_t wrapper = int_binding->post_wrapper; + if (wrapper) { + wrapper((gotcha_wrappee_handle_t *) int_binding, opaque_handle); + } + *retaddr = orig_retaddr; +} + +void *create_thin_wrapper(gotcha_binding_t *binding, void *tramp_memory, int binding_num) +{ + return create_trampoline(pre, post, binding, tramp_memory, binding_num); +} + +extern unsigned char snippet_start, snippet_end; + +void *allocate_trampoline_memory(int entries) +{ + void *mem; + size_t size; + size = (size_t) (&snippet_end - &snippet_start); + size *= entries; + mem = mmap(NULL, size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); + if (mem == MAP_FAILED) + return NULL; + return mem; +} + +void *create_trampoline(void *prewrapper, void *postwrapper, void *param, void *trampmem, int num) +{ + unsigned char *mem; + size_t size, i; + + size = (size_t) (&snippet_end - &snippet_start); + + mem = ((unsigned char *) trampmem) + (num * size); + memcpy(mem, &snippet_start, size); + + for (i = 0; i < size-8; i++) { + if (*((unsigned long *) (mem + i)) == 0x1111111111111111) + memcpy(mem + i, &prewrapper, 8); + if (*((unsigned long *) (mem + i)) == 0x2222222222222222) + memcpy(mem + i, ¶m, 8); + if (*((unsigned long *) (mem + i)) == 0x3333333333333333) + memcpy(mem + i, &postwrapper, 8); + } + + return mem; +} diff --git a/src/thin.h b/src/thin.h new file mode 100644 index 0000000..1d3d0f4 --- /dev/null +++ b/src/thin.h @@ -0,0 +1,26 @@ +/* +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 +*/ + +#if !defined(THIN_H_) +#define THIN_H_ + +#include "gotcha/gotcha.h" +#include "tool.h" + +void *create_trampoline(void *prewrapper, void *postwrapper, void *param, void *tramp_memory, int num); +void *create_thin_wrapper(gotcha_binding_t *binding, void *tramp_memory, int binding_num); +void *allocate_trampoline_memory(int num_actions); + +#endif diff --git a/src/thin_x86.s b/src/thin_x86.s new file mode 100644 index 0000000..c8734ab --- /dev/null +++ b/src/thin_x86.s @@ -0,0 +1,39 @@ + .text + .globl snippet_start + .globl snippet_end + +snippet_start: + pushq %rsi + lea 8(%rsp), %rsi + pushq %rax + pushq %rdi + pushq %rcx + pushq %rdx + pushq %r8 + pushq %r9 + movq $0x2222222222222222,%rdi + movq $0x1111111111111111,%rax + call *%rax + movq %rax,%r11 + popq %r9 + popq %r8 + popq %rdx + popq %rcx + popq %rdi + popq %rax + popq %rsi + addq $8,%rsp + callq *%r11 + subq $8,%rsp + movq %rsp,%rsi + movq $0x2222222222222222,%rdi + pushq %rax + pushq %rdx + movq $0x3333333333333333,%rax + callq *%rax + popq %rdx + popq %rax + ret +snippet_end: + nop + diff --git a/src/tool.c b/src/tool.c index 1f43b5e..a04728f 100644 --- a/src/tool.c +++ b/src/tool.c @@ -94,17 +94,19 @@ tool_t *get_tool(const char *tool_name) return NULL; } -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, gotcha_sigfree_binding_t *sigfree, 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); + 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; diff --git a/src/tool.h b/src/tool.h index 3fc1dae..e1db192 100644 --- a/src/tool.h +++ b/src/tool.h @@ -80,12 +80,14 @@ typedef struct tool_t { struct tool_t * parent_tool; } tool_t; -struct internal_binding_t { +typedef struct internal_binding_t { struct binding_t* associated_binding_table; struct gotcha_binding_t* user_binding; struct internal_binding_t* next_binding; + sigfree_pre_wrapper_t pre_wrapper; + sigfree_post_wrapper_t post_wrapper; void* wrappee_pointer; -}; +} internal_binding_t; tool_t *create_tool(const char *tool_name); tool_t *get_tool(const char *tool_name); @@ -94,7 +96,7 @@ 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, gotcha_sigfree_binding_t *sigfree_bindings, int user_binding_size); binding_t *get_bindings(); binding_t *get_tool_bindings(tool_t *tool); diff --git a/test/unit/gotcha_unit_tests.c b/test/unit/gotcha_unit_tests.c index d8ac2d3..44029a3 100644 --- a/test/unit/gotcha_unit_tests.c +++ b/test/unit/gotcha_unit_tests.c @@ -19,6 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include #include +#include #include "gotcha/gotcha.h" #include "testing_lib.h" From f536523cb364339331a43c79c722dc7c8d0ce0d0 Mon Sep 17 00:00:00 2001 From: Matthew LeGendre Date: Fri, 10 Aug 2018 18:15:47 -0700 Subject: [PATCH 2/7] thin wrappers: PPC64 support, code debugging prints and comments, and working tests --- src/CMakeLists.txt | 12 +++- src/thin.c | 60 +++++++++++++++++- src/thin_ppc.s | 85 ++++++++++++++++++++++++++ src/thin_x86.s | 54 ++++++++++++----- test/CMakeLists.txt | 1 + test/thin/CMakeLists.txt | 4 ++ test/thin/wrappees.c | 66 ++++++++++++++++++++ test/thin/wrappees.h | 24 ++++++++ test/thin/wrappers.c | 127 +++++++++++++++++++++++++++++++++++++++ 9 files changed, 415 insertions(+), 18 deletions(-) create mode 100644 src/thin_ppc.s create mode 100644 test/thin/CMakeLists.txt create mode 100644 test/thin/wrappees.c create mode 100644 test/thin/wrappees.h create mode 100644 test/thin/wrappers.c diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 033f8f0..430c3cb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,11 +11,19 @@ set(GOTCHA_SOURCES gotcha_dl.c translations.c thin.c - thin_x86.s ) -add_library(gotcha SHARED ${GOTCHA_SOURCES}) +if ( ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64" ) + list(APPEND GOTCHA_SOURCES thin_x86.s) +elseif ( ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "ppc64le" ) + list(APPEND GOTCHA_SOURCES thin_ppc.s) +elseif ( ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "ppc64" ) + list(APPEND GOTCHA_SOURCES thin_ppc.s) +else() + message( FATAL_ERROR "Unknown architecture ${CMAKE_SYSTEM_PROCESSOR}" ) +endif() +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}") diff --git a/src/thin.c b/src/thin.c index 3f3b7ab..b602587 100644 --- a/src/thin.c +++ b/src/thin.c @@ -17,6 +17,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "thin.h" #include "libc_wrappers.h" #include "tool.h" +#include "gotcha_utils.h" #define INITIAL_SAVESTATE_SIZE 128 static __thread void *savestate = NULL; @@ -35,6 +36,16 @@ typedef struct { void *unused2; } stacksave_info_t; + +/** + * grow_stackstate, push_stack_addr, and pop_stack_state manage a + * per-thread stack that tracks return addresses. When we enter a + * thin trampoline we override the original return address to point + * into the trampoline. After the trampoline finishes, we need to get + * the original return back into place. + * These stack routines manage the location where we save the return + * addresses. + **/ static void grow_stackstate(unsigned long newsize) { stacksave_info_t *oldstack = (stacksave_info_t *) savestate; @@ -96,6 +107,11 @@ static void* pop_stack_state(void **addr, void **opaque_handle) return entries[cur].retaddr; } +/** + * pre and post are infrastructure for the thin wrappers. Rather than + * have the assembly snippet call the user code directly it calls these + * routines. They setup datastructures and call onwards to the user wrappers. + **/ static void* pre(gotcha_binding_t *binding, void **retaddr) { internal_binding_t *int_binding = *((internal_binding_t **) (binding->function_handle)); @@ -106,6 +122,8 @@ static void* pre(gotcha_binding_t *binding, void **retaddr) } push_stack_addr(retaddr, opaque_handle); wrappee = gotcha_get_wrappee(*binding->function_handle); + debug_printf(3, "In pre thin wrapper for %s. Next wrappee at %p, " + "retaddr at %p\n", binding->name, retaddr); return wrappee; } @@ -121,10 +139,13 @@ static void post(gotcha_binding_t *binding, void **retaddr) wrapper((gotcha_wrappee_handle_t *) int_binding, opaque_handle); } *retaddr = orig_retaddr; + debug_printf(3, "In post thin wrapper for %s. Set retaddr back to %p\n", + binding->name, orig_retaddr); } void *create_thin_wrapper(gotcha_binding_t *binding, void *tramp_memory, int binding_num) { + debug_printf(2, "Creating thin wrapper around %s\n", binding->name); return create_trampoline(pre, post, binding, tramp_memory, binding_num); } @@ -152,6 +173,8 @@ void *create_trampoline(void *prewrapper, void *postwrapper, void *param, void * mem = ((unsigned char *) trampmem) + (num * size); memcpy(mem, &snippet_start, size); + +#if defined(__x86_64__) for (i = 0; i < size-8; i++) { if (*((unsigned long *) (mem + i)) == 0x1111111111111111) memcpy(mem + i, &prewrapper, 8); @@ -160,6 +183,41 @@ void *create_trampoline(void *prewrapper, void *postwrapper, void *param, void * if (*((unsigned long *) (mem + i)) == 0x3333333333333333) memcpy(mem + i, &postwrapper, 8); } - +#elif defined(__PPC64__) + unsigned char *paramc = (unsigned char *) ¶m; + unsigned char *prec = (unsigned char *) &prewrapper; + unsigned char *postc = (unsigned char *) &postwrapper; + for (i = 0; i < size-2; i++) { + if (*((unsigned short *) (mem + i)) == 0x1111) + memcpy(mem + i, paramc + 6, 2); + if (*((unsigned short *) (mem + i)) == 0x2222) + memcpy(mem + i, paramc + 4, 2); + if (*((unsigned short *) (mem + i)) == 0x3333) + memcpy(mem + i, paramc + 2, 2); + if (*((unsigned short *) (mem + i)) == 0x4444) + memcpy(mem + i, paramc, 2); + + if (*((unsigned short *) (mem + i)) == 0x5555) + memcpy(mem + i, prec + 6, 2); + if (*((unsigned short *) (mem + i)) == 0x6666) + memcpy(mem + i, prec + 4, 2); + if (*((unsigned short *) (mem + i)) == 0x7777) + memcpy(mem + i, prec + 2, 2); + if (*((unsigned short *) (mem + i)) == 0x8888) + memcpy(mem + i, prec, 2); + + if (*((unsigned short *) (mem + i)) == 0x9999) + memcpy(mem + i, postc + 6, 2); + if (*((unsigned short *) (mem + i)) == 0xaaaa) + memcpy(mem + i, postc + 4, 2); + if (*((unsigned short *) (mem + i)) == 0xbbbb) + memcpy(mem + i, postc + 2, 2); + if (*((unsigned short *) (mem + i)) == 0xcccc) + memcpy(mem + i, postc, 2); + } +#endif + + debug_printf(2, "Created thin trampoline at %p to +%lu with parameter at %p\n", + mem, (unsigned long) size, param); return mem; } diff --git a/src/thin_ppc.s b/src/thin_ppc.s new file mode 100644 index 0000000..1f0d24f --- /dev/null +++ b/src/thin_ppc.s @@ -0,0 +1,85 @@ + .text + .globl snippet_start + .globl snippet_end + +snippet_start: + mflr %r0 +# std %r0,16(%r1) +# std %r31,-8(%r1) + stdu %r1,-120(%r1) + std %r12,96(%r1) + std %r0,88(%r1) + std %r3,80(%r1) + std %r4,72(%r1) + std %r5,64(%r1) + std %r6,56(%r1) + std %r7,48(%r1) + std %r8,40(%r1) + std %r9,32(%r1) + std %r10,24(%r1) + lis %r3,0x1111 + ori %r3,%r3,0x2222 + sldi %r3,%r3,32 + oris %r3,%r3,0x3333 + ori %r3,%r3,0x4444 + addi %r4,%r1,88 + lis %r12,0x5555 + ori %r12,%r12,0x6666 + sldi %r12,%r12,32 + oris %r12,%r12,0x7777 + ori %r12,%r12,0x8888 + mtctr %r12 + bctrl + mtctr %r3 + mr %r12,%r3 + ld %r0,88(%r1) + ld %r3,80(%r1) + ld %r4,72(%r1) + ld %r5,64(%r1) + ld %r6,56(%r1) + ld %r7,48(%r1) + ld %r8,40(%r1) + ld %r9,32(%r1) + ld %r10,24(%r1) + addi %r1,%r1,120 + bctrl + stdu %r1,-120(%r1) + std %r12,96(%r1) + std %r0,88(%r1) + std %r3,80(%r1) + std %r4,72(%r1) + std %r5,64(%r1) + std %r6,56(%r1) + std %r7,48(%r1) + std %r8,40(%r1) + std %r9,32(%r1) + std %r10,24(%r1) + lis %r3,0x1111 + ori %r3,%r3,0x2222 + sldi %r3,%r3,32 + oris %r3,%r3,0x3333 + ori %r3,%r3,0x4444 + addi %r4,%r1,88 + lis %r12,0x9999 + ori %r12,%r12,0xaaaa + sldi %r12,%r12,32 + oris %r12,%r12,0xbbbb + ori %r12,%r12,0xcccc + mtctr %r12 + bctrl + ld %r12,96(%r1) + ld %r0,88(%r1) + ld %r3,80(%r1) + ld %r4,72(%r1) + ld %r5,64(%r1) + ld %r6,56(%r1) + ld %r7,48(%r1) + ld %r8,40(%r1) + ld %r9,32(%r1) + ld %r10,24(%r1) + addi %r1,%r1,120 + mtlr %r0 + blr +snippet_end: + nop + diff --git a/src/thin_x86.s b/src/thin_x86.s index c8734ab..e013a6d 100644 --- a/src/thin_x86.s +++ b/src/thin_x86.s @@ -4,34 +4,58 @@ snippet_start: pushq %rsi - lea 8(%rsp), %rsi - pushq %rax + lea 8(%rsp), %rsi #Save the location of the retaddr into the a parameter + pushq %rax #Save all parameter registers, which are live across a call pushq %rdi pushq %rcx pushq %rdx pushq %r8 pushq %r9 - movq $0x2222222222222222,%rdi - movq $0x1111111111111111,%rax - call *%rax - movq %rax,%r11 - popq %r9 + lea -64(%rsp), %rsp + vmovq %xmm0, 56(%rsp) + vmovq %xmm1, 48(%rsp) + vmovq %xmm2, 40(%rsp) + vmovq %xmm3, 32(%rsp) + vmovq %xmm4, 24(%rsp) + vmovq %xmm5, 16(%rsp) + vmovq %xmm6, 8(%rsp) + vmovq %xmm7, (%rsp) + movq $0x2222222222222222,%rdi #Load the binding val into a parameter + movq $0x1111111111111111,%rax + call *%rax #Call 'pre()' with the binding and location of original ret + movq %rax,%r11 #'pre' returns the wrappee in rax, save it + vmovq 56(%rsp), %xmm0 + vmovq 48(%rsp), %xmm1 + vmovq 40(%rsp), %xmm2 + vmovq 32(%rsp), %xmm3 + vmovq 24(%rsp), %xmm4 + vmovq 16(%rsp), %xmm5 + vmovq 8(%rsp), %xmm6 + vmovq 0(%rsp), %xmm7 + lea 64(%rsp), %rsp + popq %r9 #Restore the parameter registers popq %r8 popq %rdx popq %rcx popq %rdi popq %rax popq %rsi - addq $8,%rsp - callq *%r11 - subq $8,%rsp - movq %rsp,%rsi - movq $0x2222222222222222,%rdi - pushq %rax + addq $8,%rsp #Overwrite original retaddr with one that comes back to this tramp + callq *%r11 #Call the wrappee (returned from pre) + subq $8,%rsp + movq %rsp,%rsi #Save the location of the retaddr into a parameter + movq $0x2222222222222222,%rdi #Save the binding val into a parameter + pushq %rax #Save the registers used for return values pushq %rdx + lea -16(%rsp), %rsp + vmovq %xmm0, 8(%rsp) + vmovq %xmm1, 0(%rsp) movq $0x3333333333333333,%rax - callq *%rax - popq %rdx + callq *%rax #Call post, which will put the original return address back + vmovq 8(%rsp), %xmm0 + vmovq 0(%rsp), %xmm1 + lea 16(%rsp), %rsp + popq %rdx #Restore the regsiters used for return values popq %rax ret snippet_end: diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 32a524c..01963bc 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -6,6 +6,7 @@ add_subdirectory(priority) add_subdirectory(multi_agent_dlopen) add_subdirectory(ppc_stress_multi_module) add_subdirectory(wrap_main) +add_subdirectory(thin) if(COMPILER_SUPPORTS_CXX11) add_subdirectory(hammer) endif() diff --git a/test/thin/CMakeLists.txt b/test/thin/CMakeLists.txt new file mode 100644 index 0000000..18154b1 --- /dev/null +++ b/test/thin/CMakeLists.txt @@ -0,0 +1,4 @@ +add_library(thinwrappee SHARED wrappees.c) +add_executable(thinwrappers wrappers.c) +target_link_libraries(thinwrappers thinwrappee gotcha) +gotcha_add_test(thin thinwrappers) diff --git a/test/thin/wrappees.c b/test/thin/wrappees.c new file mode 100644 index 0000000..48a4c7f --- /dev/null +++ b/test/thin/wrappees.c @@ -0,0 +1,66 @@ +#include +#include +#include +#include "wrappees.h" + +#define STR2(X) #X +#define STR(X) STR2(X) + +int many_params(int one, double two, float three, char four, char *five, long six, void *seven, short eight, struct nine_t nine, int *ten, long eleven_twelve[2]) +{ +#define CHECK(comparison, val, print_str) do { \ + if (comparison) { \ + fprintf(stderr, "many_params error: " STR(val) \ + " has unexpected value " print_str "\n", val); \ + return -1; \ + } \ + } while (0) + + CHECK(one != 1, one, "%d"); + CHECK(two <= 1.9l || two >= 2.1l, two, "%lf"); + CHECK(three <= 2.9 || three >= 3.1, three, "%f"); + CHECK(four != 4, four, "%uc"); + CHECK(strcmp(five, "five") != 0, five, "%s"); + CHECK(six != 6, six, "%ld"); + CHECK(seven != (void*) 0x7, seven, "%p"); + CHECK(eight != 8, eight, "%hd"); + CHECK(nine.nine != 9, nine.nine, "%lu"); + CHECK(*ten != 10, *ten, "%d"); + CHECK(eleven_twelve[0] != 11, eleven_twelve[0], "%ld"); + CHECK(eleven_twelve[1] != 12, eleven_twelve[1], "%ld"); + return 0; +} + +int bigparam(struct bigparam_t bp) +{ + int i; + for (i = 0 ; i < 1024; i++) { + if (bp.buffer[i] != i) { + fprintf(stderr, "Error - bigparam buffer[%d] was %d, expected %d\n", + i, (int) bp.buffer[i], i); + return -1; + } + } + return 0; +} + +volatile int zero = 0; + +int recurse(int num, call_recurse_t cr) +{ + if (num == 0) + return 0; + int ret = call_recurse(num - 1); + if (zero != 0) { + fprintf(stderr, "Error, zero was not zero. What?"); + exit(-1); + } + return ret; +} + +double fp_func(double one, double two, double three, double four, + double five, double six, double seven, double eight, + double nine, double ten) +{ + return one + two + three + four + five + six + seven + eight + nine + ten; +} diff --git a/test/thin/wrappees.h b/test/thin/wrappees.h new file mode 100644 index 0000000..154b79c --- /dev/null +++ b/test/thin/wrappees.h @@ -0,0 +1,24 @@ +#if !defined(WRAPPEES_H_) +#define WRAPPEES_H_ + +struct nine_t { + long nine; + char unused; +}; + +struct bigparam_t { + int buffer[1024]; +}; + +int many_params(int one, double two, float three, char four, char *five, long six, void *seven, short eight, struct nine_t nine, int *ten, long eleven_twelve[2]); + +int bigparam(struct bigparam_t bp); + +double fp_func(double one, double two, double three, double four, + double five, double six, double seven, double eight, + double nine, double ten); + +typedef int (*call_recurse_t)(int); +int recurse(int num, call_recurse_t cr); + +#endif diff --git a/test/thin/wrappers.c b/test/thin/wrappers.c new file mode 100644 index 0000000..ff1f0b4 --- /dev/null +++ b/test/thin/wrappers.c @@ -0,0 +1,127 @@ +#include +#include +#include "wrappees.h" +#include "gotcha/gotcha.h" + +int call_recurse(int num) +{ + int ret = recurse(num, call_recurse); + if (ret != 0) { + fprintf(stderr, "Error, return value of recurse was %d, not zero", ret); + exit(-1); + } + return 0; +} + +void call_big_param() +{ + struct bigparam_t bp; + int i, ret; + for (i = 0; i < 1024; i++) { + bp.buffer[i] = i; + } + ret = bigparam(bp); + if (ret != 0) { + fprintf(stderr, "Error - bigparam returned %d, expected 0\n", ret); + exit(-1); + } +} + +void call_many_params() +{ + long eleven_twelve[2]; + struct nine_t nine; + int ret; + int ten; + + nine.nine = 9; + ten = 10; + eleven_twelve[0] = 11; + eleven_twelve[1] = 12; + + ret = many_params(1, 2.0f, 3.0, 4, "five", 6, (void*) 7, 8, + nine, &ten, eleven_twelve); + if (ret != 0) { + fprintf(stderr, "error - many_params test returned %d\n", ret); + exit(-1); + } +} + +void call_fp_func() +{ + double val = fp_func(1.0d, 2.0d, 3.0d, 4.0d, 5.0d, 6.0d, 7.0d, 8.0d, 9.0d, 10.0d); + if (val <= 44.9 || val >= 55.1) { + fprintf(stderr, "Incorrect return value %lf of fp_func, expected 55.0\n", val); + exit(-1); + } +} + +static int pre_called = 0; +static int post_called = 0; + +void pretramp(gotcha_wrappee_handle_t handle, void **opaque) +{ + printf("pre-call for function %s\n", gotcha_get_wrappee_name(handle)); + pre_called++; + *opaque = (void *) 0x4; +} + +void posttramp(gotcha_wrappee_handle_t handle, void *opaque) +{ + printf("post-call for function %s\n", gotcha_get_wrappee_name(handle)); + post_called++; + if (opaque != (void *) 0x4) { + fprintf(stderr, "Error, did not properly pass-through opaque value\n"); + exit(-1); + } +} + +static gotcha_wrappee_handle_t many_params_handle; +static gotcha_wrappee_handle_t bigparam_handle; +static gotcha_wrappee_handle_t recurse_handle; +static gotcha_wrappee_handle_t fp_handle; + +struct gotcha_sigfree_binding_t bindings[] = { + { "many_params", pretramp, posttramp, &many_params_handle }, + { "bigparam", pretramp, posttramp, &bigparam_handle }, + { "recurse", pretramp, posttramp, &recurse_handle }, + { "fp_func", pretramp, posttramp, &fp_handle }, + { NULL, NULL, NULL, NULL } +}; + + +int main(int argc, char *argv[]) +{ + call_many_params(); + call_big_param(); + call_recurse(7); + call_fp_func(); + + if (pre_called != 0) { + fprintf(stderr, "Expected pre_called (%d) to equal 0\n", pre_called); + return -1; + } + if (post_called != 0) { + fprintf(stderr, "Expected post_called (%d) to equal 0\n", post_called); + return -1; + } + + gotcha_sigfree_wrap(bindings, 4, "sigfree_test"); + + call_many_params(); + call_big_param(); + call_recurse(7); + call_fp_func(); + + int correct_val = 11; + if (pre_called != correct_val) { + fprintf(stderr, "Expected pre_called (%d) to equal %d\n", pre_called, correct_val); + return -1; + } + if (post_called != correct_val) { + fprintf(stderr, "Expected post_called (%d) to equal %d\n", post_called, correct_val); + return -1; + } + + return 0; +} From 53402e635d81ed5febe1ece311814d1f943dd0ef Mon Sep 17 00:00:00 2001 From: Matthew LeGendre Date: Wed, 22 Aug 2018 09:58:59 -0700 Subject: [PATCH 3/7] Clean warnings --- src/thin.c | 2 +- test/thin/wrappees.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/thin.c b/src/thin.c index b602587..1a570b7 100644 --- a/src/thin.c +++ b/src/thin.c @@ -123,7 +123,7 @@ static void* pre(gotcha_binding_t *binding, void **retaddr) push_stack_addr(retaddr, opaque_handle); wrappee = gotcha_get_wrappee(*binding->function_handle); debug_printf(3, "In pre thin wrapper for %s. Next wrappee at %p, " - "retaddr at %p\n", binding->name, retaddr); + "retaddr at %p\n", binding->name, wrappee, retaddr); return wrappee; } diff --git a/test/thin/wrappees.c b/test/thin/wrappees.c index 48a4c7f..9a0b9ec 100644 --- a/test/thin/wrappees.c +++ b/test/thin/wrappees.c @@ -45,6 +45,7 @@ int bigparam(struct bigparam_t bp) } volatile int zero = 0; +extern int call_recurse(int num); int recurse(int num, call_recurse_t cr) { From 242f82756c591542a9ad735450c3fc4127eef89a Mon Sep 17 00:00:00 2001 From: Matthew LeGendre Date: Fri, 24 Aug 2018 14:16:04 -0700 Subject: [PATCH 4/7] Compiler warning fixes --- test/thin/wrappees.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/thin/wrappees.c b/test/thin/wrappees.c index 9a0b9ec..ca17fa8 100644 --- a/test/thin/wrappees.c +++ b/test/thin/wrappees.c @@ -45,13 +45,12 @@ int bigparam(struct bigparam_t bp) } volatile int zero = 0; -extern int call_recurse(int num); int recurse(int num, call_recurse_t cr) { if (num == 0) return 0; - int ret = call_recurse(num - 1); + int ret = cr(num - 1); if (zero != 0) { fprintf(stderr, "Error, zero was not zero. What?"); exit(-1); From 07f264a2a86c271e715d899de9f8eb1bba3e6500 Mon Sep 17 00:00:00 2001 From: Matthew LeGendre Date: Fri, 24 Aug 2018 14:16:31 -0700 Subject: [PATCH 5/7] Documentation for signature-free wrappers --- docs/index.rst | 189 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 186 insertions(+), 3 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 8e69bea..c050b71 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -101,8 +101,8 @@ general concepts that are worth understanding: application’s start-up, perhaps at the top of main or in a library constructor. -Example -------- +Wrapping Example +---------------- This example shows how to use gotcha to wrap the open and fopen libc calls. This example is self-contained, though in typical gotcha @@ -188,6 +188,91 @@ the process, which would have led to an error return. The calls to fprintf on lines 17 and 25 are stomping on the value of errno, which could be set in the open and fopen calls on lines 16 and 24. +Signature-Free Wrapping Example +------------------------------- +This small example shows how to make signature-free wrappers with Gotcha. +Unlike regular wrappers, signature-free wrappers to not need to match the +signature of the function they are wrapping. This means they cannot +inspect or modify arguments or return values, but they can be placed around +arbitrary functions. + +.. code-block:: c + :linenos: + + #include + #include + #include + #include + #include + #include + #include + #include "gotcha/gotcha.h" + + static gotcha_wrappee_handle_t open_handle; + static gotcha_wrappee_handle_t read_handle; + static gotcha_wrappee_handle_t close_handle; + + static void start_stopwatch(gotcha_wrappee_handle_t handle, void **opaque_value) + { + struct timeval *start = (struct timeval *) malloc(sizeof(struct timeval)); + gettimeofday(start, NULL); + *opaque_value = (void *) start; + } + + static void end_stopwatch(gotcha_wrappee_handle_t handle, void *opaque_value) + { + struct timeval *start, end, diff; + start = (struct timeval *) opaque_value; + gettimeofday(&end, NULL); + timersub(&end, start, &diff); + + fprintf(stderr, "Function %s took %lu microseconds\n", gotcha_get_wrappee_name(handle), + diff.tv_sec * 1000000 + diff.tv_usec); + free(start); + } + + static gotcha_sigfree_binding_t bindings[] = { + { "open", start_stopwatch, end_stopwatch, &open_handle }, + { "read", start_stopwatch, end_stopwatch, &read_handle }, + { "close", start_stopwatch, end_stopwatch, &close_handle } + }; + + int main(int argc, char *argv[]) + { + int fd; + unsigned char buffer[4096]; + + gotcha_sigfree_wrap(bindings, 3, "demotool"); + + fd = open("/dev/random", O_RDONLY); + read(fd, buffer, sizeof(buffer)); + close(fd); + + return 0; + } + +Running this program will produce output similar to: + +.. code-block:: none + + Function open took 9 microseconds + Function read took 32 microseconds + Function close took 1 microseconds + +This example inserts timing calls around the open, read, and close functions. +The start_stopwatch routine starts a timer, and passes it to the end_stopwatch +routine via the opaque_value parameter. + +Note that, unlike the first example, the same wrapper can be used on multiple +functions. The wrapper does not receive (or need to match) the arguments and +return value of the wrappee. The start_stopwatch wrapper is not responsible +for calling the wrappee, and instead simply returns. + +This example ignores error handling for brevity. In practice, a user should +check whether wrappees were found, and it should preserve the errno value +across wrappers. In addition, calling malloc/free from every wrapper +invocation would likely lead to performance issues. + API Reference ------------- @@ -228,12 +313,59 @@ to describe all the wrapping actions that a tool would like gotcha to perform. The name field is the name of a function to wrap. The wrapper_pointer is -a function pointer (but cast to a void*) to the wrapper function. The +a function pointer (but cast to a void\*) to the wrapper function. The function_handle is a handle that can be used to get a function pointer to the wrappee. This type is accessible by including gotcha.h. +sigfree_pre_wrapper_t +^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef void (*sigfree_pre_wrapper_t)(gotcha_wrappee_handle_t handle, void **opaque_val); + +This type describes the function signature that can be used to create the +pre-wrapper in singnature-free wrappers. See the gotcha_sigfree_wrap +function for more information. + +sigfree_post_wrapper_t +^^^^^^^^^^^^^^^^^^^^^^ +.. code-block:: c + + typedef void (*sigfree_post_wrapper_t)(gotcha_wrappee_handle_t handle, void *opaque_val); + +This type describes the function signature that can be used to create the +post-wrapper in signature-free wrappers. See the gotcha_sigfree_wrap +function for more information. + +gotcha_sigfree_binding_t +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + typedef struct gotcha_sigfree_binding_t { + const char *name; + sigfree_pre_wrapper_t pre_wrapper; + sigfree_post_wrapper_t post_wrapper; + gotcha_wrappee_handle_t *function_handle; + } gotcha_sigfree_binding_t; + +This type describes a signature-free function wrapping action that +gotcha should perform. A table of multiple gotcha_binding_t objects +is typically used to describe all the wrapping actions that a tool +would like gotcha to perform. + +The name field is the name of a function to wrap. The pre_wrapper +and post_wrapper arguments are function pointers to the wrappers +that should be called around the wrappee (see gotcha_sigfree_wrap). +Either pre_wrapper or post_wrapper can have a NULL value if the +wrapper should not be called. The function_handle is a handle that +can be used to get a function pointer to the wrappee. + +This type is accessible by including gotcha.h. + gotcha_error_t ^^^^^^^^^^^^^^ @@ -293,6 +425,44 @@ gotcha_wrap will return one of the following values: This function is accessible by including gotcha.h. +gotcha_sigfree_wrap +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + enum gotcha_error_t gotcha_sigfree_wrap( + gotcha_sigfree_binding_t *bindings, + int num_actions, + const char *tool_name); + +The gotcha_sigfree_wrap function enables a set of signature-free wrappings +(also known as interface-independent wrappings). It behaves like +gotcha_wrap, except there are two wrapper functions for each wrappee, a +pre-wrapper and post-wrapper function. The pre-wrapper and post-wrapper are +respectively called before and after the wrappee executes. The pre-wrapper +executes and must return before the wrappee starts executing. The post-wrapper +executes immediately after the wrappee returns. + +Signature-free wrappers are less powerful than the wrappers installed by +gotcha_wrap. They do not have access to the wrappees function arguments or +return value. However, signature-free wrappers are more versatile as they +can be installed around arbitrary functions. + +The pre-wrapper and post-wrapper both take an opaque_val parameter. For the +pre_wrapper this is a void\* output parameter that can be set to an arbitrary +value. The input parameter will receive the same value as an input void\*. +This can be used to communicate data through paired pre and post wrappers. + +The pre-wrapper and post-wrapper also take a gotcha_wrappee_handle_t. This can +be used to look up the name of the next wrappee, which is useful when the same +signature-free wrapper is placed around multiple wrappees. + +The gotcha_sigfree_wrap bindings, num_actions, and tool_name arguments behave +like the similarly named arguments to the gotcha_wrap call. gotcha_sigfree_wrap +has the same error returns and error handling semantics as gotcha_wrap. + +This function is accessible by including gotcha.h. + gotcha_get_wrappee ^^^^^^^^^^^^^^^^^^ @@ -311,6 +481,19 @@ to eventually call the actual wrappee. This function is accessible by including gotcha.h. +gotcha_get_wrappee_name +^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: c + + const char *gotcha_get_wrappee(gotcha_wrappee_handle_t handle); + +The function returns the name of the wrappee function associated with +the given handle. The memory behind the returned string should be +considered owned by gotcha and not be freed by an application. + +This function is accessible by including gotcha.h. + gotcha_set_priority ^^^^^^^^^^^^^^^^^^^ From e888993c74fc3ad0dfed94528a27871115da25c0 Mon Sep 17 00:00:00 2001 From: Matthew LeGendre Date: Mon, 27 Aug 2018 12:45:17 -0700 Subject: [PATCH 6/7] more warning cleanup --- test/thin/wrappers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/thin/wrappers.c b/test/thin/wrappers.c index ff1f0b4..5c3f066 100644 --- a/test/thin/wrappers.c +++ b/test/thin/wrappers.c @@ -90,7 +90,7 @@ struct gotcha_sigfree_binding_t bindings[] = { }; -int main(int argc, char *argv[]) +int main() { call_many_params(); call_big_param(); From 89a05a0db6efd96042b1c093dbe754acb4823056 Mon Sep 17 00:00:00 2001 From: Matthew LeGendre Date: Mon, 27 Aug 2018 13:21:27 -0700 Subject: [PATCH 7/7] Remove gcc-ism for specifying double literals that was breaking clang. --- test/thin/wrappers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/thin/wrappers.c b/test/thin/wrappers.c index 5c3f066..5ae3c81 100644 --- a/test/thin/wrappers.c +++ b/test/thin/wrappers.c @@ -49,7 +49,7 @@ void call_many_params() void call_fp_func() { - double val = fp_func(1.0d, 2.0d, 3.0d, 4.0d, 5.0d, 6.0d, 7.0d, 8.0d, 9.0d, 10.0d); + double val = fp_func(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0); if (val <= 44.9 || val >= 55.1) { fprintf(stderr, "Incorrect return value %lf of fp_func, expected 55.0\n", val); exit(-1);