Rename Omnitrace to ROCm Systems Profiler (#4)

The Omnitrace program is being renamed. 

Full name: "ROCm Systems Profiler"
Package name: "rocprofiler-systems"
Binary / Library names: "rocprof-sys-*"

---------
Co-authored-by: Xuan Chen <xuchen@amd.com>
Signed-off-by: David Galiffi <David.Galiffi@amd.com>

[ROCm/rocprofiler-systems commit: d07bf508a9]
This commit is contained in:
David Galiffi
2024-10-15 11:20:40 -04:00
committed by GitHub
parent c444ba6131
commit 489eda995d
420 changed files with 10418 additions and 9914 deletions
@@ -0,0 +1,16 @@
curRPC
DYNINSTversion
DYNINSTobsCostLow
DYNINSTglobalData
DYNINSTinit
DYNINSTos_init
pcAtLastIRPC
DYNINSTos_malloc
DYNINSTos_free
DYNINSTheap_useMalloc
DYNINSTheap_mmapFdOpen
DYNINSTheap_mmapFdClose
DYNINSTgetMemoryMap
DYNINSTstaticHeap_16M_textHeap_1
DYNINSTstaticHeap_16M_anyHeap_1
DYNINSTstaticHeap_32K_lowmemHeap_1
@@ -0,0 +1,814 @@
/*
* 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: RTcommon.c,v 1.78 2008/04/15 16:43:44 roundy Exp $ */
#include "RTcommon.h"
#include "RTthread.h"
#include "h/dyninstAPI_RT.h"
#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
unsigned int DYNINSTobsCostLow;
DLLEXPORT unsigned int DYNINSThasInitialized = 0;
struct DYNINST_bootstrapStruct DYNINST_bootstrap_info;
char gLoadLibraryErrorString[ERROR_STRING_LENGTH];
int DYNINSTdebugRTlib = 0;
DLLEXPORT int DYNINSTstaticMode = 1;
/**
* Allocate the Dyninst heaps
*
* The IA-64 requires that instruction be 16-byte aligned, so we have to
* align the heaps if we want to use them for inferior RPCs.
**/
#define HEAP_TYPE double
#define ALIGN_ATTRIB
#if defined(os_linux) || defined(os_freebsd)
# define HEAP_LOCAL extern
#else
# define HEAP_LOCAL DLLEXPORT
#endif
HEAP_LOCAL HEAP_TYPE
DYNINSTglobalData[SYN_INST_BUF_SIZE / sizeof(HEAP_TYPE)] ALIGN_ATTRIB;
#if !defined(target_smallmem)
HEAP_LOCAL HEAP_TYPE
DYNINSTstaticHeap_512K_lowmemHeap_1[512 * 1024 / sizeof(HEAP_TYPE)] ALIGN_ATTRIB;
HEAP_LOCAL HEAP_TYPE
DYNINSTstaticHeap_16M_anyHeap_1[16 * 1024 * 1024 / sizeof(HEAP_TYPE)] ALIGN_ATTRIB;
/* These are necessary due to silly C-style 'extern'/linking conventions. */
const unsigned long sizeOfLowMemHeap1 = sizeof(DYNINSTstaticHeap_512K_lowmemHeap_1);
const unsigned long sizeOfAnyHeap1 = sizeof(DYNINSTstaticHeap_16M_anyHeap_1);
#else
HEAP_LOCAL HEAP_TYPE
DYNINSTstaticHeap_8K_lowmemHeap_1[8 * 1024 / sizeof(HEAP_TYPE)] ALIGN_ATTRIB;
HEAP_LOCAL HEAP_TYPE
DYNINSTstaticHeap_32K_anyHeap_1[32 * 1024 / sizeof(HEAP_TYPE)] ALIGN_ATTRIB;
/* These are necessary due to silly C-style 'extern'/linking conventions. */
const unsigned long sizeOfLowMemHeap1 = sizeof(DYNINSTstaticHeap_8K_lowmemHeap_1);
const unsigned long sizeOfAnyHeap1 = sizeof(DYNINSTstaticHeap_32K_anyHeap_1);
#endif
/**
* One some platforms we can tell when a fork or exec is occurring through
* system-provided events. On others we do it ourselves. Enumerated type
* defined in header file
**/
DLLEXPORT DYNINST_synch_event_t DYNINST_synch_event_id = DSE_undefined;
DLLEXPORT void* DYNINST_synch_event_arg1;
/* Code to read args 2,3 would have to be moved from dyninstAPI's*/
/* process::handleStopThread to signalgenerator::decodeRTSignal in*/
/* order for other signals to make use of them, as currently only the*/
/* stopThread event needs makes use of them. */
DLLEXPORT void* DYNINST_synch_event_arg2 = NULL; /* not read in dyninst's decodeRTSignal*/
DLLEXPORT void* DYNINST_synch_event_arg3 = NULL; /* not read in dyninst's decodeRTSignal*/
DLLEXPORT int DYNINST_break_point_event = 0;
/**
* These variables are used to pass arguments into DYNINSTinit
* when it is called as an _init function
**/
int libdyninstAPI_RT_init_localCause = -1;
int libdyninstAPI_RT_init_localPid = -1;
int libdyninstAPI_RT_init_maxthreads = -1;
int libdyninstAPI_RT_init_debug_flag = 0;
int DYNINST_mutatorPid;
int DYNINSTdebugPrintRT = 0;
int isMutatedExec = 0;
// stopThread cache variables
char cacheLRUflags[TARGET_CACHE_WIDTH];
DLLEXPORT void* DYNINST_target_cache[TARGET_CACHE_WIDTH][TARGET_CACHE_WAYS];
FILE* stOut;
int fakeTickCount;
#ifdef _MSC_VER
# define TLS_VAR __declspec(thread)
#else
// Note, the initial-exec model gives us static TLS which can be accessed
// directly, unlike dynamic TLS that calls __tls_get_addr(). Such calls risk
// recursing back to us if they're also instrumented, ad infinitum. Static TLS
// must be used very sparingly though, because it is a limited resource.
// *** This case is very special -- do not use IE in general libraries! ***
# if defined(DYNINST_RT_STATIC_LIB)
# define TLS_VAR __thread __attribute__((tls_model("local-exec")))
# else
# define TLS_VAR __thread __attribute__((tls_model("initial-exec")))
# endif
#endif
// It's tempting to make this a char, but glibc < 2.17 hits a bug:
// https://sourceware.org/bugzilla/show_bug.cgi?id=14898
static TLS_VAR short DYNINST_tls_tramp_guard = 1;
DLLEXPORT int
DYNINST_lock_tramp_guard()
{
if(!DYNINST_tls_tramp_guard) return 0;
DYNINST_tls_tramp_guard = 0;
return 1;
}
DLLEXPORT void
DYNINST_unlock_tramp_guard()
{
DYNINST_tls_tramp_guard = 1;
}
DECLARE_DYNINST_LOCK(DYNINST_trace_lock);
/**
* Init the FPU. We've seen bugs with Linux (e.g., Redhat 6.2 stock kernel on
* PIIIs) where processes started by Paradyn started with FPU uninitialized.
* DYNINSTdummydouble is global so the compiler won't optimize away FP code
* in initFPU
**/
double DYNINSTdummydouble = 4321.71;
static void
initFPU()
{
double x = 17.1234;
DYNINSTdummydouble *= x;
}
/**
* This function is called in both static and dynamic rewriting, on
* all platforms that support binary rewriting, but before DYNINSTinit
**/
void
DYNINSTBaseInit()
{
#if defined(cap_mutatee_traps)
DYNINSTinitializeTrapHandler();
#endif
DYNINST_unlock_tramp_guard();
DYNINSThasInitialized = 1;
RTuntranslatedEntryCounter = 0;
}
/**
* The Dyninst API arranges for this function to be called at the entry to
* main() via libdyninstAPI_RT_init (defined in RTposix.c and RTwinnt.c).
* libdyninstAPI_RT_init is called by one of the following methods:
* GCC: link with gcc -shared, and use __attribute__((constructor));
* Linux: ld with -init libdyninstAPI_RT_init
* gcc with -Wl,-init -Wl,...
* Windows: called from DllMain, which exists in lieu of libdyninstAPI_RT_init
*
* This is only called in the Dynamic instrumentation case. Static
* libraries don't call this.
**/
void
DYNINSTinit()
{
rtdebug_printf("%s[%d]: DYNINSTinit: welcome to DYNINSTinit()\n", __FILE__,
__LINE__);
initFPU();
mark_heaps_exec();
tc_lock_init(&DYNINST_trace_lock);
DYNINSThasInitialized = 1;
rtdebug_printf("%s[%d]: welcome to DYNINSTinit\n", __FILE__, __LINE__);
/* sanity check */
assert(sizeof(int64_t) == 8);
assert(sizeof(int32_t) == 4);
/* defensive stuff */
memset(DYNINST_target_cache, 0,
sizeof(void*) * TARGET_CACHE_WIDTH * TARGET_CACHE_WAYS);
memset(cacheLRUflags, 1, sizeof(char) * TARGET_CACHE_WIDTH);
// stOut = fopen("rtdump.txt","w");
rtdebug_printf("%s[%d]: leaving DYNINSTinit\n", __FILE__, __LINE__);
fakeTickCount = 0;
/* Memory emulation */
}
/**
* Does what it's called. Used by the paradyn daemon as a default in certain
* cases (MT in particular)
**/
int
DYNINSTreturnZero()
{
return 0;
}
/* Used to by dyninst breakpoint snippet */
void
DYNINST_snippetBreakpoint()
{
tc_lock_lock(&DYNINST_trace_lock);
/* Set the state so the mutator knows what's up */
DYNINST_synch_event_id = DSE_snippetBreakpoint;
DYNINST_synch_event_arg1 = NULL;
/* Stop ourselves */
DYNINSTbreakPoint();
/* Once the stop completes, clean up */
DYNINST_synch_event_id = DSE_undefined;
tc_lock_unlock(&DYNINST_trace_lock);
}
/* Used to instrument (and report) the entry of fork */
DLLEXPORT void
DYNINST_instForkEntry()
{
tc_lock_lock(&DYNINST_trace_lock);
/* Set the state so the mutator knows what's up */
DYNINST_synch_event_id = DSE_forkEntry;
DYNINST_synch_event_arg1 = NULL;
/* Stop ourselves */
DYNINSTbreakPoint();
/* Once the stop completes, clean up */
DYNINST_synch_event_id = DSE_undefined;
DYNINST_synch_event_arg1 = NULL;
tc_lock_unlock(&DYNINST_trace_lock);
}
/* Used to instrument (and report) the exit of fork */
/* We use the safe breakpoint on the child side of fork
as we may not be attached at that point. The parent
side uses the normal version. */
DLLEXPORT void
DYNINST_instForkExit(void* arg1)
{
//#warning "This function is not implemented for AARCH64 yet!"
#if !defined(arch_aarch64)
tc_lock_lock(&DYNINST_trace_lock);
/* Set the state so the mutator knows what's up */
DYNINST_synch_event_id = DSE_forkExit;
DYNINST_synch_event_arg1 = arg1;
/* Stop ourselves */
if((long int) arg1 == 0)
{
/* Child... */
DYNINSTsafeBreakPoint();
}
else
{
DYNINSTbreakPoint();
}
/* Once the stop completes, clean up */
DYNINST_synch_event_id = DSE_undefined;
DYNINST_synch_event_arg1 = NULL;
tc_lock_unlock(&DYNINST_trace_lock);
#else
// Silence compiler warnings
(void) arg1;
assert(0);
#endif
}
/* Used to instrument (and report) the entry of exec */
DLLEXPORT void
DYNINST_instExecEntry(void* arg1)
{
//#warning "This function is not implemented for AARCH64 yet!"
#if !defined(arch_aarch64)
tc_lock_lock(&DYNINST_trace_lock);
/* Set the state so the mutator knows what's up */
DYNINST_synch_event_id = DSE_execEntry;
DYNINST_synch_event_arg1 = arg1;
/* Stop ourselves */
DYNINSTbreakPoint();
/* Once the stop completes, clean up */
DYNINST_synch_event_id = DSE_undefined;
DYNINST_synch_event_arg1 = NULL;
tc_lock_unlock(&DYNINST_trace_lock);
#endif
// Silence compiler warnings
(void) arg1;
}
/* Used to instrument (and report) the exit of exec */
DLLEXPORT void
DYNINST_instExecExit(void* arg1)
{
tc_lock_lock(&DYNINST_trace_lock);
/* Set the state so the mutator knows what's up */
DYNINST_synch_event_id = DSE_execExit;
DYNINST_synch_event_arg1 = arg1;
/* Stop ourselves */
DYNINSTbreakPoint();
/* Once the stop completes, clean up */
DYNINST_synch_event_id = DSE_undefined;
DYNINST_synch_event_arg1 = NULL;
tc_lock_unlock(&DYNINST_trace_lock);
}
/* Used to instrument (and report) the entry of exit */
DLLEXPORT void
DYNINST_instExitEntry(void* arg1)
{
tc_lock_lock(&DYNINST_trace_lock);
/* Set the state so the mutator knows what's up */
DYNINST_synch_event_id = DSE_exitEntry;
DYNINST_synch_event_arg1 = arg1;
/* Stop ourselves */
DYNINSTbreakPoint();
/* Once the stop completes, clean up */
DYNINST_synch_event_id = DSE_undefined;
DYNINST_synch_event_arg1 = NULL;
tc_lock_unlock(&DYNINST_trace_lock);
}
/* Used to instrument (and report) the entry of exit */
DLLEXPORT void
DYNINST_instLoadLibrary(void* arg1)
{
tc_lock_lock(&DYNINST_trace_lock);
/* Set the state so the mutator knows what's up */
DYNINST_synch_event_id = DSE_loadLibrary;
DYNINST_synch_event_arg1 = arg1;
/* Stop ourselves */
DYNINSTbreakPoint();
/* Once the stop completes, clean up */
DYNINST_synch_event_id = DSE_undefined;
DYNINST_synch_event_arg1 = NULL;
tc_lock_unlock(&DYNINST_trace_lock);
}
/* Used to instrument (and report) the entry of exit */
DLLEXPORT void
DYNINST_instLwpExit(void)
{
tc_lock_lock(&DYNINST_trace_lock);
/* Set the state so the mutator knows what's up */
DYNINST_synch_event_id = DSE_lwpExit;
DYNINST_synch_event_arg1 = NULL;
/* Stop ourselves */
DYNINSTbreakPoint();
/* Once the stop completes, clean up */
DYNINST_synch_event_id = DSE_undefined;
DYNINST_synch_event_arg1 = NULL;
tc_lock_unlock(&DYNINST_trace_lock);
}
// implementation of an N=2 way associative cache to keep access time low
// width = 32
// the cache contains valid addresses
// add to the cache when an instrumented instruction misses in the cache
// update flags for the cache when an instrumented instruction hits in the cache
// instrumentation will take the form of a call to cache check
RT_Boolean
cacheLookup(void* calculation)
{
int index = ((unsigned long) calculation) % TARGET_CACHE_WIDTH;
if(DYNINST_target_cache[index][0] == calculation)
{
cacheLRUflags[index] = 0;
return RT_TRUE;
}
else if(DYNINST_target_cache[index][1] == calculation)
{
cacheLRUflags[index] = 1;
return RT_TRUE;
}
else
{ // miss
if(cacheLRUflags[index] == 0)
{
DYNINST_target_cache[index][1] = calculation;
cacheLRUflags[index] = 1;
}
else
{
DYNINST_target_cache[index][0] = calculation;
cacheLRUflags[index] = 0;
}
return RT_FALSE;
}
}
/**
* Receives two snippets as arguments and stops the mutatee
* while the mutator reads the arguments, saved to
* DYNINST_synch_event... global variables.
*
* if flag useCache==1, does a cache lookup and stops only
* if there is a cache miss
*
* The flags are:
* bit 0: useCache
* bit 1: true if interpAsTarget
* bit 2: true if interpAsReturnAddr
**/
//#define STACKDUMP
void
DYNINST_stopThread(void* pointAddr, void* callBackID, void* flags, void* calculation)
{
static int reentrant = 0;
RT_Boolean isInCache = RT_FALSE;
if(reentrant == 1)
{
return;
}
reentrant = 1;
tc_lock_lock(&DYNINST_trace_lock);
rtdebug_printf("RT_st: pt[%lx] flags[%lx] calc[%lx] ", (unsigned long) pointAddr,
(unsigned long) flags, (unsigned long) calculation);
#if 0 && defined STACKDUMP
//if (0 && ((unsigned long)calculation == 0x9746a3 ||
// (unsigned long)calculation == 0x77dd761b))
//{
fprintf(stOut,"RT_st: %lx(%lx)\n", (long)pointAddr,&calculation);
fprintf(stOut,"at instr w/ targ=%lx\n",(long)calculation);
for (bidx=0; bidx < 0x100; bidx+=4) {
fprintf(stOut,"0x%x: ", (int)stackBase+bidx);
fprintf(stOut,"%02hhx", stackBase[bidx]);
fprintf(stOut,"%02hhx", stackBase[bidx+1]);
fprintf(stOut,"%02hhx", stackBase[bidx+2]);
fprintf(stOut,"%02hhx", stackBase[bidx+3]);
fprintf(stOut,"\n");
}
//}
// fsg: read from 40a4aa, how did it become 40a380?
#endif
if((((long) flags) & 0x04))
{
rtdebug_printf("ret-addr stopThread yields %lx", (unsigned long) calculation);
// fprintf(stderr,"[$0x%lx]\n", (long)calculation);
}
if(0 != (((long) flags) & 0x03))
{
// do the lookup if the useCache bit is set, or if it represents
// the address of real code, so that we add the address to the cache
// even if we will stop the thread if there's a cache hit
isInCache = cacheLookup(calculation);
}
// if the cache flag bit is not set, or if we get a cache miss,
// stop the thread so that we can call back to the mutatee
if(0 == (((long) flags) & 0x01) || !isInCache)
{
/* Set vars for Dyninst to read */
DYNINST_synch_event_id = DSE_stopThread;
DYNINST_synch_event_arg1 = pointAddr;
DYNINST_synch_event_arg2 = callBackID;
DYNINST_synch_event_arg3 = calculation;
// encode interp as target or as return addr by making
// callback ID negative
if(0 != (((long) flags) & 0x06))
{
DYNINST_synch_event_arg2 = (void*) (-1 * (long) DYNINST_synch_event_arg2);
}
rtdebug_printf("stopping! isInCache=%d\n", isInCache);
/* Stop ourselves */
DYNINSTbreakPoint();
/* Once the stop completes, clean up */
DYNINST_synch_event_id = DSE_undefined;
DYNINST_synch_event_arg1 = NULL;
DYNINST_synch_event_arg2 = NULL;
DYNINST_synch_event_arg3 = NULL;
}
fflush(stOut);
tc_lock_unlock(&DYNINST_trace_lock);
reentrant = 0;
return;
}
// zeroes out the useCache flag if the call is interprocedural
void
DYNINST_stopInterProc(void* pointAddr, void* callBackID, void* flags, void* calculation,
void* objStart, void* objEnd)
{
#if defined STACKDUMP
fprintf(stOut, "RT_sip: calc=%lx objStart=%lx objEnd=%lx\n", calculation, objStart,
objEnd);
fflush(stOut);
#endif
if(calculation < objStart || calculation >= objEnd)
{
flags = (void*) ((long) (((int) ((long) flags)) & 0xfffffffe));
}
DYNINST_stopThread(pointAddr, callBackID, flags, calculation);
}
// boundsArray is a sequence of (blockStart,blockEnd) pairs
DLLEXPORT RT_Boolean
DYNINST_boundsCheck(void** boundsArray_, void* arrayLen_, void* writeTarget_)
{
RT_Boolean callStopThread = RT_FALSE;
const unsigned long writeTarget = (unsigned long) writeTarget_;
const long arrayLen = (long) arrayLen_;
unsigned long* boundsArray = (unsigned long*) boundsArray_;
// set idx to halfway into the array, ensuring we use a blockStart address
int idx = (int) arrayLen / 4 * 2;
int lowIdx = 0;
int highIdx = (int) arrayLen;
// fprintf(stderr,"D_bc@%p: boundsArray=%p target=%lx idx=%d arrayLen=%d [%d]\n",
// (void*)DYNINST_boundsCheck, boundsArray_, writeTarget_, idx, arrayLen, __LINE__);
// rtdebug_printf("D_bc@%p: boundsArray=%p target=%lx idx=%d arrayLen=%d [%d]\n",
// (void*)DYNINST_boundsCheck, boundsArray_, writeTarget_, idx, arrayLen, __LINE__);
if((unsigned long) boundsArray < 0x10000000)
{
printf("D_bc: boundsArray_ = %lx, returning false\n",
(unsigned long) boundsArray);
return RT_FALSE;
}
while(lowIdx < highIdx)
{
if(idx > arrayLen || idx < 0)
rtdebug_printf("ERROR: out of bounds idx=%d, arrayLen = %ld [%d]\n", idx,
arrayLen, __LINE__);
rtdebug_printf("D_bc: low=%d high=%d arr[%d]=%lx [%d]\n", lowIdx, highIdx, idx,
boundsArray[idx], __LINE__);
if(writeTarget < boundsArray[idx])
{
rtdebug_printf("D_bc: [%d]\n", __LINE__);
highIdx = idx;
idx = (highIdx - lowIdx) / 4 * 2 + lowIdx;
}
else if(boundsArray[idx + 1] <= writeTarget)
{
rtdebug_printf("D_bc: [%d]\n", __LINE__);
lowIdx = idx + 2;
idx = (highIdx - lowIdx) / 4 * 2 + lowIdx;
}
else
{
rtdebug_printf("D_bc: callST=true [%d]\n", __LINE__);
callStopThread = RT_TRUE;
break;
}
}
rtdebug_printf("D_bc: boundsArray=%p ret=%d [%d]\n", (void*) boundsArray,
callStopThread, __LINE__);
return callStopThread;
}
/**
* Used to report addresses of functions called at dynamic call sites
**/
DLLEXPORT int
DYNINSTasyncDynFuncCall(void* call_target, void* call_addr)
{
if(DYNINSTstaticMode) return 0;
tc_lock_lock(&DYNINST_trace_lock);
/* Set the state so the mutator knows what's up */
DYNINST_synch_event_id = DSE_dynFuncCall;
DYNINST_synch_event_arg1 = call_target;
DYNINST_synch_event_arg2 = call_addr;
/* Stop ourselves */
DYNINSTbreakPoint();
/* Once the stop completes, clean up */
DYNINST_synch_event_id = DSE_undefined;
DYNINST_synch_event_arg1 = NULL;
DYNINST_synch_event_arg2 = NULL;
tc_lock_unlock(&DYNINST_trace_lock);
return 0;
}
int
DYNINSTuserMessage(void* msg, unsigned int msg_size)
{
unsigned long msg_size_long = (unsigned long) msg_size;
if(DYNINSTstaticMode)
{
return 0;
}
tc_lock_lock(&DYNINST_trace_lock);
/* Set the state so the mutator knows what's up */
DYNINST_synch_event_id = DSE_userMessage;
DYNINST_synch_event_arg1 = msg;
DYNINST_synch_event_arg2 = (void*) msg_size_long;
/* Stop ourselves */
DYNINSTbreakPoint();
/* Once the stop completes, clean up */
DYNINST_synch_event_id = DSE_undefined;
DYNINST_synch_event_arg1 = NULL;
DYNINST_synch_event_arg2 = NULL;
tc_lock_unlock(&DYNINST_trace_lock);
return 0;
}
int
tc_lock_init(tc_lock_t* t)
{
t->mutex = 0;
t->tid = (dyntid_t) DYNINST_INITIAL_LOCK_PID;
return 0;
}
int
tc_lock_unlock(tc_lock_t* t)
{
t->tid = (dyntid_t) DYNINST_INITIAL_LOCK_PID;
t->mutex = 0;
return 0;
}
int
tc_lock_destroy(tc_lock_t* t)
{
t->tid = (dyntid_t) DYNINST_INITIAL_LOCK_PID;
t->mutex = 0;
return 0;
}
void
dyninst_init_lock(dyninst_lock_t* lock)
{
lock->tid = (dyntid_t) DYNINST_INITIAL_LOCK_PID;
lock->mutex = 0;
}
void
dyninst_free_lock(dyninst_lock_t* lock)
{
(void) lock; /* unused parameter */
}
int
dyninst_lock(dyninst_lock_t* lock)
{
return tc_lock_lock(lock);
}
void
dyninst_unlock(dyninst_lock_t* lock)
{
tc_lock_unlock(lock);
}
int
rtdebug_printf(const char* format, ...)
{
int ret;
va_list va;
if(!DYNINSTdebugRTlib) return 0;
if(NULL == format) return DYNINST_PRINTF_ERRVAL;
fprintf(stderr, "[RTLIB]");
va_start(va, format);
ret = vfprintf(stderr, format, va);
va_end(va);
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)
{
switch(t)
{
CASE_RETURN_STR(rtBPatch_nullEvent);
CASE_RETURN_STR(rtBPatch_newConnectionEvent);
CASE_RETURN_STR(rtBPatch_internalShutDownEvent);
CASE_RETURN_STR(rtBPatch_threadCreateEvent);
CASE_RETURN_STR(rtBPatch_threadDestroyEvent);
CASE_RETURN_STR(rtBPatch_dynamicCallEvent);
CASE_RETURN_STR(rtBPatch_userEvent);
default: return "bad_async_event_type";
}
}
DLLEXPORT volatile unsigned long dyninstTrapTableUsed;
DLLEXPORT volatile unsigned long dyninstTrapTableVersion;
DLLEXPORT volatile trapMapping_t* dyninstTrapTable;
DLLEXPORT volatile unsigned long dyninstTrapTableIsSorted;
void*
dyninstTrapTranslate(void* source, volatile unsigned long* table_used,
volatile unsigned long* table_version,
volatile trapMapping_t** trap_table,
volatile unsigned long* is_sorted)
{
volatile unsigned local_version;
unsigned i;
void* target;
do
{
local_version = *table_version;
target = NULL;
if(*is_sorted)
{
unsigned min = 0;
unsigned mid = 0;
unsigned max = *table_used;
unsigned prev = max + 1;
for(;;)
{
mid = (min + max) / 2;
if(mid == prev)
{
fprintf(stderr,
"ERROR: dyninstTrapTranslate couldn't find "
"entry for %p: min=%x mid=%x max=%x prev=%x\n",
source, min, mid, max, prev);
break;
}
prev = mid;
if((*trap_table)[mid].source < source)
min = mid;
else if((*trap_table)[mid].source > source)
max = mid;
else
{
target = (*trap_table)[mid].target;
break;
}
}
}
else
{ /*!dyninstTrapTableIsSorted*/
for(i = 0; i < *table_used; i++)
{
if((*trap_table)[i].source == source)
{
target = (*trap_table)[i].target;
break;
}
}
}
} while(local_version != *table_version);
return target;
}
DLLEXPORT void
DYNINSTtrapFunction()
{
__asm__ __volatile__("nop\n" :::);
}
@@ -0,0 +1,84 @@
/*
* 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
*/
#ifndef _RTCOMMON_H_
#define _RTCOMMON_H_
#include "RTthread.h"
#include "h/compiler_annotations.h"
#include "h/dyninstAPI_RT.h"
#include <stdarg.h>
void
DYNINSTtrapFunction();
void
DYNINSTbreakPoint();
/* Use a signal that is safe if we're not attached. */
void
DYNINSTsafeBreakPoint();
void
DYNINSTinit();
int
DYNINSTreturnZero();
int
DYNINSTwriteEvent(void* ev, size_t sz);
int
DYNINSTasyncConnect(int pid);
int
DYNINSTinitializeTrapHandler();
void*
dyninstTrapTranslate(void* source, volatile unsigned long* table_used,
volatile unsigned long* table_version,
volatile trapMapping_t** trap_table,
volatile unsigned long* is_sorted);
extern int DYNINST_mutatorPid;
extern int libdyninstAPI_RT_init_localCause;
extern int libdyninstAPI_RT_init_localPid;
extern int libdyninstAPI_RT_init_maxthreads;
extern int libdyninstAPI_RT_init_debug_flag;
extern int DYNINSTdebugPrintRT;
extern tc_lock_t DYNINST_trace_lock;
extern void*
map_region(void* addr, int len, int fd);
extern int
unmap_region(void* addr, int len);
extern void
mark_heaps_exec(void);
extern int DYNINSTdebugRTlib;
DLLEXPORT extern int DYNINSTstaticMode;
int
rtdebug_printf(const char* format, ...) DYNINST_PRINTF_ANNOTATION(1, 2);
#endif
@@ -0,0 +1,729 @@
/*
* 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;
}
*/
@@ -0,0 +1,85 @@
/*
* 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;
}
@@ -0,0 +1,132 @@
/*
* 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: RTheap-linux.c,v 1.9 2008/01/31 18:01:54 legendre Exp $ */
/* RTheap-linux.c: Linux-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 1 // defined(MUTATEE64)
int DYNINSTheap_align = 4; /* heaps are word-aligned */
Address DYNINSTheap_loAddr = 0x10000; /* Bump to 64k to make SELinux happier */
Address DYNINSTheap_hiAddr = ~(Address) 0x0;
#elif defined(arch_power)
int DYNINSTheap_align = 4; /* heaps are word-aligned */
Address DYNINSTheap_loAddr =
~(Address) 0; // should be defined by getpagesize() when used.
Address DYNINSTheap_hiAddr = ~(Address) 0;
#else
int DYNINSTheap_align = 4; /* heaps are word-aligned */
Address DYNINSTheap_loAddr = 0x50000000;
Address DYNINSTheap_hiAddr = 0xb0000000;
#endif
int DYNINSTheap_mmapFlags = MAP_ANONYMOUS | 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. */
(void) lo; /* unused parameter */
(void) hi; /* unused parameter */
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)
{
FILE* procmaps;
Address saddr = 0, eaddr = 0;
int num_matches;
procmaps = fopen("/proc/self/maps", "r");
dyninstmm_t* maps = *mapp;
if(procmaps == NULL) return -1;
*nump = 0;
while(((num_matches = fscanf(procmaps, "%lx-%lx", &saddr, &eaddr)) != EOF) &&
(*nump < 1024))
{
if(num_matches == 2)
{
maps[*nump].pr_vaddr = saddr;
maps[*nump].pr_size = eaddr - saddr;
(*nump)++;
// skip to next line
int ch;
while((ch = fgetc(procmaps)) != '\n' && ch != EOF)
{
if(ch == EOF) break;
}
}
else
{
break;
}
}
fclose(procmaps);
return *nump < 1024;
/*
Here are two lines from 'cat /proc/self/maps' on Linux 2.2. Each
describes a segment of the address space. We parse out the first
two addresses for the start address and length of the segment. We
throw away the rest.
|SADDR-| |EADDR-|
0804a000-0804c000 rw-p 00001000 08:09 12089 /bin/cat
0804c000-0804f000 rwxp 00000000 00:00 0
*/
}
@@ -0,0 +1,153 @@
/*
* 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;
}
@@ -0,0 +1,223 @@
/*
* 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: RTheap.c,v 1.25 2006/05/03 00:31:25 jodom Exp $ */
/* RTheap.c: platform-generic heap management */
#include <stdio.h>
#include <stdlib.h>
#if !defined(os_windows) /* ccw 15 may 2000 : 29 mar 2001 */
/* win does not have these header files. it appears the only
one that is used assert.h anyway.
*/
# include <errno.h>
# include <fcntl.h> /* open() */
# include <sys/stat.h> /* open() */
# include <sys/types.h>
# include <unistd.h>
#else
extern int
getpagesize();
#endif
#include <assert.h>
#include "src/RTcommon.h"
#include "src/RTheap.h"
typedef enum
{
HEAP_TYPE_UNKNOWN = 0x0,
HEAP_TYPE_MMAP = 0x1,
HEAP_TYPE_MALLOC = 0x2
} heapType_t;
typedef struct heap_t
{
void* ret_addr; /* address returned to mutator */
void* addr; /* actual heap address */
size_t len; /* actual heap length */
heapType_t type; /* heap allocation type */
} heap_t;
typedef struct heapList_t
{
heap_t heap;
struct heapList_t* prev;
struct heapList_t* next;
} heapList_t;
/* local variables */
static heapList_t* Heaps = NULL;
static int psize = -1;
static Address
heap_alignUp(Address addr, int align)
{
if(addr % align == 0) return addr;
return ((addr / align) + 1) * align;
}
static Address
trymmap(size_t len, Address beg, Address end, size_t inc, int fd)
{
Address addr;
void* result;
/*We have a possibly large region (beg to end) and a hopefully smaller */
/* allocation size (len). We try to map at every page in the region*/
/* until we get one that succeeds.*/
for(addr = beg; addr + len <= end; addr += inc)
{
result = map_region((void*) addr, len, fd);
if(result)
{
/* Success doesn't necessarily mean it actually mapped at the hinted
* address. Return if it's in range, else unmap and try again. */
if((Address) result >= beg && (Address) result + len <= end)
return (Address) result;
unmap_region(result, len);
}
}
return (Address) NULL;
}
void*
DYNINSTos_malloc(size_t nbytes, void* lo_addr, void* hi_addr)
{
char* heap;
size_t size = nbytes;
heapList_t* node = NULL;
/* initialize page size */
if(psize == -1) psize = getpagesize();
/* buffer size must be aligned */
if(size % DYNINSTheap_align != 0)
{
return ((void*) -1);
}
/* use malloc() if appropriate */
if(DYNINSTheap_useMalloc(lo_addr, hi_addr))
{
char* ret_heap;
int size_heap = size + DYNINSTheap_align + sizeof(heapList_t);
heap = malloc(size_heap);
if(heap == NULL)
{
#ifdef DEBUG
fprintf(stderr, "Failed to MALLOC\n");
#endif
return NULL;
}
ret_heap = (char*) heap_alignUp((Address) heap, DYNINSTheap_align);
/* malloc buffer must meet range constraints */
if(ret_heap < (char*) lo_addr || ret_heap + size - 1 > (char*) hi_addr)
{
free(heap);
#ifdef DEBUG
fprintf(stderr, "MALLOC'd area fails range constraints\n");
#endif
return NULL;
}
/* define new heap */
node = (heapList_t*) (ret_heap + size);
node->heap.ret_addr = (void*) ret_heap;
node->heap.addr = heap;
node->heap.len = size_heap;
node->heap.type = HEAP_TYPE_MALLOC;
}
else
{ /* use mmap() for allocation */
Address lo = heap_alignUp((Address) lo_addr, psize);
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);
/* define new heap */
node->heap.addr = heap;
node->heap.ret_addr = heap;
node->heap.len = size + sizeof(struct heapList_t);
node->heap.type = HEAP_TYPE_MMAP;
}
/* insert new heap into heap list */
node->prev = NULL;
node->next = Heaps;
if(Heaps) Heaps->prev = node;
Heaps = node;
#ifdef DEBUG
fprintf(stderr, "new heap at %lx, size %lx\n", node->heap.ret_addr, node->heap.len);
#endif
return node->heap.ret_addr;
}
int
DYNINSTos_free(void* buf)
{
int ret = 0;
heapList_t* t;
/*
fprintf(stderr, "*** DYNINSTos_free(0x%08x)\n", buf);
*/
for(t = Heaps; t != NULL; t = t->next)
{
/* lookup heap by (returned) address */
heap_t* heap = &t->heap;
if(heap->ret_addr != buf) continue;
/* remove heap from list */
if(t->next) t->next->prev = t->prev;
if(t->prev) t->prev->next = t->next;
if(Heaps == t) Heaps = t->next;
/* deallocate heap */
switch(heap->type)
{
case HEAP_TYPE_MMAP:
if(!unmap_region(heap->addr, heap->len))
{
perror("DYNINSTos_free(munmap)");
ret = -1;
}
break;
case HEAP_TYPE_MALLOC: free(heap->addr); break;
default:
fprintf(stderr, "DYNINSTos_free(): unknown inferior heap type\n");
ret = -1;
break;
}
break;
}
return ret;
}
@@ -0,0 +1,83 @@
/*
* 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: RTheap.h,v 1.10 2007/01/18 07:53:56 jaw Exp $ */
#ifndef _RT_HEAP_H
#define _RT_HEAP_H
#include "h/dyninstAPI_RT.h" /* RT_Boolean, Address */
#if defined(os_linux) || defined(os_freebsd)
/* LINUX */
typedef struct
{
Address pr_vaddr;
unsigned long pr_size;
} dyninstmm_t;
#elif defined(os_windows)
typedef struct
{
Address pr_vaddr;
unsigned long pr_size;
} dyninstmm_t;
#else
# error Dynamic heaps are not implemented on this platform
#endif
/*
* platform-specific variables
*/
extern int DYNINSTheap_align;
extern Address DYNINSTheap_loAddr;
extern Address DYNINSTheap_hiAddr;
extern int DYNINSTheap_mmapFlags;
/*
* platform-specific functions
*/
RT_Boolean
DYNINSTheap_useMalloc(void* lo, void* hi);
int
DYNINSTheap_mmapFdOpen();
void
DYNINSTheap_mmapFdClose(int fd);
int
DYNINSTheap_getMemoryMap(unsigned*, dyninstmm_t** mmap);
int
DYNINSTgetMemoryMap(unsigned* nump, dyninstmm_t** mapp);
#endif /* _RT_HEAP_H */
@@ -0,0 +1,829 @@
/*
* 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>
#if !defined(DYNINST_RT_STATIC_LIB)
# include <dlfcn.h>
#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>
#include <sys/types.h>
#if defined(DYNINST_RT_STATIC_LIB)
/*
* The weak symbol here removes the dependence of the static version of this
* library on pthread_self. If pthread_self is available, then it will be
* linked. Otherwise, the linker will ignore it.
*/
# pragma weak pthread_self
extern pthread_t
pthread_self(void);
#else
# include <pthread.h>
#endif
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);
#if defined(arch_power) && defined(arch_64bit) && defined(os_linux)
unsigned long DYNINSTlinkSave;
unsigned long DYNINSTtocSave;
#endif
/************************************************************************
* void DYNINSTbreakPoint(void)
*
* stop oneself.
************************************************************************/
#ifndef SYS_tkill
# define SYS_tkill 238
#endif
int
t_kill(int pid, int sig)
{
static int has_tkill = 1;
long int result = 0;
if(has_tkill)
{
result = syscall(SYS_tkill, pid, sig);
if(result == -1 && errno == ENOSYS)
{
has_tkill = 0;
}
}
if(!has_tkill)
{
result = kill(pid, sig);
}
return (result == 0);
}
void
DYNINSTbreakPoint()
{
if(DYNINSTstaticMode) return;
// Call into a funtion that contains a
// trap instruction.
DYNINSTtrapFunction();
}
static int failed_breakpoint = 0;
void
uncaught_breakpoint(int sig)
{
(void) sig; /* unused parameter */
failed_breakpoint = 1;
}
void
DYNINSTsafeBreakPoint()
{
if(DYNINSTstaticMode) return;
DYNINST_break_point_event = 2; /* Not the same as above */
// while (DYNINST_break_point_event)
kill(dyn_lwp_self(), SIGSTOP);
}
void
mark_heaps_exec()
{
/* 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() */
/************************************************************************
* void DYNINSTos_init(void)
*
* OS initialization function
************************************************************************/
int DYNINST_sysEntry;
#if !defined(DYNINST_RT_STATIC_LIB)
/*
* For now, removing dependence of static version of this library
* on libdl.
*/
typedef struct dlopen_args
{
const char* libname;
int mode;
void* result;
void* caller;
} dlopen_args_t;
void* (*DYNINST_do_dlopen)(dlopen_args_t*) = NULL;
static int
get_dlopen_error()
{
char* err_str;
err_str = dlerror();
if(err_str)
{
strncpy(gLoadLibraryErrorString, err_str, (size_t) ERROR_STRING_LENGTH);
return 1;
}
else
{
sprintf(gLoadLibraryErrorString, "unknown error with dlopen");
return 0;
}
return 0;
}
int
DYNINSTloadLibrary(char* libname)
{
void* res;
gLoadLibraryErrorString[0] = '\0';
res = dlopen(libname, RTLD_LAZY | RTLD_GLOBAL);
if(res)
{
return 1;
}
get_dlopen_error();
# if defined(arch_x86)
/* dlopen on recent glibcs has a "security check" so that
only registered modules can call it. Unfortunately, progs
that don't include libdl break this check, so that we
can only call _dl_open (the dlopen worker function) from
within glibc. We do this by calling do_dlopen
We fool this check by calling an addr written by the
mutator */
if(strstr(gLoadLibraryErrorString, "invalid caller") != NULL &&
DYNINST_do_dlopen != NULL)
{
dlopen_args_t args;
args.libname = libname;
args.mode = RTLD_NOW | RTLD_GLOBAL;
args.result = 0;
args.caller = (void*) DYNINST_do_dlopen;
// There's a do_dlopen function in glibc. However, it's _not_
// exported; thus, getting the address is a bit of a pain.
(*DYNINST_do_dlopen)(&args);
// Duplicate the above
if(args.result != NULL)
{
return 1;
}
else
get_dlopen_error();
}
# endif
return 0;
}
#endif
// Define this value so that we can compile on a system that doesn't have
// gettid and still run on one that does.
#if !defined(SYS_gettid)
# if defined(arch_x86)
# define SYS_gettid 224
# elif defined(arch_x86_64)
# define SYS_gettid 186
# endif
#endif
int
dyn_lwp_self()
{
static int gettid_not_valid = 0;
int result;
if(gettid_not_valid) return getpid();
result = syscall((long int) SYS_gettid);
if(result == -1 && errno == ENOSYS)
{
gettid_not_valid = 1;
return getpid();
}
return result;
}
int
dyn_pid_self()
{
return getpid();
}
dyntid_t (*DYNINST_pthread_self)(void);
dyntid_t
dyn_pthread_self()
{
dyntid_t me;
if(DYNINSTstaticMode)
{
#if defined(DYNINST_RT_STATIC_LIB)
/* This special case is necessary because the static
* version of libc doesn't define a version of pthread_self
* unlike the shared version of the library.
*/
if(!pthread_self)
{
return (dyntid_t) DYNINST_SINGLETHREADED;
}
#endif
return (dyntid_t) pthread_self();
}
if(!DYNINST_pthread_self)
{
return (dyntid_t) DYNINST_SINGLETHREADED;
}
me = (*DYNINST_pthread_self)();
return (dyntid_t) me;
}
/*
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)
{
(void) tid; /* unused parameter */
if(dyn_lwp_self() == getpid())
{
return 1;
}
return 0;
} /* end DYNINST_am_initial_thread() */
#if defined(cap_mutatee_traps)
# include <ucontext.h>
// Register numbers experimentally verified
# if defined(arch_x86)
# define UC_PC(x) x->uc_mcontext.gregs[14]
# elif defined(arch_x86_64)
# if defined(MUTATEE_32)
# define UC_PC(x) x->uc_mcontext.gregs[14]
# else // 64-bit
# define UC_PC(x) x->uc_mcontext.gregs[16]
# endif // amd-64
# 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
# define UC_PC(x) x->uc_mcontext.pc
# endif // UC_PC
extern volatile unsigned long dyninstTrapTableUsed;
extern volatile unsigned long dyninstTrapTableVersion;
extern volatile trapMapping_t* dyninstTrapTable;
extern volatile 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;
(void) sig; /* unused parameter */
(void) sg; /* unused parameter */
orig_ip = (void*) 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);
assert(hdr);
volatile trapMapping_t* mapping = &(hdr->traps[0]);
trap_to = dyninstTrapTranslate(orig_ip, (unsigned long*) &hdr->num_entries, &zero,
&mapping, &one);
}
else
{
trap_to =
dyninstTrapTranslate(orig_ip, &dyninstTrapTableUsed, &dyninstTrapTableVersion,
&dyninstTrapTable, &dyninstTrapTableIsSorted);
}
UC_PC(context) = (long) trap_to;
}
# 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()
{
# 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
}
# 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];
# if !defined(arch_x86_64) || defined(MUTATEE_32)
typedef Elf32_Dyn ElfX_Dyn;
# else
typedef Elf64_Dyn ElfX_Dyn;
# endif
struct trap_mapping_header*
getStaticTrapMap(unsigned long addr);
# if !defined(arch_aarch64)
static unsigned all_headers_current[NUM_LIBRARIES_BITMASK_SIZE];
static unsigned all_headers_last[NUM_LIBRARIES_BITMASK_SIZE];
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 char get_bit(unsigned *bit_mask, int bit);
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;
# endif
static struct trap_mapping_header*
getStaticTrapMap(unsigned long addr)
{
# if !defined(arch_aarch64)
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;
rtdebug_printf("%s[%d]: getStaticTrapMap: returning NULL\n", __FILE__,
__LINE__);
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;
# else
// Silence compiler warnings
(void) addr;
assert(0);
return NULL;
# endif
}
# if !defined(arch_aarch64)
static int
parse_libs()
{
struct link_map* l_current;
l_current = _r_debug.r_map;
if(!l_current)
{
rtdebug_printf("%s[%d]: parse_libs: _r_debug.r_map was not set\n", __FILE__,
__LINE__);
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);
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) + l->l_addr);
header->traps[i].target =
(void*) (((unsigned long) header->traps[i].target) + l->l_addr);
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 < 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);
}
}
// Wasn't actually needed
/*
static char get_bit(unsigned *bit_mask, int bit) {
assert(bit < NUM_LIBRARIES);
unsigned *word = bit_mask + bit / WORD_SIZE;
unsigned shift = bit % WORD_SIZE;
return (*word & (1 << shift)) ? 1 : 0;
}
*/
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
#endif /* cap_mutatee_traps */
#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
r_debugCheck();
extern void
DYNINSTBaseInit();
void
runDYNINSTBaseInit() __attribute__((constructor));
void
runDYNINSTBaseInit()
{
r_debugCheck();
DYNINSTBaseInit();
}
#endif
/*
//Small program for finding the correct values to fill in pos_in_pthreadt
// above
#include <pthread.h>
#include <stdio.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#define gettid() syscall(SYS_gettid)
pthread_attr_t attr;
void *foo(void *f) {
pid_t pid, tid;
unsigned stack_addr;
unsigned best_stack = 0xffffffff;
int best_stack_pos = 0;
void *start_func;
int *p;
int i = 0;
pid = getpid();
tid = gettid();
start_func = foo;
//x86 only.
asm("movl %%ebp,%0" : "=r" (stack_addr));
p = (int *) pthread_self();
while (i < 1000)
{
if (*p == (unsigned) pid)
printf("pid @ %d\n", i);
if (*p == (unsigned) tid)
printf("lwp @ %d\n", i);
if (*p > stack_addr && *p < best_stack)
{
best_stack = *p;
best_stack_pos = i;
}
if (*p == (unsigned) start_func)
printf("func @ %d\n", i);
i += sizeof(int);
p++;
}
printf("stack @ %d\n", best_stack_pos);
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;
}
*/
@@ -0,0 +1,205 @@
/*
* 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);
}
}
}
@@ -0,0 +1,308 @@
/*
* 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: RTposix.c,v 1.37 2008/04/11 23:30:45 legendre Exp $
* RTposix.c: runtime instrumentation functions for generic posix.
************************************************************************/
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <memory.h>
#include <pwd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
#include "h/dyninstAPI_RT.h"
#include "src/RTcommon.h"
#include "src/RTheap.h"
#define SOCKLEN_T socklen_t
#if !(defined(arch_power) && defined(os_linux))
void
RTmutatedBinary_init()
{
return;
}
#endif
#if defined(__GNUC) || defined(__GNUC__)
# if defined(DYNINST_RT_STATIC_LIB)
/*
* In the static version of the library, constructors cannot be
* used to run code at initialization. See DYNINSTglobal_ctors_handler.
*/
void
libdyninstAPI_RT_init(void);
# else
void
libdyninstAPI_RT_init(void) __attribute__((constructor));
# endif
#endif
#if defined(cap_async_events)
struct passwd* passwd_info = NULL;
#endif
void
libdyninstAPI_RT_init()
{
static int initCalledOnce = 0;
rtdebug_printf("%s[%d]: DYNINSTinit: welcome to libdyninstAPI_RT_init()\n",
__FILE__, __LINE__);
if(initCalledOnce) return;
initCalledOnce++;
DYNINSTinit();
rtdebug_printf("%s[%d]: did DYNINSTinit\n", __FILE__, __LINE__);
}
/************************************************************************
* void DYNINSTasyncConnect(int pid)
*
* Connect to mutator's async handler thread. <pid> is pid of mutator
************************************************************************/
static int async_socket = -1;
static int needToDisconnect = 0;
static char socket_path[255];
int
DYNINSTasyncConnect(int pid)
{
if(DYNINSTstaticMode) return 0;
#if defined(cap_async_events)
int sock_fd;
struct sockaddr_un sadr;
int res;
int mutatee_pid;
uid_t euid;
rtdebug_printf("%s[%d]: DYNINSTasyncConnnect: entry\n", __FILE__, __LINE__);
rtdebug_printf("%s[%d]: DYNINSTinit: before geteuid\n", __FILE__, __LINE__);
euid = geteuid();
passwd_info = getpwuid(euid);
assert(passwd_info);
if(async_socket != -1)
{
fprintf(stderr, "%s[%d]: - DYNINSTasyncConnect already initialized\n", __FILE__,
__LINE__);
rtdebug_printf("%s[%d]: DYNINSTasyncConnnect: already connected\n", __FILE__,
__LINE__);
return 0;
}
rtdebug_printf("%s[%d]: DYNINSTasyncConnnect: before socket 2\n", __FILE__,
__LINE__);
mutatee_pid = getpid();
snprintf(socket_path, (size_t) 255, "%s/dyninstAsync.%s.%d.%d", P_tmpdir,
passwd_info->pw_name, pid, mutatee_pid);
rtdebug_printf("%s[%d]: DYNINSTasyncConnnect: before socket: %s\n", __FILE__,
__LINE__, socket_path);
errno = 0;
sock_fd = socket(PF_UNIX, SOCK_STREAM, 0);
if(sock_fd < 0)
{
fprintf(stderr, "%s[%d]: DYNINSTasyncConnect() socket(%s): %s\n", __FILE__,
__LINE__, socket_path, strerror(errno));
abort();
}
rtdebug_printf("%s[%d]: DYNINSTasyncConnnect: after socket\n", __FILE__, __LINE__);
sadr.sun_family = PF_UNIX;
strcpy(sadr.sun_path, socket_path);
rtdebug_printf("%s[%d]: DYNINSTasyncConnnect: before connect\n", __FILE__,
__LINE__);
res = 0;
errno = 0;
res = connect(sock_fd, (struct sockaddr*) &sadr, sizeof(sadr));
if(res < 0)
{
perror("DYNINSTasyncConnect() connect()");
}
rtdebug_printf(
"%s[%d]: DYNINSTasyncConnnect: after connect to %s, res = %d, -- %s\n",
__FILE__, __LINE__, socket_path, res, strerror(errno));
/* maybe need to do fcntl to set nonblocking writes on this fd */
if(async_socket == -1)
{
rtdebug_printf("%s[%d]: WARN: async socket has not been reset!!\n", __FILE__,
__LINE__);
}
async_socket = sock_fd;
needToDisconnect = 1;
/* atexit(exit_func); */
rtdebug_printf("%s[%d]: leaving DYNINSTasyncConnect\n", __FILE__, __LINE__);
return 1;
#else
fprintf(stderr, "%s[%d]: called DYNINSTasyncConect when async_events disabled\n",
__FILE__, __LINE__);
return 0;
#endif
}
int
DYNINSTasyncDisconnect()
{
if(DYNINSTstaticMode) return 0;
rtdebug_printf("%s[%d]: welcome to DYNINSTasyncDisconnect\n", __FILE__, __LINE__);
if(needToDisconnect)
{
close(async_socket);
needToDisconnect = 0;
}
async_socket = -1;
return 0;
}
int
DYNINSTwriteEvent(void* ev, size_t sz)
{
ssize_t res;
if(DYNINSTstaticMode) return 0;
rtdebug_printf("%s[%d]: welcome to DYNINSTwriteEvent: %zu bytes\n", __FILE__,
__LINE__, sz);
if(-1 == async_socket)
{
rtdebug_printf("%s[%d]: failed to DYNINSTwriteEvent, no socket\n", __FILE__,
__LINE__);
return -1;
}
try_again:
res = write(async_socket, ev, sz);
if(-1 == res)
{
if(errno == EINTR || errno == EAGAIN)
goto try_again;
else
{
perror("write");
return -1;
}
}
if((size_t) res != sz)
{
/* maybe we need logic to handle partial writes? */
fprintf(stderr, "%s[%d]: partial ? write error, %zd bytes, should be %zu\n",
__FILE__, __LINE__, res, sz);
return -1;
}
return 0;
}
// Important note: addr will be zero in two cases here
// One is the case where we're doing a constrained low mmap, in which case MAP_32BIT
// is precisely correct. The other is the case where our
// constrained map attempts have failed, and we're doing a scan for first available
// mappable page. In that case, MAP_32BIT does no harm.
void*
map_region(void* addr, int len, int fd)
{
void* result;
int flags = DYNINSTheap_mmapFlags;
#if defined(arch_x86_64)
if(addr == 0) flags |= MAP_32BIT;
#endif
result = mmap(addr, len, PROT_READ | PROT_WRITE | PROT_EXEC, flags, fd, 0);
if(result == MAP_FAILED) return NULL;
return result;
}
int
unmap_region(void* addr, int len)
{
int result;
result = munmap(addr, len);
if(result == -1) return 0;
return 1;
}
#if defined(cap_mutatee_traps)
extern void
dyninstTrapHandler(int sig, siginfo_t* info, void* context);
int
DYNINSTinitializeTrapHandler()
{
int result;
struct sigaction new_handler;
int signo = SIGTRAP;
// If environment variable DYNINST_SIGNAL_TRAMPOLINE_SIGILL is set,
// we use SIGILL as the signal for signal trampoline.
// The mutatee has to be generated with DYNINST_SIGNAL_TRAMPOLINE_SIGILL set
// so that the mutator will generates illegal instructions as trampolines.
if(getenv("DYNINST_SIGNAL_TRAMPOLINE_SIGILL"))
{
signo = SIGILL;
}
new_handler.sa_sigaction = dyninstTrapHandler;
// new_handler.sa_restorer = NULL; obsolete
sigemptyset(&new_handler.sa_mask);
new_handler.sa_flags = SA_SIGINFO | SA_NODEFER;
result = sigaction(signo, &new_handler, NULL);
return (result == 0) ? 1 /*Success*/ : 0 /*Fail*/;
}
#endif
@@ -0,0 +1,64 @@
/*
* 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
*/
/*
DYNINSTsigill:
DYNINSTsigill executes an illegal instruction, causing SIGILL to be
sent to the calling process. It is only needed for
detach-on-the-fly, where detached mutatees stop to wait for the
mutator or paradynd to reattach by sending themselves SIGILL.
A detached mutatee that stops itself with SIGSTOP will not be
noticed by the mutator or paradynd. It must send SIGILL to be
noticed.
There are two ways to send SIGILL to yourself: call kill() or
execute an illegal instruction.
We chose to use illegal instructions. The SIGILL handler has a
simpler implementation if SIGILL is caused by an illegal
instruction. We do not use kill() to send SIGILL.
The test suite calls this function through the dynamic loader to
avoid duplication of code in the test suite and additional makefile
complexity.
3000 bytes of source code for 3 bytes of object code.
*/
.text
.globl DYNINSTsigill
DYNINSTsigill:
ud2
ret
.section .note.GNU-stack,"",@progbits
@@ -0,0 +1,30 @@
.globl dyninstTrapHandler2
.type dyninstTrapHandler2, @function
dyninstTrapHandler2:
pushf
pushl %ebp
movl %esp, %ebp
call __i686.get_pc_thunk.bx
addl $_GLOBAL_OFFSET_TABLE_, %ebx
call .Lnext_insn
.Lnext_insn:
addl $.Lret_point-.Lnext_insn,(%esp)
pushl 0x4(%ebp)
pushl 0x14(%ebp)
call dyninstSetupContext@PLT
movl $0x0, 0x0
.Lret_point:
popf
ret
#if defined(DYNINST_RT_STATIC_LIB)
__i686.get_pc_thunk.bx:
mov (%esp), %ebx
ret
__i686.get_pc_thunk.cx:
mov (%esp), %ecx
ret
#endif
.section .note.GNU-stack,"",@progbits
@@ -0,0 +1,21 @@
.globl dyninstTrapHandler2
.type dyninstTrapHandler2, @function
dyninstTrapHandler2:
pushfq
pushq %rbp
mov %rsp, %rbp
mov %rdx, %rdi
leaq 0(%rip), %rdx
.Lnext_insn:
addq $.Lret_point - .Lnext_insn, %rdx
mov 0x8(%rbp), %rsi
call dyninstSetupContext@PLT
movl $0x0, 0x0
.Lret_point:
pop %rax
pop %r10
pop %r11
popfq
retq
.section .note.GNU-stack,"",@progbits
@@ -0,0 +1,66 @@
/*
* 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
*/
/************************************************************************
* RTsignal.c: C-language signal handling code
************************************************************************/
#include <signal.h>
#include <stdio.h>
#include "h/dyninstAPI_RT.h"
typedef void (*dynsighandler_t)(int);
DLLEXPORT int
dyn_sigaction(int signum, const struct sigaction* act, struct sigaction* oldact)
{
if(signum != SIGTRAP)
{
return sigaction(signum, act, oldact);
}
else
{
return 0;
}
}
DLLEXPORT dynsighandler_t
dyn_signal(int signum, dynsighandler_t handler)
{
if(signum != SIGTRAP)
{
return signal(signum, handler);
}
else
{
return SIG_DFL;
}
}
@@ -0,0 +1,18 @@
.file "RTspace.s"
.globl DYNINSTstaticHeap_8K_lowmemHeap_1
.type DYNINSTstaticHeap_8K_lowmemHeap_1, @object
.size DYNINSTstaticHeap_8K_lowmemHeap_1, 8192
.globl DYNINSTstaticHeap_32K_anyHeap_1
.type DYNINSTstaticHeap_32K_anyHeap_1, @object
.size DYNINSTstaticHeap_32K_anyHeap_1, 32768
.section .dyninst_heap,"awx",@nobits
.align 16
DYNINSTstaticHeap_8K_lowmemHeap_1:
.skip 8192
DYNINSTstaticHeap_32K_anyHeap_1:
.skip 32768
.section .note.GNU-stack,"",@progbits
@@ -0,0 +1,18 @@
.file "RTspace.s"
.globl DYNINSTstaticHeap_512K_lowmemHeap_1
.type DYNINSTstaticHeap_512K_lowmemHeap_1, @object
.size DYNINSTstaticHeap_512K_lowmemHeap_1, 524288
.globl DYNINSTstaticHeap_16M_anyHeap_1
.type DYNINSTstaticHeap_16M_anyHeap_1, @object
.size DYNINSTstaticHeap_16M_anyHeap_1, 16777216
.section .dyninst_heap,"aw",@nobits
.align 16
DYNINSTstaticHeap_512K_lowmemHeap_1:
.skip 524288
DYNINSTstaticHeap_16M_anyHeap_1:
.skip 16777216
.section .note.GNU-stack,"",@progbits
@@ -0,0 +1,82 @@
/*
* 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
@@ -0,0 +1,102 @@
/*
* 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
@@ -0,0 +1,72 @@
/*
* 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
@@ -0,0 +1,129 @@
/*
* 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>
void* DYNINSTirel_start;
void* DYNINSTirel_end;
extern void (*DYNINSTctors_begin)(void);
extern void (*DYNINSTdtors_begin)(void);
extern void (*DYNINSTctors_end)(void);
extern void (*DYNINSTdtors_end)(void);
extern void
DYNINSTBaseInit();
typedef struct
{
long* offset;
long info;
long (*ptr)(void);
} rela_t;
typedef struct
{
long* offset;
long info;
} rel_t;
/*
* 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 (**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++;
}
}
void
DYNINSTglobal_irel_handler()
{
if(sizeof(long) == 8)
{
rela_t* rel = 0;
for(rel = (rela_t*) (&DYNINSTirel_start); rel != (rela_t*) (&DYNINSTirel_end);
++rel)
{
long result = 0;
if(rel->info != 0x25) continue;
result = (rel->ptr());
*(rel->offset) = result;
}
}
else
{
rel_t* rel = 0;
for(rel = (rel_t*) (&DYNINSTirel_start); rel != (rel_t*) (&DYNINSTirel_end);
++rel)
{
typedef long (*funcptr)(void);
long (*ptr)(void) = 0;
long result = 0;
if(rel->info != 0x2a) continue;
ptr = (funcptr)(*rel->offset);
result = ptr();
*(rel->offset) = result;
}
}
}
#endif
@@ -0,0 +1,4 @@
#if defined(DYNINST_RT_STATIC_LIB)
void (*DYNINSTctors_begin)(void) __attribute__((section(".init_array")));
void (*DYNINSTdtors_begin)(void) __attribute__((section(".fini_array")));
#endif
@@ -0,0 +1,4 @@
#if defined(DYNINST_RT_STATIC_LIB)
void (*DYNINSTctors_end)(void) __attribute__((section(".init_array")));
void (*DYNINSTdtors_end)(void) __attribute__((section(".fini_array")));
#endif
@@ -0,0 +1,41 @@
/*
* 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;
}
@@ -0,0 +1,9 @@
#include "RTconst.h"
#include "../../dyninstAPI/src/inst-power.h"
.machine "push"
#ifndef __clang__
.machine "ppc"
#endif
.machine "pop"
.section .note.GNU-stack,"",@progbits
@@ -0,0 +1,77 @@
.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
@@ -0,0 +1,63 @@
/*
* 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;
}
@@ -0,0 +1,54 @@
/*
* 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"
static int
atomic_set(volatile int* val)
{
int result = 1;
__asm__ __volatile__("xchgl %0, %1\n" : "+r"(result), "+m"(*val)::"memory");
return !result;
}
int
tc_lock_lock(tc_lock_t* tc)
{
dyntid_t me;
me = dyn_pthread_self();
if(me == tc->tid) return DYNINST_DEAD_LOCK;
while(!atomic_set(&tc->mutex))
;
tc->tid = me;
return 0;
}
@@ -0,0 +1,89 @@
/*
* 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 <assert.h>
/**
* atomic_set will do the following atomically:
* if (*val == 0) {
* *val = 1;
* return 1;
* }
* return 0;
*
* We need two versions since windows uses a different assembly syntax
* (AT&T syntax on Linux and Intel on Windows)
**/
#if defined(os_windows)
int
atomic_set(volatile int* val)
{
int result;
# ifdef _WIN64
result = _InterlockedCompareExchange(val, 1, 0);
return !result;
# else
__asm
{
mov eax, 0 ;
mov ebx, 1 ;
mov ecx, val ;
lock cmpxchg [ecx],ebx ;
setz al ;
mov result, eax ;
}
# endif
return result;
}
#else
static int
atomic_set(volatile int* val)
{
int result = 1;
__asm__ __volatile__("xchgl %0, %1\n" : "+r"(result), "+m"(*val)::"memory");
return !result;
}
#endif
int
tc_lock_lock(tc_lock_t* tc)
{
dyntid_t me;
me = dyn_pthread_self();
if(me == tc->tid) return DYNINST_DEAD_LOCK;
while(!atomic_set(&tc->mutex))
;
tc->tid = me;
return 0;
}
@@ -0,0 +1,51 @@
/*
* 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 <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "RTcommon.h"
#include "RTthread.h"
#include "h/dyninstAPI_RT.h"
#include "h/dyninstRTExport.h"
int DYNINST_multithread_capable;
extern unsigned int DYNINSThasInitialized;
static void (*rt_newthr_cb)(int) = NULL;
void
setNewthrCB(void (*cb)(int))
{
rt_newthr_cb = cb;
}
#define IDX_NONE -1
@@ -0,0 +1,62 @@
/*
* 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
*/
#ifndef _RTTHREAD_H_
#define _RTTHREAD_H_
#include "h/dyninstAPI_RT.h"
#include "h/dyninstRTExport.h"
DLLEXPORT dyntid_t
dyn_pthread_self(); /*Thread library identifier*/
int
dyn_lwp_self(); /*LWP used by the kernel identifier*/
int
dyn_pid_self(); /*PID identifier representing the containing process*/
extern int DYNINST_multithread_capable;
typedef dyninst_lock_t tc_lock_t;
#define DECLARE_TC_LOCK(l) tc_lock_t l = { 0, (dyntid_t) -1 }
int
tc_lock_init(tc_lock_t*);
int
tc_lock_lock(tc_lock_t*);
int
tc_lock_unlock(tc_lock_t*);
int
tc_lock_destroy(tc_lock_t*);
int
DYNINST_am_initial_thread(dyntid_t tid);
#endif
@@ -0,0 +1,54 @@
/*
* 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
*/
/*
* This function is used to help support TLS when rewriting static binaries.
* It is originally provided by the dynamic linker (which is unavailable to
* static binaries). One TLS model is to call the function with a module
* index in order to retrieve a TLS variable (see general dynamic). This model
* is unnecessarily general for static binaries but does exist in some non-PIC
* relocatable files. The GNU ld approach is to perform code transformations to
* relax the TLS model. In order to keep the rewriter for static binaries
* simple, the approach of emulating a call to ___tls_get_addr was used instead
* of implementing these link-time code transformations.
*/
#if defined(DYNINST_RT_STATIC_LIB)
.text
.globl ___tls_get_addr
___tls_get_addr:
mov (%eax), %eax /* Gets the TLS offset of the variable */
add %gs:0, %eax /* Gets the absolute address of the variable */
ret
#endif
.section .note.GNU-stack,"",@progbits
@@ -0,0 +1,58 @@
/*
* 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
*/
/*
* This function is used to help support TLS when rewriting static binaries.
* It is originally provided by the dynamic linker (which is unavailable to
* static binaries). One TLS model is to call the function with a module
* index in order to retrieve a TLS variable (see general dynamic). This model
* is unnecessarily general for static binaries but does exist in some non-PIC
* relocatable files. The GNU ld approach is to perform code transformations to
* relax the TLS model. In order to keep the rewriter for static binaries
* simple, the approach of emulating a call to ___tls_get_addr was used instead
* of implementing these link-time code transformations.
*/
#if defined(DYNINST_RT_STATIC_LIB)
.text
.globl ___tls_get_addr
.globl __tls_get_addr
__tls_get_addr:
___tls_get_addr:
mov (%rdi), %rax /* Get the TLS offset of the variable */
add %fs:0, %rax /* Get the absolute address of the variable */
ret
#endif
.section .note.GNU-stack,"",@progbits
@@ -0,0 +1,565 @@
/*
* 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());
}
}
@@ -0,0 +1,23 @@
.toc
.csect .text[PR]
.globl DYNINSTstaticHeap_1048576_textHeap_libSpace
.globl .DYNINSTstaticHeap_1048576_textHeap_libSpace
.csect DYNINSTstaticHeap_1048576_textHeap_libSpace[DS]
DYNINSTstaticHeap_1048576_textHeap_libSpace:
.long .DYNINSTstaticHeap_1048576_textHeap_libSpace, TOC[tc0], 0
.csect .text[PR]
.DYNINSTstaticHeap_1048576_textHeap_libSpace:
blr
.space 1048576
LT..DYNINSTstaticHeap_1048576_textHeap_libSpace:
.long 0
.byte 0,0,32,96,128,1,0,1
.long LT..DYNINSTstaticHeap_1048576_textHeap_libSpace-.DYNINSTstaticHeap_1048576_textHeap_libSpace
.short 43
.byte "DYNINSTstaticHeap_1048576_textHeap_libSpace"
.byte 31
_section_.text:
.csect .data[RW],3
.long _section_.text
.section .note.GNU-stack,"",@progbits
@@ -0,0 +1,23 @@
.toc
.csect .text[PR]
.globl DYNINSTstaticHeap_1048576_textHeap_libSpace
.globl .DYNINSTstaticHeap_1048576_textHeap_libSpace
.csect DYNINSTstaticHeap_1048576_textHeap_libSpace[DS]
DYNINSTstaticHeap_1048576_textHeap_libSpace:
.llong .DYNINSTstaticHeap_1048576_textHeap_libSpace, TOC[tc0], 0
.csect .text[PR]
.DYNINSTstaticHeap_1048576_textHeap_libSpace:
blr
.space 1048576
LT..DYNINSTstaticHeap_1048576_textHeap_libSpace:
.llong 0
.byte 0,0,32,96,128,1,0,1
.llong LT..DYNINSTstaticHeap_1048576_textHeap_libSpace-.DYNINSTstaticHeap_1048576_textHeap_libSpace
.short 43
.byte "DYNINSTstaticHeap_1048576_textHeap_libSpace"
.byte 31
_section_.text:
.csect .data[RW],3
.llong _section_.text
.section .note.GNU-stack,"",@progbits