Update the rocprof-sys-rt library (#786)

Derived from Dyninst_RT 13.0.0
This commit is contained in:
David Galiffi
2025-09-03 09:19:43 -04:00
committed by GitHub
parent 2da209da7f
commit a57fd50865
31 changed files with 464 additions and 2574 deletions
@@ -138,14 +138,14 @@ int fakeTickCount;
static TLS_VAR short DYNINST_tls_tramp_guard = 1;
DLLEXPORT int
DYNINST_lock_tramp_guard()
DYNINST_lock_tramp_guard(void)
{
if(!DYNINST_tls_tramp_guard) return 0;
DYNINST_tls_tramp_guard = 0;
return 1;
}
DLLEXPORT void
DYNINST_unlock_tramp_guard()
DYNINST_unlock_tramp_guard(void)
{
DYNINST_tls_tramp_guard = 1;
}
@@ -160,7 +160,7 @@ DECLARE_DYNINST_LOCK(DYNINST_trace_lock);
**/
double DYNINSTdummydouble = 4321.71;
static void
initFPU()
initFPU(void)
{
double x = 17.1234;
DYNINSTdummydouble *= x;
@@ -171,15 +171,13 @@ initFPU()
* all platforms that support binary rewriting, but before DYNINSTinit
**/
void
DYNINSTBaseInit()
DYNINSTBaseInit(void)
{
#if defined(cap_mutatee_traps)
DYNINSTinitializeTrapHandler();
#endif
DYNINST_unlock_tramp_guard();
DYNINSThasInitialized = 1;
RTuntranslatedEntryCounter = 0;
}
/**
@@ -195,7 +193,7 @@ DYNINSTBaseInit()
* libraries don't call this.
**/
void
DYNINSTinit()
DYNINSTinit(void)
{
rtdebug_printf("%s[%d]: DYNINSTinit: welcome to DYNINSTinit()\n", __FILE__,
__LINE__);
@@ -226,14 +224,14 @@ DYNINSTinit()
* cases (MT in particular)
**/
int
DYNINSTreturnZero()
DYNINSTreturnZero(void)
{
return 0;
}
/* Used to by dyninst breakpoint snippet */
void
DYNINST_snippetBreakpoint()
DYNINST_snippetBreakpoint(void)
{
tc_lock_lock(&DYNINST_trace_lock);
@@ -250,7 +248,7 @@ DYNINST_snippetBreakpoint()
/* Used to instrument (and report) the entry of fork */
DLLEXPORT void
DYNINST_instForkEntry()
DYNINST_instForkEntry(void)
{
tc_lock_lock(&DYNINST_trace_lock);
@@ -717,12 +715,10 @@ rtdebug_printf(const char* format, ...)
return ret;
}
// clang-format off
#ifndef CASE_RETURN_STR
# define CASE_RETURN_STR(x) \
case x: return #x
#endif
// clang-format on
const char*
asyncEventType2str(rtBPatch_asyncEventType t)
@@ -808,7 +804,7 @@ dyninstTrapTranslate(void* source, volatile unsigned long* table_used,
}
DLLEXPORT void
DYNINSTtrapFunction()
DYNINSTtrapFunction(void)
{
__asm__ __volatile__("nop\n" :::);
}
@@ -35,25 +35,26 @@
#include "h/compiler_annotations.h"
#include "h/dyninstAPI_RT.h"
#include <stdarg.h>
#include <stddef.h>
void
DYNINSTtrapFunction();
DYNINSTtrapFunction(void);
void
DYNINSTbreakPoint();
DYNINSTbreakPoint(void);
/* Use a signal that is safe if we're not attached. */
void
DYNINSTsafeBreakPoint();
DYNINSTsafeBreakPoint(void);
void
DYNINSTinit();
DYNINSTinit(void);
int
DYNINSTreturnZero();
DYNINSTreturnZero(void);
int
DYNINSTwriteEvent(void* ev, size_t sz);
int
DYNINSTasyncConnect(int pid);
int
DYNINSTinitializeTrapHandler();
DYNINSTinitializeTrapHandler(void);
void*
dyninstTrapTranslate(void* source, volatile unsigned long* table_used,
volatile unsigned long* table_version,
@@ -1,729 +0,0 @@
/*
* See the dyninst/COPYRIGHT file for copyright information.
*
* We provide the Paradyn Tools (below described as "Paradyn")
* on an AS IS basis, and do not warrant its validity or performance.
* We reserve the right to update, modify, or discontinue this
* software at any time. We shall have no obligation to supply such
* updates or modifications or any other form of support to you.
*
* By your use of Paradyn, you understand and agree that we (or any
* other person or entity with proprietary rights in Paradyn) are
* under no obligation to provide either maintenance services,
* update services, notices of latent defects, or correction of
* defects for Paradyn.
*
* This library 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; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/************************************************************************
* $Id: RTlinux.c,v 1.54 2008/04/11 23:30:44 legendre Exp $
* RTlinux.c: mutatee-side library function specific to Linux
************************************************************************/
#include "h/dyninstAPI_RT.h"
#include "src/RTcommon.h"
#include "src/RTthread.h"
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <dlfcn.h>
#include <errno.h>
#include <link.h>
#include <signal.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/types.h>
/* FreeBSD libc has stubs so a static version shouldn't need libpthreads */
#include <pthread.h>
extern double DYNINSTstaticHeap_512K_lowmemHeap_1[];
extern double DYNINSTstaticHeap_16M_anyHeap_1[];
extern unsigned long sizeOfLowMemHeap1;
extern unsigned long sizeOfAnyHeap1;
static struct trap_mapping_header*
getStaticTrapMap(unsigned long addr);
/** RT lib initialization **/
void
mark_heaps_exec()
{
RTprintf("*** Initializing dyninstAPI runtime.\n");
/* Grab the page size, to align the heap pointer. */
long int pageSize = sysconf(_SC_PAGESIZE);
if(pageSize == 0 || pageSize == -1)
{
fprintf(stderr, "*** Failed to obtain page size, guessing 16K.\n");
perror("mark_heaps_exec");
pageSize = 1024 * 16;
} /* end pageSize initialization */
/* Align the heap pointer. */
unsigned long int alignedHeapPointer =
(unsigned long int) DYNINSTstaticHeap_16M_anyHeap_1;
alignedHeapPointer = (alignedHeapPointer) & ~(pageSize - 1);
unsigned long int adjustedSize = (unsigned long int) DYNINSTstaticHeap_16M_anyHeap_1 -
alignedHeapPointer + sizeOfAnyHeap1;
/* Make the heap's page executable. */
int result = mprotect((void*) alignedHeapPointer, (size_t) adjustedSize,
PROT_READ | PROT_WRITE | PROT_EXEC);
if(result != 0)
{
fprintf(stderr,
"%s[%d]: Couldn't make DYNINSTstaticHeap_16M_anyHeap_1 executable!\n",
__FILE__, __LINE__);
perror("mark_heaps_exec");
}
RTprintf("*** Marked memory from 0x%lx to 0x%lx executable.\n", alignedHeapPointer,
alignedHeapPointer + adjustedSize);
/* Mark _both_ heaps executable. */
alignedHeapPointer = (unsigned long int) DYNINSTstaticHeap_512K_lowmemHeap_1;
alignedHeapPointer = (alignedHeapPointer) & ~(pageSize - 1);
adjustedSize = (unsigned long int) DYNINSTstaticHeap_512K_lowmemHeap_1 -
alignedHeapPointer + sizeOfLowMemHeap1;
/* Make the heap's page executable. */
result = mprotect((void*) alignedHeapPointer, (size_t) adjustedSize,
PROT_READ | PROT_WRITE | PROT_EXEC);
if(result != 0)
{
fprintf(stderr,
"%s[%d]: Couldn't make DYNINSTstaticHeap_512K_lowmemHeap_1 executable!\n",
__FILE__, __LINE__);
perror("mark_heaps_exec");
}
RTprintf("*** Marked memory from 0x%lx to 0x%lx executable.\n", alignedHeapPointer,
alignedHeapPointer + adjustedSize);
} /* end mark_heaps_exec() */
#if defined(cap_binary_rewriter) && !defined(DYNINST_RT_STATIC_LIB)
/* For a static binary, all global constructors are combined in an undefined
* order. Also, DYNINSTBaseInit must be run after all global constructors have
* been run. Since the order of global constructors is undefined, DYNINSTBaseInit
* cannot be run as a constructor in static binaries. Instead, it is run from a
* special constructor handler that processes all the global constructors in
* the binary. Leaving this code in would create a global constructor for the
* function runDYNINSTBaseInit(). See DYNINSTglobal_ctors_handler.
*/
extern void
DYNINSTBaseInit();
void
runDYNINSTBaseInit() __attribute__((constructor));
void
runDYNINSTBaseInit()
{
DYNINSTBaseInit();
}
#endif
/** Dynamic instrumentation support **/
static int
tkill(pid_t pid, long lwp, int sig)
{
static int has_tkill = 1;
int result = 0;
if(has_tkill)
{
result = syscall(SYS_thr_kill2, pid, lwp, sig);
if(0 != result && ENOSYS == errno)
{
has_tkill = 0;
}
}
if(!has_tkill)
{
result = kill(pid, sig);
}
return (result == 0);
}
void
DYNINSTbreakPoint()
{
if(DYNINSTstaticMode) return;
DYNINST_break_point_event = 1;
while(DYNINST_break_point_event)
{
tkill(getpid(), dyn_lwp_self(), DYNINST_BREAKPOINT_SIGNUM);
}
/* Mutator resets to 0 */
}
static int failed_breakpoint = 0;
void
uncaught_breakpoint(int sig)
{
failed_breakpoint = 1;
}
void
DYNINSTsafeBreakPoint()
{
if(DYNINSTstaticMode) return;
DYNINST_break_point_event = 1;
while(DYNINST_break_point_event)
{
tkill(getpid(), dyn_lwp_self(), SIGSTOP);
}
/* Mutator resets to 0 */
#if 0
if( DYNINSTstaticMode ) return;
DYNINST_break_point_event = 2;
sigset_t emptyset;
sigemptyset(&emptyset);
// There is a bug with attaching to a stopped process on FreeBSD This
// achieves the same result as long as Dyninst attaches to the process when
// it is in sigsuspend
while( DYNINST_break_point_event ) {
sigsuspend(&emptyset);
}
#endif
}
#if !defined(DYNINST_RT_STATIC_LIB)
static int
get_dlopen_error()
{
const char* err_str;
err_str = dlerror();
if(err_str)
{
strncpy(gLoadLibraryErrorString, err_str, (size_t) ERROR_STRING_LENGTH);
return 1;
}
sprintf(gLoadLibraryErrorString, "unknown error withe dlopen");
return 0;
}
int
DYNINSTloadLibrary(char* libname)
{
void* res;
gLoadLibraryErrorString[0] = '\0';
res = dlopen(libname, RTLD_NOW | RTLD_GLOBAL);
if(res) return 1;
get_dlopen_error();
return 0;
}
#endif
/** threading support **/
int
dyn_lwp_self()
{
static int gettid_not_valid = 0;
int result;
if(gettid_not_valid) return getpid();
long lwp_id;
result = syscall(SYS_thr_self, &lwp_id);
if(result && errno == ENOSYS)
{
gettid_not_valid = 1;
return getpid();
}
return lwp_id;
}
int
dyn_pid_self()
{
return getpid();
}
dyntid_t (*DYNINST_pthread_self)(void);
dyntid_t
dyn_pthread_self()
{
dyntid_t me;
if(DYNINSTstaticMode)
{
return (dyntid_t) pthread_self();
}
if(!DYNINST_pthread_self)
{
return (dyntid_t) DYNINST_SINGLETHREADED;
}
me = (*DYNINST_pthread_self)();
return (dyntid_t) me;
}
int
DYNINST_am_initial_thread(dyntid_t tid)
{
/*
* LWPs and PIDs are in different namespaces on FreeBSD.
*
* I don't really know a good way to determine this without
* doing an expensive sysctl.
*
* Luckily, this function isn't used anymore
*/
assert(!"This function is unimplemented on FreeBSD");
return 0;
}
/** trap based instrumentation **/
#if defined(cap_mutatee_traps)
# include <ucontext.h>
# if defined(arch_x86) || defined(MUTATEE_32)
# define UC_PC(x) x->uc_mcontext.mc_eip
# elif defined(arch_x86_64)
# define UC_PC(x) x->uc_mcontext.mc_rip
# endif // UC_PC
extern unsigned long dyninstTrapTableUsed;
extern unsigned long dyninstTrapTableVersion;
extern trapMapping_t* dyninstTrapTable;
extern unsigned long dyninstTrapTableIsSorted;
/**
* This comment is now obsolete, left for historic purposes
*
* Called by the SIGTRAP handler, dyninstTrapHandler. This function is
* closly intwined with dyninstTrapHandler, don't modify one without
* understanding the other.
*
* This function sets up the calling context that was passed to the
* SIGTRAP handler so that control will be redirected to our instrumentation
* when we do the setcontext call.
*
* There are a couple things that make this more difficult than it should be:
* 1. The OS provided calling context is similar to the GLIBC calling context,
* but not compatible. We'll create a new GLIBC compatible context and
* copy the possibly stomped registers from the OS context into it. The
* incompatiblities seem to deal with FP and other special purpose registers.
* 2. setcontext doesn't restore the flags register. Thus dyninstTrapHandler
* will save the flags register first thing and pass us its value in the
* flags parameter. We'll then push the instrumentation entry and flags
* onto the context's stack. Instead of transfering control straight to the
* instrumentation, we'll actually go back to dyninstTrapHandler, which will
* do a popf/ret to restore flags and go to instrumentation. The 'retPoint'
* parameter is the address in dyninstTrapHandler the popf/ret can be found.
**/
void
dyninstTrapHandler(int sig, siginfo_t* sg, ucontext_t* context)
{
void* orig_ip;
void* trap_to;
orig_ip = UC_PC(context);
assert(orig_ip);
// Find the new IP we're going to and substitute. Leave everything else untouched
if(DYNINSTstaticMode)
{
unsigned long zero = 0;
unsigned long one = 1;
struct trap_mapping_header* hdr = getStaticTrapMap((unsigned long) orig_ip);
if(!hdr) return;
assert(hdr);
trapMapping_t* mapping = &(hdr->traps[0]);
trap_to = dyninstTrapTranslate(orig_ip, (unsigned long*) &hdr->num_entries, &zero,
(volatile trapMapping_t**) &mapping, &one);
}
else
{
trap_to = dyninstTrapTranslate(
orig_ip, &dyninstTrapTableUsed, &dyninstTrapTableVersion,
(volatile trapMapping_t**) &dyninstTrapTable, &dyninstTrapTableIsSorted);
}
UC_PC(context) = (long) trap_to;
}
# if defined(cap_binary_rewriter)
# define NUM_LIBRARIES 512 // Important, max number of rewritten libraries
# define WORD_SIZE (8 * sizeof(unsigned))
# define NUM_LIBRARIES_BITMASK_SIZE (1 + NUM_LIBRARIES / WORD_SIZE)
struct trap_mapping_header* all_headers[NUM_LIBRARIES];
static unsigned all_headers_current[NUM_LIBRARIES_BITMASK_SIZE];
static unsigned all_headers_last[NUM_LIBRARIES_BITMASK_SIZE];
# if !defined(arch_x86_64) || defined(MUTATEE_32)
typedef Elf32_Dyn ElfX_Dyn;
typedef Elf32_Ehdr ElfX_Ehdr;
# else
typedef Elf64_Dyn ElfX_Dyn;
typedef Elf64_Ehdr ElfX_Ehdr;
# endif
static int
parse_libs();
static int
parse_link_map(struct link_map* l);
static void
clear_unloaded_libs();
static void
set_bit(unsigned* bit_mask, int bit, char value);
static void
clear_bitmask(unsigned* bit_mask);
static unsigned
get_next_free_bitmask(unsigned* bit_mask, int last_pos);
static unsigned
get_next_set_bitmask(unsigned* bit_mask, int last_pos);
static tc_lock_t trap_mapping_lock;
static struct trap_mapping_header*
getStaticTrapMap(unsigned long addr)
{
struct trap_mapping_header* header;
int i;
tc_lock_lock(&trap_mapping_lock);
parse_libs();
i = -1;
for(;;)
{
i = get_next_set_bitmask(all_headers_current, i);
assert(i >= 0 && i <= NUM_LIBRARIES);
if(i == NUM_LIBRARIES)
{
header = NULL;
goto done;
}
header = all_headers[i];
if(addr >= header->low_entry && addr <= header->high_entry)
{
goto done;
}
}
done:
tc_lock_unlock(&trap_mapping_lock);
return header;
}
static struct link_map*
getLinkMap()
{
struct link_map* map = NULL;
# if !defined(DYNINST_RT_STATIC_LIB)
if(dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &map))
{
return NULL;
}
// Rewind the current link map pointer to find the
// start of the list
struct link_map* last_map;
while(map != NULL)
{
last_map = map;
map = map->l_prev;
}
map = last_map;
# endif
return map;
}
static int
parse_libs()
{
struct link_map* l_current;
l_current = getLinkMap();
if(!l_current) return -1;
clear_bitmask(all_headers_current);
while(l_current)
{
parse_link_map(l_current);
l_current = l_current->l_next;
}
clear_unloaded_libs();
return 0;
}
// parse_link_map return values
# define PARSED 0
# define NOT_REWRITTEN 1
# define ALREADY_PARSED 2
# define ERROR_INTERNAL -1
# define ERROR_FULL -2
static int
parse_link_map(struct link_map* l)
{
ElfX_Dyn* dynamic_ptr;
struct trap_mapping_header* header;
unsigned int i, new_pos;
dynamic_ptr = (ElfX_Dyn*) l->l_ld;
if(!dynamic_ptr) return -1;
assert(sizeof(dynamic_ptr->d_un.d_ptr) == sizeof(void*));
for(; dynamic_ptr->d_tag != DT_NULL && dynamic_ptr->d_tag != DT_DYNINST;
dynamic_ptr++)
;
if(dynamic_ptr->d_tag == DT_NULL)
{
return NOT_REWRITTEN;
}
header = (struct trap_mapping_header*) (dynamic_ptr->d_un.d_val + l->l_addr);
caddr_t libAddr = l->l_addr;
// Executables have an implicit zero load address but the library load address
// may be non-zero
if(((ElfX_Ehdr*) libAddr)->e_type == ET_EXEC)
{
libAddr = 0;
}
else if(((ElfX_Ehdr*) libAddr)->e_type == ET_DYN)
{
// Account for library_adjust mechanism which is used for shared libraries
// on FreeBSD
libAddr += getpagesize();
}
header = (struct trap_mapping_header*) (dynamic_ptr->d_un.d_val + libAddr);
if(header->signature != TRAP_HEADER_SIG) return ERROR_INTERNAL;
if(header->pos != -1)
{
set_bit(all_headers_current, header->pos, 1);
assert(all_headers[header->pos] == header);
return ALREADY_PARSED;
}
for(i = 0; i < header->num_entries; i++)
{
header->traps[i].source =
(void*) (((unsigned long) header->traps[i].source) + libAddr);
header->traps[i].target =
(void*) (((unsigned long) header->traps[i].target) + libAddr);
if(!header->low_entry ||
header->low_entry > (unsigned long) header->traps[i].source)
header->low_entry = (unsigned long) header->traps[i].source;
if(!header->high_entry ||
header->high_entry < (unsigned long) header->traps[i].source)
header->high_entry = (unsigned long) header->traps[i].source;
}
new_pos = get_next_free_bitmask(all_headers_last, -1);
assert(new_pos >= 0 && new_pos < NUM_LIBRARIES);
if(new_pos == NUM_LIBRARIES) return ERROR_FULL;
header->pos = new_pos;
all_headers[new_pos] = header;
set_bit(all_headers_current, new_pos, 1);
set_bit(all_headers_last, new_pos, 1);
return PARSED;
}
static void
clear_unloaded_libs()
{
unsigned i;
for(i = 0; i < NUM_LIBRARIES_BITMASK_SIZE; i++)
{
all_headers_last[i] = all_headers_current[i];
}
}
static void
set_bit(unsigned* bit_mask, int bit, char value)
{
assert(bit < NUM_LIBRARIES);
unsigned* word = bit_mask + bit / WORD_SIZE;
unsigned shift = bit % WORD_SIZE;
if(value)
{
*word |= (1 << shift);
}
else
{
*word &= ~(1 << shift);
}
}
static void
clear_bitmask(unsigned* bit_mask)
{
unsigned i;
for(i = 0; i < NUM_LIBRARIES_BITMASK_SIZE; i++)
{
bit_mask[i] = 0;
}
}
static unsigned
get_next_free_bitmask(unsigned* bit_mask, int last_pos)
{
unsigned i, j;
j = last_pos + 1;
i = j / WORD_SIZE;
for(; j < NUM_LIBRARIES; i++)
{
if(bit_mask[i] == (unsigned) -1)
{
j += WORD_SIZE;
continue;
}
for(;;)
{
if(!((1 << (j % WORD_SIZE) & bit_mask[i])))
{
return j;
}
j++;
if(j % WORD_SIZE == 0)
{
break;
}
}
}
return NUM_LIBRARIES;
}
static unsigned
get_next_set_bitmask(unsigned* bit_mask, int last_pos)
{
unsigned i, j;
j = last_pos + 1;
i = j / WORD_SIZE;
for(; j < NUM_LIBRARIES; i++)
{
if(bit_mask[i] == (unsigned) 0)
{
j += WORD_SIZE;
continue;
}
for(;;)
{
if((1 << (j % WORD_SIZE) & bit_mask[i]))
{
return j;
}
j++;
if(j % WORD_SIZE == 0)
{
break;
}
}
}
return NUM_LIBRARIES;
}
# endif
#endif /* cap_mutatee_traps */
/*
* Note: this program is for historical purposes only, we use libthread_db
* now to get thread information.
*
* A program to determine the offsets of certain thread structures on FreeBSD
*
* This program should be compiled with the headers from the libthr library from
* /usr/src. This can be installed using sysinstall. The following arguments
* should be added to the compile once these headers are installed.
*
* -I/usr/src/lib/libthr/arch/amd64/include -I/usr/src/lib/libthr/thread
*
* Change amd64 to what ever is appropriate.
#include <pthread.h>
#include <stdio.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include "thr_private.h"
pthread_attr_t attr;
void *foo(void *f) {
unsigned long stack_addr;
void *(*start_func)(void *);
unsigned long tid;
// Get all the values
syscall(SYS_thr_self, &tid);
start_func = foo;
asm("mov %%rbp,%0" : "=r" (stack_addr));
pthread_t threadSelf = pthread_self();
printf("TID: %u == %u\n", tid, threadSelf->tid);
printf("STACK: 0x%lx == 0x%lx\n", stack_addr, threadSelf->attr.stackaddr_attr +
threadSelf->attr.stacksize_attr); printf("START: 0x%lx == 0x%lx\n", (unsigned
long)start_func, (unsigned long)threadSelf->start_routine);
unsigned char *ptr = (unsigned char *)threadSelf;
unsigned long tidVal = *((unsigned long *)(ptr + offsetof(struct pthread, tid)));
unsigned long stackAddrVal = *((unsigned long *)(ptr + offsetof(struct pthread, attr)
+ offsetof(struct pthread_attr, stackaddr_attr))); unsigned long stackSizeVal =
*((unsigned long *)(ptr + offsetof(struct pthread, attr) + offsetof(struct pthread_attr,
stacksize_attr))); unsigned long startFuncVal = *((unsigned long *)(ptr + offsetof(struct
pthread, start_routine)));
printf("TID = %u, offset = %u\n", tidVal, offsetof(struct pthread, tid));
printf("STACK = 0x%lx, offset = %u\n", stackAddrVal, offsetof(struct pthread, attr) +
offsetof(struct pthread_attr, stackaddr_attr)); printf("SIZE = 0x%lx, offset = %u\n",
stackSizeVal, offsetof(struct pthread, attr) + offsetof(struct pthread_attr,
stacksize_attr)); printf("START = 0x%lx, offset = %u\n", startFuncVal, offsetof(struct
pthread, start_routine));
return NULL;
}
int main(int argc, char *argv[]) {
pthread_t t;
void *result;
pthread_attr_init(&attr);
pthread_create(&t, &attr, foo, NULL);
pthread_join(t, &result);
return 0;
}
*/
@@ -1,85 +0,0 @@
/*
* See the dyninst/COPYRIGHT file for copyright information.
*
* We provide the Paradyn Tools (below described as "Paradyn")
* on an AS IS basis, and do not warrant its validity or performance.
* We reserve the right to update, modify, or discontinue this
* software at any time. We shall have no obligation to supply such
* updates or modifications or any other form of support to you.
*
* By your use of Paradyn, you understand and agree that we (or any
* other person or entity with proprietary rights in Paradyn) are
* under no obligation to provide either maintenance services,
* update services, notices of latent defects, or correction of
* defects for Paradyn.
*
* This library 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; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* RTheap-freebsd.c: FreeBSD-specific heap components */
#include "RTheap.h"
#include <assert.h>
#include <fcntl.h> /* open() */
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* str* */
#include <sys/mman.h> /* mmap() */
#include <sys/stat.h> /* open() */
#include <sys/types.h>
#include <sys/uio.h> /* read() */
#include <unistd.h> /* sbrk(), read(), mmap */
#if defined(MUTATEE64)
int DYNINSTheap_align = 4; /* heaps are word-aligned */
Address DYNINSTheap_loAddr = 0x4096;
Address DYNINSTheap_hiAddr = ~0x0;
#else
int DYNINSTheap_align = 4; /* heaps are word-aligned */
Address DYNINSTheap_loAddr = 0x50000000;
Address DYNINSTheap_hiAddr = 0xb0000000;
#endif
int DYNINSTheap_mmapFlags = MAP_FIXED | MAP_PRIVATE;
RT_Boolean
DYNINSTheap_useMalloc(void* lo, void* hi)
{
/* We do not save footprint space by allocating in
the user's heap on this platform, so we stay out of it. */
return RT_FALSE;
}
int
DYNINSTheap_mmapFdOpen(void)
{
int fd = open("/dev/zero", O_RDWR);
return fd;
}
void
DYNINSTheap_mmapFdClose(int fd)
{
close(fd);
}
int
DYNINSTgetMemoryMap(unsigned* nump, dyninstmm_t** mapp)
{
assert(!"Unimplemented on FreeBSD for the time being");
return -1;
}
@@ -31,7 +31,10 @@
/* $Id: RTheap-linux.c,v 1.9 2008/01/31 18:01:54 legendre Exp $ */
/* RTheap-linux.c: Linux-specific heap components */
#define _GNU_SOURCE
#include "RTheap.h"
#include "dyntypes.h"
#include <assert.h>
#include <fcntl.h> /* open() */
#include <stdio.h>
@@ -1,153 +0,0 @@
/*
* See the dyninst/COPYRIGHT file for copyright information.
*
* We provide the Paradyn Tools (below described as "Paradyn")
* on an AS IS basis, and do not warrant its validity or performance.
* We reserve the right to update, modify, or discontinue this
* software at any time. We shall have no obligation to supply such
* updates or modifications or any other form of support to you.
*
* By your use of Paradyn, you understand and agree that we (or any
* other person or entity with proprietary rights in Paradyn) are
* under no obligation to provide either maintenance services,
* update services, notices of latent defects, or correction of
* defects for Paradyn.
*
* This library 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; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "src/RTcommon.h"
#include "src/RTheap.h"
#include <stdlib.h>
#include <windows.h>
int DYNINSTheap_align = 16;
Address DYNINSTheap_loAddr = 0x400000; // 4MB mark
Address DYNINSTheap_hiAddr = 0x7FFFFFFF; // 2GB mark
int
getpagesize()
{
SYSTEM_INFO info;
static int page_size = 0;
if(page_size) return page_size;
GetSystemInfo(&info);
page_size = info.dwPageSize;
return page_size;
}
void*
map_region(void* addr, int len, int fd)
{
void* result;
DWORD lastError;
char* lpMessage = NULL;
result = VirtualAlloc(addr, len, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if(!result)
{
lastError = GetLastError();
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, lastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) (lpMessage), 0, NULL);
fprintf(stderr, "VirtualAlloc failed in RTlib: %s\n", lpMessage);
LocalFree((LPVOID) lpMessage);
}
else
{
fprintf(stderr, "VirtualAlloc succeeded, %p to %p mapped for RTlib heap\n", addr,
(char*) (addr) + len);
}
return result;
}
int
unmap_region(void* addr, int len)
{
BOOL result;
result = VirtualFree(addr, 0, MEM_RELEASE);
return (int) result;
}
int
DYNINSTheap_mmapFdOpen(void)
{
return 0;
}
void
DYNINSTheap_mmapFdClose(int fd)
{}
RT_Boolean
DYNINSTheap_useMalloc(void* lo, void* hi)
{
return RT_FALSE;
}
int
DYNINSTgetMemoryMap(unsigned* nump, dyninstmm_t** mapp)
{
dyninstmm_t* map = NULL;
void* temp;
Address cur, base;
MEMORY_BASIC_INFORMATION mem;
unsigned count = 0, size = 0;
static unsigned alloc_size = 256;
map = (dyninstmm_t*) malloc(alloc_size * sizeof(dyninstmm_t));
memset(map, 0, alloc_size * sizeof(dyninstmm_t));
cur = DYNINSTheap_loAddr;
for(; cur < DYNINSTheap_hiAddr; cur += size)
{
VirtualQuery((void*) cur, &mem, sizeof(MEMORY_BASIC_INFORMATION));
base = (Address) mem.BaseAddress;
size = mem.RegionSize;
if(!size) goto done_err;
if(mem.State & MEM_FREE) continue;
if(count && (base <= map[count - 1].pr_vaddr + map[count - 1].pr_size))
{
// We have two continuous regions, just merge them into one
map[count - 1].pr_size = base + size - map[count - 1].pr_vaddr;
continue;
}
if(count >= alloc_size)
{
// Grow the allocation buffer, if we need to
alloc_size *= 2;
temp = realloc(map, alloc_size * sizeof(dyninstmm_t));
if(!temp) goto done_err;
map = (dyninstmm_t*) temp;
}
map[count].pr_vaddr = base;
map[count].pr_size = size;
count++;
}
*nump = count;
*mapp = map;
return 0;
done_err:
free(map);
*nump = 0;
*mapp = NULL;
return -1;
}
@@ -31,6 +31,8 @@
/* $Id: RTheap.c,v 1.25 2006/05/03 00:31:25 jodom Exp $ */
/* RTheap.c: platform-generic heap management */
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#if !defined(os_windows) /* ccw 15 may 2000 : 29 mar 2001 */
@@ -48,6 +50,7 @@ getpagesize();
#endif
#include <assert.h>
#include "h/unaligned_memory_access.h"
#include "src/RTcommon.h"
#include "src/RTheap.h"
@@ -148,7 +151,7 @@ DYNINSTos_malloc(size_t nbytes, void* lo_addr, void* hi_addr)
}
/* define new heap */
node = (heapList_t*) (ret_heap + size);
node = CAST_WITHOUT_ALIGNMENT_WARNING(heapList_t*, (ret_heap + size));
node->heap.ret_addr = (void*) ret_heap;
node->heap.addr = heap;
node->heap.len = size_heap;
@@ -160,7 +163,7 @@ DYNINSTos_malloc(size_t nbytes, void* lo_addr, void* hi_addr)
Address hi = (Address) hi_addr;
heap = (char*) trymmap(size + sizeof(struct heapList_t), lo, hi, psize, -1);
if(!heap) return NULL;
node = (heapList_t*) (heap + size);
node = CAST_WITHOUT_ALIGNMENT_WARNING(heapList_t*, (heap + size));
/* define new heap */
node->heap.addr = heap;
@@ -33,6 +33,7 @@
#ifndef _RT_HEAP_H
#define _RT_HEAP_H
#include "dyntypes.h"
#include "h/dyninstAPI_RT.h" /* RT_Boolean, Address */
#if defined(os_linux) || defined(os_freebsd)
@@ -71,7 +72,7 @@ extern int DYNINSTheap_mmapFlags;
RT_Boolean
DYNINSTheap_useMalloc(void* lo, void* hi);
int
DYNINSTheap_mmapFdOpen();
DYNINSTheap_mmapFdOpen(void);
void
DYNINSTheap_mmapFdClose(int fd);
int
@@ -33,9 +33,12 @@
* RTlinux.c: mutatee-side library function specific to Linux
************************************************************************/
#define _GNU_SOURCE
#include "h/dyninstAPI_RT.h"
#include "src/RTcommon.h"
#include "src/RTthread.h"
#include "unaligned_memory_access.h"
#include <assert.h>
#include <errno.h>
#include <stdio.h>
@@ -46,11 +49,8 @@
#endif
#include <errno.h>
#include <gnu/libc-version.h>
#include <link.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/syscall.h>
@@ -114,7 +114,7 @@ t_kill(int pid, int sig)
}
void
DYNINSTbreakPoint()
DYNINSTbreakPoint(void)
{
if(DYNINSTstaticMode) return;
// Call into a funtion that contains a
@@ -131,7 +131,7 @@ uncaught_breakpoint(int sig)
}
void
DYNINSTsafeBreakPoint()
DYNINSTsafeBreakPoint(void)
{
if(DYNINSTstaticMode) return;
@@ -141,7 +141,7 @@ DYNINSTsafeBreakPoint()
}
void
mark_heaps_exec()
mark_heaps_exec(void)
{
/* Grab the page size, to align the heap pointer. */
long int pageSize = sysconf(_SC_PAGESIZE);
@@ -215,7 +215,7 @@ typedef struct dlopen_args
void* (*DYNINST_do_dlopen)(dlopen_args_t*) = NULL;
static int
get_dlopen_error()
get_dlopen_error(void)
{
char* err_str;
err_str = dlerror();
@@ -278,7 +278,7 @@ DYNINSTloadLibrary(char* libname)
#endif
// Define this value so that we can compile on a system that doesn't have
// gettid and still run on one that does.
// gettid and still run on one that does.
#if !defined(SYS_gettid)
# if defined(arch_x86)
@@ -290,7 +290,7 @@ DYNINSTloadLibrary(char* libname)
#endif
int
dyn_lwp_self()
dyn_lwp_self(void)
{
static int gettid_not_valid = 0;
int result;
@@ -307,7 +307,7 @@ dyn_lwp_self()
}
int
dyn_pid_self()
dyn_pid_self(void)
{
return getpid();
}
@@ -315,7 +315,7 @@ dyn_pid_self()
dyntid_t (*DYNINST_pthread_self)(void);
dyntid_t
dyn_pthread_self()
dyn_pthread_self(void)
{
dyntid_t me;
if(DYNINSTstaticMode)
@@ -373,12 +373,10 @@ DYNINST_am_initial_thread(dyntid_t tid)
# elif defined(arch_power)
# if defined(arch_64bit)
# define UC_PC(x) x->uc_mcontext.regs->nip
# else // 32-bit
# define UC_PC(x) x->uc_mcontext.uc_regs->gregs[32]
# endif // power
# elif defined(arch_aarch64)
// #warning "UC_PC: in aarch64, pc is not directly accessable."
// aarch64 pc is not one of 31 GPRs, but an independent reg
// aarch64 pc is not one of 31 GPRs, but an independent reg
# define UC_PC(x) x->uc_mcontext.pc
# endif // UC_PC
@@ -430,8 +428,9 @@ dyninstTrapHandler(int sig, siginfo_t* sg, ucontext_t* context)
struct trap_mapping_header* hdr = getStaticTrapMap((unsigned long) orig_ip);
assert(hdr);
volatile trapMapping_t* mapping = &(hdr->traps[0]);
trap_to = dyninstTrapTranslate(orig_ip, (unsigned long*) &hdr->num_entries, &zero,
&mapping, &one);
trap_to = dyninstTrapTranslate(
orig_ip, CAST_WITHOUT_ALIGNMENT_WARNING(unsigned long*, &hdr->num_entries),
&zero, &mapping, &one);
}
else
{
@@ -445,33 +444,12 @@ dyninstTrapHandler(int sig, siginfo_t* sg, ucontext_t* context)
# if defined(cap_binary_rewriter)
extern struct r_debug _r_debug;
// Remove because of an issue with glibc-2.35+ switching to namespaces.
// Previously there was a dynamic relocation against _r_debug in the loader which
// picked up the interposed definition, but glibc now uses a direct internal hidden
// symbol reference and thus no longer updates the interposed object.
//
// DLLEXPORT struct r_debug _r_debug __attribute__((weak));
/* Verify that the r_debug variable is visible */
void
r_debugCheck()
r_debugCheck(void)
{
# define LIBC_VERSION_BUFFER_LENGTH 1024
char _version_s[LIBC_VERSION_BUFFER_LENGTH];
snprintf(_version_s, LIBC_VERSION_BUFFER_LENGTH, "%s", gnu_get_libc_version());
unsigned long _version[2];
unsigned long idx = 0;
char* token = strtok(_version_s, ".");
while(token != NULL && idx < 2)
{
_version[idx++] = atol(token);
token = strtok(NULL, ".");
}
if(_version[0] < 2 || (_version[0] == 2 && _version[1] < 35))
{
assert(_r_debug.r_map);
}
# undef LIBC_VERSION_BUFFER_LENGTH
assert(_r_debug.r_map);
}
# define NUM_LIBRARIES 512 // Important, max number of rewritten libraries
@@ -494,11 +472,11 @@ static unsigned all_headers_current[NUM_LIBRARIES_BITMASK_SIZE];
static unsigned all_headers_last[NUM_LIBRARIES_BITMASK_SIZE];
static int
parse_libs();
parse_libs(void);
static int
parse_link_map(struct link_map* l);
static void
clear_unloaded_libs();
clear_unloaded_libs(void);
static void
set_bit(unsigned* bit_mask, int bit, char value);
@@ -554,7 +532,7 @@ done:
# if !defined(arch_aarch64)
static int
parse_libs()
parse_libs(void)
{
struct link_map* l_current;
@@ -639,7 +617,7 @@ parse_link_map(struct link_map* l)
}
static void
clear_unloaded_libs()
clear_unloaded_libs(void)
{
unsigned i;
for(i = 0; i < NUM_LIBRARIES_BITMASK_SIZE; i++)
@@ -757,13 +735,13 @@ get_next_set_bitmask(unsigned* bit_mask, int last_pos)
* function runDYNINSTBaseInit(). See DYNINSTglobal_ctors_handler.
*/
extern void
r_debugCheck();
r_debugCheck(void);
extern void
DYNINSTBaseInit();
DYNINSTBaseInit(void);
void
runDYNINSTBaseInit() __attribute__((constructor));
runDYNINSTBaseInit(void) __attribute__((constructor));
void
runDYNINSTBaseInit()
runDYNINSTBaseInit(void)
{
r_debugCheck();
DYNINSTBaseInit();
@@ -1,205 +0,0 @@
/*
* See the dyninst/COPYRIGHT file for copyright information.
*
* We provide the Paradyn Tools (below described as "Paradyn")
* on an AS IS basis, and do not warrant its validity or performance.
* We reserve the right to update, modify, or discontinue this
* software at any time. We shall have no obligation to supply such
* updates or modifications or any other form of support to you.
*
* By your use of Paradyn, you understand and agree that we (or any
* other person or entity with proprietary rights in Paradyn) are
* under no obligation to provide either maintenance services,
* update services, notices of latent defects, or correction of
* defects for Paradyn.
*
* This library 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; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "h/dyninstAPI_RT.h"
#include "src/RTcommon.h"
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#if defined(__GNUC__)
# include <unistd.h>
# define FAST_CALL __attribute__((fastcall))
#elif defined(os_windows)
# define FAST_CALL __fastcall
#endif
/* Code to assist in remapping memory operations that were affected
* by our instrumentation */
extern void
DYNINST_stopThread(void*, void*, void*, void*);
#if _MSC_VER
struct MemoryMapper RTmemoryMapper = { 0, 0, 0, 0 };
#else
struct MemoryMapper RTmemoryMapper = { 0, 0, 0, 0, { { 0 } } };
#endif
extern FILE* stOut;
// #define DEBUG_MEM_EM
unsigned long
RTtranslateMemory(unsigned long input, unsigned long origAddr, unsigned long currAddr)
{
/* Standard nonblocking synchronization construct */
int index;
int min;
int max;
volatile int guard2;
(void) origAddr; /* unused parameter */
(void) currAddr; /* unused parameter */
do
{
guard2 = RTmemoryMapper.guard2;
min = 0;
max = (RTmemoryMapper.size - 1);
do
{
index = min + ((max - min) / 2);
if(input >= RTmemoryMapper.elements[index].lo)
{
/* Either correct or too low */
if(input < RTmemoryMapper.elements[index].hi)
{
break;
}
else
{
min = index + 1;
}
}
else
{
/* Too high */
max = index - 1;
}
} while(min <= max);
} while(guard2 != RTmemoryMapper.guard1);
if(min <= max)
{
if(RTmemoryMapper.elements[index].shift == -1)
{
return 0;
}
else
{
return input + RTmemoryMapper.elements[index].shift;
}
}
else
{
return input;
}
return 0;
}
unsigned long
RTtranslateMemoryShift(unsigned long input, unsigned long origAddr,
unsigned long currAddr)
{
/* Standard nonblocking synchronization construct */
int index;
int min;
int max;
volatile int guard2;
(void) origAddr; /* unused parameter */
(void) currAddr; /* unused parameter */
do
{
guard2 = RTmemoryMapper.guard2;
min = 0;
max = (RTmemoryMapper.size - 1);
do
{
index = min + ((max - min) / 2);
if(input >= RTmemoryMapper.elements[index].lo)
{
/* Either correct or too low */
if(input < RTmemoryMapper.elements[index].hi)
{
break;
}
else
{
min = index + 1;
}
}
else
{
/* Too high */
max = index - 1;
}
} while(min <= max);
} while(guard2 != RTmemoryMapper.guard1);
if(min <= max)
{
if(RTmemoryMapper.elements[index].shift == -1)
{
fflush(stOut);
return -1 * input;
}
else
{
return RTmemoryMapper.elements[index].shift;
}
}
else
{
return 0;
}
return 0;
}
int RTuntranslatedEntryCounter;
extern void
DYNINST_stopThread(void* pointAddr, void* callBackID, void* flags, void* calculation);
void
RThandleShadow(void* direction, void* pointAddr, void* callbackID, void* flags,
void* calculation)
{
(void) calculation; /* unused parameter */
if((int) ((long) direction) == 1)
{
if(RTuntranslatedEntryCounter == 0)
{
// Entering a system call...
DYNINST_stopThread(pointAddr, callbackID, flags, (void*) 1);
}
RTuntranslatedEntryCounter++;
}
else
{
if(RTuntranslatedEntryCounter > 0)
{
RTuntranslatedEntryCounter--;
}
if(RTuntranslatedEntryCounter == 0)
{
DYNINST_stopThread(pointAddr, callbackID, flags, (void*) 0);
}
}
}
@@ -33,6 +33,8 @@
* RTposix.c: runtime instrumentation functions for generic posix.
************************************************************************/
#define _GNU_SOURCE
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
@@ -56,7 +58,7 @@
#if !(defined(arch_power) && defined(os_linux))
void
RTmutatedBinary_init()
RTmutatedBinary_init(void)
{
return;
}
@@ -81,7 +83,7 @@ struct passwd* passwd_info = NULL;
#endif
void
libdyninstAPI_RT_init()
libdyninstAPI_RT_init(void)
{
static int initCalledOnce = 0;
@@ -198,7 +200,7 @@ DYNINSTasyncConnect(int pid)
}
int
DYNINSTasyncDisconnect()
DYNINSTasyncDisconnect(void)
{
if(DYNINSTstaticMode) return 0;
rtdebug_printf("%s[%d]: welcome to DYNINSTasyncDisconnect\n", __FILE__, __LINE__);
@@ -281,7 +283,7 @@ extern void
dyninstTrapHandler(int sig, siginfo_t* info, void* context);
int
DYNINSTinitializeTrapHandler()
DYNINSTinitializeTrapHandler(void)
{
int result;
struct sigaction new_handler;
@@ -32,6 +32,8 @@
* RTsignal.c: C-language signal handling code
************************************************************************/
#define _GNU_SOURCE
#include <signal.h>
#include <stdio.h>
@@ -1,82 +0,0 @@
/*
* See the dyninst/COPYRIGHT file for copyright information.
*
* We provide the Paradyn Tools (below described as "Paradyn")
* on an AS IS basis, and do not warrant its validity or performance.
* We reserve the right to update, modify, or discontinue this
* software at any time. We shall have no obligation to supply such
* updates or modifications or any other form of support to you.
*
* By your use of Paradyn, you understand and agree that we (or any
* other person or entity with proprietary rights in Paradyn) are
* under no obligation to provide either maintenance services,
* update services, notices of latent defects, or correction of
* defects for Paradyn.
*
* This library 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; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
// #warning "This file is not implemented yet!"
#if defined(DYNINST_RT_STATIC_LIB)
# include <assert.h>
void (*DYNINSTctors_addr)(void);
void (*DYNINSTdtors_addr)(void);
// #if defined(MUTATEE64)
// static const unsigned long long CTOR_LIST_TERM = 0x0000000000000000ULL;
// static const unsigned long long CTOR_LIST_START = 0xffffffffffffffffULL;
// static const unsigned long long DTOR_LIST_TERM = 0x0000000000000000ULL;
// static const unsigned long long DTOR_LIST_START = 0xffffffffffffffffULL;
// #else
/*
static const unsigned CTOR_LIST_TERM = 0x00000000;
static const unsigned CTOR_LIST_START = 0xffffffff;
static const unsigned DTOR_LIST_TERM = 0x00000000;
static const unsigned DTOR_LIST_START = 0xffffffff;
*/
// #endif
extern void
DYNINSTBaseInit();
/*
* When rewritting a static binary, .ctors and .dtors sections of
* instrumentation code needs to be combined with the existing .ctors
* and .dtors sections of the static binary.
*
* The following functions process the .ctors and .dtors sections
* that have been rewritten. The rewriter will relocate the
* address of DYNINSTctors_addr and DYNINSTdtors_addr to point to
* new .ctors and .dtors sections.
*/
void
DYNINSTglobal_ctors_handler()
{
// #warning "This function is not implemented yet!"
assert(0);
}
void
DYNINSTglobal_dtors_handler()
{
// #warning "This function is not implemented yet!"
assert(0);
}
#endif
@@ -1,102 +0,0 @@
/*
* See the dyninst/COPYRIGHT file for copyright information.
*
* We provide the Paradyn Tools (below described as "Paradyn")
* on an AS IS basis, and do not warrant its validity or performance.
* We reserve the right to update, modify, or discontinue this
* software at any time. We shall have no obligation to supply such
* updates or modifications or any other form of support to you.
*
* By your use of Paradyn, you understand and agree that we (or any
* other person or entity with proprietary rights in Paradyn) are
* under no obligation to provide either maintenance services,
* update services, notices of latent defects, or correction of
* defects for Paradyn.
*
* This library 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; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if defined(DYNINST_RT_STATIC_LIB)
void (*DYNINSTctors_addr)(void);
void (*DYNINSTdtors_addr)(void);
# if defined(MUTATEE64)
static const unsigned long long CTOR_LIST_TERM = 0x0000000000000000ULL;
static const unsigned long long CTOR_LIST_START = 0xffffffffffffffffULL;
static const unsigned long long DTOR_LIST_TERM = 0x0000000000000000ULL;
static const unsigned long long DTOR_LIST_START = 0xffffffffffffffffULL;
# else
static const unsigned CTOR_LIST_TERM = 0x00000000;
static const unsigned CTOR_LIST_START = 0xffffffff;
static const unsigned DTOR_LIST_TERM = 0x00000000;
static const unsigned DTOR_LIST_START = 0xffffffff;
# endif
extern void
DYNINSTBaseInit();
/*
* When rewritting a static binary, .ctors and .dtors sections of
* instrumentation code needs to be combined with the existing .ctors
* and .dtors sections of the static binary.
*
* The following functions process the .ctors and .dtors sections
* that have been rewritten. The rewriter will relocate the
* address of DYNINSTctors_addr and DYNINSTdtors_addr to point to
* new .ctors and .dtors sections.
*/
void
DYNINSTglobal_ctors_handler()
{
void (**ctors_array)(void) = &DYNINSTctors_addr;
// Find end of function pointer list
void (**tmp_ptr)(void) = ctors_array;
unsigned size = 0;
while(*tmp_ptr != ((void (*)(void)) CTOR_LIST_TERM))
{
size++;
tmp_ptr++;
}
// Constructors are called in the reverse order that they are listed
tmp_ptr = &ctors_array[size - 1]; // skip list end
while(*tmp_ptr != ((void (*)(void)) CTOR_LIST_START))
{
(*tmp_ptr)();
tmp_ptr--;
}
// This ensures that instrumentation cannot execute until all global
// constructors have run
DYNINSTBaseInit();
}
void
DYNINSTglobal_dtors_handler()
{
void (**dtors_array)(void) = &DYNINSTdtors_addr;
// Destructors are called in the forward order that they are listed
void (**tmp_ptr)(void) = &dtors_array[1]; // skip list start
while(*tmp_ptr != ((void (*)(void)) DTOR_LIST_TERM))
{
(*tmp_ptr)();
tmp_ptr++;
}
}
#endif
@@ -1,72 +0,0 @@
/*
* See the dyninst/COPYRIGHT file for copyright information.
*
* We provide the Paradyn Tools (below described as "Paradyn")
* on an AS IS basis, and do not warrant its validity or performance.
* We reserve the right to update, modify, or discontinue this
* software at any time. We shall have no obligation to supply such
* updates or modifications or any other form of support to you.
*
* By your use of Paradyn, you understand and agree that we (or any
* other person or entity with proprietary rights in Paradyn) are
* under no obligation to provide either maintenance services,
* update services, notices of latent defects, or correction of
* defects for Paradyn.
*
* This library 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; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if defined(DYNINST_RT_STATIC_LIB)
# include <stdint.h>
extern void (*DYNINSTctors_begin)(void);
extern void (*DYNINSTdtors_begin)(void);
extern void (*DYNINSTctors_end)(void);
extern void (*DYNINSTdtors_end)(void);
extern void
DYNINSTBaseInit();
void
DYNINSTglobal_ctors_handler()
{
void (**ctor)(void) = &DYNINSTctors_begin;
while(ctor != (&DYNINSTctors_end))
{
if(*ctor && ((intptr_t) *ctor != -1)) (*ctor)();
ctor++;
}
// This ensures that instrumentation cannot execute until all global
// constructors have run
DYNINSTBaseInit();
}
void
DYNINSTglobal_dtors_handler()
{
void (**dtor)(void) = &DYNINSTdtors_begin;
// Destructors are called in the forward order that they are listed
while(dtor != (&DYNINSTdtors_end))
{
if(*dtor && ((intptr_t) *dtor != -1)) (*dtor)();
dtor++;
}
}
#endif
@@ -39,7 +39,7 @@ extern void (*DYNINSTctors_end)(void);
extern void (*DYNINSTdtors_end)(void);
extern void
DYNINSTBaseInit();
DYNINSTBaseInit(void);
typedef struct
{
@@ -66,7 +66,7 @@ typedef struct
*/
void
DYNINSTglobal_ctors_handler()
DYNINSTglobal_ctors_handler(void)
{
void (**ctor)(void) = &DYNINSTctors_begin;
@@ -82,7 +82,7 @@ DYNINSTglobal_ctors_handler()
}
void
DYNINSTglobal_dtors_handler()
DYNINSTglobal_dtors_handler(void)
{
void (**dtor)(void) = &DYNINSTdtors_begin;
@@ -95,7 +95,7 @@ DYNINSTglobal_dtors_handler()
}
void
DYNINSTglobal_irel_handler()
DYNINSTglobal_irel_handler(void)
{
if(sizeof(long) == 8)
{
@@ -1,41 +0,0 @@
/*
* See the dyninst/COPYRIGHT file for copyright information.
*
* We provide the Paradyn Tools (below described as "Paradyn")
* on an AS IS basis, and do not warrant its validity or performance.
* We reserve the right to update, modify, or discontinue this
* software at any time. We shall have no obligation to supply such
* updates or modifications or any other form of support to you.
*
* By your use of Paradyn, you understand and agree that we (or any
* other person or entity with proprietary rights in Paradyn) are
* under no obligation to provide either maintenance services,
* update services, notices of latent defects, or correction of
* defects for Paradyn.
*
* This library 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; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "src/RTthread.h"
#include <stdbool.h>
int
tc_lock_lock(tc_lock_t* t)
{
dyntid_t me = dyn_pthread_self();
volatile bool* l = (volatile bool*) (&(t->mutex));
while(__atomic_test_and_set(l, __ATOMIC_ACQUIRE))
if(t->tid == me) return DYNINST_DEAD_LOCK;
return 0;
}
@@ -1,9 +0,0 @@
#include "RTconst.h"
#include "../../dyninstAPI/src/inst-power.h"
.machine "push"
#ifndef __clang__
.machine "ppc"
#endif
.machine "pop"
.section .note.GNU-stack,"",@progbits
@@ -1,77 +0,0 @@
.file "RTthread-powerpc-asm.S"
.machine "push"
#if defined(arch_ppc_little_endian)
.abiversion 2
#endif
#ifndef __clang__
# if defined(arch_64bit)
.machine "ppc64"
# else
.machine "ppc"
# endif
#endif
.section ".text"
.align 2
# /* ------------------------------------------- */
# /* int atomic_set(volatile int *int_ptr); */
# /* */
# /* The only possible values at the given */
# /* memory location are 0 and 1. Attempt to */
# /* atomically update the value from 0 to 1. */
# /* Return 1 if such an atomic update occurred; */
# /* return 0 otherwise. */
# /* ------------------------------------------- */
#if defined(arch_ppc_little_endian)
.section ".toc", "aw"
.section ".text"
.align 2
.p2align 4,,15
.globl atomic_set
.type atomic_set, @function
atomic_set:
#elif defined(arch_64bit)
.globl atomic_set
.section ".opd", "aw"
.align 3
atomic_set:
.quad .atomic_set, .TOC.@tocbase, 0
.size atomic_set, 24
.previous
.globl .atomic_set
.type .atomic_set, @function
.atomic_set:
#else
.globl atomic_set
.type atomic_set, @function
atomic_set:
#endif
addi 4,0,1 # r4 = 1
# Attempt atomic memory swap
lwarx 5,0,3 # r5 = *int_ptr (load reserve indexed)
stwcx. 4,0,3 # *int_ptr = 1 (store conditional indexed)
bne- atomic_set_return_0 # if atomic swap failed, return 0
cmpw 5,4 # if original value was already 1,
beq- atomic_set_return_0 # return 0 because no value update occurred
addi 3,0,1 # function return value = r3 = 1
blr # branch via link register (function return)
atomic_set_return_0:
addi 3,0,0 # function return value = r3 = 0
blr # branch via link register (function return)
#if defined(arch_ppc_little_endian)
.size atomic_set, . - atomic_set
#elif defined(arch_64bit)
.size .atomic_set, . - .atomic_set
#else
.size atomic_set, . - atomic_set
#endif
.machine "pop"
.section .note.GNU-stack,"",@progbits
@@ -1,63 +0,0 @@
/*
* See the dyninst/COPYRIGHT file for copyright information.
*
* We provide the Paradyn Tools (below described as "Paradyn")
* on an AS IS basis, and do not warrant its validity or performance.
* We reserve the right to update, modify, or discontinue this
* software at any time. We shall have no obligation to supply such
* updates or modifications or any other form of support to you.
*
* By your use of Paradyn, you understand and agree that we (or any
* other person or entity with proprietary rights in Paradyn) are
* under no obligation to provide either maintenance services,
* update services, notices of latent defects, or correction of
* defects for Paradyn.
*
* This library 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; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "src/RTthread.h"
/**
* atomic_set will do the following atomically:
* if (*val == 0) {
* *val = 1;
* return 1;
* }
* return 0;
*
**/
extern int
atomic_set(volatile int* int_ptr);
int
tc_lock_lock(tc_lock_t* tc)
{
dyntid_t me;
me = dyn_pthread_self();
if(me == tc->tid) return DYNINST_DEAD_LOCK;
while(1)
{
if(tc->mutex == 0 && atomic_set(&tc->mutex))
{
tc->tid = me;
break;
}
}
return 0;
}
@@ -35,11 +35,11 @@
#include "h/dyninstRTExport.h"
DLLEXPORT dyntid_t
dyn_pthread_self(); /*Thread library identifier*/
dyn_pthread_self(void); /*Thread library identifier*/
int
dyn_lwp_self(); /*LWP used by the kernel identifier*/
dyn_lwp_self(void); /*LWP used by the kernel identifier*/
int
dyn_pid_self(); /*PID identifier representing the containing process*/
dyn_pid_self(void); /*PID identifier representing the containing process*/
extern int DYNINST_multithread_capable;
@@ -1,565 +0,0 @@
/*
* See the dyninst/COPYRIGHT file for copyright information.
*
* We provide the Paradyn Tools (below described as "Paradyn")
* on an AS IS basis, and do not warrant its validity or performance.
* We reserve the right to update, modify, or discontinue this
* software at any time. We shall have no obligation to supply such
* updates or modifications or any other form of support to you.
*
* By your use of Paradyn, you understand and agree that we (or any
* other person or entity with proprietary rights in Paradyn) are
* under no obligation to provide either maintenance services,
* update services, notices of latent defects, or correction of
* defects for Paradyn.
*
* This library 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; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/************************************************************************
* $Id: RTwinnt.c,v 1.22 2006/06/09 03:50:49 jodom Exp $
* RTwinnt.c: runtime instrumentation functions for Windows NT
************************************************************************/
#include "RTcommon.h"
#include "h/dyninstAPI_RT.h"
#include <Dbghelp.h>
#include <Psapi.h>
#include <WS2tcpip.h>
#include <WinSock2.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <io.h>
#include <limits.h>
#include <mmsystem.h>
#include <process.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <windows.h>
extern unsigned long dyninstTrapTableUsed;
extern unsigned long dyninstTrapTableVersion;
extern trapMapping_t* dyninstTrapTable;
extern unsigned long dyninstTrapTableIsSorted;
extern void
DYNINSTBaseInit();
extern double DYNINSTstaticHeap_512K_lowmemHeap_1[];
extern double DYNINSTstaticHeap_16M_anyHeap_1[];
extern unsigned long sizeOfLowMemHeap1;
extern unsigned long sizeOfAnyHeap1;
/************************************************************************
* void DYNINSTbreakPoint(void)
*
* stop oneself.
************************************************************************/
void
DYNINSTbreakPoint(void)
{
/* TODO: how do we stop all threads? */
DYNINST_break_point_event = 1;
DebugBreak();
DYNINST_break_point_event = 0;
}
void
DYNINSTsafeBreakPoint()
{
DYNINSTbreakPoint();
}
static dyntid_t initial_thread_tid;
/* this function is automatically called when windows loads this dll
if we are launching a mutatee to instrument, dyninst will place
the correct values in libdyninstAPI_RT_DLL_localPid and
libdyninstAPI_RT_DLL_localCause and they will be passed to
DYNINSTinit to correctly initialize the dll. this keeps us
from having to instrument two steps from the mutator (load and then
the execution of DYNINSTinit()
*/
BOOL WINAPI
DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
static int DllMainCalledOnce = 0;
// fprintf(stderr,"RTLIB: In DllMain staticmode=%d %s[%d]\n", DYNINSTstaticMode,
// __FILE__,__LINE__);
if(DllMainCalledOnce) return 1;
DllMainCalledOnce++;
DYNINSTinit();
#if defined(cap_mutatee_traps)
if(DYNINSTstaticMode)
{
DYNINSTinitializeTrapHandler();
}
#endif
return 1;
}
char gLoadLibraryErrorString[ERROR_STRING_LENGTH];
int
DYNINSTloadLibrary(char* libname)
{
HMODULE res;
gLoadLibraryErrorString[0] = '\0';
res = LoadLibrary(libname);
if(res == NULL)
{
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), gLoadLibraryErrorString,
ERROR_STRING_LENGTH, NULL);
return 0;
}
return 1;
}
/************************************************************************
* void DYNINSTasyncConnect()
*
* Connect to mutator's async handler thread. <pid> is pid of mutator
************************************************************************/
// CRITICAL_SECTION comms_mutex;
int async_socket = -1;
int connect_port = 0;
int
DYNINSTasyncConnect(int mutatorpid)
{
int sock_fd;
struct sockaddr_in sadr;
struct in_addr* inadr;
struct addrinfo* result = NULL;
WORD wsversion = MAKEWORD(2, 0);
WSADATA wsadata;
rtBPatch_asyncEventRecord ev;
if(async_socket != -1)
{
/*fprintf(stderr, "%s[%d]: already connected\n", __FILE__, __LINE__);*/
return 0;
}
RTprintf("%s[%d]: inside DYNINSTasyncConnect\n", __FILE__, __LINE__);
if(0 == connect_port)
{
fprintf(stderr, "%s[%d]: DYNINSTasyncConnect, no port\n", __FILE__, __LINE__);
}
WSAStartup(wsversion, &wsadata);
RTprintf("%s[%d]: DYNINSTasyncConnect before gethostbyname\n", __FILE__, __LINE__);
getaddrinfo("localhost", NULL, NULL, &result);
inadr = (struct in_addr*) result->ai_addr;
RTprintf("%s[%d]: inside DYNINSTasyncConnect before memset\n", __FILE__, __LINE__);
memset((void*) &sadr, 0, sizeof(sadr));
sadr.sin_family = PF_INET;
sadr.sin_port = htons((u_short) connect_port);
sadr.sin_addr = *inadr;
RTprintf("%s[%d]: DYNINSTasyncConnect before socket\n", __FILE__, __LINE__);
sock_fd = socket(PF_INET, SOCK_STREAM, 0);
if(sock_fd == INVALID_SOCKET)
{
fprintf(stderr, "DYNINST: socket failed: %d\n", WSAGetLastError());
}
RTprintf("%s[%d]: DYNINSTasyncConnect before connect\n", __FILE__, __LINE__);
if(connect(sock_fd, (struct sockaddr*) &sadr, sizeof(sadr)) == SOCKET_ERROR)
{
fprintf(stderr, "DYNINSTasyncConnect: connect failed: %d\n", WSAGetLastError());
}
/* maybe need to do fcntl to set nonblocking writes on this fd */
async_socket = sock_fd;
RTprintf("%s[%d]: DYNINSTasyncConnect before write\n", __FILE__, __LINE__);
/* after connecting, we need to send along our pid */
ev.type = rtBPatch_newConnectionEvent;
ev.pid = _getpid();
if(!DYNINSTwriteEvent((void*) &ev, sizeof(rtBPatch_asyncEventRecord)))
{
fprintf(stderr, "%s[%d]: DYNINSTwriteEventFailed\n", __FILE__, __LINE__);
}
/* initialize comms mutex */
// InitializeCriticalSection(&comms_mutex);
// fprintf(stderr, "%s[%d]: DYNINSTasyncConnect appears to have succeeded\n",
// __FILE__, __LINE__);
RTprintf("%s[%d]: leaving DYNINSTasyncConnect\n", __FILE__, __LINE__);
freeaddrinfo(result);
return 1; /*true*/
}
int
DYNINSTasyncDisconnect()
{
WSACleanup();
return _close(async_socket);
}
void
printSysError(unsigned errNo)
{
char buf[1000];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errNo,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 1000, NULL);
fprintf(stderr, "*** System error [%d]: %s\n", errNo, buf);
fflush(stderr);
}
int
DYNINSTwriteEvent(void* ev, size_t sz)
{
DYNINSTasyncConnect(DYNINST_mutatorPid);
if(send((SOCKET) async_socket, ev, sz, 0) != sz)
{
printSysError(WSAGetLastError());
printf("DYNINSTwriteTrace: send error %d, %d %d\n", WSAGetLastError(), sz,
async_socket);
if(async_socket == -1) return 1;
return 0;
}
return 1;
}
int
dyn_pid_self()
{
return _getpid();
}
int
dyn_lwp_self()
{
#ifdef _WIN64
return GetCurrentThreadId();
#else
/* return GetCurrentThreadId(); */
/* getCurrentThreadId() is conflicting with SD-Dyninst instrumentation.
* So I'm doing the massively unportable thing here and hard-coding the assembly
* FOR GREAT JUSTICE!
*/
/* This will do stack frame setup, but that seems harmless in this context... */
__asm {
mov EAX,FS:[0x18]
mov EAX,DS:[EAX+0x24]
}
#endif
}
dyntid_t
dyn_pthread_self()
{
return (dyntid_t) dyn_lwp_self();
}
int
DYNINSTthreadInfo(BPatch_newThreadEventRecord* ev)
{
return 1;
}
/*
We reserve index 0 for the initial thread. This value varies by
platform but is always constant for that platform. Wrap that
platform-ness here.
*/
int
DYNINST_am_initial_thread(dyntid_t tid)
{
return (tid == initial_thread_tid);
}
// Check that the address is backed by a file,
// get the binary's load address,
// get the PE header, assuming there is one,
// see if the last section has been tagged with "DYNINST_REWRITE"
// get trap-table header from last binary section's end - label - size
// sets allocBase to the binary's load address
static struct trap_mapping_header*
getStaticTrapMap(unsigned long addr, unsigned long* allocBase)
{
struct trap_mapping_header* header = NULL;
char fileName[ERROR_STRING_LENGTH];
DWORD actualNameLen = 0;
MEMORY_BASIC_INFORMATION memInfo;
int numSections = 0;
PIMAGE_NT_HEADERS peHdr = NULL;
IMAGE_SECTION_HEADER curSecn;
int sidx = 0;
char* str = NULL;
// check that the address is backed by a file
actualNameLen = GetMappedFileName(GetCurrentProcess(), (LPVOID) addr, fileName,
ERROR_STRING_LENGTH);
if(!actualNameLen)
{
fileName[0] = '\0';
goto done; // no file mapped at trap address
}
fileName[ERROR_STRING_LENGTH - 1] = '\0';
// get the binary's load address, size
if(!VirtualQuery((LPCVOID) addr, &memInfo, sizeof(memInfo)) ||
MEM_COMMIT != memInfo.State)
{
fprintf(stderr, "ERROR IN RTLIB: getStaticTrapMap %s[%d]\n", __FILE__, __LINE__);
goto done; // shouldn't be possible given previous query, but hey
}
*allocBase = (unsigned long) memInfo.AllocationBase;
rtdebug_printf("RTLIB: getStaticTrapMap addr=%lx meminfo.BaseAddress=%lx "
"meminfo.AllocationBase = %lx, memInfo.RegionSize = %lx, "
"%s[%d]\n",
addr, memInfo.BaseAddress, memInfo.AllocationBase, memInfo.RegionSize,
__FILE__, __LINE__);
// get the PE header, assuming there is one
peHdr = ImageNtHeader(memInfo.AllocationBase);
if(!peHdr)
{
fprintf(stderr, "ERROR IN RTLIB: getStaticTrapMap %s[%d]\n", __FILE__, __LINE__);
goto done; // no pe header
}
// see if the last section has been tagged with "DYNINST_REWRITE"
numSections = peHdr->FileHeader.NumberOfSections;
curSecn = *(PIMAGE_SECTION_HEADER) (((unsigned char*) peHdr) + sizeof(DWORD) +
sizeof(IMAGE_FILE_HEADER) +
peHdr->FileHeader.SizeOfOptionalHeader +
sizeof(IMAGE_SECTION_HEADER) * (numSections - 1));
// fprintf(stderr, "RTLIB: PE section header address = %lx\n", curSecn);
// fprintf(stderr, "curSecn.chars = %lx %s[%d]\n",curSecn.Characteristics,
// __FILE__,__LINE__);
if((sizeof(void*) + 16) > curSecn.SizeOfRawData)
{
fprintf(stderr, "ERROR IN RTLIB: getStaticTrapMap %s[%d]\n", __FILE__, __LINE__);
goto done; // last section is uninitialized, doesn't have trap table
}
// fprintf(stderr, "RTLIB %s[%d]\n", __FILE__,__LINE__);
// fprintf(stderr, "RTLIB mi.ab =%lx cs.va =%lx cs.srd=%lx %s[%d]\n",
// memInfo.AllocationBase, curSecn.VirtualAddress, curSecn.SizeOfRawData,
// __FILE__,__LINE__);
str = (char*) ((long) memInfo.AllocationBase + curSecn.VirtualAddress +
curSecn.SizeOfRawData - 16);
if(0 != strncmp("DYNINST_REWRITE", str, 15))
{
fprintf(stderr,
"ERROR IN RTLIB: getStaticTrapMap found bad string [%s] at %p (%s[%d])\n",
str, str, __FILE__, __LINE__);
goto done; // doesn't have DYNINST_REWRITE label
}
// get trap-table header
header = (struct trap_mapping_header*) ((unsigned long) memInfo.AllocationBase +
*((unsigned long*) (str - sizeof(void*))));
done:
if(header)
{
rtdebug_printf("RTLIB: found trap map header at %lx: [%lx %lx]\n",
(unsigned long) header, header->low_entry, header->high_entry);
}
else
{
rtdebug_printf("ERROR: didn't find trap table\n");
}
return header;
}
// Find the target IP and substitute. Leave everything else untouched.
LONG
dyn_trapHandler(PEXCEPTION_POINTERS e)
{
void* trap_to = 0;
void* trap_addr = (void*) ((unsigned char*) e->ExceptionRecord->ExceptionAddress);
unsigned long zero = 0;
unsigned long one = 1;
unsigned long loadAddr = 0;
struct trap_mapping_header* hdr = NULL;
trapMapping_t* mapping = NULL;
rtdebug_printf("RTLIB: In dyn_trapHandler for exception type 0x%lx at 0x%lx\n",
e->ExceptionRecord->ExceptionCode, trap_addr);
assert(DYNINSTstaticMode && "detach on the fly not implemented on Windows");
if(EXCEPTION_BREAKPOINT != e->ExceptionRecord->ExceptionCode)
{
fprintf(stderr,
"RTLIB: dyn_trapHandler exiting early, exception "
"type = 0x%lx triggered at %p is not breakpoint %s[%d]\n",
e->ExceptionRecord->ExceptionCode, trap_addr, __FILE__, __LINE__);
return EXCEPTION_CONTINUE_SEARCH;
}
hdr = getStaticTrapMap((unsigned long) trap_addr, &loadAddr);
assert(hdr);
mapping = &(hdr->traps[0]);
rtdebug_printf("RTLIB: calling dyninstTrapTranslate(\n\t0x%lx, \n\t"
"0x%lx, \n\t0x%lx, \n\t0x%lx, \n\t0x%lx)\n",
(unsigned long) trap_addr - loadAddr + 1, hdr->num_entries, zero,
mapping, one);
trap_to = dyninstTrapTranslate((void*) ((unsigned long) trap_addr - loadAddr + 1),
(unsigned long*) &hdr->num_entries, &zero,
(volatile trapMapping_t**) &mapping, &one);
#ifdef _WIN64
rtdebug_printf("RTLIB: changing Rip from trap at 0x%lx to 0x%lx\n",
e->ContextRecord->Rip, (long) trap_to + loadAddr);
e->ContextRecord->Rip = (long) trap_to + loadAddr;
#else
rtdebug_printf("RTLIB: changing Eip from trap at 0x%lx to 0x%lx\n",
e->ContextRecord->Eip, (long) trap_to + loadAddr);
e->ContextRecord->Eip = (long) trap_to + loadAddr;
#endif
return EXCEPTION_CONTINUE_EXECUTION;
}
PVOID fake_AVEH_handle;
/* registers the trap handler by calling AddVectoredExceptionHandler
*/
int
DYNINSTinitializeTrapHandler()
{
fake_AVEH_handle = AddVectoredExceptionHandler(
RT_TRUE, (PVECTORED_EXCEPTION_HANDLER) dyn_trapHandler);
rtdebug_printf("RTLIB: added vectored trap handler\n");
return fake_AVEH_handle != 0;
}
PVOID
dyn_AddVectoredExceptionHandler(ULONG isFirst, PVECTORED_EXCEPTION_HANDLER handler)
{
PVOID handlerHandle;
if(isFirst)
{
RemoveVectoredExceptionHandler(fake_AVEH_handle);
handlerHandle = AddVectoredExceptionHandler(isFirst, handler);
fake_AVEH_handle = AddVectoredExceptionHandler(
isFirst, (PVECTORED_EXCEPTION_HANDLER) dyn_trapHandler);
}
else
{
handlerHandle = AddVectoredExceptionHandler(isFirst, handler);
}
return handlerHandle;
}
extern int fakeTickCount;
extern FILE* stOut;
DWORD __stdcall DYNINST_FakeTickCount()
{
DWORD tmp = 0x12345678;
if(0 == fakeTickCount)
{
fakeTickCount = tmp;
}
else
{
fakeTickCount = fakeTickCount + 2;
// fakeTickCount = fakeTickCount + (tmp - fakeTickCount)/1000 + 1;
}
fprintf(stOut, "0x%lx = DYNINST_FakeTickCount()\n", fakeTickCount);
return (DWORD) fakeTickCount;
}
BOOL __stdcall DYNINST_FakeBlockInput(BOOL blockit)
{
BOOL ret = RT_TRUE;
fprintf(stOut, "0x%lx = DYNINST_FakeBlockInput(%d)\n", ret, blockit);
return ret;
}
DWORD __stdcall DYNINST_FakeSuspendThread(HANDLE hThread)
{
DWORD suspendCnt = 0;
fprintf(stOut, "%d = DYNINST_FakeSuspendThread(%p)\n", suspendCnt, hThread);
return suspendCnt;
}
BOOL __stdcall DYNINST_FakeCheckRemoteDebuggerPresent(HANDLE hProcess,
PBOOL bpDebuggerPresent)
{
BOOL ret = RT_FALSE;
fprintf(stOut, "%d = DYNINST_FakeCheckRemoteDebuggerPresent(%p,%p)\n", ret, hProcess,
bpDebuggerPresent);
(*bpDebuggerPresent) = ret;
return ret;
}
VOID __stdcall DYNINST_FakeGetSystemTime(LPSYSTEMTIME lpSystemTime)
{
lpSystemTime->wYear = 2009;
lpSystemTime->wMonth = 5;
lpSystemTime->wDayOfWeek = 0;
lpSystemTime->wDay = 3;
lpSystemTime->wHour = 10;
lpSystemTime->wMinute = 1;
lpSystemTime->wSecond = 33;
lpSystemTime->wMilliseconds = 855;
fprintf(stOut, "called DYNINST_FakeGetSystemTime()\n");
fflush(stOut);
}
void
mark_heaps_exec()
{
int OK;
DWORD old_permissions;
OK = VirtualProtect(DYNINSTstaticHeap_16M_anyHeap_1, sizeOfAnyHeap1,
PAGE_EXECUTE_READWRITE, &old_permissions);
if(!OK)
{
fprintf(stderr, "ERROR: 16M/any heap not usable in RTlib: %d\n", GetLastError());
}
OK = VirtualProtect(DYNINSTstaticHeap_512K_lowmemHeap_1, sizeOfLowMemHeap1,
PAGE_EXECUTE_READWRITE, &old_permissions);
if(!OK)
{
fprintf(stderr, "ERROR: 512k/lowmem heap not usable in RTlib: %d\n",
GetLastError());
}
}
@@ -20,4 +20,4 @@ _section_.text:
.csect .data[RW],3
.llong _section_.text
.section .note.GNU-stack,"",@progbits
.section .note.GNU-stack,"",@progbits