1
1

opal: add code patcher framework

This commit adds a framework to abstract runtime code patching.
Components in the new framework can provide functions for either
patching a named function or a function pointer. The later
functionality is not being used but may provide a way to allow memory
hooks when dlopen functionality is disabled.

This commit adds two different flavors of code patching. The first is
provided by the overwrite component. This component overwrites the
first several instructions of the target function with code to jump to
the provided hook function. The hook is expected to provide the full
functionality of the hooked function.

The linux patcher component is based on the memory hooks in ucx. It
only works on linux and operates by overwriting function pointers in
the symbol table. In this case the hook is free to call the original
function using the function pointer returned by dlsym.

Both components restore the original functions when the patcher
framework closes.

Changes had to be made to support Power/PowerPC with the Linux
dynamic loader patcher. Some of the changes:

 - Move code necessary for powerpc/power support to the patcher
   base. The code is needed by both the overwrite and linux
   components.

 - Move patch structure down to base and move the patch list to
   mca_patcher_base_module_t. The structure has been modified to
   include a function pointer to the function that will unapply the
   patch. This allows the mixing of multiple different types of
   patches in the patch_list.

 - Update linux patching code to keep track of the matching between
   got entry and original (unpatched) address. This allows us to
   completely clean up the patch on finalize.

All patchers keep track of the changes they made so that they can be
reversed when the patcher framework is closed.

At this time there are bugs in the Linux dynamic loader patcher so
its priority is lower than the overwrite patcher.

Signed-off-by: Nathan Hjelm <hjelmn@lanl.gov>
Этот коммит содержится в:
Nathan Hjelm 2016-03-28 22:35:18 -06:00 коммит произвёл Nathan Hjelm
родитель b1670f844d
Коммит 27f8a4e806
26 изменённых файлов: 1525 добавлений и 277 удалений

Просмотреть файл

@ -32,8 +32,5 @@ enable_mca_direct=pml-ob1
# enable development headers
with_devel_headers=yes
# enable ptmalloc (enables lazy deregistration)
with_memory_manager=linux
# disable valgrind
with_valgrind=no

Просмотреть файл

@ -38,8 +38,5 @@ enable_mca_direct=pml-ob1
# enable development headers
with_devel_headers=yes
# enable ptmalloc (enables lazy deregistration)
with_memory_manager=linux
# disable valgrind
with_valgrind=no

Просмотреть файл

@ -4,3 +4,4 @@ opal_show_help_yyleng
opal_show_help_yytext
opal_util_keyval_yyleng
opal_util_keyval_yytext
__curbrk

Просмотреть файл

