Skip to content

Commit e401a03

Browse files
committed
patcher: fix powerpc/power support in patcher/linux
This commit does the following: - 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. Signed-off-by: Nathan Hjelm <hjelmn@lanl.gov>
1 parent 5783f52 commit e401a03

File tree

11 files changed

+415
-298
lines changed

11 files changed

+415
-298
lines changed

opal/mca/patcher/base/Makefile.am

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,5 @@
2121

2222
headers += base/base.h
2323

24-
libmca_patcher_la_SOURCES += base/patcher_base_frame.c
24+
libmca_patcher_la_SOURCES += base/patcher_base_frame.c \
25+
base/patcher_base_patch.c

opal/mca/patcher/base/base.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,54 @@
3030

3131
BEGIN_C_DECLS
3232

33+
#define MCA_BASE_PATCHER_MAX_PATCH 32
34+
35+
struct mca_patcher_base_patch_t;
36+
37+
typedef void (*mca_patcher_base_restore_fn_t) (struct mca_patcher_base_patch_t *);
38+
39+
struct mca_patcher_base_patch_t {
40+
/** patches are list items */
41+
opal_list_item_t super;
42+
/** name symbol to patch */
43+
char *patch_symbol;
44+
/** address of function to call instead */
45+
uintptr_t patch_value;
46+
/** original address of function */
47+
uintptr_t patch_orig;
48+
/** patch data */
49+
unsigned char patch_data[MCA_BASE_PATCHER_MAX_PATCH];
50+
/** original data */
51+
unsigned char patch_orig_data[MCA_BASE_PATCHER_MAX_PATCH];
52+
/** size of patch data */
53+
unsigned patch_data_size;
54+
/** function to undo the patch */
55+
mca_patcher_base_restore_fn_t patch_restore;
56+
};
57+
58+
typedef struct mca_patcher_base_patch_t mca_patcher_base_patch_t;
59+
60+
OBJ_CLASS_DECLARATION(mca_patcher_base_patch_t);
61+
3362
/**
3463
* Framework struct declaration for this framework
3564
*/
3665
OPAL_DECLSPEC extern mca_base_framework_t opal_patcher_base_framework;
3766
OPAL_DECLSPEC int opal_patcher_base_select (void);
67+
OPAL_DECLSPEC int mca_patcher_base_patch_hook (mca_patcher_base_module_t *module, uintptr_t hook);
68+
OPAL_DECLSPEC void mca_base_patcher_patch_apply_binary (mca_patcher_base_patch_t *patch);
69+
70+
static inline uintptr_t mca_patcher_base_addr_text (uintptr_t addr) {
71+
#if (defined(__PPC64__) || defined(__powerpc64__) || defined(__PPC__)) && _CALL_ELF != 2
72+
struct odp_t {
73+
uintptr_t text;
74+
uintptr_t toc;
75+
} *odp = (struct odp_t *) addr;
76+
return (odp)?odp->text:0;
77+
#else
78+
return addr;
79+
#endif
80+
}
3881

3982
END_C_DECLS
4083
#endif /* OPAL_BASE_PATCHER_H */

opal/mca/patcher/base/patcher_base_frame.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ int opal_patcher_base_select (void)
3939
return rc;
4040
}
4141

