root/opal/mca/memory/patcher/memory_patcher_component.c

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

DEFINITIONS

This source file includes following definitions.
  1. intercept_mmap
  2. _intercept_munmap
  3. intercept_munmap
  4. _intercept_mremap
  5. intercept_mremap
  6. intercept_mremap
  7. _intercept_madvise
  8. intercept_madvise
  9. _intercept_brk
  10. intercept_brk
  11. memory_patcher_get_shm_seg_size
  12. _intercept_shmdt
  13. intercept_shmdt
  14. patcher_register
  15. patcher_query
  16. patcher_open
  17. patcher_close

   1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
   2 /*
   3  * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana
   4  *                         University Research and Technology
   5  *                         Corporation.  All rights reserved.
   6  * Copyright (c) 2004-2005 The University of Tennessee and The University
   7  *                         of Tennessee Research Foundation.  All rights
   8  *                         reserved.
   9  * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
  10  *                         University of Stuttgart.  All rights reserved.
  11  * Copyright (c) 2004-2005 The Regents of the University of California.
  12  *                         All rights reserved.
  13  * Copyright (c) 2009-2017 Cisco Systems, Inc.  All rights reserved
  14  * Copyright (c) 2013-2017 Los Alamos National Security, LLC. All rights
  15  *                         reserved.
  16  * Copyright (c) 2016-2017 Research Organization for Information Science
  17  *                         and Technology (RIST). All rights reserved.
  18  * Copyright (c) 2016      IBM Corporation.  All rights reserved.
  19  *
  20  * $COPYRIGHT$
  21  *
  22  * Additional copyrights may follow
  23  *
  24  * $HEADER$
  25  */
  26 
  27 #include "memory_patcher.h"
  28 
  29 #include "opal/util/output.h"
  30 #include "opal/util/show_help.h"
  31 #include "opal/mca/memory/base/empty.h"
  32 #include "opal/mca/memory/base/base.h"
  33 #include "opal/memoryhooks/memory.h"
  34 #include "opal/mca/patcher/base/base.h"
  35 
  36 #include <stdlib.h>
  37 #include <stdint.h>
  38 #include <unistd.h>
  39 #include <errno.h>
  40 #include <stdarg.h>
  41 #include <sys/mman.h>
  42 #include <dlfcn.h>
  43 #include <assert.h>
  44 #include <sys/time.h>
  45 #if defined(HAVE_SYS_SYSCALL_H)
  46 #include <sys/syscall.h>
  47 #endif
  48 #if defined(HAVE_LINUX_MMAN_H)
  49 #include <linux/mman.h>
  50 #endif
  51 
  52 #include "memory_patcher.h"
  53 #undef opal_memory_changed
  54 
  55 static int patcher_open(void);
  56 static int patcher_close(void);
  57 static int patcher_register(void);
  58 static int patcher_query (int *);
  59 
  60 static int mca_memory_patcher_priority;
  61 
  62 opal_memory_patcher_component_t mca_memory_patcher_component = {
  63     .super = {
  64         .memoryc_version = {
  65             OPAL_MEMORY_BASE_VERSION_2_0_0,
  66 
  67             /* Component name and version */
  68             .mca_component_name = "patcher",
  69             MCA_BASE_MAKE_VERSION(component, OPAL_MAJOR_VERSION, OPAL_MINOR_VERSION,
  70                                   OPAL_RELEASE_VERSION),
  71 
  72             /* Component open and close functions */
  73             .mca_open_component = patcher_open,
  74             .mca_close_component = patcher_close,
  75             .mca_register_component_params = patcher_register,
  76         },
  77         .memoryc_data = {
  78             /* The component is checkpoint ready */
  79             MCA_BASE_METADATA_PARAM_CHECKPOINT
  80         },
  81 
  82         /* Memory framework functions. */
  83         .memoryc_query = patcher_query,
  84         .memoryc_register = opal_memory_base_component_register_empty,
  85         .memoryc_deregister = opal_memory_base_component_deregister_empty,
  86         .memoryc_set_alignment = opal_memory_base_component_set_alignment_empty,
  87     },
  88 
  89     /* Component-specific data, filled in later (compiler will 0/NULL
  90        it out) */
  91 };
  92 
  93 #if HAVE_DECL___SYSCALL && defined(HAVE___SYSCALL)
  94 /* calling __syscall is preferred on some systems when some arguments may be 64-bit. it also
  95  * has the benefit of having an off_t return type */
  96 #define memory_patcher_syscall __syscall
  97 #else
  98 #define memory_patcher_syscall syscall
  99 #endif
 100 
 101 /* All the hooks in this file have two levels. The first level has the OPAL_PATCHER_* macros
 102  * around the call to the second level. This was done because with xlc the compiler was
 103  * generating an access to r2 before the OPAL_PATCHER_* assembly. This was loading invalid
 104  * data. If this can be resolved the two levels can be joined.
 105  */
 106 
 107 /*
 108  * The following block of code is #if 0'ed out because we do not need
 109  * to intercept mmap() any more (mmap() only deals with memory
 110  * protection; it does not invalidate any rcache entries for a given
 111  * region).  But if we do someday, this is the code that we'll need.
 112  * It's a little non-trivial, so we might as well keep it (and #if 0
 113  * it out).
 114  */
 115 #if 0
 116 
 117 #if defined(HAVE___MMAP) && !HAVE_DECL___MMAP
 118 /* prototype for Apple's internal mmap function */
 119 void *__mmap (void *start, size_t length, int prot, int flags, int fd, off_t offset);
 120 #endif
 121 
 122 static void *(*original_mmap)(void *, size_t, int, int, int, off_t);
 123 
 124 static void *intercept_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset)
 125 {
 126     OPAL_PATCHER_BEGIN;
 127     void *result = 0;
 128 
 129     if (prot == PROT_NONE) {
 130         opal_mem_hooks_release_hook (start, length, true);
 131     }
 132 
 133     if (!original_mmap) {
 134 #ifdef HAVE___MMAP
 135         /* the darwin syscall returns an int not a long so call the underlying __mmap function */
 136         result = __mmap (start, length, prot, flags, fd, offset);
 137 #else
 138         result = (void*)(intptr_t) memory_patcher_syscall(SYS_mmap, start, length, prot, flags, fd, offset);
 139 #endif
 140 
 141         // I thought we had some issue in the past with the above line for IA32,
 142         // like maybe syscall() wouldn't handle that many arguments. But just now
 143         // I used gcc -m32 and it worked on a recent system. But there's a possibility
 144         // that older ia32 systems may need some other code to make the above syscall.
 145     } else {
 146         result = original_mmap (start, length, prot, flags, fd, offset);
 147     }
 148 
 149     OPAL_PATCHER_END;
 150     return result;
 151 }
 152 
 153 #endif
 154 
 155 #if defined (SYS_munmap)
 156 static int (*original_munmap) (void *, size_t);
 157 
 158 static int _intercept_munmap(void *start, size_t length)
 159 {
 160     int result = 0;
 161 
 162     /* could be in a malloc implementation */
 163     opal_mem_hooks_release_hook (start, length, true);
 164 
 165     if (!original_munmap) {
 166         result = memory_patcher_syscall(SYS_munmap, start, length);
 167     } else {
 168         result = original_munmap (start, length);
 169     }
 170 
 171     return result;
 172 }
 173 
 174 static int intercept_munmap(void *start, size_t length)
 175 {
 176     OPAL_PATCHER_BEGIN;
 177     int result = _intercept_munmap (start, length);
 178     OPAL_PATCHER_END;
 179     return result;
 180 }
 181 
 182 #endif
 183 
 184 #if defined (SYS_mremap)
 185 
 186 #if defined(__linux__)
 187 /* on linux this function has an optional extra argument but ... can not be used here because it
 188  * causes issues when intercepting a 4-argument mremap call */
 189 static void *(*original_mremap) (void *, size_t, size_t, int, void *);
 190 #else
 191 /* mremap has a different signature on BSD systems */
 192 static void *(*original_mremap) (void *, size_t, void *, size_t, int);
 193 #endif
 194 
 195 #if defined(__linux__)
 196 static void *_intercept_mremap (void *start, size_t oldlen, size_t newlen, int flags, void *new_address)
 197 #else
 198 static void *_intercept_mremap (void *start, size_t oldlen, void *new_address, size_t newlen, int flags)
 199 #endif
 200 {
 201     void *result = MAP_FAILED;
 202 
 203     if (MAP_FAILED != start && oldlen > 0) {
 204         opal_mem_hooks_release_hook (start, oldlen, true);
 205     }
 206 
 207 #if defined(MREMAP_FIXED)
 208     if (!(flags & MREMAP_FIXED)) {
 209         new_address = NULL;
 210     }
 211 #endif
 212 
 213 #if defined(__linux__)
 214     if (!original_mremap) {
 215         result = (void *)(intptr_t) memory_patcher_syscall (SYS_mremap, start, oldlen, newlen, flags, new_address);
 216     } else {
 217         result = original_mremap (start, oldlen, newlen, flags, new_address);
 218     }
 219 #else
 220     if (!original_mremap) {
 221         result = (void *)(intptr_t) memory_patcher_syscall (SYS_mremap, start, oldlen, new_address, newlen, flags);
 222     } else {
 223         result = original_mremap (start, oldlen, new_address, newlen, flags);
 224     }
 225 #endif
 226 
 227     return result;
 228 }
 229 
 230 #if defined(__linux__)
 231 static void *intercept_mremap (void *start, size_t oldlen, size_t newlen, int flags, void *new_address)
 232 {
 233     OPAL_PATCHER_BEGIN;
 234     void *result = _intercept_mremap (start, oldlen, newlen, flags, new_address);
 235     OPAL_PATCHER_END;
 236     return result;
 237 }
 238 #else
 239 static void *intercept_mremap (void *start, size_t oldlen, void *new_address, size_t newlen, int flags)
 240 {
 241     OPAL_PATCHER_BEGIN;
 242     void *result = _intercept_mremap (start, oldlen, new_address, newlen, flags);
 243     OPAL_PATCHER_END;
 244     return result;
 245 }
 246 #endif
 247 
 248 #endif
 249 
 250 #if defined (SYS_madvise)
 251 
 252 static int (*original_madvise) (void *, size_t, int);
 253 
 254 static int _intercept_madvise (void *start, size_t length, int advice)
 255 {
 256     int result = 0;
 257 
 258     if (advice == MADV_DONTNEED ||
 259 #ifdef MADV_REMOVE
 260         advice == MADV_REMOVE ||
 261 #endif
 262         advice == POSIX_MADV_DONTNEED)
 263     {
 264         opal_mem_hooks_release_hook (start, length, false);
 265     }
 266 
 267     if (!original_madvise) {
 268         result = memory_patcher_syscall(SYS_madvise, start, length, advice);
 269     } else {
 270         result = original_madvise (start, length, advice);
 271     }
 272 
 273     return result;
 274 }
 275 static int intercept_madvise (void *start, size_t length, int advice)
 276 {
 277     OPAL_PATCHER_BEGIN;
 278     int result = _intercept_madvise (start, length, advice);
 279     OPAL_PATCHER_END;
 280     return result;
 281 }
 282 
 283 #endif
 284 
 285 #if defined SYS_brk
 286 
 287 #ifdef HAVE___CURBRK
 288 extern void *__curbrk; /* in libc */
 289 #endif
 290 
 291 static int (*original_brk) (void *);
 292 
 293 static int _intercept_brk (void *addr)
 294 {
 295     int result = 0;
 296     void *old_addr, *new_addr;
 297 
 298 #ifdef HAVE___CURBRK
 299     old_addr = __curbrk;
 300 #else
 301     old_addr = sbrk (0);
 302 #endif
 303 
 304     if (!original_brk) {
 305         /* get the current_addr */
 306         new_addr = (void *) (intptr_t) memory_patcher_syscall(SYS_brk, addr);
 307 
 308 #ifdef HAVE___CURBRK
 309         /*
 310          * Note: if we were using glibc brk/sbrk, their __curbrk would get
 311          * updated, but since we're going straight to the syscall, we have
 312          * to update __curbrk or else glibc won't see it.
 313          */
 314         __curbrk = new_addr;
 315 #endif
 316     } else {
 317         result = original_brk (addr);
 318 #ifdef HAVE___CURBRK
 319         new_addr = __curbrk;
 320 #else
 321         new_addr = sbrk (0);
 322 #endif
 323     }
 324 
 325     if (new_addr < addr) {
 326         errno = ENOMEM;
 327         result = -1;
 328     } else if (new_addr < old_addr) {
 329         opal_mem_hooks_release_hook (new_addr, (intptr_t) old_addr - (intptr_t) new_addr, true);
 330     }
 331     return result;
 332 }
 333 
 334 static int intercept_brk (void *addr)
 335 {
 336     OPAL_PATCHER_BEGIN;
 337     int result = _intercept_brk (addr);
 338     OPAL_PATCHER_END;
 339     return result;
 340 }
 341 
 342 #endif
 343 
 344 #if defined(SYS_shmdt) && defined(__linux__)
 345 
 346 #include <stdio.h>
 347 #include <fcntl.h>
 348 #include <sys/shm.h>
 349 
 350 static size_t memory_patcher_get_shm_seg_size (const void *shmaddr)
 351 {
 352     unsigned long start_addr, end_addr;
 353     char *ptr, *newline;
 354     char buffer[1024];
 355     size_t seg_size = 0;
 356     int fd;
 357 
 358     seg_size = 0;
 359 
 360     fd = open ("/proc/self/maps", O_RDONLY);
 361     if (fd < 0) {
 362         return 0;
 363     }
 364 
 365     for (size_t read_offset = 0 ; ; ) {
 366         ssize_t nread = read(fd, buffer + read_offset, sizeof(buffer) - 1 - read_offset);
 367         if (nread <= 0) {
 368             if (errno == EINTR) {
 369                 continue;
 370             }
 371 
 372             break;
 373         } else {
 374             buffer[nread + read_offset] = '\0';
 375         }
 376 
 377         ptr = buffer;
 378         while ( (newline = strchr(ptr, '\n')) != NULL ) {
 379             /* 00400000-0040b000 r-xp ... \n */
 380             int ret = sscanf(ptr, "%lx-%lx ", &start_addr, &end_addr);
 381             if (ret != 2) {
 382                 continue;
 383             }
 384 
 385             if (start_addr == (uintptr_t)shmaddr) {
 386                 seg_size = end_addr - start_addr;
 387                 goto out_close;
 388             }
 389 
 390             newline = strchr(ptr, '\n');
 391             if (newline == NULL) {
 392                 break;
 393             }
 394 
 395             ptr = newline + 1;
 396         }
 397 
 398         read_offset = strlen(ptr);
 399         memmove(buffer, ptr, read_offset);
 400     }
 401 
 402  out_close:
 403     close(fd);
 404     return seg_size;
 405 }
 406 
 407 static int (*original_shmdt) (const void *);
 408 
 409 static int _intercept_shmdt (const void *shmaddr)
 410 {
 411     int result;
 412 
 413     /* opal_mem_hooks_release_hook should probably be updated to take a const void *.
 414      * for now just cast away the const */
 415     opal_mem_hooks_release_hook ((void *) shmaddr, memory_patcher_get_shm_seg_size (shmaddr), false);
 416 
 417     if (original_shmdt) {
 418         result = original_shmdt (shmaddr);
 419     } else {
 420         result = memory_patcher_syscall (SYS_shmdt, shmaddr);
 421     }
 422 
 423     return result;
 424 }
 425 
 426 static int intercept_shmdt (const void *shmaddr)
 427 {
 428     OPAL_PATCHER_BEGIN;
 429     int result = _intercept_shmdt (shmaddr);
 430     OPAL_PATCHER_END;
 431     return result;
 432 }
 433 #endif
 434 
 435 static int patcher_register (void)
 436 {
 437     mca_memory_patcher_priority = 80;
 438     mca_base_component_var_register (&mca_memory_patcher_component.super.memoryc_version,
 439                                      "priority", "Priority of the patcher memory hook component",
 440                                      MCA_BASE_VAR_TYPE_INT, NULL, 0, 0, OPAL_INFO_LVL_5,
 441                                      MCA_BASE_VAR_SCOPE_CONSTANT, &mca_memory_patcher_priority);
 442 
 443     return OPAL_SUCCESS;
 444 }
 445 
 446 static int patcher_query (int *priority)
 447 {
 448     int rc;
 449 
 450     rc = mca_base_framework_open (&opal_patcher_base_framework, 0);
 451     if (OPAL_SUCCESS != rc) {
 452         *priority = -1;
 453         return OPAL_SUCCESS;
 454     }
 455 
 456     *priority = mca_memory_patcher_priority;
 457 
 458     return OPAL_SUCCESS;
 459 }
 460 
 461 static int patcher_open (void)
 462 {
 463     static int was_executed_already = 0;
 464     int rc;
 465 
 466     if (was_executed_already) {
 467         return OPAL_SUCCESS;
 468     }
 469 
 470     was_executed_already = 1;
 471 
 472     rc = opal_patcher_base_select ();
 473     if (OPAL_SUCCESS != rc) {
 474         mca_base_framework_close (&opal_patcher_base_framework);
 475         return OPAL_ERR_NOT_AVAILABLE;
 476     }
 477 
 478     /* set memory hooks support level */
 479     opal_mem_hooks_set_support (OPAL_MEMORY_FREE_SUPPORT | OPAL_MEMORY_MUNMAP_SUPPORT);
 480 
 481 #if 0
 482     /* See above block to see why mmap() functionality is #if 0'ed
 483        out */
 484     rc = opal_patcher->patch_symbol ("mmap", (uintptr_t) intercept_mmap, (uintptr_t *) &original_mmap);
 485     if (OPAL_SUCCESS != rc) {
 486         return rc;
 487     }
 488 #endif
 489 
 490 #if defined (SYS_munmap)
 491     rc = opal_patcher->patch_symbol ("munmap", (uintptr_t)intercept_munmap, (uintptr_t *) &original_munmap);
 492     if (OPAL_SUCCESS != rc) {
 493         return rc;
 494     }
 495 #endif
 496 
 497 #if defined (SYS_mremap)
 498     rc = opal_patcher->patch_symbol ("mremap",(uintptr_t)intercept_mremap, (uintptr_t *) &original_mremap);
 499     if (OPAL_SUCCESS != rc) {
 500         return rc;
 501     }
 502 #endif
 503 
 504 #if defined (SYS_madvise)
 505     rc = opal_patcher->patch_symbol ("madvise", (uintptr_t)intercept_madvise, (uintptr_t *) &original_madvise);
 506     if (OPAL_SUCCESS != rc) {
 507         return rc;
 508     }
 509 #endif
 510 
 511 #if defined(SYS_shmdt) && defined(__linux__)
 512     rc = opal_patcher->patch_symbol ("shmdt", (uintptr_t) intercept_shmdt, (uintptr_t *) &original_shmdt);
 513     if (OPAL_SUCCESS != rc) {
 514         return rc;
 515     }
 516 #endif
 517 
 518 #if defined (SYS_brk)
 519     rc = opal_patcher->patch_symbol ("brk", (uintptr_t)intercept_brk, (uintptr_t *) &original_brk);
 520 #endif
 521 
 522     return rc;
 523 }
 524 
 525 static int patcher_close(void)
 526 {
 527     mca_base_framework_close (&opal_patcher_base_framework);
 528 
 529     /* Note that we don't need to unpatch any symbols here; the
 530        patcher framework will take care of all of that for us. */
 531     return OPAL_SUCCESS;
 532 }

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