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-2017 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    res = VG_(do_syscall6)(__NR_mmap, (UWord)start, length,
    163                          prot, flags, fd, offset);
    164 #  elif defined(VGP_x86_darwin)
    165    if (fd == 0  &&  (flags & VKI_MAP_ANONYMOUS)) {
    166        fd = -1;  // MAP_ANON with fd==0 is EINVAL
    167    }
    168    res = VG_(do_syscall7)(__NR_mmap, (UWord)start, length,
    169                           prot, flags, fd, offset & 0xffffffff, offset >> 32);
    170 #  elif defined(VGP_amd64_darwin)
    171    if (fd == 0  &&  (flags & VKI_MAP_ANONYMOUS)) {
    172        fd = -1;  // MAP_ANON with fd==0 is EINVAL
    173    }
    174    res = VG_(do_syscall6)(__NR_mmap, (UWord)start, length,
    175                           prot, flags, (UInt)fd, offset);
    176 #  elif defined(VGP_x86_solaris)
    177    /* MAP_ANON with fd==0 is EINVAL. */
    178    if (fd == 0 && (flags & VKI_MAP_ANONYMOUS))
    179       fd = -1;
    180    res = VG_(do_syscall7)(__NR_mmap64, (UWord)start, length, prot, flags,
    181                           (UInt)fd, offset & 0xffffffff, offset >> 32);
    182 #  elif defined(VGP_amd64_solaris)
    183    /* MAP_ANON with fd==0 is EINVAL. */
    184    if (fd == 0 && (flags & VKI_MAP_ANONYMOUS))
    185       fd = -1;
    186    res = VG_(do_syscall6)(__NR_mmap, (UWord)start, length, prot, flags,
    187                           (UInt)fd, offset);
    188 #  else
    189 #    error Unknown platform
    190 #  endif
    191    return res;
    192 }
    193 
    194 static
    195 SysRes local_do_mprotect_NO_NOTIFY(Addr start, SizeT length, UInt prot)
    196 {
    197    return VG_(do_syscall3)(__NR_mprotect, (UWord)start, length, prot );
    198 }
    199 
    200 SysRes ML_(am_do_munmap_NO_NOTIFY)(Addr start, SizeT length)
    201 {
    202    return VG_(do_syscall2)(__NR_munmap, (UWord)start, length );
    203 }
    204 
    205 #if HAVE_MREMAP
    206 /* The following are used only to implement mremap(). */
    207 
    208 SysRes ML_(am_do_extend_mapping_NO_NOTIFY)(
    209           Addr  old_addr,
    210           SizeT old_len,
    211           SizeT new_len
    212        )
    213 {
    214    /* Extend the mapping old_addr .. old_addr+old_len-1 to have length
    215       new_len, WITHOUT moving it.  If it can't be extended in place,
    216       fail. */
    217 #  if defined(VGO_linux)
    218    return VG_(do_syscall5)(
    219              __NR_mremap,
    220              old_addr, old_len, new_len,
    221              0/*flags, meaning: must be at old_addr, else FAIL */,
    222              0/*new_addr, is ignored*/
    223           );
    224 #  else
    225 #    error Unknown OS
    226 #  endif
    227 }
    228 
    229 SysRes ML_(am_do_relocate_nooverlap_mapping_NO_NOTIFY)(
    230           Addr old_addr, Addr old_len,
    231           Addr new_addr, Addr new_len
    232        )
    233 {
    234    /* Move the mapping old_addr .. old_addr+old_len-1 to the new
    235       location and with the new length.  Only needs to handle the case
    236       where the two areas do not overlap, neither length is zero, and
    237       all args are page aligned. */
    238 #  if defined(VGO_linux)
    239    return VG_(do_syscall5)(
    240              __NR_mremap,
    241              old_addr, old_len, new_len,
    242              VKI_MREMAP_MAYMOVE|VKI_MREMAP_FIXED/*move-or-fail*/,
    243              new_addr
    244           );
    245 #  else
    246 #    error Unknown OS
    247 #  endif
    248 }
    249 
    250 #endif
    251 
    252 /* --- Pertaining to files --- */
    253 
    254 SysRes ML_(am_open) ( const HChar* pathname, Int flags, Int mode )
    255 {
    256 #  if defined(VGP_arm64_linux)
    257    /* ARM64 wants to use __NR_openat rather than __NR_open. */
    258    SysRes res = VG_(do_syscall4)(__NR_openat,
    259                                  VKI_AT_FDCWD, (UWord)pathname, flags, mode);
    260 #  elif defined(VGO_linux) || defined(VGO_darwin)
    261    SysRes res = VG_(do_syscall3)(__NR_open, (UWord)pathname, flags, mode);
    262 #  elif defined(VGO_solaris)
    263    SysRes res = VG_(do_syscall4)(__NR_openat, VKI_AT_FDCWD, (UWord)pathname,
    264                                  flags, mode);
    265 #  else
    266 #    error Unknown OS
    267 #  endif
    268    return res;
    269 }
    270 
    271 Int ML_(am_read) ( Int fd, void* buf, Int count)
    272 {
    273    SysRes res = VG_(do_syscall3)(__NR_read, fd, (UWord)buf, count);
    274    return sr_isError(res) ? -1 : sr_Res(res);
    275 }
    276 
    277 void ML_(am_close) ( Int fd )
    278 {
    279    (void)VG_(do_syscall1)(__NR_close, fd);
    280 }
    281 
    282 Int ML_(am_readlink)(const HChar* path, HChar* buf, UInt bufsiz)
    283 {
    284    SysRes res;
    285 #  if defined(VGP_arm64_linux)
    286    res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD,
    287                                            (UWord)path, (UWord)buf, bufsiz);
    288 #  elif defined(VGO_linux) || defined(VGO_darwin)
    289    res = VG_(do_syscall3)(__NR_readlink, (UWord)path, (UWord)buf, bufsiz);
    290 #  elif defined(VGO_solaris)
    291    res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD, (UWord)path,
    292                           (UWord)buf, bufsiz);
    293 #  else
    294 #    error Unknown OS
    295 #  endif
    296    return sr_isError(res) ? -1 : sr_Res(res);
    297 }
    298 
    299 Int ML_(am_fcntl) ( Int fd, Int cmd, Addr arg )
    300 {
    301 #  if defined(VGO_linux) || defined(VGO_solaris)
    302    SysRes res = VG_(do_syscall3)(__NR_fcntl, fd, cmd, arg);
    303 #  elif defined(VGO_darwin)
    304    SysRes res = VG_(do_syscall3)(__NR_fcntl_nocancel, fd, cmd, arg);
    305 #  else
    306 #  error "Unknown OS"
    307 #  endif
    308    return sr_isError(res) ? -1 : sr_Res(res);
    309 }
    310 
    311 /* Get the dev, inode and mode info for a file descriptor, if
    312    possible.  Returns True on success. */
    313 Bool ML_(am_get_fd_d_i_m)( Int fd,
    314                            /*OUT*/ULong* dev,
    315                            /*OUT*/ULong* ino, /*OUT*/UInt* mode )
    316 {
    317 #  if defined(VGO_linux) || defined(VGO_darwin)
    318    SysRes          res;
    319    struct vki_stat buf;
    320 #  if defined(VGO_linux) && defined(__NR_fstat64)
    321    /* Try fstat64 first as it can cope with minor and major device
    322       numbers outside the 0-255 range and it works properly for x86
    323       binaries on amd64 systems where fstat seems to be broken. */
    324    struct vki_stat64 buf64;
    325    res = VG_(do_syscall2)(__NR_fstat64, fd, (UWord)&buf64);
    326    if (!sr_isError(res)) {
    327       *dev  = (ULong)buf64.st_dev;
    328       *ino  = (ULong)buf64.st_ino;
    329       *mode = (UInt) buf64.st_mode;
    330       return True;
    331    }
    332 #  endif
    333    res = VG_(do_syscall2)(__NR_fstat, fd, (UWord)&buf);
    334    if (!sr_isError(res)) {
    335       *dev  = (ULong)buf.st_dev;
    336       *ino  = (ULong)buf.st_ino;
    337       *mode = (UInt) buf.st_mode;
    338       return True;
    339    }
    340    return False;
    341 #  elif defined(VGO_solaris)
    342 #  if defined(VGP_x86_solaris)
    343    struct vki_stat64 buf64;
    344    SysRes res = VG_(do_syscall4)(__NR_fstatat64, fd, 0, (UWord)&buf64, 0);
    345 #  elif defined(VGP_amd64_solaris)
    346    struct vki_stat buf64;
    347    SysRes res = VG_(do_syscall4)(__NR_fstatat, fd, 0, (UWord)&buf64, 0);
    348 #  else
    349 #    error "Unknown platform"
    350 #  endif
    351    if (!sr_isError(res)) {
    352       *dev  = (ULong)buf64.st_dev;
    353       *ino  = (ULong)buf64.st_ino;
    354       *mode = (UInt) buf64.st_mode;
    355       return True;
    356    }
    357    return False;
    358 #  else
    359 #    error Unknown OS
    360 #  endif
    361 }
    362 
    363 Bool ML_(am_resolve_filename) ( Int fd, /*OUT*/HChar* buf, Int nbuf )
    364 {
    365 #if defined(VGO_linux)
    366    Int i;
    367    HChar tmp[64];    // large enough
    368    for (i = 0; i < nbuf; i++) buf[i] = 0;
    369    ML_(am_sprintf)(tmp, "/proc/self/fd/%d", fd);
    370    if (ML_(am_readlink)(tmp, buf, nbuf) > 0 && buf[0] == '/')
    371       return True;
    372    else
    373       return False;
    374 
    375 #elif defined(VGO_darwin)
    376    HChar tmp[VKI_MAXPATHLEN+1];
    377    if (0 == ML_(am_fcntl)(fd, VKI_F_GETPATH, (UWord)tmp)) {
    378       if (nbuf > 0) {
    379          VG_(strncpy)( buf, tmp, nbuf < sizeof(tmp) ? nbuf : sizeof(tmp) );
    380          buf[nbuf-1] = 0;
    381       }
    382       if (tmp[0] == '/') return True;
    383    }
    384    return False;
    385 
    386 #elif defined(VGO_solaris)
    387    Int i;
    388    HChar tmp[64];
    389    for (i = 0; i < nbuf; i++) buf[i] = 0;
    390    ML_(am_sprintf)(tmp, "/proc/self/path/%d", fd);
    391    if (ML_(am_readlink)(tmp, buf, nbuf) > 0 && buf[0] == '/')
    392       return True;
    393    else
    394       return False;
    395 
    396 #  else
    397 #     error Unknown OS
    398 #  endif
    399 }
    400 
    401 
    402 
    403 
    404 /*-----------------------------------------------------------------*/
    405 /*---                                                           ---*/
    406 /*--- Manage stacks for Valgrind itself.                        ---*/
    407 /*---                                                           ---*/
    408 /*-----------------------------------------------------------------*/
    409 struct _VgStack {
    410    HChar bytes[1];
    411    // We use a fake size of 1. A bigger size is allocated
    412    // by VG_(am_alloc_VgStack).
    413 };
    414 
    415 /* Allocate and initialise a VgStack (anonymous valgrind space).
    416    Protect the stack active area and the guard areas appropriately.
    417    Returns NULL on failure, else the address of the bottom of the
    418    stack.  On success, also sets *initial_sp to what the stack pointer
    419    should be set to. */
    420 
    421 VgStack* VG_(am_alloc_VgStack)( /*OUT*/Addr* initial_sp )
    422 {
    423    Int      szB;
    424    SysRes   sres;
    425    VgStack* stack;
    426    UInt*    p;
    427    Int      i;
    428 
    429    /* Allocate the stack. */
    430    szB = VG_STACK_GUARD_SZB
    431          + VG_(clo_valgrind_stacksize) + VG_STACK_GUARD_SZB;
    432 
    433    sres = VG_(am_mmap_anon_float_valgrind)( szB );
    434    if (sr_isError(sres))
    435       return NULL;
    436 
    437    stack = (VgStack*)(Addr)sr_Res(sres);
    438 
    439    aspacem_assert(VG_IS_PAGE_ALIGNED(szB));
    440    aspacem_assert(VG_IS_PAGE_ALIGNED(stack));
    441 
    442    /* Protect the guard areas. */
    443    sres = local_do_mprotect_NO_NOTIFY(
    444              (Addr) &stack[0],
    445              VG_STACK_GUARD_SZB, VKI_PROT_NONE
    446           );
    447    if (sr_isError(sres)) goto protect_failed;
    448    VG_(am_notify_mprotect)(
    449       (Addr) &stack->bytes[0],
    450       VG_STACK_GUARD_SZB, VKI_PROT_NONE
    451    );
    452 
    453    sres = local_do_mprotect_NO_NOTIFY(
    454              (Addr) &stack->bytes[VG_STACK_GUARD_SZB + VG_(clo_valgrind_stacksize)],
    455              VG_STACK_GUARD_SZB, VKI_PROT_NONE
    456           );
    457    if (sr_isError(sres)) goto protect_failed;
    458    VG_(am_notify_mprotect)(
    459       (Addr) &stack->bytes[VG_STACK_GUARD_SZB + VG_(clo_valgrind_stacksize)],
    460       VG_STACK_GUARD_SZB, VKI_PROT_NONE
    461    );
    462 
    463    /* Looks good.  Fill the active area with junk so we can later
    464       tell how much got used. */
    465 
    466    p = (UInt*)&stack->bytes[VG_STACK_GUARD_SZB];
    467    for (i = 0; i < VG_(clo_valgrind_stacksize)/sizeof(UInt); i++)
    468       p[i] = 0xDEADBEEF;
    469 
    470    *initial_sp = (Addr)&stack->bytes[VG_STACK_GUARD_SZB + VG_(clo_valgrind_stacksize)];
    471    *initial_sp -= 8;
    472    *initial_sp &= ~((Addr)0x1F); /* 32-align it */
    473 
    474    VG_(debugLog)( 1,"aspacem",
    475                   "allocated valgrind thread stack at 0x%llx size %d\n",
    476                   (ULong)(Addr)stack, szB);
    477    ML_(am_do_sanity_check)();
    478    return stack;
    479 
    480   protect_failed:
    481    /* The stack was allocated, but we can't protect it.  Unmap it and
    482       return NULL (failure). */
    483    (void)ML_(am_do_munmap_NO_NOTIFY)( (Addr)stack, szB );
    484    ML_(am_do_sanity_check)();
    485    return NULL;
    486 }
    487 
    488 
    489 /* Figure out how many bytes of the stack's active area have not
    490    been used.  Used for estimating if we are close to overflowing it. */
    491 
    492 SizeT VG_(am_get_VgStack_unused_szB)( const VgStack* stack, SizeT limit )
    493 {
    494    SizeT i;
    495    const UInt* p;
    496 
    497    p = (const UInt*)&stack->bytes[VG_STACK_GUARD_SZB];
    498    for (i = 0; i < VG_(clo_valgrind_stacksize)/sizeof(UInt); i++) {
    499       if (p[i] != 0xDEADBEEF)
    500          break;
    501       if (i * sizeof(UInt) >= limit)
    502          break;
    503    }
    504 
    505    return i * sizeof(UInt);
    506 }
    507 
    508 
    509 /*--------------------------------------------------------------------*/
    510 /*--- end                                                          ---*/
    511 /*--------------------------------------------------------------------*/
    512