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