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@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)) 55void ML_(am_exit)( Int status ) 56{ 57 VG_(exit_now) (status); 58} 59 60void 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 67void 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 76void 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 89Int 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 101static 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 107static 108UInt 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 121UInt 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_. */ 143SysRes 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 195static 196SysRes 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 201SysRes 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 209SysRes 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 230SysRes 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 255SysRes 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 275Int 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 281void ML_(am_close) ( Int fd ) 282{ 283 (void)VG_(do_syscall1)(__NR_close, fd); 284} 285 286Int 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 306Int 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. */ 320Bool 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 370Bool 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/*-----------------------------------------------------------------*/ 416struct _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 428VgStack* 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 499SizeT 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