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:
@@ -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;
|
||||
}
|
||||
*/
|
||||
Reference in New Issue
Block a user