Home | History | Annotate | Download | only in m_aspacemgr
      1 
      2 /*--------------------------------------------------------------------*/
      3 /*--- The address space manager: stuff common to all platforms     ---*/
      4 /*---                                                              ---*/
      5 /*---                                         m_aspacemgr-common.c ---*/
      6 /*--------------------------------------------------------------------*/
      7 
      8 /*
      9    This file is part of Valgrind, a dynamic binary instrumentation
     10    framework.
     11 
     12    Copyright (C) 2006-2015 OpenWorks LLP
     13       info (at) open-works.co.uk
     14 
     15    This program is free software; you can redistribute it and/or
     16    modify it under the terms of the GNU General Public License as
     17    published by the Free Software Foundation; either version 2 of the
     18    License, or (at your option) any later version.
     19 
     20    This program is distributed in the hope that it will be useful, but
     21    WITHOUT ANY WARRANTY; without even the implied warranty of
     22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     23    General Public License for more details.
     24 
     25    You should have received a copy of the GNU General Public License
     26    along with this program; if not, write to the Free Software
     27    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
     28    02111-1307, USA.
     29 
     30    The GNU General Public License is contained in the file COPYING.
     31 */
     32 
     33 /* *************************************************************
     34    DO NOT INCLUDE ANY OTHER FILES HERE.
     35    ADD NEW INCLUDES ONLY TO priv_aspacemgr.h
     36    AND THEN ONLY AFTER READING DIRE WARNINGS THERE TOO.
     37    ************************************************************* */
     38 
     39 #include "priv_aspacemgr.h"
     40 #include "config.h"
     41 
     42 
     43 /*-----------------------------------------------------------------*/
     44 /*---                                                           ---*/
     45 /*--- Stuff to make aspacem almost completely independent of    ---*/
     46 /*--- the rest of Valgrind.                                     ---*/
     47 /*---                                                           ---*/
     48 /*-----------------------------------------------------------------*/
     49 
     50 //--------------------------------------------------------------
     51 // Simple assert and assert-like fns, which avoid dependence on
     52 // m_libcassert, and hence on the entire debug-info reader swamp
     53 
     54 __attribute__ ((noreturn))
     55 void ML_(am_exit)( Int status )
     56 {
     57    VG_(exit_now) (status);
     58 }
     59 
     60 void ML_(am_barf) ( const HChar* what )
     61 {
     62    VG_(debugLog)(0, "aspacem", "Valgrind: FATAL: %s\n", what);
     63    VG_(debugLog)(0, "aspacem", "Exiting now.\n");
     64    ML_(am_exit)(1);
     65 }
     66 
     67 void ML_(am_barf_toolow) ( const HChar* what )
     68 {
     69    VG_(debugLog)(0, "aspacem",
     70                     "Valgrind: FATAL: %s is too low.\n", what);
     71    VG_(debugLog)(0, "aspacem", "  Increase it and rebuild.  "
     72                                "Exiting now.\n");
     73    ML_(am_exit)(1);
     74 }
     75 
     76 void ML_(am_assert_fail)( const HChar* expr,
     77                           const HChar* file,
     78                           Int line,
     79                           const HChar* fn )
     80 {
     81    VG_(debugLog)(0, "aspacem",
     82                     "Valgrind: FATAL: aspacem assertion failed:\n");
     83    VG_(debugLog)(0, "aspacem", "  %s\n", expr);
     84    VG_(debugLog)(0, "aspacem", "  at %s:%d (%s)\n", file,line,fn);
     85    VG_(debugLog)(0, "aspacem", "Exiting now.\n");
     86    ML_(am_exit)(1);
     87 }
     88 
     89 Int ML_(am_getpid)( void )
     90 {
     91    SysRes sres = VG_(do_syscall0)(__NR_getpid);
     92    aspacem_assert(!sr_isError(sres));
     93    return sr_Res(sres);
     94 }
     95 
     96 
     97 //--------------------------------------------------------------
     98 // A simple sprintf implementation, so as to avoid dependence on
     99 // m_libcprint.
    100 
    101 static void local_add_to_aspacem_sprintf_buf ( HChar c, void *p )
    102 {
    103    HChar** aspacem_sprintf_ptr = p;
    104    *(*aspacem_sprintf_ptr)++ = c;
    105 }
    106 
    107 static
    108 UInt local_vsprintf ( HChar* buf, const HChar *format, va_list vargs )
    109 {
    110    Int ret;
    111    HChar *aspacem_sprintf_ptr = buf;
    112 
    113    ret = VG_(debugLog_vprintf)
    114             ( local_add_to_aspacem_sprintf_buf,
    115               &aspacem_sprintf_ptr, format, vargs );
    116    local_add_to_aspacem_sprintf_buf('\0', &aspacem_sprintf_ptr);
    117 
    118    return ret;
    119 }
    120 
    121 UInt ML_(am_sprintf) ( HChar* buf, const HChar *format, ... )
    122 {
    123    UInt ret;
    124    va_list vargs;
    125 
    126    va_start(vargs,format);
    127    ret = local_vsprintf(buf, format, vargs);
    128    va_end(vargs);
    129 
    130    return ret;
    131 }
    132 
    133 
    134 //--------------------------------------------------------------
    135 // Direct access to a handful of syscalls.  This avoids dependence on
    136 // m_libc*.  THESE DO NOT UPDATE THE aspacem-internal DATA
    137 // STRUCTURES (SEGMENT ARRAY).  DO NOT USE THEM UNLESS YOU KNOW WHAT
    138 // YOU ARE DOING.
    139 
    140 /* --- Pertaining to mappings --- */
    141 
    142 /* Note: this is VG_, not ML_. */
    143 SysRes VG_(am_do_mmap_NO_NOTIFY)( Addr start, SizeT length, UInt prot,
    144                                   UInt flags, Int fd, Off64T offset)
    145 {
    146    SysRes res;
    147    aspacem_assert(VG_IS_PAGE_ALIGNED(offset));
    148 
    149 #  if defined(VGP_arm64_linux)
    150    res = VG_(do_syscall6)(__NR3264_mmap, (UWord)start, length,
    151                          prot, flags, fd, offset);
    152 #  elif defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
    153         || defined(VGP_arm_linux)
    154    /* mmap2 uses 4096 chunks even if actual page size is bigger. */
    155    aspacem_assert((offset % 4096) == 0);
    156    res = VG_(do_syscall6)(__NR_mmap2, (UWord)start, length,
    157                           prot, flags, fd, offset / 4096);
    158 #  elif defined(VGP_amd64_linux) \
    159         || defined(VGP_ppc64be_linux)  || defined(VGP_ppc64le_linux) \
    160         || defined(VGP_s390x_linux) || defined(VGP_mips32_linux) \
    161         || defined(VGP_mips64_linux) || defined(VGP_arm64_linux) \
    162         || defined(VGP_tilegx_linux)
    163    res = VG_(do_syscall6)(__NR_mmap, (UWord)start, length,
    164                          prot, flags, fd, offset);
    165 #  elif defined(VGP_x86_darwin)
    166    if (fd == 0  &&  (flags & VKI_MAP_ANONYMOUS)) {
    167        fd = -1;  // MAP_ANON with fd==0 is EINVAL
    168    }
    169    res = VG_(do_syscall7)(__NR_mmap, (UWord)start, length,
    170                           prot, flags, fd, offset & 0xffffffff, offset >> 32);
    171 #  elif defined(VGP_amd64_darwin)
    172    if (fd == 0  &&  (flags & VKI_MAP_ANONYMOUS)) {
    173        fd = -1;  // MAP_ANON with fd==0 is EINVAL
    174    }
    175    res = VG_(do_syscall6)(__NR_mmap, (UWord)start, length,
    176                           prot, flags, (UInt)fd, offset);
    177 #  elif defined(VGP_x86_solaris)
    178    /* MAP_ANON with fd==0 is EINVAL. */
    179    if (fd == 0 && (flags & VKI_MAP_ANONYMOUS))
    180       fd = -1;
    181    res = VG_(do_syscall7)(__NR_mmap64, (UWord)start, length, prot, flags,
    182                           (UInt)fd, offset & 0xffffffff, offset >> 32);
    183 #  elif defined(VGP_amd64_solaris)
    184    /* MAP_ANON with fd==0 is EINVAL. */
    185    if (fd == 0 && (flags & VKI_MAP_ANONYMOUS))
    186       fd = -1;
    187    res = VG_(do_syscall6)(__NR_mmap, (UWord)start, length, prot, flags,
    188                           (UInt)fd, offset);
    189 #  else
    190 #    error Unknown platform
    191 #  endif
    192    return res;
    193 }
    194 
    195 static
    196 SysRes local_do_mprotect_NO_NOTIFY(Addr start, SizeT length, UInt prot)
    197 {
    198    return VG_(do_syscall3)(__NR_mprotect, (UWord)start, length, prot );
    199 }
    200 
    201 SysRes ML_(am_do_munmap_NO_NOTIFY)(Addr start, SizeT length)
    202 {
    203    return VG_(do_syscall2)(__NR_munmap, (UWord)start, length );
    204 }
    205 
    206 #if HAVE_MREMAP
    207 /* The following are used only to implement mremap(). */
    208 
    209 SysRes ML_(am_do_extend_mapping_NO_NOTIFY)(
    210           Addr  old_addr,
    211           SizeT old_len,
    212           SizeT new_len
    213        )
    214 {
    215    /* Extend the mapping old_addr .. old_addr+old_len-1 to have length
    216       new_len, WITHOUT moving it.  If it can't be extended in place,
    217       fail. */
    218 #  if defined(VGO_linux)
    219    return VG_(do_syscall5)(
    220              __NR_mremap,
    221              old_addr, old_len, new_len,
    222              0/*flags, meaning: must be at old_addr, else FAIL */,
    223              0/*new_addr, is ignored*/
    224           );
    225 #  else
    226 #    error Unknown OS
    227 #  endif
    228 }
    229 
    230 SysRes ML_(am_do_relocate_nooverlap_mapping_NO_NOTIFY)(
    231           Addr old_addr, Addr old_len,
    232           Addr new_addr, Addr new_len
    233        )
    234 {
    235    /* Move the mapping old_addr .. old_addr+old_len-1 to the new
    236       location and with the new length.  Only needs to handle the case
    237       where the two areas do not overlap, neither length is zero, and
    238       all args are page aligned. */
    239 #  if defined(VGO_linux)
    240    return VG_(do_syscall5)(
    241              __NR_mremap,
    242              old_addr, old_len, new_len,
    243              VKI_MREMAP_MAYMOVE|VKI_MREMAP_FIXED/*move-or-fail*/,
    244              new_addr
    245           );
    246 #  else
    247 #    error Unknown OS
    248 #  endif
    249 }
    250 
    251 #endif
    252 
    253 /* --- Pertaining to files --- */
    254 
    255 SysRes ML_(am_open) ( const HChar* pathname, Int flags, Int mode )
    256 {
    257 #  if defined(VGP_arm64_linux)
    258    /* ARM64 wants to use __NR_openat rather than __NR_open. */
    259    SysRes res = VG_(do_syscall4)(__NR_openat,
    260                                  VKI_AT_FDCWD, (UWord)pathname, flags, mode);
    261 #  elif defined(VGP_tilegx_linux)
    262    SysRes res = VG_(do_syscall4)(__NR_openat, VKI_AT_FDCWD, (UWord)pathname,
    263                                  flags, mode);
    264 #  elif defined(VGO_linux) || defined(VGO_darwin)
    265    SysRes res = VG_(do_syscall3)(__NR_open, (UWord)pathname, flags, mode);
    266 #  elif defined(VGO_solaris)
    267    SysRes res = VG_(do_syscall4)(__NR_openat, VKI_AT_FDCWD, (UWord)pathname,
    268                                  flags, mode);
    269 #  else
    270 #    error Unknown OS
    271 #  endif
    272    return res;
    273 }
    274 
    275 Int ML_(am_read) ( Int fd, void* buf, Int count)
    276 {
    277    SysRes res = VG_(do_syscall3)(__NR_read, fd, (UWord)buf, count);
    278    return sr_isError(res) ? -1 : sr_Res(res);
    279 }
    280 
    281 void ML_(am_close) ( Int fd )
    282 {
    283    (void)VG_(do_syscall1)(__NR_close, fd);
    284 }
    285 
    286 Int ML_(am_readlink)(const HChar* path, HChar* buf, UInt bufsiz)
    287 {
    288    SysRes res;
    289 #  if defined(VGP_arm64_linux)
    290    res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD,
    291                                            (UWord)path, (UWord)buf, bufsiz);
    292 #  elif defined(VGP_tilegx_linux)
    293    res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD, (UWord)path,
    294                           (UWord)buf, bufsiz);
    295 #  elif defined(VGO_linux) || defined(VGO_darwin)
    296    res = VG_(do_syscall3)(__NR_readlink, (UWord)path, (UWord)buf, bufsiz);
    297 #  elif defined(VGO_solaris)
    298    res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD, (UWord)path,
    299                           (UWord)buf, bufsiz);
    300 #  else
    301 #    error Unknown OS
    302 #  endif
    303    return sr_isError(res) ? -1 : sr_Res(res);
    304 }
    305 
    306 Int ML_(am_fcntl) ( Int fd, Int cmd, Addr arg )
    307 {
    308 #  if defined(VGO_linux) || defined(VGO_solaris)
    309    SysRes res = VG_(do_syscall3)(__NR_fcntl, fd, cmd, arg);
    310 #  elif defined(VGO_darwin)
    311    SysRes res = VG_(do_syscall3)(__NR_fcntl_nocancel, fd, cmd, arg);
    312 #  else
    313 #  error "Unknown OS"
    314 #  endif
    315    return sr_isError(res) ? -1 : sr_Res(res);
    316 }
    317 
    318 /* Get the dev, inode and mode info for a file descriptor, if
    319    possible.  Returns True on success. */
    320 Bool ML_(am_get_fd_d_i_m)( Int fd,
    321                            /*OUT*/ULong* dev,
    322                            /*OUT*/ULong* ino, /*OUT*/UInt* mode )
    323 {
    324 #  if defined(VGO_linux) || defined(VGO_darwin)
    325    SysRes          res;
    326    struct vki_stat buf;
    327 #  if defined(VGO_linux) && defined(__NR_fstat64)
    328    /* Try fstat64 first as it can cope with minor and major device
    329       numbers outside the 0-255 range and it works properly for x86
    330       binaries on amd64 systems where fstat seems to be broken. */
    331    struct vki_stat64 buf64;
    332    res = VG_(do_syscall2)(__NR_fstat64, fd, (UWord)&buf64);
    333    if (!sr_isError(res)) {
    334       *dev  = (ULong)buf64.st_dev;
    335       *ino  = (ULong)buf64.st_ino;
    336       *mode = (UInt) buf64.st_mode;
    337       return True;
    338    }
    339 #  endif
    340    res = VG_(do_syscall2)(__NR_fstat, fd, (UWord)&buf);
    341    if (!sr_isError(res)) {
    342       *dev  = (ULong)buf.st_dev;
    343       *ino  = (ULong)buf.st_ino;
    344       *mode = (UInt) buf.st_mode;
    345       return True;
    346    }
    347    return False;
    348 #  elif defined(VGO_solaris)
    349 #  if defined(VGP_x86_solaris)
    350    struct vki_stat64 buf64;
    351    SysRes res = VG_(do_syscall4)(__NR_fstatat64, fd, 0, (UWord)&buf64, 0);
    352 #  elif defined(VGP_amd64_solaris)
    353    struct vki_stat buf64;
    354    SysRes res = VG_(do_syscall4)(__NR_fstatat, fd, 0, (UWord)&buf64, 0);
    355 #  else
    356 #    error "Unknown platform"
    357 #  endif
    358    if (!sr_isError(res)) {
    359       *dev  = (ULong)buf64.st_dev;
    360       *ino  = (ULong)buf64.st_ino;
    361       *mode = (UInt) buf64.st_mode;
    362       return True;
    363    }
    364    return False;
    365 #  else
    366 #    error Unknown OS
    367 #  endif
    368 }
    369 
    370 Bool ML_(am_resolve_filename) ( Int fd, /*OUT*/HChar* buf, Int nbuf )
    371 {
    372 #if defined(VGO_linux)
    373    Int i;
    374    HChar tmp[64];    // large enough
    375    for (i = 0; i < nbuf; i++) buf[i] = 0;
    376    ML_(am_sprintf)(tmp, "/proc/self/fd/%d", fd);
    377    if (ML_(am_readlink)(tmp, buf, nbuf) > 0 && buf[0] == '/')
    378       return True;
    379    else
    380       return False;
    381 
    382 #elif defined(VGO_darwin)
    383    HChar tmp[VKI_MAXPATHLEN+1];
    384    if (0 == ML_(am_fcntl)(fd, VKI_F_GETPATH, (UWord)tmp)) {
    385       if (nbuf > 0) {
    386          VG_(strncpy)( buf, tmp, nbuf < sizeof(tmp) ? nbuf : sizeof(tmp) );
    387          buf[nbuf-1] = 0;
    388       }
    389       if (tmp[0] == '/') return True;
    390    }
    391    return False;
    392 
    393 #elif defined(VGO_solaris)
    394    Int i;
    395    HChar tmp[64];
    396    for (i = 0; i < nbuf; i++) buf[i] = 0;
    397    ML_(am_sprintf)(tmp, "/proc/self/path/%d", fd);
    398    if (ML_(am_readlink)(tmp, buf, nbuf) > 0 && buf[0] == '/')
    399       return True;
    400    else
    401       return False;
    402 
    403 #  else
    404 #     error Unknown OS
    405 #  endif
    406 }
    407 
    408 
    409 
    410 
    411 /*-----------------------------------------------------------------*/
    412 /*---                                                           ---*/
    413 /*--- Manage stacks for Valgrind itself.                        ---*/
    414 /*---                                                           ---*/
    415 /*-----------------------------------------------------------------*/
    416 struct _VgStack {
    417    HChar bytes[1];
    418    // We use a fake size of 1. A bigger size is allocated
    419    // by VG_(am_alloc_VgStack).
    420 };
    421 
    422 /* Allocate and initialise a VgStack (anonymous valgrind space).
    423    Protect the stack active area and the guard areas appropriately.
    424    Returns NULL on failure, else the address of the bottom of the
    425    stack.  On success, also sets *initial_sp to what the stack pointer
    426    should be set to. */
    427 
    428 VgStack* VG_(am_alloc_VgStack)( /*OUT*/Addr* initial_sp )
    429 {
    430    Int      szB;
    431    SysRes   sres;
    432    VgStack* stack;
    433    UInt*    p;
    434    Int      i;
    435 
    436    /* Allocate the stack. */
    437    szB = VG_STACK_GUARD_SZB
    438          + VG_(clo_valgrind_stacksize) + VG_STACK_GUARD_SZB;
    439 
    440    sres = VG_(am_mmap_anon_float_valgrind)( szB );
    441    if (sr_isError(sres))
    442       return NULL;
    443 
    444    stack = (VgStack*)(Addr)sr_Res(sres);
    445 
    446    aspacem_assert(VG_IS_PAGE_ALIGNED(szB));
    447    aspacem_assert(VG_IS_PAGE_ALIGNED(stack));
    448 
    449    /* Protect the guard areas. */
    450    sres = local_do_mprotect_NO_NOTIFY(
    451              (Addr) &stack[0],
    452              VG_STACK_GUARD_SZB, VKI_PROT_NONE
    453           );
    454    if (sr_isError(sres)) goto protect_failed;
    455    VG_(am_notify_mprotect)(
    456       (Addr) &stack->bytes[0],
    457       VG_STACK_GUARD_SZB, VKI_PROT_NONE
    458    );
    459 
    460    sres = local_do_mprotect_NO_NOTIFY(
    461              (Addr) &stack->bytes[VG_STACK_GUARD_SZB + VG_(clo_valgrind_stacksize)],
    462              VG_STACK_GUARD_SZB, VKI_PROT_NONE
    463           );
    464    if (sr_isError(sres)) goto protect_failed;
    465    VG_(am_notify_mprotect)(
    466       (Addr) &stack->bytes[VG_STACK_GUARD_SZB + VG_(clo_valgrind_stacksize)],
    467       VG_STACK_GUARD_SZB, VKI_PROT_NONE
    468    );
    469 
    470    /* Looks good.  Fill the active area with junk so we can later
    471       tell how much got used. */
    472 
    473    p = (UInt*)&stack->bytes[VG_STACK_GUARD_SZB];
    474    for (i = 0; i < VG_(clo_valgrind_stacksize)/sizeof(UInt); i++)
    475       p[i] = 0xDEADBEEF;
    476 
    477    *initial_sp = (Addr)&stack->bytes[VG_STACK_GUARD_SZB + VG_(clo_valgrind_stacksize)];
    478    *initial_sp -= 8;
    479    *initial_sp &= ~((Addr)0x1F); /* 32-align it */
    480 
    481    VG_(debugLog)( 1,"aspacem",
    482                   "allocated valgrind thread stack at 0x%llx size %d\n",
    483                   (ULong)(Addr)stack, szB);
    484    ML_(am_do_sanity_check)();
    485    return stack;
    486 
    487   protect_failed:
    488    /* The stack was allocated, but we can't protect it.  Unmap it and
    489       return NULL (failure). */
    490    (void)ML_(am_do_munmap_NO_NOTIFY)( (Addr)stack, szB );
    491    ML_(am_do_sanity_check)();
    492    return NULL;
    493 }
    494 
    495 
    496 /* Figure out how many bytes of the stack's active area have not
    497    been used.  Used for estimating if we are close to overflowing it. */
    498 
    499 SizeT VG_(am_get_VgStack_unused_szB)( const VgStack* stack, SizeT limit )
    500 {
    501    SizeT i;
    502    const UInt* p;
    503 
    504    p = (const UInt*)&stack->bytes[VG_STACK_GUARD_SZB];
    505    for (i = 0; i < VG_(clo_valgrind_stacksize)/sizeof(UInt); i++) {
    506       if (p[i] != 0xDEADBEEF)
    507          break;
    508       if (i * sizeof(UInt) >= limit)
    509          break;
    510    }
    511 
    512    return i * sizeof(UInt);
    513 }
    514 
    515 
    516 /*--------------------------------------------------------------------*/
    517 /*--- end                                                          ---*/
    518 /*--------------------------------------------------------------------*/
    519