@ -21,7 +21,7 @@
#
# $HEADER$
#
AC_DEFUN([MCA_opal_memory_patcher_PRIORITY], [40])
AC_DEFUN([MCA_opal_memory_patcher_PRIORITY], [41])
AC_DEFUN([MCA_opal_memory_patcher_COMPILE_MODE], [
AC_MSG_CHECKING([for MCA component $2:$3 compile mode])

Просмотреть файл

@ -16,7 +16,7 @@
#include "opal_config.h"
#include "opal/mca/memory/memory.h"
#include "opal/util/opal_patcher.h"
#include "opal/mca/patcher/patcher.h"
typedef struct opal_memory_patcher_component_t {
opal_memory_base_component_2_0_0_t super;

Просмотреть файл

@ -28,6 +28,7 @@
#include "opal/util/output.h"
#include "opal/util/show_help.h"
#include "opal/mca/memory/base/empty.h"
#include "opal/mca/memory/base/base.h"
#include "opal/memoryhooks/memory.h"
#include <stdlib.h>
@ -95,39 +96,51 @@ void *__mmap (void *start, size_t length, int prot, int flags, int fd, off_t off
#define memory_patcher_syscall syscall
#endif
static void *(*original_mmap)(void *, size_t, int, int, int, off_t);
static void *intercept_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset)
{
OPAL_PATCHER_BEGIN;
void *result = 0;
if (prot == PROT_NONE) {
opal_mem_hooks_release_hook (start, length, 0);
opal_mem_hooks_release_hook (start, length, true);
}
if (!original_mmap) {
#if OPAL_MEMORY_PATCHER_HAVE___MMAP
/* the darwin syscall returns an int not a long so call the underlying __mmap function */
result = __mmap (start, length, prot, flags, fd, offset);
/* the darwin syscall returns an int not a long so call the underlying __mmap function */
result = __mmap (start, length, prot, flags, fd, offset);
#else
result = (void*)(intptr_t) memory_patcher_syscall(SYS_mmap, start, length, prot, flags, fd, offset);
result = (void*)(intptr_t) memory_patcher_syscall(SYS_mmap, start, length, prot, flags, fd, offset);
#endif
// I thought we had some issue in the past with the above line for IA32,
// like maybe syscall() wouldn't handle that many arguments. But just now
// I used gcc -m32 and it worked on a recent system. But there's a possibility
// that older ia32 systems may need some other code to make the above syscall.
// I thought we had some issue in the past with the above line for IA32,
// like maybe syscall() wouldn't handle that many arguments. But just now
// I used gcc -m32 and it worked on a recent system. But there's a possibility
// that older ia32 systems may need some other code to make the above syscall.
} else {
result = original_mmap (start, length, prot, flags, fd, offset);
}
OPAL_PATCHER_END;
return result;
}
static int (*original_munmap) (void *, size_t);
static int intercept_munmap(void *start, size_t length)
{
OPAL_PATCHER_BEGIN;
int result = 0;
opal_mem_hooks_release_hook (start, length, 0);
opal_mem_hooks_release_hook (start, length, false);
result=memory_patcher_syscall(SYS_munmap, start, length);
if (!original_munmap) {
result = memory_patcher_syscall(SYS_munmap, start, length);
} else {
result = original_munmap (start, length);
}
OPAL_PATCHER_END;
return result;
@ -135,38 +148,42 @@ static int intercept_munmap(void *start, size_t length)
#if defined (SYS_mremap)
static void *(*original_mremap) (void *, size_t, size_t, int, ...);
static void *intercept_mremap (void *start, size_t oldlen, size_t newlen, int flags, ...)
{
OPAL_PATCHER_BEGIN;
void *result = 0;
#ifdef MREMAP_FIXED
va_list ap;
void *new_address;
#endif
void *new_address = NULL;
opal_mem_hooks_release_hook (start, oldlen, 0);
opal_mem_hooks_release_hook (start, oldlen, false);
#ifdef MREMAP_FIXED
if (flags & MREMAP_FIXED) {
va_start(ap, flags);
new_address = va_arg(ap, void*);
result=(void *)(intptr_t) memory_patcher_syscall(
SYS_mremap, start, oldlen, newlen, flags, new_address);
va_end(ap);
} else {
result=(void*)memory_patcher_syscall(
SYS_mremap, start, oldlen, newlen, flags);
}
#else
result=(void*)(intptr_t) memory_patcher_syscall(SYS_mremap, start, oldlen, newlen, flags);
#endif
if (!original_mremap) {
result = (void *)(intptr_t) memory_patcher_syscall (SYS_mremap, start, oldlen, newlen, flags, new_address);
} else {
result = original_mremap (start, oldlen, newlen, flags, new_address);
}
OPAL_PATCHER_END;
return result;
}
#endif
static int (*original_madvise) (void *, size_t, int);
static int intercept_madvise (void *start, size_t length, int advice)
{
OPAL_PATCHER_BEGIN;
@ -178,9 +195,14 @@ static int intercept_madvise (void *start, size_t length, int advice)
#endif
advice == POSIX_MADV_DONTNEED)
{
opal_mem_hooks_release_hook (start, length, 0);
opal_mem_hooks_release_hook (start, length, false);
}
if (!original_madvise) {
result = memory_patcher_syscall(SYS_madvise, start, length, advice);
} else {
result = original_madvise (start, length, advice);
}
result = memory_patcher_syscall(SYS_madvise, start, length, advice);
OPAL_PATCHER_END;
return result;
@ -192,6 +214,8 @@ static int intercept_madvise (void *start, size_t length, int advice)
void *__curbrk; /* in libc */
#endif
static int (*original_brk) (void *);
static int intercept_brk (void *addr)
{
OPAL_PATCHER_BEGIN;
@ -204,23 +228,32 @@ static int intercept_brk (void *addr)
old_addr = sbrk (0);
#endif
/* get the current_addr */
new_addr = (void *) (intptr_t) memory_patcher_syscall(SYS_brk, addr);
if (!original_brk) {
/* get the current_addr */
new_addr = (void *) (intptr_t) memory_patcher_syscall(SYS_brk, addr);
#if OPAL_MEMORY_PATCHER_HAVE___CURBRK
/*
* Note: if we were using glibc brk/sbrk, their __curbrk would get
* updated, but since we're going straight to the syscall, we have
* to update __curbrk or else glibc won't see it.
*/
__curbrk = new_addr;
/*
* Note: if we were using glibc brk/sbrk, their __curbrk would get
* updated, but since we're going straight to the syscall, we have
* to update __curbrk or else glibc won't see it.
*/
__curbrk = new_addr;
#endif
} else {
result = original_brk (addr);
#if OPAL_MEMORY_PATCHER_HAVE___CURBRK
new_addr = __curbrk;
#else
new_addr = sbrk (0);
#endif
}
if (new_addr < addr) {
errno = ENOMEM;
result = -1;
} else if (new_addr < old_addr) {
opal_mem_hooks_release_hook (new_addr, (intptr_t) old_addr - (intptr_t) new_addr, 0);
opal_mem_hooks_release_hook (new_addr, (intptr_t) old_addr - (intptr_t) new_addr, true);
}
OPAL_PATCHER_END;
return result;
@ -241,7 +274,7 @@ static int patcher_register (void)
static int patcher_query (int *priority)
{
if (opal_patch_supported ()) {
if (opal_patcher->patch_symbol) {
*priority = mca_memory_patcher_priority;
} else {
*priority = -1;
@ -263,30 +296,30 @@ static int patcher_open (void)
/* set memory hooks support level */
opal_mem_hooks_set_support (OPAL_MEMORY_FREE_SUPPORT | OPAL_MEMORY_MUNMAP_SUPPORT);
rc = opal_patch_symbol ("mmap", (uintptr_t) intercept_mmap);
rc = opal_patcher->patch_symbol ("mmap", (uintptr_t) intercept_mmap, (uintptr_t *) &original_mmap);
if (OPAL_SUCCESS != rc) {
return rc;
}
rc = opal_patch_symbol ("munmap", (uintptr_t)intercept_munmap);
rc = opal_patcher->patch_symbol ("munmap", (uintptr_t)intercept_munmap, (uintptr_t *) &original_munmap);
if (OPAL_SUCCESS != rc) {
return rc;
}
#if defined (SYS_mremap)
rc = opal_patch_symbol ("mremap",(uintptr_t)intercept_mremap);
rc = opal_patcher->patch_symbol ("mremap",(uintptr_t)intercept_mremap, (uintptr_t *) &original_mremap);
if (OPAL_SUCCESS != rc) {
return rc;
}
#endif
rc = opal_patch_symbol ("madvise", (uintptr_t)intercept_madvise);
rc = opal_patcher->patch_symbol ("madvise", (uintptr_t)intercept_madvise, (uintptr_t *) &original_madvise);
if (OPAL_SUCCESS != rc) {
return rc;
}
#if defined (SYS_brk)
rc = opal_patch_symbol ("brk", (uintptr_t)intercept_brk);
rc = opal_patcher->patch_symbol ("brk", (uintptr_t)intercept_brk, (uintptr_t *) &original_brk);
#endif
return rc;

39
opal/mca/patcher/Makefile.am Обычный файл
Просмотреть файл

@ -0,0 +1,39 @@
#
# Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
# University Research and Technology
# Corporation. All rights reserved.
# Copyright (c) 2004-2005 The University of Tennessee and The University
# of Tennessee Research Foundation. All rights
# reserved.
# Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
# University of Stuttgart. All rights reserved.
# Copyright (c) 2004-2005 The Regents of the University of California.
# All rights reserved.
# Copyright (c) 2010 Cisco Systems, Inc. All rights reserved.
# Copyright (c) 2016 Los Alamos National Security, LLC. All rights
# reserved.
# $COPYRIGHT$
#
# Additional copyrights may follow
#
# $HEADER$
#
# main library setup
noinst_LTLIBRARIES = libmca_patcher.la
libmca_patcher_la_SOURCES =
# local files
headers = patcher.h
libmca_patcher_la_SOURCES += $(headers)
# Conditionally install the header files
if WANT_INSTALL_HEADERS
opaldir = $(opalincludedir)/$(subdir)
nobase_opal_HEADERS = $(headers)
endif
include base/Makefile.am
distclean-local:
rm -f base/static-components.h

25
opal/mca/patcher/base/Makefile.am Обычный файл
Просмотреть файл

@ -0,0 +1,25 @@
#
# Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
# University Research and Technology
# Corporation. All rights reserved.
# Copyright (c) 2004-2005 The University of Tennessee and The University
# of Tennessee Research Foundation. All rights
# reserved.
# Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
# University of Stuttgart. All rights reserved.
# Copyright (c) 2004-2005 The Regents of the University of California.
# All rights reserved.
# Copyright (c) 2009 Cisco Systems, Inc. All rights reserved.
# Copyright (c) 2016 Los Alamos National Security, LLC. All rights
# reserved.
# $COPYRIGHT$
#
# Additional copyrights may follow
#
# $HEADER$
#
headers += base/base.h
libmca_patcher_la_SOURCES += base/patcher_base_frame.c \
base/patcher_base_patch.c

83
opal/mca/patcher/base/base.h Обычный файл
Просмотреть файл

@ -0,0 +1,83 @@
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
/*
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
* University Research and Technology
* Corporation. All rights reserved.
* Copyright (c) 2004-2006 The University of Tennessee and The University
* of Tennessee Research Foundation. All rights
* reserved.
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
* University of Stuttgart. All rights reserved.
* Copyright (c) 2004-2005 The Regents of the University of California.
* All rights reserved.
* Copyright (c) 2016 Los Alamos National Security, LLC. All rights
* reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*
*/
#ifndef OPAL_PATCHER_BASE_H
#define OPAL_PATCHER_BASE_H
#include "opal_config.h"
#include "opal/mca/base/mca_base_framework.h"
#include "opal/mca/patcher/patcher.h"
BEGIN_C_DECLS
#define MCA_BASE_PATCHER_MAX_PATCH 32
struct mca_patcher_base_patch_t;
typedef void (*mca_patcher_base_restore_fn_t) (struct mca_patcher_base_patch_t *);
struct mca_patcher_base_patch_t {
/** patches are list items */
opal_list_item_t super;
/** name symbol to patch */
char *patch_symbol;
/** address of function to call instead */
uintptr_t patch_value;
/** original address of function */
uintptr_t patch_orig;
/** patch data */
unsigned char patch_data[MCA_BASE_PATCHER_MAX_PATCH];
/** original data */
unsigned char patch_orig_data[MCA_BASE_PATCHER_MAX_PATCH];
/** size of patch data */
unsigned patch_data_size;
/** function to undo the patch */
mca_patcher_base_restore_fn_t patch_restore;
};
typedef struct mca_patcher_base_patch_t mca_patcher_base_patch_t;
OBJ_CLASS_DECLARATION(mca_patcher_base_patch_t);
/**
* Framework struct declaration for this framework
*/
OPAL_DECLSPEC extern mca_base_framework_t opal_patcher_base_framework;
OPAL_DECLSPEC int opal_patcher_base_select (void);
OPAL_DECLSPEC int mca_patcher_base_patch_hook (mca_patcher_base_module_t *module, uintptr_t hook);
OPAL_DECLSPEC void mca_base_patcher_patch_apply_binary (mca_patcher_base_patch_t *patch);
static inline uintptr_t mca_patcher_base_addr_text (uintptr_t addr) {
#if (defined(__PPC64__) || defined(__powerpc64__) || defined(__PPC__)) && _CALL_ELF != 2
struct odp_t {
uintptr_t text;
uintptr_t toc;
} *odp = (struct odp_t *) addr;
return (odp)?odp->text:0;
#else
return addr;
#endif
}
END_C_DECLS
#endif /* OPAL_BASE_PATCHER_H */

81
opal/mca/patcher/base/patcher_base_frame.c Обычный файл
Просмотреть файл

@ -0,0 +1,81 @@
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
/*
* Copyright (c) 2016 Los Alamos National Security, LLC. All rights
* reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#include "opal_config.h"
#include "opal/mca/patcher/patcher.h"
#include "opal/mca/patcher/base/base.h"
#include "opal/mca/patcher/base/static-components.h"
/*
* Local variables
*/
static mca_patcher_base_module_t empty_module;
/*
* Globals
*/
mca_patcher_base_module_t *opal_patcher = &empty_module;
int opal_patcher_base_select (void)
{
mca_patcher_base_module_t *best_module;
mca_patcher_base_component_t *best_component;
int rc, priority;
rc = mca_base_select ("patcher", opal_patcher_base_framework.framework_output,
&opal_patcher_base_framework.framework_components,
(mca_base_module_t **) &best_module, (mca_base_component_t **) &best_component,
&priority);
if (OPAL_SUCCESS != rc) {
return rc;
}
OBJ_CONSTRUCT(&best_module->patch_list, opal_list_t);
OBJ_CONSTRUCT(&best_module->patch_list_mutex, opal_mutex_t);
if (best_module->patch_init) {
rc = best_module->patch_init ();
if (OPAL_SUCCESS != rc) {
return rc;
}
}
opal_patcher = best_module;
return OPAL_SUCCESS;
}
static int opal_patcher_base_close (void)
{
if (opal_patcher == &empty_module) {
return OPAL_SUCCESS;
}
mca_patcher_base_patch_t *patch;
OPAL_LIST_FOREACH_REV(patch, &opal_patcher->patch_list, mca_patcher_base_patch_t) {
patch->patch_restore (patch);
}
OPAL_LIST_DESTRUCT(&opal_patcher->patch_list);
OBJ_DESTRUCT(&opal_patcher->patch_list_mutex);
if (opal_patcher->patch_fini) {
return opal_patcher->patch_fini ();
}
return OPAL_SUCCESS;
}
/* Use default register/open functions */
MCA_BASE_FRAMEWORK_DECLARE(opal, patcher, "runtime code patching", NULL, NULL,
opal_patcher_base_close, mca_patcher_base_static_components,
0);

175
opal/mca/patcher/base/patcher_base_patch.c Обычный файл
Просмотреть файл

@ -0,0 +1,175 @@
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
/*
* Copyright (c) 2016 Los Alamos National Security, LLC. All rights
* reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#include "opal_config.h"
#include "opal/mca/patcher/patcher.h"
#include "opal/mca/patcher/base/base.h"
#include "opal/util/sys_limits.h"
#include "opal/prefetch.h"
#include <sys/mman.h>
static void mca_patcher_base_patch_construct (mca_patcher_base_patch_t *patch)
{
patch->patch_symbol = NULL;
patch->patch_data_size = 0;
}
static void mca_patcher_base_patch_destruct (mca_patcher_base_patch_t *patch)
{
free (patch->patch_symbol);
}
OBJ_CLASS_INSTANCE(mca_patcher_base_patch_t, opal_list_item_t,
mca_patcher_base_patch_construct,
mca_patcher_base_patch_destruct);
#if defined(__PPC__)
// PowerPC instructions used in patching
// Reference: "PowerPC User Instruction Set Architecture"
static unsigned int addis(unsigned int RT, unsigned int RS, unsigned int UI) {
return (15<<26) + (RT<<21) + (RS<<16) + (UI&0xffff);
}
static unsigned int ori(unsigned int RT, unsigned int RS, unsigned int UI) {
return (24<<26) + (RS<<21) + (RT<<16) + (UI&0xffff);
}
static unsigned int oris(unsigned int RT, unsigned int RS, unsigned int UI) {
return (25<<26) + (RS<<21) + (RT<<16) + (UI&0xffff);
}
static unsigned int mtspr(unsigned int SPR, unsigned int RS) {
return (31<<26) + (RS<<21) + ((SPR&0x1f)<<16) + ((SPR>>5)<<11) + (467<<1);
}
static unsigned int bcctr(unsigned int BO, unsigned int BI, unsigned int BH) {
return (19<<26) + (BO<<21) + (BI<<16) + (BH<<11) + (528<<1);
}
static unsigned int rldicr(unsigned int RT, unsigned int RS, unsigned int SH, unsigned int MB)
{
return (30<<26) + (RS<<21) + (RT<<16) + ((SH&0x1f)<<11) + ((SH>>5)<<1)
+ ((MB&0x1f)<<6) + ((MB>>5)<<5) + (1<<2);
}
static int PatchLoadImm (uintptr_t addr, unsigned int reg, size_t value)
{
#if defined(__PPC64__)
*(unsigned int *) (addr + 0) = addis ( reg, 0, (value >> 48));
*(unsigned int *) (addr + 4) = ori ( reg, reg, (value >> 32));
*(unsigned int *) (addr + 8) = rldicr( reg, reg, 32, 31);
*(unsigned int *) (addr +12) = oris ( reg, reg, (value >> 16));
*(unsigned int *) (addr +16) = ori ( reg, reg, (value >> 0));
return 20;
#else
*(unsigned int *) (addr + 0) = addis ( reg, 0, (value >> 16));
*(unsigned int *) (addr + 4) = ori ( reg, reg, (value >> 0));
return 8;
#endif
}
#endif
#if defined(__i386__) || defined(__x86_64__) || defined(__ia64__)
static void flush_and_invalidate_cache (unsigned long a)
{
#if defined(__i386__)
/* does not work with AMD processors */
__asm__ volatile("mfence;clflush %0;mfence" : :"m" (*(char*)a));
#elif defined(__x86_64__)
__asm__ volatile("mfence;clflush %0;mfence" : :"m" (*(char*)a));
#elif defined(__ia64__)
__asm__ volatile ("fc %0;; sync.i;; srlz.i;;" : : "r"(a) : "memory");
#endif
}
#endif
// modify protection of memory range
static void ModifyMemoryProtection (uintptr_t addr, size_t length, int prot)
{
long page_size = opal_getpagesize ();
uintptr_t base = (addr & ~(page_size-1));
uintptr_t bound = ((addr + length + page_size-1) & ~(page_size-1));
length = bound - base;
#if defined(__PPC__)
/* NTH: is a loop necessary here? */
do {
if (mprotect((void *)base, page_size, prot))
perror("MemHook: mprotect failed");
base += page_size;
} while (base < addr + length);
#else
if (mprotect((void *) base, length, prot)) {
perror("MemHook: mprotect failed");
}
#endif
}
static inline void apply_patch (unsigned char *patch_data, uintptr_t address, size_t data_size)
{
ModifyMemoryProtection (address, data_size, PROT_EXEC|PROT_READ|PROT_WRITE);
memcpy ((void *) address, patch_data, data_size);
#if defined(__i386__) || defined(__x86_64__) || defined(__ia64__)
for (size_t i = 0 ; i < data_size ; i += 16) {
flush_and_invalidate_cache (address + i);
}
#endif
ModifyMemoryProtection (address, data_size, PROT_EXEC|PROT_READ);
}
static void mca_base_patcher_patch_unapply_binary (mca_patcher_base_patch_t *patch)
{
apply_patch (patch->patch_orig_data, patch->patch_orig, patch->patch_data_size);
}
void mca_base_patcher_patch_apply_binary (mca_patcher_base_patch_t *patch)
{
memcpy (patch->patch_orig_data, (void *) patch->patch_orig, patch->patch_data_size);
apply_patch (patch->patch_data, patch->patch_orig, patch->patch_data_size);
patch->patch_restore = mca_base_patcher_patch_unapply_binary;
}
int mca_patcher_base_patch_hook (mca_patcher_base_module_t *module, uintptr_t hook_addr)
{
#if defined(__PPC64__) || defined(__powerpc64__) || defined(__PPC__)
mca_patcher_base_patch_t *hook_patch;
const unsigned int nop = 0x60000000;
unsigned int *nop_addr;
fprintf (stderr, "Patching hook @ 0x%lx\n", hook_addr);
hook_patch = OBJ_NEW(mca_patcher_base_patch_t);
if (OPAL_UNLIKELY(NULL == hook_patch)) {
return OPAL_ERR_OUT_OF_RESOURCE;
}
// locate reserved code space in hook function
for (nop_addr = (unsigned int *)hook_addr ; ; nop_addr++) {
if (nop_addr[0] == nop && nop_addr[1] == nop && nop_addr[2] == nop
&& nop_addr[3] == nop && nop_addr[4] == nop) {
break;
}
}
// generate code to restore TOC
register unsigned long toc asm("r2");
hook_patch->patch_orig = (uintptr_t) nop_addr;
hook_patch->patch_data_size = PatchLoadImm((uintptr_t)hook_patch->patch_data, 2, toc);
/* put the hook patch on the patch list so it will be undone on finalize */
opal_list_append (&module->patch_list, &hook_patch->super);
mca_base_patcher_patch_apply_binary (hook_patch);
#endif
return OPAL_SUCCESS;
}

47
opal/mca/patcher/linux/Makefile.am Обычный файл
Просмотреть файл

@ -0,0 +1,47 @@
#
# Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
# University Research and Technology
# Corporation. All rights reserved.
# Copyright (c) 2004-2005 The University of Tennessee and The University
# of Tennessee Research Foundation. All rights
# reserved.
# Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
# University of Stuttgart. All rights reserved.
# Copyright (c) 2004-2005 The Regents of the University of California.
# All rights reserved.
# Copyright (c) 2009-2010 Cisco Systems, Inc. All rights reserved.
# Copyright (c) 2015 Research Organization for Information Science
# and Technology (RIST). All rights reserved.
# Copyright (c) 2016 Los Alamos National Security, LLC. All rights
# reserved.
# $COPYRIGHT$
#
# Additional copyrights may follow
#
# $HEADER$
#
if MCA_BUILD_opal_patcher_linux_DSO
component_noinst =
component_install = mca_patcher_linux.la
else
component_noinst = libmca_patcher_linux.la
component_install =
endif
linux_SOURCES = \
patcher_linux.h \
patcher_linux_module.c \
patcher_linux_component.c
mcacomponentdir = $(opallibdir)
mcacomponent_LTLIBRARIES = $(component_install)
mca_patcher_linux_la_SOURCES = $(linux_SOURCES)
nodist_mca_patcher_linux_la_SOURCES = $(linux_nodist_SOURCES)
mca_patcher_linux_la_LDFLAGS = -module -avoid-version
noinst_LTLIBRARIES = $(component_noinst)
libmca_patcher_linux_la_SOURCES = $(linux_SOURCES)
nodist_libmca_patcher_linux_la_SOURCES = $(linux_nodist_SOURCES)
libmca_patcher_linux_la_LIBADD = $(patcher_linux_LIBS)
libmca_patcher_linux_la_LDFLAGS = -module -avoid-version

43
opal/mca/patcher/linux/configure.m4 Обычный файл
Просмотреть файл

@ -0,0 +1,43 @@
# -*- shell-script -*-
#
# Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
# University Research and Technology
# Corporation. All rights reserved.
# Copyright (c) 2004-2005 The University of Tennessee and The University
# of Tennessee Research Foundation. All rights
# reserved.
# Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
# University of Stuttgart. All rights reserved.
# Copyright (c) 2004-2005 The Regents of the University of California.
# All rights reserved.
# Copyright (c) 2008-2010 Cisco Systems, Inc. All rights reserved.
# Copyright (c) 2015 Research Organization for Information Science
# and Technology (RIST). All rights reserved.
# Copyright (c) 2016 Los Alamos National Security, LLC. All rights
# reserved.
# $COPYRIGHT$
#
# Additional copyrights may follow
#
# $HEADER$
#
# MCA_patcher_linux_CONFIG(action-if-can-compile,
# [action-if-cant-compile])
# ------------------------------------------------
AC_DEFUN([MCA_opal_patcher_linux_CONFIG],[
AC_CONFIG_FILES([opal/mca/patcher/linux/Makefile])
OPAL_VAR_SCOPE_PUSH([opal_patcher_linux_CPPFLAGS_save])
opal_patcher_linux_happy=no
if test $OPAL_ENABLE_DLOPEN_SUPPORT = 1; then
OPAL_CHECK_PACKAGE([patcher_linux], [dlfcn.h], [dl], [dl_iterate_phdr], [], [], [],
[opal_patcher_linux_happy=yes],[])
AC_CHECK_HEADERS([elf.h],[],[opal_patcher_linux_happy=no])
AC_CHECK_HEADERS([sys/auxv.h])
fi
AS_IF([test $opal_patcher_linux_happy = yes], [$1], [$2])
OPAL_VAR_SCOPE_POP
])

45
opal/mca/patcher/linux/patcher_linux.h Обычный файл
Просмотреть файл

@ -0,0 +1,45 @@
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
/*
* Copyright (c) 2016 Los Alamos National Security, LLC. All rights
* reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#if !defined(OPAL_PATCHER_LINUX_H)
#define OPAL_PATCHER_LINUX_H
#include "opal_config.h"
#include "opal/mca/patcher/base/base.h"
#include "opal/mca/patcher/patcher.h"
#include "opal/class/opal_list.h"
#include "opal/threads/mutex.h"
struct mca_patcher_linux_patch_got_t {
opal_list_item_t super;
void **got_entry;
void *got_orig;
};
typedef struct mca_patcher_linux_patch_got_t mca_patcher_linux_patch_got_t;
OBJ_CLASS_DECLARATION(mca_patcher_linux_patch_got_t);
struct mca_patcher_linux_patch_t {
mca_patcher_base_patch_t super;
opal_list_t patch_got_list;
};
typedef struct mca_patcher_linux_patch_t mca_patcher_linux_patch_t;
OBJ_CLASS_DECLARATION(mca_patcher_linux_patch_t);
extern mca_patcher_base_module_t mca_patcher_linux_module;
extern mca_patcher_base_component_t mca_patcher_linux_component;
#endif /* !defined(OPAL_PATCHER_LINUX_H) */

Просмотреть файл

@ -0,0 +1,43 @@
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
/*
* Copyright (c) 2016 Los Alamos National Security, LLC. All rights
* reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#include "patcher_linux.h"
static int mca_patcher_linux_priority;
static int mca_patcher_linux_register (void)
{
mca_patcher_linux_priority = 13;
mca_base_component_var_register (&mca_patcher_linux_component.patcherc_version,
"priority", "Priority of the linux binary patcher component",
MCA_BASE_VAR_TYPE_INT, NULL, 0, 0, OPAL_INFO_LVL_5,
MCA_BASE_VAR_SCOPE_CONSTANT, &mca_patcher_linux_priority);
return OPAL_SUCCESS;
}
static int mca_patcher_linux_query (mca_base_module_t **module, int *priority)
{
*module = &mca_patcher_linux_module.super;
*priority = mca_patcher_linux_priority;
return OPAL_SUCCESS;
}
mca_patcher_base_component_t mca_patcher_linux_component = {
.patcherc_version = {
OPAL_PATCHER_BASE_VERSION_1_0_0,
.mca_component_name = "linux",
MCA_BASE_MAKE_VERSION(component, OPAL_MAJOR_VERSION, OPAL_MINOR_VERSION,
OPAL_RELEASE_VERSION),
.mca_query_component = mca_patcher_linux_query,
.mca_register_component_params = mca_patcher_linux_register,
},
};

460
opal/mca/patcher/linux/patcher_linux_module.c Обычный файл
Просмотреть файл

@ -0,0 +1,460 @@
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
/*
* Copyright (C) Mellanox Technologies Ltd. 2001-2015. ALL RIGHTS RESERVED.
* Copyright (c) 2016 Los Alamos National Security, LLC. All rights
* reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
/*
* Copied from OpenUCX
*/
#include "patcher_linux.h"
#include "opal/mca/patcher/base/base.h"
#include "opal/constants.h"
#include "opal/util/sys_limits.h"
#include "opal/util/output.h"
#include "opal/prefetch.h"
#if defined(HAVE_SYS_AUXV_H)
#include <sys/auxv.h>
#endif
#include <elf.h>
#include <sys/mman.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <link.h>
static void *mca_patcher_linux_dlopen(const char *filename, int flag);
typedef struct mca_patcher_linux_elf_strtab {
char *tab;
ElfW(Xword) size;
} mca_patcher_linux_elf_strtab_t;
typedef struct mca_patcher_linux_elf_jmpreltab {
ElfW(Rela) *tab;
ElfW(Xword) size;
} mca_patcher_linux_elf_jmprel_t;
typedef struct mca_patcher_linux_elf_symtab {
ElfW(Sym) *tab;
ElfW(Xword) entsz;
} mca_patcher_linux_elf_symtab_t;
typedef struct mca_patcher_linux_dl_iter_context {
mca_patcher_linux_patch_t *patch;
bool remove;
int status;
} mca_patcher_linux_dl_iter_context_t;
OBJ_CLASS_INSTANCE(mca_patcher_linux_patch_got_t, opal_list_item_t, NULL, NULL);
static void mca_patcher_linux_patch_construct (mca_patcher_linux_patch_t *patch)
{
OBJ_CONSTRUCT(&patch->patch_got_list, opal_list_t);
}
static void mca_patcher_linux_patch_destruct (mca_patcher_linux_patch_t *patch)
{
OPAL_LIST_DESTRUCT(&patch->patch_got_list);
}
OBJ_CLASS_INSTANCE(mca_patcher_linux_patch_t, mca_patcher_base_patch_t, mca_patcher_linux_patch_construct,
mca_patcher_linux_patch_destruct);
/* List of patches to be applied to additional libraries */
static void *(*orig_dlopen) (const char *, int);
static const ElfW(Phdr) *
mca_patcher_linux_get_phdr_dynamic(const ElfW(Phdr) *phdr, uint16_t phnum, int phent)
{
for (uint16_t i = 0; i < phnum; ++i) {
if (phdr->p_type == PT_DYNAMIC) {
return phdr;
}
phdr = (ElfW(Phdr)*)((char*)phdr + phent);
}
return NULL;
}
static const ElfW(Dyn)*
mca_patcher_linux_get_dynentry(ElfW(Addr) base, const ElfW(Phdr) *pdyn, uint32_t type)
{
for (ElfW(Dyn) *dyn = (ElfW(Dyn)*)(base + pdyn->p_vaddr); dyn->d_tag; ++dyn) {
if (dyn->d_tag == type) {
return dyn;
}
}
return NULL;
}
static void mca_patcher_linux_get_jmprel(ElfW(Addr) base, const ElfW(Phdr) *pdyn,
mca_patcher_linux_elf_jmprel_t *table)
{
const ElfW(Dyn) *dyn;
dyn = mca_patcher_linux_get_dynentry(base, pdyn, DT_JMPREL);
table->tab = (dyn == NULL) ? NULL : (ElfW(Rela)*)dyn->d_un.d_ptr;
dyn = mca_patcher_linux_get_dynentry(base, pdyn, DT_PLTRELSZ);
table->size = (dyn == NULL) ? 0 : dyn->d_un.d_val;
}
static void mca_patcher_linux_get_symtab(ElfW(Addr) base, const ElfW(Phdr) *pdyn,
mca_patcher_linux_elf_symtab_t *table)
{
const ElfW(Dyn) *dyn;
dyn = mca_patcher_linux_get_dynentry(base, pdyn, DT_SYMTAB);
table->tab = (dyn == NULL) ? NULL : (ElfW(Sym)*)dyn->d_un.d_ptr;
dyn = mca_patcher_linux_get_dynentry(base, pdyn, DT_SYMENT);
table->entsz = (dyn == NULL) ? 0 : dyn->d_un.d_val;
}
static void mca_patcher_linux_get_strtab(ElfW(Addr) base, const ElfW(Phdr) *pdyn,
mca_patcher_linux_elf_strtab_t *table)
{
const ElfW(Dyn) *dyn;
dyn = mca_patcher_linux_get_dynentry(base, pdyn, DT_STRTAB);
table->tab = (dyn == NULL) ? NULL : (char *)dyn->d_un.d_ptr;
dyn = mca_patcher_linux_get_dynentry(base, pdyn, DT_STRSZ);
table->size = (dyn == NULL) ? 0 : dyn->d_un.d_val;
}
static void * mca_patcher_linux_get_got_entry (ElfW(Addr) base, const ElfW(Phdr) *phdr, int16_t phnum,
int phent, const char *symbol)
{
mca_patcher_linux_elf_jmprel_t jmprel;
mca_patcher_linux_elf_symtab_t symtab;
mca_patcher_linux_elf_strtab_t strtab;
ElfW(Rela) *rela, *relaend;
const ElfW(Phdr) *dphdr;
const char *relsymname;
uint32_t relsymidx;
dphdr = mca_patcher_linux_get_phdr_dynamic (phdr, phnum, phent);
mca_patcher_linux_get_jmprel (base, dphdr, &jmprel);
mca_patcher_linux_get_symtab (base, dphdr, &symtab);
mca_patcher_linux_get_strtab (base, dphdr, &strtab);
relaend = (ElfW(Rela) *)((char *)jmprel.tab + jmprel.size);
for (rela = jmprel.tab; rela < relaend; ++rela) {
#if SIZEOF_VOID_P == 8
relsymidx = ELF64_R_SYM(rela->r_info);
#else
relsymidx = ELF32_R_SYM(rela->r_info);
#endif
relsymname = strtab.tab + symtab.tab[relsymidx].st_name;
if (!strcmp(symbol, relsymname)) {
return (void *)(base + rela->r_offset);
}
}
return NULL;
}
static int mca_patcher_linux_get_aux_phent (void)
{
#if !defined(HAVE_SYS_AUXV_H)
#define MCA_PATCHER_LINUX_AUXV_BUF_LEN 16
static const char *proc_auxv_filename = "/proc/self/auxv";
static int phent = 0;
#if SIZEOF_VOID_P == 8
Elf64_auxv_t buffer[MCA_PATCHER_LINUX_AUXV_BUF_LEN];
#else
Elf32_auxv_t buffer[MCA_PATCHER_LINUX_AUXV_BUF_LEN];
#endif
unsigned count;
ssize_t nread;
int fd;
/* Can avoid lock here - worst case we'll read the file more than once */
if (phent == 0) {
fd = open(proc_auxv_filename, O_RDONLY);
if (fd < 0) {
opal_output_verbose (MCA_BASE_VERBOSE_ERROR, opal_patcher_base_framework.framework_output,
"failed to open '%s' for reading: %s", proc_auxv_filename,
strerror (errno));
return OPAL_ERROR;
}
/* Use small buffer on the stack, avoid using malloc() */
do {
nread = read(fd, buffer, sizeof(buffer));
if (nread < 0) {
opal_output_verbose (MCA_BASE_VERBOSE_ERROR, opal_patcher_base_framework.framework_output,
"failed to read %lu bytes from %s (ret=%ld): %s", sizeof (buffer),
proc_auxv_filename, nread, strerror (errno));
break;
}
count = nread / sizeof(buffer[0]);
for (unsigned i = 0 ; i < count && AT_NULL != buffer[i].a_type ; ++i) {
if (AT_PHENT == buffer[i].a_type) {
phent = buffer[i].a_un.a_val;
opal_output_verbose (MCA_BASE_VERBOSE_ERROR, opal_patcher_base_framework.framework_output,
"read phent from %s: %d", proc_auxv_filename, phent);
break;
}
}
} while ((count > 0) && (phent == 0));
close(fd);
}
return phent;
#else
return getauxval (AT_PHENT);
#endif
}
static int
mca_patcher_linux_modify_got (ElfW(Addr) base, const ElfW(Phdr) *phdr, const char *phname,
int16_t phnum, int phent, mca_patcher_linux_dl_iter_context_t *ctx)
{
long page_size = opal_getpagesize ();
void **entry;
void *page;
int ret;
entry = mca_patcher_linux_get_got_entry (base, phdr, phnum, phent, ctx->patch->super.patch_symbol);
if (entry == NULL) {
return OPAL_SUCCESS;
}
page = (void *)((intptr_t)entry & ~(page_size - 1));
ret = mprotect(page, page_size, PROT_READ|PROT_WRITE);
if (ret < 0) {
opal_output_verbose (MCA_BASE_VERBOSE_ERROR, opal_patcher_base_framework.framework_output,
"failed to modify GOT page %p to rw: %s", page, strerror (errno));
return OPAL_ERR_NOT_SUPPORTED;
}
if (!ctx->remove) {
if (*entry != (void *) ctx->patch->super.patch_value) {
mca_patcher_linux_patch_got_t *patch_got = OBJ_NEW(mca_patcher_linux_patch_got_t);
if (NULL == patch_got) {
return OPAL_ERR_OUT_OF_RESOURCE;
}
opal_output_verbose (MCA_BASE_VERBOSE_TRACE, opal_patcher_base_framework.framework_output,
"patch %p (%s): modifying got entry %p. original value %p. new value %p\n", ctx->patch,
ctx->patch->super.patch_symbol, (void *) entry, *entry, (void *) ctx->patch->super.patch_value);
patch_got->got_entry = entry;
patch_got->got_orig = *entry;
opal_list_append (&ctx->patch->patch_got_list, &patch_got->super);
*entry = (void *) ctx->patch->super.patch_value;
}
} else {
if (*entry == (void *) ctx->patch->super.patch_value) {
/* find the appropriate entry and restore the original value */
mca_patcher_linux_patch_got_t *patch_got;
OPAL_LIST_FOREACH_REV(patch_got, &ctx->patch->patch_got_list, mca_patcher_linux_patch_got_t) {
if (patch_got->got_entry == entry) {
opal_output_verbose (MCA_BASE_VERBOSE_TRACE, opal_patcher_base_framework.framework_output,
"restoring got entry %p with original value %p\n", (void *) entry, patch_got->got_orig);
*entry = patch_got->got_orig;
opal_list_remove_item (&ctx->patch->patch_got_list, &patch_got->super);
OBJ_RELEASE(patch_got);
break;
}
}
}
}
return OPAL_SUCCESS;
}
static int mca_patcher_linux_phdr_iterator(struct dl_phdr_info *info, size_t size, void *data)
{
mca_patcher_linux_dl_iter_context_t *ctx = data;
int phent;
phent = mca_patcher_linux_get_aux_phent();
if (phent <= 0) {
opal_output_verbose (MCA_BASE_VERBOSE_ERROR, opal_patcher_base_framework.framework_output,
"failed to read phent size");
ctx->status = OPAL_ERR_NOT_SUPPORTED;
return -1;
}
ctx->status = mca_patcher_linux_modify_got (info->dlpi_addr, info->dlpi_phdr,
info->dlpi_name, info->dlpi_phnum,
phent, ctx);
if (ctx->status == OPAL_SUCCESS) {
return 0; /* continue iteration and patch all objects */
} else {
return -1; /* stop iteration if got a real error */
}
}
/* called with lock held */
static int mca_patcher_linux_apply_patch (mca_patcher_linux_patch_t *patch)
{
mca_patcher_linux_dl_iter_context_t ctx = {
.patch = patch,
.remove = false,
.status = OPAL_SUCCESS,
};
/* Avoid locks here because we don't modify ELF data structures.
* Worst case the same symbol will be written more than once.
*/
(void)dl_iterate_phdr(mca_patcher_linux_phdr_iterator, &ctx);
if (ctx.status == OPAL_SUCCESS) {
opal_output_verbose (MCA_BASE_VERBOSE_INFO, opal_patcher_base_framework.framework_output,
"modified '%s' to 0x%lx", ctx.patch->super.patch_symbol, ctx.patch->super.patch_value);
}
return ctx.status;
}
static int mca_patcher_linux_remove_patch (mca_patcher_linux_patch_t *patch)
{
mca_patcher_linux_dl_iter_context_t ctx = {
.patch = patch,
.remove = true,
.status = OPAL_SUCCESS,
};
/* Avoid locks here because we don't modify ELF data structures.
* Worst case the same symbol will be written more than once.
*/
(void)dl_iterate_phdr(mca_patcher_linux_phdr_iterator, &ctx);
if (ctx.status == OPAL_SUCCESS) {
opal_output_verbose (MCA_BASE_VERBOSE_INFO, opal_patcher_base_framework.framework_output,
"modified '%s' to 0x%lx", ctx.patch->super.patch_symbol, ctx.patch->super.patch_value);
}
return ctx.status;
}
static void *mca_patcher_linux_dlopen(const char *filename, int flag)
{
OPAL_PATCHER_BEGIN;
mca_patcher_linux_patch_t *patch;
void *handle;
assert (orig_dlopen);
handle = orig_dlopen (filename, flag);
if (handle != NULL) {
/*
* Every time a new object is loaded, we must update its relocations
* with our list of patches (including dlopen itself). This code is less
* efficient and will modify all existing objects every time, but good
* enough.
*/
opal_mutex_lock (&mca_patcher_linux_module.patch_list_mutex);
OPAL_LIST_FOREACH(patch, &mca_patcher_linux_module.patch_list, mca_patcher_linux_patch_t) {
opal_output_verbose (MCA_BASE_VERBOSE_INFO, opal_patcher_base_framework.framework_output,
"in dlopen(), re-applying '%s' to %p", patch->super.patch_symbol, (void *) patch->super.patch_value);
/* ignore hook binary patches */
if (!patch->super.patch_data_size) {
mca_patcher_linux_apply_patch (patch);
}
}
opal_mutex_unlock (&mca_patcher_linux_module.patch_list_mutex);
}
OPAL_PATCHER_END;
return handle;
}
static intptr_t mca_patcher_linux_get_orig (const char *symbol, void *replacement)
{
const char *error;
void *func_ptr;
func_ptr = dlsym(RTLD_DEFAULT, symbol);
if (func_ptr == replacement) {
(void)dlerror();
func_ptr = dlsym(RTLD_NEXT, symbol);
if (func_ptr == NULL) {
error = dlerror();
opal_output_verbose (MCA_BASE_VERBOSE_ERROR, opal_patcher_base_framework.framework_output,
"could not find address of original %s(): %s", symbol, error ? error : "Unknown error");
}
}
opal_output_verbose (MCA_BASE_VERBOSE_INFO, opal_patcher_base_framework.framework_output,
"original %s() is at %p", symbol, func_ptr);
return (intptr_t) func_ptr;
}
static int mca_patcher_linux_patch_symbol (const char *symbol_name, uintptr_t replacement, uintptr_t *orig)
{
mca_patcher_linux_patch_t *patch = OBJ_NEW(mca_patcher_linux_patch_t);
int rc;
if (OPAL_UNLIKELY(NULL == patch)) {
return OPAL_ERR_OUT_OF_RESOURCE;
}
patch->super.patch_symbol = strdup (symbol_name);
if (NULL == patch->super.patch_symbol) {
OBJ_RELEASE(patch);
return OPAL_ERR_OUT_OF_RESOURCE;
}
patch->super.patch_value = mca_patcher_base_addr_text (replacement);
patch->super.patch_restore = (mca_patcher_base_restore_fn_t) mca_patcher_linux_remove_patch;
/* Take lock first to handle a possible race where dlopen() is called
* from another thread and we may end up not patching it.
*/
opal_mutex_lock (&mca_patcher_linux_module.patch_list_mutex);
do {
rc = mca_patcher_base_patch_hook (&mca_patcher_linux_module, patch->super.patch_value);
if (OPAL_SUCCESS != rc) {
OBJ_RELEASE(patch);
break;
}
rc = mca_patcher_linux_apply_patch (patch);
if (OPAL_SUCCESS != rc) {
OBJ_RELEASE(patch);
break;
}
*orig = mca_patcher_linux_get_orig (patch->super.patch_symbol, (void *) replacement);
opal_list_append (&mca_patcher_linux_module.patch_list, &patch->super.super);
} while (0);
opal_mutex_unlock (&mca_patcher_linux_module.patch_list_mutex);
return rc;
}
/* called with lock held */
static int mca_patcher_linux_install_dlopen (void)
{
return mca_patcher_linux_patch_symbol ("dlopen", (uintptr_t) mca_patcher_linux_dlopen,
(uintptr_t *) &orig_dlopen);
}
static int mca_patcher_linux_init (void)
{
return mca_patcher_linux_install_dlopen ();
}
mca_patcher_base_module_t mca_patcher_linux_module = {
.patch_init = mca_patcher_linux_init,
.patch_symbol = mca_patcher_linux_patch_symbol,
};

47
opal/mca/patcher/overwrite/Makefile.am Обычный файл
Просмотреть файл

@ -0,0 +1,47 @@
#
# Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
# University Research and Technology
# Corporation. All rights reserved.
# Copyright (c) 2004-2005 The University of Tennessee and The University
# of Tennessee Research Foundation. All rights
# reserved.
# Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
# University of Stuttgart. All rights reserved.
# Copyright (c) 2004-2005 The Regents of the University of California.
# All rights reserved.
# Copyright (c) 2009-2010 Cisco Systems, Inc. All rights reserved.
# Copyright (c) 2015 Research Organization for Information Science
# and Technology (RIST). All rights reserved.
# Copyright (c) 2016 Los Alamos National Security, LLC. All rights
# reserved.
# $COPYRIGHT$
#
# Additional copyrights may follow
#
# $HEADER$
#
if MCA_BUILD_opal_patcher_overwrite_DSO
component_noinst =
component_install = mca_patcher_overwrite.la
else
component_noinst = libmca_patcher_overwrite.la
component_install =
endif
overwrite_SOURCES = \
patcher_overwrite.h \
patcher_overwrite_module.c \
patcher_overwrite_component.c
mcacomponentdir = $(opallibdir)
mcacomponent_LTLIBRARIES = $(component_install)
mca_patcher_overwrite_la_SOURCES = $(overwrite_SOURCES)
nodist_mca_patcher_overwrite_la_SOURCES = $(overwrite_nodist_SOURCES)
mca_patcher_overwrite_la_LDFLAGS = -module -avoid-version
noinst_LTLIBRARIES = $(component_noinst)
libmca_patcher_overwrite_la_SOURCES = $(overwrite_SOURCES)
nodist_libmca_patcher_overwrite_la_SOURCES = $(overwrite_nodist_SOURCES)
libmca_patcher_overwrite_la_LIBADD = $(patcher_overwrite_LIBS)
libmca_patcher_overwrite_la_LDFLAGS = -module -avoid-version

41
opal/mca/patcher/overwrite/configure.m4 Обычный файл
Просмотреть файл

@ -0,0 +1,41 @@
# -*- shell-script -*-
#
# Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
# University Research and Technology
# Corporation. All rights reserved.
# Copyright (c) 2004-2005 The University of Tennessee and The University
# of Tennessee Research Foundation. All rights
# reserved.
# Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
# University of Stuttgart. All rights reserved.
# Copyright (c) 2004-2005 The Regents of the University of California.
# All rights reserved.
# Copyright (c) 2008-2010 Cisco Systems, Inc. All rights reserved.
# Copyright (c) 2015 Research Organization for Information Science
# and Technology (RIST). All rights reserved.
# Copyright (c) 2016 Los Alamos National Security, LLC. All rights
# reserved.
# $COPYRIGHT$
#
# Additional copyrights may follow
#
# $HEADER$
#
# MCA_patcher_overwrite_CONFIG(action-if-can-compile,
# [action-if-cant-compile])
# ------------------------------------------------
AC_DEFUN([MCA_opal_patcher_overwrite_CONFIG],[
AC_CONFIG_FILES([opal/mca/patcher/overwrite/Makefile])
opal_patcher_overwrite_happy=no
if test $OPAL_ENABLE_DLOPEN_SUPPORT = 1; then
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#if !defined(__i386__) && !defined(__x86_64__) && !defined(__ia64__) && !defined(__PPC__)
#error "platform not supported"
#endif
]],[])],[opal_patcher_overwrite_happy=yes],[])
fi
AS_IF([test $opal_patcher_overwrite_happy = yes], [$1], [$2])
])

Просмотреть файл

@ -0,0 +1,32 @@
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
/*
* Copyright (c) 2016 Los Alamos National Security, LLC. All rights
* reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
/**
* @file pather_overwrite.h
*
* This component works by overwritting the first couple instructions in
* the target function with a jump instruction to the hook function. The
* hook function will be expected to implement the functionality of the
* hooked function when using this module.
*
* Note: This component only supports x86, x86_64, ia64, and powerpc/power.
*/
#if !defined(OPAL_PATCHER_OVERWRITE_H)
#define OPAL_PATCHER_OVERWRITE_H
#include "opal_config.h"
#include "opal/mca/patcher/patcher.h"
#include "opal/class/opal_list.h"
extern mca_patcher_base_module_t mca_patcher_overwrite_module;
extern mca_patcher_base_component_t mca_patcher_overwrite_component;
#endif /* !defined(OPAL_PATCHER_OVERWRITE_H) */

Просмотреть файл

@ -0,0 +1,45 @@
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
/*
* Copyright (c) 2016 Los Alamos National Security, LLC. All rights
* reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#include "patcher_overwrite.h"
#include "opal/mca/mca.h"
#include "opal/mca/base/base.h"
static int mca_patcher_overwrite_priority;
static int mca_patcher_overwrite_register (void)
{
mca_patcher_overwrite_priority = 37;
mca_base_component_var_register (&mca_patcher_overwrite_component.patcherc_version,
"priority", "Priority of the overwrite binary patcher component",
MCA_BASE_VAR_TYPE_INT, NULL, 0, 0, OPAL_INFO_LVL_5,
MCA_BASE_VAR_SCOPE_CONSTANT, &mca_patcher_overwrite_priority);
return OPAL_SUCCESS;
}
static int mca_patcher_overwrite_query (mca_base_module_t **module, int *priority)
{
*module = &mca_patcher_overwrite_module.super;
*priority = mca_patcher_overwrite_priority;
return OPAL_SUCCESS;
}
mca_patcher_base_component_t mca_patcher_overwrite_component = {
.patcherc_version = {
OPAL_PATCHER_BASE_VERSION_1_0_0,
.mca_component_name = "overwrite",
MCA_BASE_MAKE_VERSION(component, OPAL_MAJOR_VERSION, OPAL_MINOR_VERSION,
OPAL_RELEASE_VERSION),
.mca_query_component = mca_patcher_overwrite_query,
.mca_register_component_params = mca_patcher_overwrite_register,
},
};

Просмотреть файл

@ -10,11 +10,14 @@
* $HEADER$
*/
#include "opal_patcher.h"
#include "patcher_overwrite.h"
#include "opal/mca/patcher/base/base.h"
#include "opal/constants.h"
#include "opal/util/sys_limits.h"
#include "opal/util/output.h"
#include "opal/prefetch.h"
#include <stdio.h>
#include <stdlib.h>
@ -25,19 +28,7 @@
#include <dlfcn.h>
#include <assert.h>
#if OPAL_ENABLE_DLOPEN_SUPPORT && (defined(__i386__) || defined(__x86_64__) || defined(__ia64__))
static void flush_and_invalidate_cache (unsigned long a)
{
#if defined(__i386__)
/* does not work with AMD processors */
__asm__ volatile("mfence;clflush %0;mfence" : :"m" (*(char*)a));
#elif defined(__x86_64__)
__asm__ volatile("mfence;clflush %0;mfence" : :"m" (*(char*)a));
#elif defined(__ia64__)
__asm__ volatile ("fc %0;; sync.i;; srlz.i;;" : : "r"(a) : "memory");
#endif
}
#if defined(__i386__) || defined(__x86_64__) || defined(__ia64__)
#if defined(__ia64__)
@ -91,24 +82,22 @@ static void make_ia64_bundle (unsigned char *dst,
}
#endif /* defined(__ia64__) */
static int patch_code (uintptr_t func_old_addr, unsigned long func_new_addr)
static int mca_patcher_overwrite_apply_patch (mca_patcher_base_patch_t *patch)
{
long pg_sz = opal_getpagesize ();
if (mprotect((void*)(func_old_addr&~(pg_sz-1)), pg_sz, PROT_EXEC|PROT_READ|PROT_WRITE)) {
perror("mprotect failed\n");
}
uintptr_t func_new_addr = patch->patch_value;
{
#if defined(__i386__)
*(unsigned char*)(func_old_addr+0) = 0xe9;
*(unsigned int *)(func_old_addr+1) = (unsigned int)(func_new_addr - func_old_addr - 5);
patch->patch_data_size = 5;
*(unsigned char *)(patch->patch_data+0) = 0xe9;
*(unsigned int *) (patch->patch_data+1) = (unsigned int)(func_new_addr - func_old_addr - 5);
#elif defined(__x86_64__)
*(unsigned short*)(func_old_addr+ 0) = 0xbb49;
*(unsigned long* )(func_old_addr+ 2) = (unsigned long) func_new_addr;
*(unsigned char*) (func_old_addr+10) = 0x41;
*(unsigned char*) (func_old_addr+11) = 0xff;
*(unsigned char*) (func_old_addr+12) = 0xe3;
patch->patch_data_size = 13;
*(unsigned short*)(patch->patch_data + 0) = 0xbb49;
*(unsigned long* )(patch->patch_data + 2) = (unsigned long) func_new_addr;
*(unsigned char*) (patch->patch_data +10) = 0x41;
*(unsigned char*) (patch->patch_data +11) = 0xff;
*(unsigned char*) (patch->patch_data +12) = 0xe3;
#elif defined(__ia64__)
{
/*
@ -144,109 +133,48 @@ static int patch_code (uintptr_t func_old_addr, unsigned long func_new_addr)
(1ULL << 6) |
(0x0ULL << 0);
patch->data_size = 32;
make_ia64_bundle(buf, movl, (glb_ptr>>22)&0x1FFFFFFFFFFULL, nop, 5);
for (int i = 0 ; i < 16 ; ++i) {
((unsigned char *)func_old_addr)[16-i-1] = buf[i];
patch->patch_data[16-i-1] = buf[i];
}
make_ia64_bundle(buf, brl, ((imm64>>24)&0x7FFFFFFFFFULL)<<2, nop, 5);
for (int i = 0 ; i < 16 ; ++i) {
((unsigned char *)func_old_addr+16)[16-i-1] = buf[i];
patch->patch_data[32-i-1] = buf[i];
}
}
#endif
}
flush_and_invalidate_cache(func_old_addr+ 0);
flush_and_invalidate_cache(func_old_addr+16);
mca_base_patcher_patch_apply_binary (patch);
#if 1
if (mprotect((void*)(func_old_addr&~(pg_sz-1)), pg_sz, PROT_EXEC)) {
perror("mprotect failed\n");
}
#endif
return 0;
}
int opal_patch_symbol (const char *func_symbol_name, uintptr_t func_new_addr)
{
void *sym_addr;
char *error;
uintptr_t func_old_addr;
/* NTH: might want to update opal/mca/dl to handle lookups in the default
* handle. */
sym_addr = dlsym(RTLD_DEFAULT, func_symbol_name);
if ( (sym_addr == NULL) && ((error = dlerror()) != NULL) ) {
opal_output(0, "error locating symbol %s to patch. %s", func_symbol_name,
error);
return -1;
}
func_old_addr = (unsigned long)sym_addr;
#if defined(__ia64__)
/* On IA64 addresses are all indirect */
func_new_addr = *(unsigned long *)func_new_addr;
func_old_addr = *(unsigned long *)func_old_addr;
#endif
patch_code(func_old_addr, func_new_addr);
return OPAL_SUCCESS;
}
bool opal_patch_supported (void)
{
return true;
}
/* end of #if defined(__i386__) || defined(__x86_64__) || defined(__ia64__) */
// ------------------------------------------------- PPC equivalent:
#elif OPAL_ENABLE_DLOPEN_SUPPORT && defined(__PPC__)
static inline uintptr_t addr_text (uintptr_t addr) {
#if (defined(__PPC64__) || defined(__powerpc64__) || defined(__PPC__)) && _CALL_ELF != 2
struct odp_t {
uintptr_t text;
uintptr_t toc;
} *odp = (struct odp_t *) addr;
return (odp)?odp->text:0;
#else
return addr;
#endif
}
// modify protection of memory range
static void
ModifyMemoryProtection(uintptr_t addr, size_t length, int prot)
{
long page_size = opal_getpagesize ();
uintptr_t page_addr = (addr & ~(page_size-1));
do {
if (mprotect((void *)page_addr, page_size, prot))
perror("MemHook: mprotect failed");
page_addr += page_size;
} while (page_addr < addr + length);
}
#elif defined(__PPC__)
// PowerPC instructions used in patching
// Reference: "PowerPC User Instruction Set Architecture"
unsigned int addis(unsigned int RT, unsigned int RS, unsigned int UI) {
static unsigned int addis(unsigned int RT, unsigned int RS, unsigned int UI) {
return (15<<26) + (RT<<21) + (RS<<16) + (UI&0xffff);
}
unsigned int ori(unsigned int RT, unsigned int RS, unsigned int UI) {
static unsigned int ori(unsigned int RT, unsigned int RS, unsigned int UI) {
return (24<<26) + (RS<<21) + (RT<<16) + (UI&0xffff);
}
unsigned int oris(unsigned int RT, unsigned int RS, unsigned int UI) {
static unsigned int oris(unsigned int RT, unsigned int RS, unsigned int UI) {
return (25<<26) + (RS<<21) + (RT<<16) + (UI&0xffff);
}
unsigned int mtspr(unsigned int SPR, unsigned int RS) {
static unsigned int mtspr(unsigned int SPR, unsigned int RS) {
return (31<<26) + (RS<<21) + ((SPR&0x1f)<<16) + ((SPR>>5)<<11) + (467<<1);
}
unsigned int bcctr(unsigned int BO, unsigned int BI, unsigned int BH) {
static unsigned int bcctr(unsigned int BO, unsigned int BI, unsigned int BH) {
return (19<<26) + (BO<<21) + (BI<<16) + (BH<<11) + (528<<1);
}
unsigned int rldicr(unsigned int RT, unsigned int RS, unsigned int SH, unsigned int MB)
static unsigned int rldicr(unsigned int RT, unsigned int RS, unsigned int SH, unsigned int MB)
{
return (30<<26) + (RS<<21) + (RT<<16) + ((SH&0x1f)<<11) + ((SH>>5)<<1)
+ ((MB&0x1f)<<6) + ((MB>>5)<<5) + (1<<2);
@ -270,93 +198,110 @@ PatchLoadImm(uintptr_t addr, unsigned int reg, size_t value)
}
static void
apply_patch(char *patch, void *addr, int length)
static int mca_patcher_overwrite_apply_patch (mca_patcher_base_patch_t *patch)
{
if (length == 0) { return; }
ModifyMemoryProtection((uintptr_t)addr, length,
PROT_EXEC|PROT_READ|PROT_WRITE);
memcpy((void *)addr, patch, length);
ModifyMemoryProtection((uintptr_t)addr, length, PROT_EXEC|PROT_READ);
}
#define MAX_PATCH_SIZE 1024
int opal_patch_symbol (const char *sys_func, uintptr_t hook_addr)
{
void *addr_to_patch_hook;
int len_to_patch_hook = 0;
char patch_hook[MAX_PATCH_SIZE];
void *addr_to_patch_sys;
int len_to_patch_sys = 0;
char patch_sys[MAX_PATCH_SIZE];
int offset;
#if (defined(__PPC64__) || defined(__powerpc64__) || defined(__PPC__))
unsigned int *nop_addr;
const unsigned int nop = 0x60000000;
#endif
uintptr_t sys_addr, hook_addr;
int offset, rc;
// get system function address
uintptr_t sys_addr = add_text(dlsym(RTLD_NEXT, sys_func));
if(sys_addr == 0) sys_addr = add_text(dlsym(RTLD_DEFAULT, sys_func));
hook_addr = add_text(hook_addr);
sys_addr = mca_patcher_base_addr_text(patch->patch_orig);
hook_addr = mca_patcher_base_addr_text(patch->patch_value);
// Patch for hook function:
#if (defined(__PPC64__) || defined(__powerpc64__) || defined(__PPC__))
// locate reserved code space in hook function
nop_addr = (unsigned int *)hook_addr;
for (; ; nop_addr++)
if (nop_addr[0] == nop && nop_addr[1] == nop && nop_addr[2] == nop
&& nop_addr[3] == nop && nop_addr[4] == nop)
break;
// generate code to restore TOC
register unsigned long toc asm("r2");
addr_to_patch_hook = nop_addr;
len_to_patch_hook = PatchLoadImm((uintptr_t)patch_hook, 2, toc);
rc = mca_patcher_base_patch_hook (&mca_patcher_overwrite_module, hook_addr);
if (OPAL_SUCCESS != rc) {
return rc;
}
// save the original code
assert(len_to_patch_hook <= MAX_PATCH_SIZE);
//memcpy(save, (void *)addr_to_patch_hook, len_to_patch_hook); // meh
#endif
// Patch for system function:
#if (defined(__PPC64__) || defined(__powerpc64__) || defined(__PPC__)) && _CALL_ELF == 2
#if _CALL_ELF == 2
sys_addr += 8;
hook_addr += 8;
#endif /* _CALL_ELF == 2*/
#endif
addr_to_patch_sys = (void*) sys_addr;
// Patch for system function:
// generate patch code
// r11 is a volatile register according to PowerPC EABI
const unsigned int gr = 11;
offset = PatchLoadImm((uintptr_t)patch_sys, gr, hook_addr);
*(unsigned int *) (patch_sys + offset + 0) = mtspr (9, gr); // 9 = CTR
*(unsigned int *) (patch_sys + offset + 4) = bcctr (20, 0, 0);// 20 = always
len_to_patch_sys = offset + 8;
offset = PatchLoadImm ((uintptr_t) patch->patch_data, gr, hook_addr);
*(unsigned int *) (patch->patch_data + offset + 0) = mtspr (9, gr); // 9 = CTR
*(unsigned int *) (patch->patch_data + offset + 4) = bcctr (20, 0, 0);// 20 = always
patch->patch_data_size = offset + 8;
patch->patch_orig = sys_addr;
assert(len_to_patch_sys <= MAX_PATCH_SIZE);
//memcpy(save, (void *)addr_to_patch_sys, len_to_patch_sys);
mca_base_patcher_patch_apply_binary (patch);
apply_patch(patch_hook, addr_to_patch_hook, len_to_patch_hook);
apply_patch(patch_sys, addr_to_patch_sys, len_to_patch_sys);
return OPAL_SUCCESS;
}
bool opal_patch_supported (void)
{
return true;
}
#else
int opal_patch_symbol (const char *sys_func, uintptr_t hook_addr)
{
return OPAL_ERR_NOT_SUPPORTED;
}
bool opal_patch_supported (void)
{
return false;
}
#endif
static int mca_patcher_overwrite_patch_address (uintptr_t sys_addr, unsigned long hook_addr)
{
mca_patcher_base_patch_t *patch;
int rc;
patch = OBJ_NEW(mca_patcher_base_patch_t);
if (OPAL_UNLIKELY(NULL == patch)) {
return OPAL_ERR_OUT_OF_RESOURCE;
}
patch->patch_orig = sys_addr;
patch->patch_value = hook_addr;
opal_mutex_lock (&mca_patcher_overwrite_module.patch_list_mutex);
do {
rc = mca_patcher_overwrite_apply_patch (patch);
if (OPAL_SUCCESS != rc) {
break;
}
opal_list_append (&mca_patcher_overwrite_module.patch_list, &patch->super);
} while (0);
opal_mutex_unlock (&mca_patcher_overwrite_module.patch_list_mutex);
return OPAL_SUCCESS;
}
static int mca_patcher_overwrite_patch_symbol (const char *func_symbol_name, uintptr_t func_new_addr,
uintptr_t *func_old_addr)
{
void *sym_addr;
char *error;
uintptr_t old_addr;
/* NTH: might want to update opal/mca/dl to handle lookups in the default
* handle. */
sym_addr = dlsym (RTLD_NEXT, func_symbol_name);
if (NULL == sym_addr) {
sym_addr = dlsym(RTLD_DEFAULT, func_symbol_name);
if ( (sym_addr == NULL) && ((error = dlerror()) != NULL) ) {
opal_output(0, "error locating symbol %s to patch. %s", func_symbol_name,
error);
return OPAL_ERR_NOT_FOUND;
}
}
old_addr = (unsigned long)sym_addr;
#if defined(__ia64__)
/* On IA64 addresses are all indirect */
func_new_addr = *(unsigned long *)func_new_addr;
old_addr = *(unsigned long *) old_addr;
#endif
if (func_old_addr) {
/* we will be overwritting part of the original function. do not return
* its address */
*func_old_addr = 0;
}
return mca_patcher_overwrite_patch_address (old_addr, func_new_addr);
}
mca_patcher_base_module_t mca_patcher_overwrite_module = {
.patch_symbol = mca_patcher_overwrite_patch_symbol,
.patch_address = mca_patcher_overwrite_patch_address,
};

121
opal/mca/patcher/patcher.h Обычный файл
Просмотреть файл

@ -0,0 +1,121 @@
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
/*
* Copyright (c) 2016 Los Alamos National Security, LLC. All rights
* reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#ifndef OPAL_MCA_PATCHER_PATCHER_H
#define OPAL_MCA_PATCHER_PATCHER_H
#include "opal_config.h"
#include "opal/mca/mca.h"
#include "opal/mca/base/base.h"
#include "opal/class/opal_list.h"
/* Any function being patched in as a hook must use SYMBOLPATCH_BEGIN at the top,
* and SYMBOLPATCH_END before it returns (this is just for PPC). */
#if (defined(__PPC64__) || defined(__powerpc64__) || defined(__PPC__)) && defined(OPAL_GCC_INLINE_ASSEMBLY)
/* special processing for ppc64 to save and restore TOC (r2)
* Reference: "64-bit PowerPC ELF Application Binary Interface Supplement 1.9" */
#define OPAL_PATCHER_BEGIN \
unsigned long toc_save; \
asm volatile ("std 2, %0" : "=m" (toc_save)); \
asm volatile ("nop; nop; nop; nop; nop");
#define OPAL_PATCHER_END \
asm volatile ("ld 2, %0" : : "m" (toc_save));
#else /* !__PPC64__ */
#define OPAL_PATCHER_BEGIN
#define OPAL_PATCHER_END
#endif
/**
* Make any calls to the named function redirect to a new function
*
* @param[in] func_symbol_name function to hook
* @param[in] func_new_addr function pointer of hook
* @param[out] func_old_addr address of func_symbol_name
*
* This function redirects all calls to the function func_symbol_name to
* the function pointer func_new_addr. If it is possible for the hook
* function to call the original function the patcher module will return
* the old function's address in func_old_addr.
*/
typedef int (*mca_patcher_base_patch_symbol_fn_t)(const char *func_symbol_name, uintptr_t func_new_addr,
uintptr_t *func_old_addr);
/**
* Make any calls to a function redirect to a new function
*
* @param[in] func_symbol_name function to hook
* @param[in] func_new_addr function pointer of hook
* @param[out] func_old_addr address of func_symbol_name
*
* This function redirects all calls to the function at func_addr to
* the function pointer func_new_addr.
*/
typedef int (*mca_patcher_base_patch_address_fn_t)(uintptr_t func_addr, uintptr_t func_new_addr);
/**
* Set up the patcher module
*/
typedef int (*mca_patcher_base_init_fn_t) (void);
/**
* Finalize the patcher module
*/
typedef int (*mca_patcher_base_fini_fn_t) (void);
/**
* Structure for patcher modules.
*/
typedef struct mca_patcher_base_module_t {
mca_base_module_t super;
/** list of patches */
opal_list_t patch_list;
/** lock for patch list */
opal_mutex_t patch_list_mutex;
/** function to call if the patcher module is used. can
* be NULL. */
mca_patcher_base_init_fn_t patch_init;
/** function to call when patcher is unloaded. this function
* MUST clean up all active patches. can be NULL. */
mca_patcher_base_fini_fn_t patch_fini;
/** hook a symbol. may be NULL */
mca_patcher_base_patch_symbol_fn_t patch_symbol;
/** hook a function pointer. may be NULL */
mca_patcher_base_patch_address_fn_t patch_address;
} mca_patcher_base_module_t;
OPAL_DECLSPEC extern mca_patcher_base_module_t *opal_patcher;
/**
* Structure for patcher components.
*/
typedef struct mca_patcher_base_component_1_0_0_t {
/** MCA base component */
mca_base_component_t patcherc_version;
/** MCA base data */
mca_base_component_data_t patcherc_data;
} mca_patcher_base_component_1_0_0_t;
typedef mca_patcher_base_component_1_0_0_t mca_patcher_base_component_t;
/*
* Macro for use in components that are of type patcher
*/
#define OPAL_PATCHER_BASE_VERSION_1_0_0 \
OPAL_MCA_BASE_VERSION_2_1_0("patcher", 1, 0, 0)
#endif /* OPAL_MCA_PATCHER_PATCHER_H */

Просмотреть файл

@ -41,6 +41,7 @@
#include "opal/mca/memchecker/base/base.h"
#include "opal/mca/memcpy/base/base.h"
#include "opal/mca/memory/base/base.h"
#include "opal/mca/patcher/base/base.h"
#include "opal/mca/backtrace/base/base.h"
#include "opal/mca/sec/base/base.h"
#include "opal/mca/timer/base/base.h"
@ -160,6 +161,7 @@ opal_finalize(void)
hooks to the bowels of the mem_free code can still occur any
time between now and end of application (even post main()!) */
(void) mca_base_framework_close(&opal_memory_base_framework);
(void) mca_base_framework_close(&opal_patcher_base_framework);
/* close the memcpy framework */
(void) mca_base_framework_close(&opal_memcpy_base_framework);

Просмотреть файл

@ -45,6 +45,7 @@
#include "opal/datatype/opal_datatype.h"
#include "opal/mca/installdirs/base/base.h"
#include "opal/mca/memory/base/base.h"
#include "opal/mca/patcher/base/base.h"
#include "opal/mca/memcpy/base/base.h"
#include "opal/mca/hwloc/base/base.h"
#include "opal/mca/sec/base/base.h"
@ -430,6 +431,14 @@ opal_init(int* pargc, char*** pargv)
goto return_error;
}
if (OPAL_SUCCESS != (ret = mca_base_framework_open(&opal_patcher_base_framework, 0))) {
error = "opal_patcher_base_open";
goto return_error;
}
/* select a patcher module. if a patcher module can not be found it is not an error. */
(void) opal_patcher_base_select ();
/* open the memory manager components. Memory hooks may be
triggered before this (any time after mem_free_init(),
actually). This is a hook available for memory manager hooks

Просмотреть файл

@ -53,7 +53,6 @@ headers = \
numtostr.h \
opal_environ.h \
opal_getcwd.h \
opal_patcher.h \
opal_pty.h \
os_dirpath.h \
os_path.h \
@ -89,7 +88,6 @@ libopalutil_la_SOURCES = \
numtostr.c \
opal_environ.c \
opal_getcwd.c \
opal_patcher.c \
opal_pty.c \
os_dirpath.c \
os_path.c \

Просмотреть файл

@ -1,61 +0,0 @@
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
/*
* Copyright (c) 2016 Los Alamos National Security, LLC. All rights
* reserved.
* ******** ADD IBM COPYRIGHT HERE ******
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#if !defined(OPAL_PATCHER_H)
#define OPAL_PATCHER_H
#include "opal_config.h"
// Any function being patched in must use SYMBOLPATCH_BEGIN at the top,
// and SYMBOLPATCH_END before it returns (this is just for PPC).
#if (defined(__PPC64__) || defined(__powerpc64__) || defined(__PPC__)) && defined(OPAL_GCC_INLINE_ASSEMBLY)
// special processing for ppc64 to save and restore TOC (r2)
// Reference: "64-bit PowerPC ELF Application Binary Interface Supplement 1.9"
#define OPAL_PATCHER_BEGIN \
unsigned long toc_save; \
asm volatile ("std 2, %0" : "=m" (toc_save)); \
asm volatile ("nop; nop; nop; nop; nop");
#define OPAL_PATCHER_END \
asm volatile ("ld 2, %0" : : "m" (toc_save));
#else // !__PPC64__
#define OPAL_PATCHER_BEGIN
#define OPAL_PATCHER_END
#endif
/**
* Patch all instances of calls to a function
*
* @param[in] func_symbol_name Name of symbol to patch
* @param[in] func_new_addr Pointer to new function to call
*
* @returns OPAL_SUCCESS on success
* @returns OPAL_ERR_NOT_AVAILABLE if symbol patching is not supported on this
* platform.
*
* This function patches any calls to the named symbol with a new function
* address. Any function that is passed into func_new_addr MUST begin with
* OPAL_PATCHER_BEGIN and end with OPAL_PATCHER_END.
*/
int opal_patch_symbol (const char *func_symbol_name, uintptr_t func_new_addr);
/**
* Check if symbol patching is available
*/
bool opal_patch_supported (void);
#endif /* !defined(OPAL_PATCHER_H) */