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@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   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
194static
195SysRes 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
200SysRes 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
208SysRes 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
229SysRes 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
254SysRes 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
271Int 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
277void ML_(am_close) ( Int fd )
278{
279   (void)VG_(do_syscall1)(__NR_close, fd);
280}
281
282Int 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
299Int 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. */
313Bool 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
363Bool 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/*-----------------------------------------------------------------*/
409struct _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
421VgStack* 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
492SizeT 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