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