1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <strings.h> 29 #include <sys/shm.h> 30 #include <sys/mman.h> 31 #include <fcntl.h> 32 #include <stdlib.h> 33 #include <unistd.h> 34 #include <errno.h> 35 #include <sys/types.h> 36 #include <sys/stat.h> 37 #include <sys/auxv.h> 38 #include <stdarg.h> 39 #include <syslog.h> 40 #include <sys/param.h> 41 #include <sys/sysmacros.h> 42 #include <procfs.h> 43 #include <dlfcn.h> 44 #include <assert.h> 45 #include <libintl.h> 46 #include <locale.h> 47 48 extern int gmatch(const char *s, const char *p); 49 50 #pragma init(__madvmain) 51 52 static FILE *errfp = NULL; 53 static const char *madvident = "madv.so.1"; 54 static int pagesize; 55 static int advice_all = -1; 56 static int advice_heap = -1; 57 static int advice_shm = -1; 58 static int advice_ism = -1; 59 static int advice_dism = -1; 60 static int advice_map = -1; 61 static int advice_mapshared = -1; 62 static int advice_mapprivate = -1; 63 static int advice_mapanon = -1; 64 65 /* environment variables */ 66 67 #define ENV_MADV "MADV" 68 #define ENV_MADVCFGFILE "MADVCFGFILE" 69 #define ENV_MADVERRFILE "MADVERRFILE" 70 71 /* config file */ 72 73 #define DEF_MADVCFGFILE "/etc/madv.conf" 74 #define MAXLINELEN MAXPATHLEN + 64 75 #define CFGDELIMITER ':' 76 #define ARGDELIMITER ' ' 77 78 /* 79 * avoid malloc which causes certain applications to crash 80 */ 81 static char lbuf[MAXLINELEN]; 82 static char pbuf[MAXPATHLEN]; 83 84 #ifdef MADVDEBUG 85 #define ENV_MADVDEBUG "MADVDEBUG" 86 #define MADVPRINT(x, y) if (madvdebug & x) (void) fprintf y; 87 88 static int madvdebug = 0; 89 #else 90 #define MADVPRINT(x, y) 91 #endif 92 93 /* 94 * advice options 95 */ 96 static char *legal_optstr[] = { 97 "madv", 98 "heap", 99 "shm", 100 "ism", 101 "dism", 102 "map", 103 "mapshared", 104 "mapprivate", 105 "mapanon", 106 NULL 107 }; 108 109 enum optenum { 110 OPT_MADV, 111 OPT_HEAP, 112 OPT_SHM, 113 OPT_ISM, 114 OPT_DISM, 115 OPT_MAP, 116 OPT_MAPSHARED, 117 OPT_MAPPRIVATE, 118 OPT_MAPANON 119 }; 120 121 /* 122 * Advice values 123 * These need to correspond to the order of the MADV_ flags in mman.h 124 * since the position infers the value for the flag. 125 */ 126 static char *legal_madvice[] = { 127 "normal", 128 "random", 129 "sequential", 130 "willneed_NOT_SUPPORTED!", 131 "dontneed_NOT_SUPPORTED!", 132 "free_NOT_SUPPORTED!", 133 "access_default", 134 "access_lwp", 135 "access_many", 136 NULL 137 }; 138 139 #if !defined(TEXT_DOMAIN) 140 #define TEXT_DOMAIN "SYS_TEST" 141 #endif 142 143 /*PRINTFLIKE2*/ 144 static void 145 madverr(FILE *fp, char *fmt, ...) 146 { 147 va_list ap; 148 va_start(ap, fmt); 149 if (fp) 150 (void) vfprintf(fp, fmt, ap); 151 else 152 vsyslog(LOG_ERR, fmt, ap); 153 va_end(ap); 154 } 155 156 /* 157 * Return the pointer to the fully-resolved path name of the process's 158 * executable file obtained from the AT_SUN_EXECNAME aux vector entry. 159 */ 160 static const char * 161 mygetexecname(void) 162 { 163 const char *execname = NULL; 164 static auxv_t auxb; 165 166 /* 167 * The first time through, read the initial aux vector that was 168 * passed to the process at exec(2). Only do this once. 169 */ 170 int fd = open("/proc/self/auxv", O_RDONLY); 171 172 if (fd >= 0) { 173 while (read(fd, &auxb, sizeof (auxv_t)) == sizeof (auxv_t)) { 174 if (auxb.a_type == AT_SUN_EXECNAME) { 175 execname = auxb.a_un.a_ptr; 176 break; 177 } 178 } 179 (void) close(fd); 180 } 181 return (execname); 182 } 183 184 /* 185 * Return the process's current brk base and size. 186 */ 187 static int 188 mygetbrk(uintptr_t *base, size_t *size) 189 { 190 int fd; 191 pstatus_t ps; 192 int rc; 193 194 fd = open("/proc/self/status", O_RDONLY); 195 196 if (fd >= 0) { 197 if (read(fd, &ps, sizeof (ps)) == sizeof (ps)) { 198 *base = ps.pr_brkbase; 199 *size = ps.pr_brksize; 200 rc = 0; 201 } else { 202 rc = errno; 203 } 204 (void) close(fd); 205 } else { 206 rc = errno; 207 } 208 return (rc); 209 } 210 211 /* 212 * Check if exec name matches cfgname found in madv cfg file. 213 */ 214 static int 215 fnmatch(const char *execname, char *cfgname, char *cwd) 216 { 217 const char *ename; 218 int rc; 219 220 /* cfgname should not have a '/' unless it begins with one */ 221 if (cfgname[0] == '/') { 222 /* 223 * if execname does not begin with a '/', prepend the 224 * current directory. 225 */ 226 if (execname[0] != '/') { 227 ename = (const char *)strcat(cwd, execname); 228 } else 229 ename = execname; 230 } else { /* simple cfg name */ 231 if (ename = strrchr(execname, '/')) 232 /* execname is a path name - get the base name */ 233 ename++; 234 else 235 ename = execname; 236 } 237 rc = gmatch(ename, cfgname); 238 MADVPRINT(2, (stderr, "gmatch: %s %s %s %d\n", 239 cfgname, ename, execname, rc)); 240 241 return (rc); 242 } 243 244 /* 245 * Check if string matches any of exec arguments. 246 */ 247 static int 248 argmatch(char *str) 249 { 250 int fd; 251 psinfo_t pi; 252 int rc = 0; 253 int arg; 254 char **argv; 255 256 fd = open("/proc/self/psinfo", O_RDONLY); 257 258 if (fd >= 0) { 259 if (read(fd, &pi, sizeof (pi)) == sizeof (pi)) { 260 argv = (char **)pi.pr_argv; 261 argv++; 262 MADVPRINT(2, (stderr, "argmatch: %s ", str)); 263 for (arg = 1; arg < pi.pr_argc; arg++, argv++) { 264 if (rc = gmatch(*argv, str)) { 265 MADVPRINT(2, (stderr, "%s ", *argv)); 266 break; 267 } 268 } 269 MADVPRINT(2, (stderr, "%d\n", rc)); 270 } else { 271 madverr(errfp, dgettext(TEXT_DOMAIN, 272 "%s: /proc/self/psinfo read failed [%s]\n"), 273 madvident, strerror(errno)); 274 } 275 (void) close(fd); 276 } else { 277 madverr(errfp, dgettext(TEXT_DOMAIN, 278 "%s: /proc/self/psinfo open failed [%s]\n"), 279 madvident, strerror(errno)); 280 } 281 return (rc); 282 } 283 284 static int 285 empty(char *str) 286 { 287 char c; 288 289 while ((c = *str) == '\n' || c == ' ' || c == '\t') 290 str++; 291 return (*str == '\0'); 292 } 293 294 static int 295 strtoadv(char *advstr) 296 { 297 char *dummy, *locstr = advstr; 298 299 return (getsubopt(&locstr, legal_madvice, &dummy)); 300 } 301 302 static void 303 advice_opts(char *optstr, const char *execname, char *cfgfile, int lineno) 304 { 305 char *value; 306 int opt; 307 int advice = 0; 308 309 while (*optstr != '\0') { 310 opt = getsubopt(&optstr, legal_optstr, &value); 311 if (opt < 0) { 312 madverr(errfp, dgettext(TEXT_DOMAIN, 313 "%s: invalid advice option (%s)" 314 " for %s - cfgfile: %s, line: %d\n"), 315 madvident, value, execname, cfgfile, lineno); 316 break; 317 } else if (!value) { 318 madverr(errfp, dgettext(TEXT_DOMAIN, 319 "%s: option missing advice" 320 " for %s - cfgfile: %s, line: %d\n"), 321 madvident, execname, cfgfile, lineno); 322 break; 323 } 324 advice = strtoadv(value); 325 if (advice < 0) { 326 madverr(errfp, dgettext(TEXT_DOMAIN, 327 "%s: invalid advice specified (%s)" 328 " for %s - cfgfile: %s, line: %d\n"), 329 madvident, value, execname, cfgfile, lineno); 330 break; 331 } 332 switch (opt) { 333 case OPT_MADV: 334 advice_all = advice; 335 break; 336 case OPT_HEAP: 337 if (advice_heap < 0) { 338 advice_heap = advice; 339 } else { 340 madverr(errfp, dgettext(TEXT_DOMAIN, 341 "%s: duplicate advice specified " 342 "(%s) for %s - cfgfile: %s, line: %d\n"), 343 madvident, value, execname, cfgfile, 344 lineno); 345 } 346 break; 347 case OPT_SHM: 348 if (advice_shm < 0) { 349 advice_shm = advice; 350 } else { 351 madverr(errfp, dgettext(TEXT_DOMAIN, 352 "%s: duplicate advice specified " 353 "(%s) for %s - cfgfile: %s, line: %d\n"), 354 madvident, value, execname, cfgfile, 355 lineno); 356 } 357 break; 358 case OPT_ISM: 359 if (advice_ism < 0) { 360 advice_ism = advice; 361 } else { 362 madverr(errfp, dgettext(TEXT_DOMAIN, 363 "%s: duplicate advice specified " 364 "(%s) for %s - cfgfile: %s, line: %d\n"), 365 madvident, value, execname, cfgfile, 366 lineno); 367 } 368 break; 369 case OPT_DISM: 370 if (advice_dism < 0) { 371 advice_dism = advice; 372 } else { 373 madverr(errfp, dgettext(TEXT_DOMAIN, 374 "%s: duplicate advice specified " 375 "(%s) for %s - cfgfile: %s, line: %d\n"), 376 madvident, value, execname, cfgfile, 377 lineno); 378 } 379 break; 380 case OPT_MAP: 381 if (advice_map < 0) { 382 advice_map = advice; 383 } else { 384 madverr(errfp, dgettext(TEXT_DOMAIN, 385 "%s: duplicate advice specified " 386 "(%s) for %s - cfgfile: %s, line: %d\n"), 387 madvident, value, execname, cfgfile, 388 lineno); 389 } 390 break; 391 case OPT_MAPSHARED: 392 if (advice_mapshared < 0) { 393 advice_mapshared = advice; 394 } else { 395 madverr(errfp, dgettext(TEXT_DOMAIN, 396 "%s: duplicate advice specified " 397 "(%s) for %s - cfgfile: %s, line: %d\n"), 398 madvident, value, execname, cfgfile, 399 lineno); 400 } 401 break; 402 case OPT_MAPPRIVATE: 403 if (advice_mapprivate < 0) { 404 advice_mapprivate = advice; 405 } else { 406 madverr(errfp, dgettext(TEXT_DOMAIN, 407 "%s: duplicate advice specified " 408 "(%s) for %s - cfgfile: %s, line: %d\n"), 409 madvident, value, execname, cfgfile, 410 lineno); 411 } 412 break; 413 case OPT_MAPANON: 414 if (advice_mapanon < 0) { 415 advice_mapanon = advice; 416 } else { 417 madverr(errfp, dgettext(TEXT_DOMAIN, 418 "%s: duplicate advice specified " 419 "(%s) for %s - cfgfile: %s, line: %d\n"), 420 madvident, value, execname, cfgfile, 421 lineno); 422 } 423 break; 424 default: 425 madverr(errfp, dgettext(TEXT_DOMAIN, 426 "%s: invalid advice option (%s)" 427 " for %s - cfgfile: %s, line: %d\n"), 428 madvident, value, execname, cfgfile, lineno); 429 break; 430 } 431 } 432 } 433 434 static void 435 __madvmain() 436 { 437 char *cfgfile, *errfile; 438 FILE *fp = NULL; 439 const char *execname; 440 char *cwd; 441 int cwdlen; 442 char *tok, *tokadv, *tokarg; 443 char *str, *envadv; 444 int lineno = 0; 445 int advice; 446 uintptr_t brkbase, brkend; 447 size_t brksize; 448 int rc; 449 char *locale; 450 451 /* 452 * If a private error file is indicated then set the locale 453 * for error messages for the duration of this routine. 454 * Error messages destined for syslog should not be translated 455 * and thus come from the default C locale. 456 */ 457 if ((errfile = getenv(ENV_MADVERRFILE)) != NULL) { 458 errfp = fopen(errfile, "aF"); 459 if (errfp) { 460 locale = setlocale(LC_MESSAGES, ""); 461 } else { 462 madverr(NULL, dgettext(TEXT_DOMAIN, 463 "%s: cannot open error file: %s [%s]\n"), 464 madvident, errfile, strerror(errno)); 465 } 466 } 467 468 #ifdef MADVDEBUG 469 if (str = getenv(ENV_MADVDEBUG)) 470 madvdebug = atoi(str); 471 #endif 472 473 if (envadv = getenv(ENV_MADV)) { 474 if ((advice = strtoadv(envadv)) >= 0) 475 advice_all = advice; 476 else 477 madverr(errfp, dgettext(TEXT_DOMAIN, 478 "%s: invalid advice specified: MADV=%s\n"), 479 madvident, envadv); 480 } 481 482 /* 483 * Open specified cfg file or default one. 484 */ 485 if (cfgfile = getenv(ENV_MADVCFGFILE)) { 486 fp = fopen(cfgfile, "rF"); 487 if (!fp) { 488 madverr(errfp, dgettext(TEXT_DOMAIN, 489 "%s: cannot open configuration file: %s [%s]\n"), 490 madvident, cfgfile, strerror(errno)); 491 } 492 } else { 493 cfgfile = DEF_MADVCFGFILE; 494 fp = fopen(cfgfile, "rF"); 495 } 496 497 if (fp) { 498 execname = mygetexecname(); 499 500 cwd = getcwd(pbuf, MAXPATHLEN); 501 if (!cwd) 502 return; 503 504 cwd = strcat(cwd, "/"); 505 cwdlen = strlen(cwd); 506 507 while (fgets(lbuf, MAXLINELEN, fp)) { 508 lineno++; 509 510 /* 511 * Make sure line wasn't truncated. 512 */ 513 if (strlen(lbuf) >= MAXLINELEN - 1) { 514 madverr(errfp, dgettext(TEXT_DOMAIN, 515 "%s: invalid entry, " 516 "line too long - cfgfile:" 517 " %s, line: %d\n"), 518 madvident, cfgfile, lineno); 519 continue; 520 } 521 522 if (empty(lbuf)) 523 continue; 524 525 /* 526 * Get advice options. 527 * Parse right to left in case delimiter is in name. 528 */ 529 if (!(tokadv = strrchr(lbuf, CFGDELIMITER))) { 530 madverr(errfp, dgettext(TEXT_DOMAIN, 531 "%s: no delimiter specified - cfgfile:" 532 " %s, line: %d\n"), 533 madvident, cfgfile, lineno); 534 continue; 535 } 536 *tokadv++ = '\0'; 537 538 /* 539 * Remove newline from end of advice options. 540 */ 541 if (str = strrchr(tokadv, '\n')) 542 *str = '\0'; 543 544 /* 545 * Get optional argument string. 546 */ 547 if (tokarg = strrchr(lbuf, ARGDELIMITER)) { 548 *tokarg++ = '\0'; 549 } 550 551 /* 552 * Compare exec name. 553 */ 554 tok = lbuf; 555 if (!fnmatch(execname, tok, cwd)) { 556 tokadv = tokarg = NULL; 557 cwd[cwdlen] = '\0'; 558 continue; 559 } 560 561 /* 562 * Compare arguments if argument string specified. 563 */ 564 if (tokarg && 565 !empty(tokarg) && 566 !argmatch(tokarg)) { 567 tokadv = tokarg = NULL; 568 cwd[cwdlen] = '\0'; 569 continue; 570 } 571 572 /* 573 * Parse advice options. 574 * If empty, any advice from ENV_MADV is reset. 575 */ 576 if (empty(tokadv)) { 577 advice_all = -1; 578 } else { 579 advice_opts(tokadv, execname, cfgfile, lineno); 580 } 581 break; 582 } 583 (void) fclose(fp); 584 } 585 586 /* 587 * Pagesize needed for proper aligning by brk interpose. 588 */ 589 pagesize = sysconf(_SC_PAGESIZE); 590 591 /* 592 * Apply global advice if set. 593 * Specific options in the cfgfile take precedence. 594 */ 595 if (advice_all >= 0) { 596 if (advice_heap < 0) 597 advice_heap = advice_all; 598 if (advice_shm < 0) 599 advice_shm = advice_all; 600 if (advice_map < 0) 601 advice_map = advice_all; 602 } 603 604 MADVPRINT(2, (stderr, "advice_all %d\n", advice_all)); 605 MADVPRINT(2, (stderr, "advice_heap %d\n", advice_heap)); 606 MADVPRINT(2, (stderr, "advice_shm %d\n", advice_shm)); 607 MADVPRINT(2, (stderr, "advice_ism %d\n", advice_ism)); 608 MADVPRINT(2, (stderr, "advice_dism %d\n", advice_dism)); 609 MADVPRINT(2, (stderr, "advice_map %d\n", advice_map)); 610 MADVPRINT(2, (stderr, "advice_mapshared %d\n", advice_mapshared)); 611 MADVPRINT(2, (stderr, "advice_mapprivate %d\n", advice_mapprivate)); 612 MADVPRINT(2, (stderr, "advice_mapanon %d\n", advice_mapanon)); 613 614 /* 615 * If heap advice is specified, apply it to the existing heap. 616 * As the heap grows the kernel applies the advice automatically 617 * to new portions of the heap. 618 */ 619 if (advice_heap >= 0) { 620 if (rc = mygetbrk(&brkbase, &brksize)) { 621 madverr(errfp, dgettext(TEXT_DOMAIN, 622 "%s: /proc/self/status read failed [%s]\n"), 623 madvident, strerror(rc)); 624 } else { 625 MADVPRINT(4, (stderr, "brkbase 0x%x brksize 0x%x\n", 626 brkbase, brksize)); 627 /* 628 * Align start address for memcntl and apply advice 629 * on full pages of heap. Create a page of heap if 630 * it does not already exist. 631 */ 632 brkend = roundup(brkbase+brksize, pagesize); 633 brkbase = roundup(brkbase, pagesize); 634 brksize = brkend - brkbase; 635 if (brksize < pagesize) { 636 if (sbrk(pagesize) == (void *)-1) { 637 madverr(errfp, dgettext(TEXT_DOMAIN, 638 "%s: sbrk failed [%s]\n"), 639 madvident, strerror(errno)); 640 goto out; 641 } 642 brksize = pagesize; 643 } 644 MADVPRINT(1, (stderr, "heap advice: 0x%x 0x%x %d\n", 645 brkbase, brksize, advice_heap)); 646 if (memcntl((caddr_t)brkbase, brksize, MC_ADVISE, 647 (caddr_t)(intptr_t)advice_heap, 0, 0) < 0) { 648 madverr(errfp, dgettext(TEXT_DOMAIN, 649 "%s: memcntl() failed [%s]: heap advice\n"), 650 madvident, strerror(errno)); 651 } 652 } 653 } 654 out: 655 if (errfp) { 656 (void) fclose(errfp); 657 (void) setlocale(LC_MESSAGES, locale); 658 } else { 659 /* close log file: no-op if nothing logged to syslog */ 660 closelog(); 661 } 662 663 } 664 665 /* 666 * shmat interpose 667 */ 668 void * 669 shmat(int shmid, const void *shmaddr, int shmflag) 670 { 671 static caddr_t (*shmatfunc)() = NULL; 672 void *result; 673 int advice = -1; 674 struct shmid_ds mds; 675 #ifdef MADVDEBUG 676 int rc; 677 #endif 678 679 if (!shmatfunc) { 680 shmatfunc = (caddr_t (*)()) dlsym(RTLD_NEXT, "shmat"); 681 assert(shmatfunc); 682 } 683 684 result = shmatfunc(shmid, shmaddr, shmflag); 685 686 /* 687 * Options ism, dism take precedence over option shm. 688 */ 689 if (advice_ism >= 0 && (shmflag & SHM_SHARE_MMU)) { 690 advice = advice_ism; 691 } else if (advice_dism >= 0 && (shmflag & SHM_PAGEABLE)) { 692 advice = advice_dism; 693 } else if (advice_shm >= 0) { 694 advice = advice_shm; 695 } 696 697 /* 698 * Apply advice if specified and shmat succeeded. 699 */ 700 if (advice >= 0 && result != (void *)-1) { 701 #ifdef MADVDEBUG 702 /* First determine segment size */ 703 rc = shmctl(shmid, IPC_STAT, &mds); 704 MADVPRINT(4, (stderr, "shmctl rc %d errno %d\n", rc, errno)); 705 rc = memcntl(result, mds.shm_segsz, MC_ADVISE, 706 (caddr_t)(intptr_t)advice, 0, 0); 707 MADVPRINT(1, (stderr, 708 "shmat advice: 0x%x 0x%x %d, rc %d errno %d\n", 709 result, mds.shm_segsz, advice, rc, errno)); 710 #else 711 /* First determine segment size */ 712 (void) shmctl(shmid, IPC_STAT, &mds); 713 (void) memcntl(result, mds.shm_segsz, MC_ADVISE, 714 (caddr_t)(intptr_t)advice, 0, 0); 715 #endif 716 } 717 718 return (result); 719 } 720 721 /* 722 * mmap interpose 723 */ 724 void * 725 mmap(void *addr, size_t len, int prot, int flags, int fd, off_t pos) 726 { 727 static caddr_t (*mmapfunc)() = NULL; 728 caddr_t result; 729 int advice = -1; 730 731 if (!mmapfunc) { 732 mmapfunc = (caddr_t (*)()) dlsym(RTLD_NEXT, "mmap"); 733 assert(mmapfunc); 734 } 735 736 result = mmapfunc(addr, len, prot, flags, fd, pos); 737 738 /* 739 * Option mapanon has highest precedence while option map 740 * has lowest precedence. 741 */ 742 if (advice_mapanon >= 0 && (flags & MAP_ANON)) { 743 advice = advice_mapanon; 744 } else if (advice_mapshared >= 0 && (flags & MAP_SHARED)) { 745 advice = advice_mapshared; 746 } else if (advice_mapprivate >= 0 && (flags & MAP_PRIVATE)) { 747 advice = advice_mapprivate; 748 } else if (advice_map >= 0) { 749 advice = advice_map; 750 } 751 752 /* 753 * Apply advice if specified and mmap succeeded. 754 */ 755 if (advice >= 0 && result != MAP_FAILED) { 756 #ifdef MADVDEBUG 757 int rc; 758 759 rc = memcntl(result, len, MC_ADVISE, 760 (caddr_t)(intptr_t)advice, 0, 0); 761 MADVPRINT(1, (stderr, 762 "mmap advice: 0x%x 0x%x %d, rc %d errno %d\n", 763 result, len, advice, rc, errno)); 764 #else 765 (void) memcntl(result, len, MC_ADVISE, 766 (caddr_t)(intptr_t)advice, 0, 0); 767 #endif 768 } 769 770 return (result); 771 } 772 773 #if !defined(_LP64) 774 /* 775 * mmap64 interpose 776 */ 777 void * 778 mmap64(void *addr, size_t len, int prot, int flags, int fd, off64_t pos) 779 { 780 static caddr_t (*mmap64func)(); 781 caddr_t result; 782 int advice = -1; 783 784 if (!mmap64func) { 785 mmap64func = (caddr_t (*)()) dlsym(RTLD_NEXT, "mmap64"); 786 assert(mmap64func); 787 } 788 789 result = mmap64func(addr, len, prot, flags, fd, pos); 790 791 /* 792 * Option mapanon has highest precedence while option map 793 * has lowest precedence. 794 */ 795 if (advice_mapanon >= 0 && (flags & MAP_ANON)) { 796 advice = advice_mapanon; 797 } else if (advice_mapshared >= 0 && (flags & MAP_SHARED)) { 798 advice = advice_mapshared; 799 } else if (advice_mapprivate >= 0 && (flags & MAP_PRIVATE)) { 800 advice = advice_mapprivate; 801 } else if (advice_map >= 0) { 802 advice = advice_map; 803 } 804 805 /* 806 * Apply advice if specified and mmap succeeded. 807 */ 808 if (advice >= 0 && result != MAP_FAILED) { 809 #ifdef MADVDEBUG 810 int rc; 811 812 rc = memcntl(result, len, MC_ADVISE, (caddr_t)advice, 0, 0); 813 MADVPRINT(1, (stderr, 814 "mmap64 advice: 0x%x 0x%x %d, rc %d errno %d\n", 815 result, len, advice, rc, errno)); 816 #else 817 (void) memcntl(result, len, MC_ADVISE, (caddr_t)advice, 0, 0); 818 #endif 819 } 820 821 return (result); 822 } 823 #endif /* !_LP64 */ 824