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-2013 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 #  if defined(VGO_linux)
     58    (void)VG_(do_syscall1)(__NR_exit_group, status);
     59 #  endif
     60    (void)VG_(do_syscall1)(__NR_exit, status);
     61    /* Why are we still alive here? */
     62    /*NOTREACHED*/
     63    *(volatile Int *)0 = 'x';
     64    aspacem_assert(2+2 == 5);
     65 }
     66 
     67 void ML_(am_barf) ( const HChar* what )
     68 {
     69    VG_(debugLog)(0, "aspacem", "Valgrind: FATAL: %s\n", what);
     70    VG_(debugLog)(0, "aspacem", "Exiting now.\n");
     71    ML_(am_exit)(1);
     72 }
     73 
     74 void ML_(am_barf_toolow) ( const HChar* what )
     75 {
     76    VG_(debugLog)(0, "aspacem",
     77                     "Valgrind: FATAL: %s is too low.\n", what);
     78    VG_(debugLog)(0, "aspacem", "  Increase it and rebuild.  "
     79                                "Exiting now.\n");
     80    ML_(am_exit)(1);
     81 }
     82 
     83 void ML_(am_assert_fail)( const HChar* expr,
     84                           const HChar* file,
     85                           Int line,
     86                           const HChar* fn )
     87 {
     88    VG_(debugLog)(0, "aspacem",
     89                     "Valgrind: FATAL: aspacem assertion failed:\n");
     90    VG_(debugLog)(0, "aspacem", "  %s\n", expr);
     91    VG_(debugLog)(0, "aspacem", "  at %s:%d (%s)\n", file,line,fn);
     92    VG_(debugLog)(0, "aspacem", "Exiting now.\n");
     93    ML_(am_exit)(1);
     94 }
     95 
     96 Int ML_(am_getpid)( void )
     97 {
     98    SysRes sres = VG_(do_syscall0)(__NR_getpid);
     99    aspacem_assert(!sr_isError(sres));
    100    return sr_Res(sres);
    101 }
    102 
    103 
    104 //--------------------------------------------------------------
    105 // A simple sprintf implementation, so as to avoid dependence on
    106 // m_libcprint.
    107 
    108 static void local_add_to_aspacem_sprintf_buf ( HChar c, void *p )
    109 {
    110    HChar** aspacem_sprintf_ptr = p;
    111    *(*aspacem_sprintf_ptr)++ = c;
    112 }
    113 
    114 static
    115 UInt local_vsprintf ( HChar* buf, const HChar *format, va_list vargs )
    116 {
    117    Int ret;
    118    HChar *aspacem_sprintf_ptr = buf;
    119 
    120    ret = VG_(debugLog_vprintf)
    121             ( local_add_to_aspacem_sprintf_buf,
    122               &aspacem_sprintf_ptr, format, vargs );
    123    local_add_to_aspacem_sprintf_buf('\0', &aspacem_sprintf_ptr);
    124 
    125    return ret;
    126 }
    127 
    128 UInt ML_(am_sprintf) ( HChar* buf, const HChar *format, ... )
    129 {
    130    UInt ret;
    131    va_list vargs;
    132 
    133    va_start(vargs,format);
    134    ret = local_vsprintf(buf, format, vargs);
    135    va_end(vargs);
    136 
    137    return ret;
    138 }
    139 
    140 
    141 //--------------------------------------------------------------
    142 // Direct access to a handful of syscalls.  This avoids dependence on
    143 // m_libc*.  THESE DO NOT UPDATE THE aspacem-internal DATA
    144 // STRUCTURES (SEGMENT ARRAY).  DO NOT USE THEM UNLESS YOU KNOW WHAT
    145 // YOU ARE DOING.
    146 
    147 /* --- Pertaining to mappings --- */
    148 
    149 /* Note: this is VG_, not ML_. */
    150 SysRes VG_(am_do_mmap_NO_NOTIFY)( Addr start, SizeT length, UInt prot,
    151                                   UInt flags, Int fd, Off64T offset)
    152 {
    153    SysRes res;
    154    aspacem_assert(VG_IS_PAGE_ALIGNED(offset));
    155 
    156 #  if defined(VGP_arm64_linux)
    157    res = VG_(do_syscall6)(__NR3264_mmap, (UWord)start, length,
    158                          prot, flags, fd, offset);
    159 #  elif defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
    160         || defined(VGP_arm_linux)
    161    /* mmap2 uses 4096 chunks even if actual page size is bigger. */
    162    aspacem_assert((offset % 4096) == 0);
    163    res = VG_(do_syscall6)(__NR_mmap2, (UWord)start, length,
    164                           prot, flags, fd, offset / 4096);
    165 #  elif defined(VGP_amd64_linux) || defined(VGP_ppc64_linux) \
    166         || defined(VGP_s390x_linux) || defined(VGP_mips32_linux) \
    167         || defined(VGP_mips64_linux) || defined(VGP_arm64_linux)
    168    res = VG_(do_syscall6)(__NR_mmap, (UWord)start, length,
    169                          prot, flags, fd, offset);
    170 #  elif defined(VGP_x86_darwin)
    171    if (fd == 0  &&  (flags & VKI_MAP_ANONYMOUS)) {
    172        fd = -1;  // MAP_ANON with fd==0 is EINVAL
    173    }
    174    res = VG_(do_syscall7)(__NR_mmap, (UWord)start, length,
    175                           prot, flags, fd, offset & 0xffffffff, offset >> 32);
    176 #  elif defined(VGP_amd64_darwin)
    177    if (fd == 0  &&  (flags & VKI_MAP_ANONYMOUS)) {
    178        fd = -1;  // MAP_ANON with fd==0 is EINVAL
    179    }
    180    res = VG_(do_syscall6)(__NR_mmap, (UWord)start, length,
    181                           prot, flags, (UInt)fd, offset);
    182 #  else
    183 #    error Unknown platform
    184 #  endif
    185    return res;
    186 }
    187 
    188 static
    189 SysRes local_do_mprotect_NO_NOTIFY(Addr start, SizeT length, UInt prot)
    190 {
    191    return VG_(do_syscall3)(__NR_mprotect, (UWord)start, length, prot );
    192 }
    193 
    194 SysRes ML_(am_do_munmap_NO_NOTIFY)(Addr start, SizeT length)
    195 {
    196    return VG_(do_syscall2)(__NR_munmap, (UWord)start, length );
    197 }
    198 
    199 #if HAVE_MREMAP
    200 /* The following are used only to implement mremap(). */
    201 
    202 SysRes ML_(am_do_extend_mapping_NO_NOTIFY)(
    203           Addr  old_addr,
    204           SizeT old_len,
    205           SizeT new_len
    206        )
    207 {
    208    /* Extend the mapping old_addr .. old_addr+old_len-1 to have length
    209       new_len, WITHOUT moving it.  If it can't be extended in place,
    210       fail. */
    211 #  if defined(VGO_linux)
    212    return VG_(do_syscall5)(
    213              __NR_mremap,
    214              old_addr, old_len, new_len,
    215              0/*flags, meaning: must be at old_addr, else FAIL */,
    216              0/*new_addr, is ignored*/
    217           );
    218 #  else
    219 #    error Unknown OS
    220 #  endif
    221 }
    222 
    223 SysRes ML_(am_do_relocate_nooverlap_mapping_NO_NOTIFY)(
    224           Addr old_addr, Addr old_len,
    225           Addr new_addr, Addr new_len
    226        )
    227 {
    228    /* Move the mapping old_addr .. old_addr+old_len-1 to the new
    229       location and with the new length.  Only needs to handle the case
    230       where the two areas do not overlap, neither length is zero, and
    231       all args are page aligned. */
    232 #  if defined(VGO_linux)
    233    return VG_(do_syscall5)(
    234              __NR_mremap,
    235              old_addr, old_len, new_len,
    236              VKI_MREMAP_MAYMOVE|VKI_MREMAP_FIXED/*move-or-fail*/,
    237              new_addr
    238           );
    239 #  else
    240 #    error Unknown OS
    241 #  endif
    242 }
    243 
    244 #endif
    245 
    246 /* --- Pertaining to files --- */
    247 
    248 SysRes ML_(am_open) ( const HChar* pathname, Int flags, Int mode )
    249 {
    250 #  if defined(VGP_arm64_linux)
    251    /* ARM64 wants to use __NR_openat rather than __NR_open. */
    252    SysRes res = VG_(do_syscall4)(__NR_openat,
    253                                  VKI_AT_FDCWD, (UWord)pathname, flags, mode);
    254 #  else
    255    SysRes res = VG_(do_syscall3)(__NR_open, (UWord)pathname, flags, mode);
    256 #  endif
    257    return res;
    258 }
    259 
    260 Int ML_(am_read) ( Int fd, void* buf, Int count)
    261 {
    262    SysRes res = VG_(do_syscall3)(__NR_read, fd, (UWord)buf, count);
    263    return sr_isError(res) ? -1 : sr_Res(res);
    264 }
    265 
    266 void ML_(am_close) ( Int fd )
    267 {
    268    (void)VG_(do_syscall1)(__NR_close, fd);
    269 }
    270 
    271 Int ML_(am_readlink)(HChar* path, HChar* buf, UInt bufsiz)
    272 {
    273    SysRes res;
    274 #  if defined(VGP_arm64_linux)
    275    res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD,
    276                                            (UWord)path, (UWord)buf, bufsiz);
    277 #  else
    278    res = VG_(do_syscall3)(__NR_readlink, (UWord)path, (UWord)buf, bufsiz);
    279 #  endif
    280    return sr_isError(res) ? -1 : sr_Res(res);
    281 }
    282 
    283 Int ML_(am_fcntl) ( Int fd, Int cmd, Addr arg )
    284 {
    285 #  if defined(VGO_linux)
    286    SysRes res = VG_(do_syscall3)(__NR_fcntl, fd, cmd, arg);
    287 #  elif defined(VGO_darwin)
    288    SysRes res = VG_(do_syscall3)(__NR_fcntl_nocancel, fd, cmd, arg);
    289 #  else
    290 #  error "Unknown OS"
    291 #  endif
    292    return sr_isError(res) ? -1 : sr_Res(res);
    293 }
    294 
    295 /* Get the dev, inode and mode info for a file descriptor, if
    296    possible.  Returns True on success. */
    297 Bool ML_(am_get_fd_d_i_m)( Int fd,
    298                            /*OUT*/ULong* dev,
    299                            /*OUT*/ULong* ino, /*OUT*/UInt* mode )
    300 {
    301    SysRes          res;
    302    struct vki_stat buf;
    303 #  if defined(VGO_linux) && defined(__NR_fstat64)
    304    /* Try fstat64 first as it can cope with minor and major device
    305       numbers outside the 0-255 range and it works properly for x86
    306       binaries on amd64 systems where fstat seems to be broken. */
    307    struct vki_stat64 buf64;
    308    res = VG_(do_syscall2)(__NR_fstat64, fd, (UWord)&buf64);
    309    if (!sr_isError(res)) {
    310       *dev  = (ULong)buf64.st_dev;
    311       *ino  = (ULong)buf64.st_ino;
    312       *mode = (UInt) buf64.st_mode;
    313       return True;
    314    }
    315 #  endif
    316    res = VG_(do_syscall2)(__NR_fstat, fd, (UWord)&buf);
    317    if (!sr_isError(res)) {
    318       *dev  = (ULong)buf.st_dev;
    319       *ino  = (ULong)buf.st_ino;
    320       *mode = (UInt) buf.st_mode;
    321       return True;
    322    }
    323    return False;
    324 }
    325 
    326 Bool ML_(am_resolve_filename) ( Int fd, /*OUT*/HChar* buf, Int nbuf )
    327 {
    328 #if defined(VGO_linux)
    329    Int i;
    330    HChar tmp[64];
    331    for (i = 0; i < nbuf; i++) buf[i] = 0;
    332    ML_(am_sprintf)(tmp, "/proc/self/fd/%d", fd);
    333    if (ML_(am_readlink)(tmp, buf, nbuf) > 0 && buf[0] == '/')
    334       return True;
    335    else
    336       return False;
    337 
    338 #elif defined(VGO_darwin)
    339    HChar tmp[VKI_MAXPATHLEN+1];
    340    if (0 == ML_(am_fcntl)(fd, VKI_F_GETPATH, (UWord)tmp)) {
    341       if (nbuf > 0) {
    342          VG_(strncpy)( buf, tmp, nbuf < sizeof(tmp) ? nbuf : sizeof(tmp) );
    343          buf[nbuf-1] = 0;
    344       }
    345       if (tmp[0] == '/') return True;
    346    }
    347    return False;
    348 
    349 #  else
    350 #     error Unknown OS
    351 #  endif
    352 }
    353 
    354 
    355 
    356 
    357 /*-----------------------------------------------------------------*/
    358 /*---                                                           ---*/
    359 /*--- Manage stacks for Valgrind itself.                        ---*/
    360 /*---                                                           ---*/
    361 /*-----------------------------------------------------------------*/
    362 
    363 /* Allocate and initialise a VgStack (anonymous valgrind space).
    364    Protect the stack active area and the guard areas appropriately.
    365    Returns NULL on failure, else the address of the bottom of the
    366    stack.  On success, also sets *initial_sp to what the stack pointer
    367    should be set to. */
    368 
    369 VgStack* VG_(am_alloc_VgStack)( /*OUT*/Addr* initial_sp )
    370 {
    371    Int      szB;
    372    SysRes   sres;
    373    VgStack* stack;
    374    UInt*    p;
    375    Int      i;
    376 
    377    /* Allocate the stack. */
    378    szB = VG_STACK_GUARD_SZB
    379          + VG_STACK_ACTIVE_SZB + VG_STACK_GUARD_SZB;
    380 
    381    sres = VG_(am_mmap_anon_float_valgrind)( szB );
    382    if (sr_isError(sres))
    383       return NULL;
    384 
    385    stack = (VgStack*)(AddrH)sr_Res(sres);
    386 
    387    aspacem_assert(VG_IS_PAGE_ALIGNED(szB));
    388    aspacem_assert(VG_IS_PAGE_ALIGNED(stack));
    389 
    390    /* Protect the guard areas. */
    391    sres = local_do_mprotect_NO_NOTIFY(
    392              (Addr) &stack[0],
    393              VG_STACK_GUARD_SZB, VKI_PROT_NONE
    394           );
    395    if (sr_isError(sres)) goto protect_failed;
    396    VG_(am_notify_mprotect)(
    397       (Addr) &stack->bytes[0],
    398       VG_STACK_GUARD_SZB, VKI_PROT_NONE
    399    );
    400 
    401    sres = local_do_mprotect_NO_NOTIFY(
    402              (Addr) &stack->bytes[VG_STACK_GUARD_SZB + VG_STACK_ACTIVE_SZB],
    403              VG_STACK_GUARD_SZB, VKI_PROT_NONE
    404           );
    405    if (sr_isError(sres)) goto protect_failed;
    406    VG_(am_notify_mprotect)(
    407       (Addr) &stack->bytes[VG_STACK_GUARD_SZB + VG_STACK_ACTIVE_SZB],
    408       VG_STACK_GUARD_SZB, VKI_PROT_NONE
    409    );
    410 
    411    /* Looks good.  Fill the active area with junk so we can later
    412       tell how much got used. */
    413 
    414    p = (UInt*)&stack->bytes[VG_STACK_GUARD_SZB];
    415    for (i = 0; i < VG_STACK_ACTIVE_SZB/sizeof(UInt); i++)
    416       p[i] = 0xDEADBEEF;
    417 
    418    *initial_sp = (Addr)&stack->bytes[VG_STACK_GUARD_SZB + VG_STACK_ACTIVE_SZB];
    419    *initial_sp -= 8;
    420    *initial_sp &= ~((Addr)0x1F); /* 32-align it */
    421 
    422    VG_(debugLog)( 1,"aspacem","allocated thread stack at 0x%llx size %d\n",
    423                   (ULong)(Addr)stack, szB);
    424    ML_(am_do_sanity_check)();
    425    return stack;
    426 
    427   protect_failed:
    428    /* The stack was allocated, but we can't protect it.  Unmap it and
    429       return NULL (failure). */
    430    (void)ML_(am_do_munmap_NO_NOTIFY)( (Addr)stack, szB );
    431    ML_(am_do_sanity_check)();
    432    return NULL;
    433 }
    434 
    435 
    436 /* Figure out how many bytes of the stack's active area have not
    437    been used.  Used for estimating if we are close to overflowing it. */
    438 
    439 SizeT VG_(am_get_VgStack_unused_szB)( VgStack* stack, SizeT limit )
    440 {
    441    SizeT i;
    442    UInt* p;
    443 
    444    p = (UInt*)&stack->bytes[VG_STACK_GUARD_SZB];
    445    for (i = 0; i < VG_STACK_ACTIVE_SZB/sizeof(UInt); i++) {
    446       if (p[i] != 0xDEADBEEF)
    447          break;
    448       if (i * sizeof(UInt) >= limit)
    449          break;
    450    }
    451 
    452    return i * sizeof(UInt);
    453 }
    454 
    455 
    456 /*--------------------------------------------------------------------*/
    457 /*--- end                                                          ---*/
    458 /*--------------------------------------------------------------------*/
    459