root/opal/mca/patcher/overwrite/patcher_overwrite_module.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. copy_instr_slot
  2. make_ia64_bundle
  3. mca_patcher_overwrite_apply_patch
  4. addis
  5. ori
  6. oris
  7. mtspr
  8. bcctr
  9. rldicr
  10. PatchLoadImm
  11. mca_patcher_overwrite_apply_patch
  12. mov
  13. movk
  14. br
  15. PatchLoadImm
  16. mca_patcher_overwrite_apply_patch
  17. mca_patcher_overwrite_patch_address
  18. mca_patcher_overwrite_patch_symbol

   1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
   2 /*
   3  * Copyright (c) 2016-2018 Los Alamos National Security, LLC. All rights
   4  *                         reserved.
   5  * Copyright (c) 2016      IBM Corporation.  All rights reserved.
   6  * Copyright (c) 2017      Research Organization for Information Science
   7  *                         and Technology (RIST). All rights reserved.
   8  * $COPYRIGHT$
   9  *
  10  * Additional copyrights may follow
  11  *
  12  * $HEADER$
  13  */
  14 
  15 #include "patcher_overwrite.h"
  16 
  17 #include "opal/mca/patcher/base/base.h"
  18 
  19 #include "opal/constants.h"
  20 #include "opal/util/sys_limits.h"
  21 #include "opal/util/output.h"
  22 #include "opal/prefetch.h"
  23 
  24 #include <stdio.h>
  25 #include <stdlib.h>
  26 #include <stdint.h>
  27 #include <unistd.h>
  28 #include <string.h>
  29 #include <sys/mman.h>
  30 #include <dlfcn.h>
  31 #include <assert.h>
  32 
  33 #if (OPAL_ASSEMBLY_ARCH == OPAL_IA32) || (OPAL_ASSEMBLY_ARCH == OPAL_IA64) || (OPAL_ASSEMBLY_ARCH == OPAL_X86_64)
  34 
  35 #if (OPAL_ASSEMBLY_ARCH == OPAL_IA64)
  36 
  37 #define INSERT_BIT(d,p,v) do {                  \
  38         unsigned char c=*(d);                     \
  39         assert(((p) < 8) && ((p) >= 0));          \
  40         c&= ~(1<<(p));                            \
  41         c|= ((v)<<(p));                           \
  42         *(d) = c;                                 \
  43     } while (0)
  44 
  45 static inline void
  46 copy_instr_slot(unsigned char **dst, int *dst_bitpos, unsigned long instr_slot)
  47 {
  48     for (int i = 40 ; i >= 0 ; --i) {
  49         INSERT_BIT(*dst, *dst_bitpos, (instr_slot>>i)&1);
  50         if (*dst_bitpos == 0) {
  51             ++*dst;
  52             *dst_bitpos = 7;
  53         } else {
  54             --*dst_bitpos;
  55         }
  56     }
  57 }
  58 
  59 static void make_ia64_bundle (unsigned char *dst,
  60                               unsigned long i2,
  61                               unsigned long i1,
  62                               unsigned long i0,
  63                               unsigned template)
  64 {
  65 /*
  66  * each instr is 41 bits, template is 5 bits
  67  *
  68  * generate the bit concatenation of i2:i1:i0:t, all in all 128 bits
  69  *
  70  */
  71 
  72     int dst_bitpos = 7;
  73 
  74     copy_instr_slot(&dst, &dst_bitpos, i2);
  75     copy_instr_slot(&dst, &dst_bitpos, i1);
  76     copy_instr_slot(&dst, &dst_bitpos, i0);
  77 
  78     assert(dst_bitpos == 4);
  79 
  80     for (int i = 4 ; i >= 0 ; --i) {
  81         INSERT_BIT(dst, dst_bitpos, (template>>i)&1);
  82         --dst_bitpos;
  83     }
  84 }
  85 #endif /* defined(__ia64__) */
  86 
  87 static int mca_patcher_overwrite_apply_patch (mca_patcher_base_patch_t *patch)
  88 {
  89     uintptr_t func_new_addr = patch->patch_value;
  90 
  91     {
  92 #if (OPAL_ASSEMBLY_ARCH == OPAL_IA32)
  93         patch->patch_data_size = 5;
  94         *(unsigned char *)(patch->patch_data+0) = 0xe9;
  95         *(unsigned int *) (patch->patch_data+1) = (unsigned int)(func_new_addr - patch->patch_orig - 5);
  96 #elif (OPAL_ASSEMBLY_ARCH == OPAL_X86_64)
  97         patch->patch_data_size = 13;
  98         *(unsigned short*)(patch->patch_data + 0) = 0xbb49;
  99         *(unsigned long* )(patch->patch_data + 2) = (unsigned long) func_new_addr;
 100         *(unsigned char*) (patch->patch_data +10) = 0x41;
 101         *(unsigned char*) (patch->patch_data +11) = 0xff;
 102         *(unsigned char*) (patch->patch_data +12) = 0xe3;
 103 #elif (OPAL_ASSEMBLY_ARCH == OPAL_IA64)
 104       {
 105 /*
 106  * target64 = IP + ((i << 59 | imm39 << 20 | imm20) << 4)
 107  * imm64 = i << 63 | imm41 << 22 | ic << 21 | imm5c << 16 | imm9d << 7 | imm7b
 108  */
 109          unsigned char buf[16];
 110          unsigned long long imm64 =  func_new_addr - patch->patch_orig - 16;
 111          register unsigned long long glb_ptr  __asm__("r1");
 112          unsigned long long nop =
 113             (0x0ULL<<37) | /* O     */
 114             (0x0ULL<<36) | /* i     */
 115             (0x0ULL<<33) | /* x3    */
 116             (0x1ULL<<27) | /* x6    */
 117             (0x0ULL<< 6) | /* imm20 */
 118             (0x0ULL<< 0);  /* qp    */
 119          unsigned long long brl =
 120             (0xcULL                   << 37) |
 121             (((imm64>>63)&0x1ULL)     << 36) |
 122             (0x0ULL                   << 35) |
 123             (0x0ULL                   << 33) |
 124             (((imm64>>4)&0xFFFFFULL)  << 13) |
 125             (0x0ULL                   <<  6) |
 126             (0x0ULL                   <<  0);
 127          unsigned long long movl =
 128             (0x6ULL                    << 37) |
 129             (((glb_ptr>>63)&0x1ULL)    << 36) |
 130             (((glb_ptr>> 7)&0x1FFULL)  << 27) |
 131             (((glb_ptr>>16)&0x1FULL)   << 22) |
 132             (((glb_ptr>>21)&0x1ULL)    << 21) |
 133             (0ULL                      << 20) |
 134             (((glb_ptr>> 0)&0x7FULL)   << 13) |
 135             (1ULL                      <<  6) |
 136             (0x0ULL                    <<  0);
 137 
 138          patch->patch_data_size = 32;
 139 
 140          make_ia64_bundle(buf, movl, (glb_ptr>>22)&0x1FFFFFFFFFFULL, nop, 5);
 141          for (int i = 0 ; i < 16 ; ++i) {
 142              patch->patch_data[16-i-1] = buf[i];
 143          }
 144 
 145          make_ia64_bundle(buf, brl, ((imm64>>24)&0x7FFFFFFFFFULL)<<2, nop, 5);
 146          for (int i = 0 ; i < 16 ; ++i) {
 147              patch->patch_data[32-i-1] = buf[i];
 148          }
 149       }
 150 #endif
 151     }
 152 
 153     mca_base_patcher_patch_apply_binary (patch);
 154 
 155     return OPAL_SUCCESS;
 156 }
 157 
 158 /* end of #if defined(__i386__) || defined(__x86_64__) || defined(__ia64__) */
 159 // ------------------------------------------------- PPC equivalent:
 160 #elif (OPAL_ASSEMBLY_ARCH == OPAL_POWERPC32) || (OPAL_ASSEMBLY_ARCH == OPAL_POWERPC64)
 161 
 162 // PowerPC instructions used in patching
 163 // Reference: "PowerPC User Instruction Set Architecture"
 164 static unsigned int addis(unsigned int RT, unsigned int RS, unsigned int UI) {
 165     return (15<<26) + (RT<<21) + (RS<<16) + (UI&0xffff);
 166 }
 167 static unsigned int ori(unsigned int RT, unsigned int RS, unsigned int UI) {
 168     return (24<<26) + (RS<<21) + (RT<<16) + (UI&0xffff);
 169 }
 170 static unsigned int oris(unsigned int RT, unsigned int RS, unsigned int UI) {
 171     return (25<<26) + (RS<<21) + (RT<<16) + (UI&0xffff);
 172 }
 173 static unsigned int mtspr(unsigned int SPR, unsigned int RS) {
 174     return (31<<26) + (RS<<21) + ((SPR&0x1f)<<16) + ((SPR>>5)<<11) + (467<<1);
 175 }
 176 static unsigned int bcctr(unsigned int BO, unsigned int BI, unsigned int BH) {
 177     return (19<<26) + (BO<<21) + (BI<<16) + (BH<<11) + (528<<1);
 178 }
 179 static unsigned int rldicr(unsigned int RT, unsigned int RS, unsigned int SH, unsigned int MB)
 180 {
 181     return (30<<26) + (RS<<21) + (RT<<16) + ((SH&0x1f)<<11) + ((SH>>5)<<1)
 182         + ((MB&0x1f)<<6) + ((MB>>5)<<5) + (1<<2);
 183 }
 184 
 185 static int
 186 PatchLoadImm(uintptr_t addr, unsigned int reg, size_t value)
 187 {
 188 #if (OPAL_ASSEMBLY_ARCH == OPAL_POWERPC64)
 189     *(unsigned int *) (addr + 0) = addis ( reg, 0,   (value >> 48));
 190     *(unsigned int *) (addr + 4) = ori   ( reg, reg, (value >> 32));
 191     *(unsigned int *) (addr + 8) = rldicr( reg, reg, 32, 31);
 192     *(unsigned int *) (addr +12) = oris  ( reg, reg, (value >> 16));
 193     *(unsigned int *) (addr +16) = ori   ( reg, reg, (value >>  0));
 194     return 20;
 195 #else
 196     *(unsigned int *) (addr + 0) = addis ( reg, 0,   (value >> 16));
 197     *(unsigned int *) (addr + 4) = ori   ( reg, reg, (value >>  0));
 198     return 8;
 199 #endif
 200 }
 201 
 202 
 203 static int mca_patcher_overwrite_apply_patch (mca_patcher_base_patch_t *patch)
 204 {
 205     uintptr_t sys_addr, hook_addr;
 206     int offset, rc;
 207 
 208     // get system function address
 209     sys_addr = mca_patcher_base_addr_text(patch->patch_orig);
 210     hook_addr = mca_patcher_base_addr_text(patch->patch_value);
 211 
 212 // Patch for hook function:
 213 #if (OPAL_ASSEMBLY_ARCH == OPAL_POWERPC64)
 214     rc = mca_patcher_base_patch_hook (&mca_patcher_overwrite_module, hook_addr);
 215     if (OPAL_SUCCESS != rc) {
 216         return rc;
 217     }
 218 
 219 #if defined(_CALL_ELF) && (_CALL_ELF == 2)
 220     sys_addr += 8;
 221     hook_addr += 8;
 222 #endif /* _CALL_ELF == 2*/
 223 #endif
 224 
 225     // Patch for system function:
 226     // generate patch code
 227     // r11 is a volatile register according to PowerPC EABI
 228     const unsigned int gr = 11;
 229     offset = PatchLoadImm ((uintptr_t) patch->patch_data, gr, hook_addr);
 230     *(unsigned int *) (patch->patch_data + offset + 0) = mtspr (9, gr);   // 9 = CTR
 231     *(unsigned int *) (patch->patch_data + offset + 4) = bcctr (20, 0, 0);// 20 = always
 232     patch->patch_data_size = offset + 8;
 233     patch->patch_orig = sys_addr;
 234 
 235     mca_base_patcher_patch_apply_binary (patch);
 236 
 237     return OPAL_SUCCESS;
 238 }
 239 
 240 #elif defined(__aarch64__)
 241 
 242 /**
 243  * @brief Generate a mov immediate instruction
 244  *
 245  * @param[in] reg   register number (0-31)
 246  * @param[in] shift shift amount (0-3) * 16-bits
 247  * @param[in] value immediate value
 248  */
 249 static uint32_t mov (unsigned int reg, uint16_t shift, uint16_t value)
 250 {
 251     return (0x1a5 << 23) + ((uint32_t) shift << 21) + ((uint32_t) value << 5) + reg;
 252 }
 253 
 254 /**
 255  * @brief Generate a mov immediate with keep instruction
 256  *
 257  * @param[in] reg   register number (0-31)
 258  * @param[in] shift shift amount (0-3) * 16-bits
 259  * @param[in] value immediate value
 260  */
 261 static uint32_t movk (unsigned int reg, uint16_t shift, uint16_t value)
 262 {
 263     return (0x1e5 << 23) + ((uint32_t) shift << 21) + ((uint32_t) value << 5) + reg;
 264 }
 265 
 266 static uint32_t br (unsigned int reg)
 267 {
 268     return (0xd61f << 16) + (reg << 5);
 269 }
 270 
 271 static int
 272 PatchLoadImm(uintptr_t addr, unsigned int reg, uint64_t value)
 273 {
 274     *(uint32_t *) (addr +  0) = mov(reg, 3, value >> 48);
 275     *(uint32_t *) (addr +  4) = movk(reg, 2, value >> 32);
 276     *(uint32_t *) (addr +  8) = movk(reg, 1, value >> 16);
 277     *(uint32_t *) (addr + 12) = movk(reg, 0, value);
 278     return 16;
 279 }
 280 
 281 static int mca_patcher_overwrite_apply_patch (mca_patcher_base_patch_t *patch)
 282 {
 283     uintptr_t sys_addr, hook_addr;
 284     int offset, rc;
 285 
 286     /* get system function address */
 287     sys_addr = mca_patcher_base_addr_text(patch->patch_orig);
 288     hook_addr = mca_patcher_base_addr_text(patch->patch_value);
 289 
 290     /* Patch for hook function: */
 291     rc = mca_patcher_base_patch_hook (&mca_patcher_overwrite_module, hook_addr);
 292     if (OPAL_SUCCESS != rc) {
 293         return rc;
 294     }
 295 
 296     /* Patch for system function:
 297      * generate patch code
 298      * r15 is the highest numbered temporary register. I am assuming this one is safe
 299      * to use. */
 300     const unsigned int gr = 15;
 301     offset = PatchLoadImm ((uintptr_t) patch->patch_data, gr, hook_addr);
 302     *(uint32_t *) (patch->patch_data + offset) = br(gr);
 303     patch->patch_data_size = offset + 4;
 304     patch->patch_orig = sys_addr;
 305 
 306     mca_base_patcher_patch_apply_binary (patch);
 307 
 308     return OPAL_SUCCESS;
 309 }
 310 
 311 #endif
 312 
 313 static int mca_patcher_overwrite_patch_address (uintptr_t sys_addr, uintptr_t hook_addr)
 314 {
 315     mca_patcher_base_patch_t *patch;
 316     int rc;
 317 
 318     patch = OBJ_NEW(mca_patcher_base_patch_t);
 319     if (OPAL_UNLIKELY(NULL == patch)) {
 320         return OPAL_ERR_OUT_OF_RESOURCE;
 321     }
 322 
 323     patch->patch_orig = sys_addr;
 324     patch->patch_value = hook_addr;
 325 
 326     opal_mutex_lock (&mca_patcher_overwrite_module.patch_list_mutex);
 327     do {
 328         rc = mca_patcher_overwrite_apply_patch (patch);
 329         if (OPAL_SUCCESS != rc) {
 330             break;
 331         }
 332 
 333         opal_list_append (&mca_patcher_overwrite_module.patch_list, &patch->super);
 334     } while (0);
 335 
 336     opal_mutex_unlock (&mca_patcher_overwrite_module.patch_list_mutex);
 337 
 338     return OPAL_SUCCESS;
 339 }
 340 
 341 static int mca_patcher_overwrite_patch_symbol (const char *func_symbol_name, uintptr_t func_new_addr,
 342                                                uintptr_t *func_old_addr)
 343 {
 344     void *sym_addr;
 345     char *error;
 346     uintptr_t old_addr;
 347 
 348     /* NTH: might want to update opal/mca/dl to handle lookups in the default
 349      * handle. */
 350     sym_addr = dlsym (RTLD_NEXT, func_symbol_name);
 351     if (NULL == sym_addr) {
 352         sym_addr = dlsym(RTLD_DEFAULT, func_symbol_name);
 353         if ( (sym_addr == NULL) && ((error = dlerror()) != NULL) )  {
 354             opal_output(0, "error locating symbol %s to patch. %s", func_symbol_name,
 355                         error);
 356             return OPAL_ERR_NOT_FOUND;
 357         }
 358     }
 359 
 360     old_addr = (unsigned long)sym_addr;
 361 
 362 #if (OPAL_ASSEMBLY_ARCH == OPAL_IA64)
 363     /* On IA64 addresses are all indirect */
 364     func_new_addr = *(unsigned long *)func_new_addr;
 365     old_addr = *(unsigned long *) old_addr;
 366 #endif
 367 
 368     if (func_old_addr) {
 369         /* we will be overwritting part of the original function. do not return
 370          * its address */
 371         *func_old_addr = 0;
 372     }
 373 
 374     return mca_patcher_overwrite_patch_address (old_addr, func_new_addr);
 375 }
 376 
 377 mca_patcher_base_module_t mca_patcher_overwrite_module = {
 378     .patch_symbol = mca_patcher_overwrite_patch_symbol,
 379     .patch_address = mca_patcher_overwrite_patch_address,
 380 };

/* [<][>][^][v][top][bottom][index][help] */