42+
OBJ_CONSTRUCT(&best_module->patch_list, opal_list_t);
43+
OBJ_CONSTRUCT(&best_module->patch_list_mutex, opal_mutex_t);
44+
4245
if (best_module->patch_init) {
4346
rc = best_module->patch_init ();
4447
if (OPAL_SUCCESS != rc) {
@@ -53,6 +56,18 @@ int opal_patcher_base_select (void)
5356

5457
static int opal_patcher_base_close (void)
5558
{
59+
if (opal_patcher == &empty_module) {
60+
return OPAL_SUCCESS;
61+
}
62+
63+
mca_patcher_base_patch_t *patch;
64+
OPAL_LIST_FOREACH_REV(patch, &opal_patcher->patch_list, mca_patcher_base_patch_t) {
65+
patch->patch_restore (patch);
66+
}
67+
68+
OPAL_LIST_DESTRUCT(&opal_patcher->patch_list);
69+
OBJ_DESTRUCT(&opal_patcher->patch_list_mutex);
70+
5671
if (opal_patcher->patch_fini) {
5772
return opal_patcher->patch_fini ();
5873
}
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
2+
/*
3+
* Copyright (c) 2016 Los Alamos National Security, LLC. All rights
4+
* reserved.
5+
* $COPYRIGHT$
6+
*
7+
* Additional copyrights may follow
8+
*
9+
* $HEADER$
10+
*/
11+
12+
#include "opal_config.h"
13+
14+
#include "opal/mca/patcher/patcher.h"
15+
#include "opal/mca/patcher/base/base.h"
16+
#include "opal/util/sys_limits.h"
17+
#include "opal/prefetch.h"
18+
#include <sys/mman.h>
19+
20+
static void mca_patcher_base_patch_construct (mca_patcher_base_patch_t *patch)
21+
{
22+
patch->patch_symbol = NULL;
23+
patch->patch_data_size = 0;
24+
}
25+
26+
static void mca_patcher_base_patch_destruct (mca_patcher_base_patch_t *patch)
27+
{
28+
free (patch->patch_symbol);
29+
}
30+
31+
OBJ_CLASS_INSTANCE(mca_patcher_base_patch_t, opal_list_item_t,
32+
mca_patcher_base_patch_construct,
33+
mca_patcher_base_patch_destruct);
34+
35+
#if defined(__PPC__)
36+
37+
// PowerPC instructions used in patching
38+
// Reference: "PowerPC User Instruction Set Architecture"
39+
static unsigned int addis(unsigned int RT, unsigned int RS, unsigned int UI) {
40+
return (15<<26) + (RT<<21) + (RS<<16) + (UI&0xffff);
41+
}
42+
static unsigned int ori(unsigned int RT, unsigned int RS, unsigned int UI) {
43+
return (24<<26) + (RS<<21) + (RT<<16) + (UI&0xffff);
44+
}
45+
static unsigned int oris(unsigned int RT, unsigned int RS, unsigned int UI) {
46+
return (25<<26) + (RS<<21) + (RT<<16) + (UI&0xffff);
47+
}
48+
static unsigned int mtspr(unsigned int SPR, unsigned int RS) {
49+
return (31<<26) + (RS<<21) + ((SPR&0x1f)<<16) + ((SPR>>5)<<11) + (467<<1);
50+
}
51+
static unsigned int bcctr(unsigned int BO, unsigned int BI, unsigned int BH) {
52+
return (19<<26) + (BO<<21) + (BI<<16) + (BH<<11) + (528<<1);
53+
}
54+
static unsigned int rldicr(unsigned int RT, unsigned int RS, unsigned int SH, unsigned int MB)
55+
{
56+
return (30<<26) + (RS<<21) + (RT<<16) + ((SH&0x1f)<<11) + ((SH>>5)<<1)
57+
+ ((MB&0x1f)<<6) + ((MB>>5)<<5) + (1<<2);
58+
}
59+
60+
static int PatchLoadImm (uintptr_t addr, unsigned int reg, size_t value)
61+
{
62+
#if defined(__PPC64__)
63+
*(unsigned int *) (addr + 0) = addis ( reg, 0, (value >> 48));
64+
*(unsigned int *) (addr + 4) = ori ( reg, reg, (value >> 32));
65+
*(unsigned int *) (addr + 8) = rldicr( reg, reg, 32, 31);
66+
*(unsigned int *) (addr +12) = oris ( reg, reg, (value >> 16));
67+
*(unsigned int *) (addr +16) = ori ( reg, reg, (value >> 0));
68+
return 20;
69+
#else
70+
*(unsigned int *) (addr + 0) = addis ( reg, 0, (value >> 16));
71+
*(unsigned int *) (addr + 4) = ori ( reg, reg, (value >> 0));
72+
return 8;
73+
#endif
74+
}
75+
76+
#endif
77+
78+
#if defined(__i386__) || defined(__x86_64__) || defined(__ia64__)
79+
80+
static void flush_and_invalidate_cache (unsigned long a)
81+
{
82+
#if defined(__i386__)
83+
/* does not work with AMD processors */
84+
__asm__ volatile("mfence;clflush %0;mfence" : :"m" (*(char*)a));
85+
#elif defined(__x86_64__)
86+
__asm__ volatile("mfence;clflush %0;mfence" : :"m" (*(char*)a));
87+
#elif defined(__ia64__)
88+
__asm__ volatile ("fc %0;; sync.i;; srlz.i;;" : : "r"(a) : "memory");
89+
#endif
90+
}
91+
#endif
92+
93+
// modify protection of memory range
94+
static void ModifyMemoryProtection (uintptr_t addr, size_t length, int prot)
95+
{
96+
long page_size = opal_getpagesize ();
97+
uintptr_t base = (addr & ~(page_size-1));
98+
uintptr_t bound = ((addr + length + page_size-1) & ~(page_size-1));
99+
100+
length = bound - base;
101+
102+
#if defined(__PPC__)
103+
/* NTH: is a loop necessary here? */
104+
do {
105+
if (mprotect((void *)base, page_size, prot))
106+
perror("MemHook: mprotect failed");
107+
base += page_size;
108+
} while (base < addr + length);
109+
#else
110+
if (mprotect((void *) base, length, prot)) {
111+
perror("MemHook: mprotect failed");
112+
}
113+
#endif
114+
}
115+
116+
static inline void apply_patch (unsigned char *patch_data, uintptr_t address, size_t data_size)
117+
{
118+
ModifyMemoryProtection (address, data_size, PROT_EXEC|PROT_READ|PROT_WRITE);
119+
memcpy ((void *) address, patch_data, data_size);
120+
#if defined(__i386__) || defined(__x86_64__) || defined(__ia64__)
121+
for (size_t i = 0 ; i < data_size ; i += 16) {
122+
flush_and_invalidate_cache (address + i);
123+
}
124+
#endif
125+
126+
ModifyMemoryProtection (address, data_size, PROT_EXEC|PROT_READ);
127+
}
128+
129+
static void mca_base_patcher_patch_unapply_binary (mca_patcher_base_patch_t *patch)
130+
{
131+
apply_patch (patch->patch_orig_data, patch->patch_orig, patch->patch_data_size);
132+
}
133+
134+
void mca_base_patcher_patch_apply_binary (mca_patcher_base_patch_t *patch)
135+
{
136+
memcpy (patch->patch_orig_data, (void *) patch->patch_orig, patch->patch_data_size);
137+
apply_patch (patch->patch_data, patch->patch_orig, patch->patch_data_size);
138+
patch->patch_restore = mca_base_patcher_patch_unapply_binary;
139+
}
140+
141+
142+
int mca_patcher_base_patch_hook (mca_patcher_base_module_t *module, uintptr_t hook_addr)
143+
{
144+
#if defined(__PPC64__) || defined(__powerpc64__) || defined(__PPC__)
145+
mca_patcher_base_patch_t *hook_patch;
146+
const unsigned int nop = 0x60000000;
147+
unsigned int *nop_addr;
148+
149+
fprintf (stderr, "Patching hook @ 0x%lx\n", hook_addr);
150+
151+
hook_patch = OBJ_NEW(mca_patcher_base_patch_t);
152+
if (OPAL_UNLIKELY(NULL == hook_patch)) {
153+
return OPAL_ERR_OUT_OF_RESOURCE;
154+
}
155+
156+
// locate reserved code space in hook function
157+
for (nop_addr = (unsigned int *)hook_addr ; ; nop_addr++) {
158+
if (nop_addr[0] == nop && nop_addr[1] == nop && nop_addr[2] == nop
159+
&& nop_addr[3] == nop && nop_addr[4] == nop) {
160+
break;
161+
}
162+
}
163+
// generate code to restore TOC
164+
register unsigned long toc asm("r2");
165+
hook_patch->patch_orig = (uintptr_t) nop_addr;
166+
hook_patch->patch_data_size = PatchLoadImm((uintptr_t)hook_patch->patch_data, 2, toc);
167+
168+
/* put the hook patch on the patch list so it will be undone on finalize */
169+
opal_list_append (&module->patch_list, &hook_patch->super);
170+
171+
mca_base_patcher_patch_apply_binary (hook_patch);
172+
#endif
173+
174+
return OPAL_SUCCESS;
175+
}

opal/mca/patcher/linux/patcher_linux.h

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,35 +20,25 @@
2020
#include "opal/class/opal_list.h"
2121
#include "opal/threads/mutex.h"
2222

23-
struct mca_patcher_linux_patch_t {
24-
/** patches are list items */
23+
struct mca_patcher_linux_patch_got_t {
2524
opal_list_item_t super;
26-
/** name symbol to patch */
27-
char *symbol;
28-
/** address of function to call instead */
29-
uintptr_t value;
30-
/** original address of function */
31-
uintptr_t orig;
25+
void **got_entry;
26+
void *got_orig;
3227
};
3328

34-
typedef struct mca_patcher_linux_patch_t mca_patcher_linux_patch_t;
35-
36-
OBJ_CLASS_DECLARATION(mca_patcher_linux_patch_t);
29+
typedef struct mca_patcher_linux_patch_got_t mca_patcher_linux_patch_got_t;
3730

38-
struct mca_patcher_linux_module_t {
39-
mca_patcher_base_module_t super;
31+
OBJ_CLASS_DECLARATION(mca_patcher_linux_patch_got_t);
4032

41-
opal_list_t patch_list;
42-
opal_mutex_t patch_list_mutex;
33+
struct mca_patcher_linux_patch_t {
34+
mca_patcher_base_patch_t super;
35+
opal_list_t patch_got_list;
4336
};
4437

45-
typedef struct mca_patcher_linux_module_t mca_patcher_linux_module_t;
38+
typedef struct mca_patcher_linux_patch_t mca_patcher_linux_patch_t;
4639

47-
extern mca_patcher_linux_module_t mca_patcher_linux_module;
40+
OBJ_CLASS_DECLARATION(mca_patcher_linux_patch_t);
4841

49-
int mca_patcher_linux_install_dlopen (void);
50-
int mca_patcher_linux_remove_dlopen (void);
51-
int mca_patcher_linux_patch_symbol (const char *symbol_name, uintptr_t replacement, uintptr_t *orig);
52-
int mca_patcher_linux_remove_patch (mca_patcher_linux_patch_t *patch);
42+
extern mca_patcher_base_module_t mca_patcher_linux_module;
5343

5444
#endif /* !defined(OPAL_PATCHER_LINUX_H) */

opal/mca/patcher/linux/patcher_linux_component.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
static int mca_patcher_linux_query (mca_base_module_t **module, int *priority)
1515
{
16-
*module = &mca_patcher_linux_module.super.super;
16+
*module = &mca_patcher_linux_module.super;
1717
*priority = 37;
1818
return OPAL_SUCCESS;
1919
}

0 commit comments

Comments
 (0)