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-2010 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))
ML_(am_exit)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
ML_(am_barf)67 void ML_(am_barf) ( 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
ML_(am_barf_toolow)74 void ML_(am_barf_toolow) ( 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
ML_(am_assert_fail)83 void ML_(am_assert_fail)( const HChar* expr,
84 const Char* file,
85 Int line,
86 const Char* 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
ML_(am_getpid)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
local_add_to_aspacem_sprintf_buf(HChar c,void * p)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
local_vsprintf(HChar * buf,const HChar * format,va_list vargs)115 UInt local_vsprintf ( HChar* buf, const HChar *format, va_list vargs )
116 {
117 Int ret;
118 Char *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
ML_(am_sprintf)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 ANY aspacem-internal DATA
144 // STRUCTURES (SEGMENT LISTS). 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_. */
VG_(am_do_mmap_NO_NOTIFY)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 # if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
156 || defined(VGP_arm_linux)
157 /* mmap2 uses 4096 chunks even if actual page size is bigger. */
158 aspacem_assert((offset % 4096) == 0);
159 res = VG_(do_syscall6)(__NR_mmap2, (UWord)start, length,
160 prot, flags, fd, offset / 4096);
161 # elif defined(VGP_amd64_linux) || defined(VGP_ppc64_linux) \
162 || defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
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 # else
178 # error Unknown platform
179 # endif
180 return res;
181 }
182
183 static
local_do_mprotect_NO_NOTIFY(Addr start,SizeT length,UInt prot)184 SysRes local_do_mprotect_NO_NOTIFY(Addr start, SizeT length, UInt prot)
185 {
186 return VG_(do_syscall3)(__NR_mprotect, (UWord)start, length, prot );
187 }
188
ML_(am_do_munmap_NO_NOTIFY)189 SysRes ML_(am_do_munmap_NO_NOTIFY)(Addr start, SizeT length)
190 {
191 return VG_(do_syscall2)(__NR_munmap, (UWord)start, length );
192 }
193
194 #if HAVE_MREMAP
195 /* The following are used only to implement mremap(). */
196
ML_(am_do_extend_mapping_NO_NOTIFY)197 SysRes ML_(am_do_extend_mapping_NO_NOTIFY)(
198 Addr old_addr,
199 SizeT old_len,
200 SizeT new_len
201 )
202 {
203 /* Extend the mapping old_addr .. old_addr+old_len-1 to have length
204 new_len, WITHOUT moving it. If it can't be extended in place,
205 fail. */
206 # if defined(VGO_linux)
207 return VG_(do_syscall5)(
208 __NR_mremap,
209 old_addr, old_len, new_len,
210 0/*flags, meaning: must be at old_addr, else FAIL */,
211 0/*new_addr, is ignored*/
212 );
213 # elif defined(VGO_aix5)
214 ML_(am_barf)("ML_(am_do_extend_mapping_NO_NOTIFY) on AIX5");
215 /* NOTREACHED, but gcc doesn't understand that */
216 return VG_(mk_SysRes_Error)(0);
217 # else
218 # error Unknown OS
219 # endif
220 }
221
ML_(am_do_relocate_nooverlap_mapping_NO_NOTIFY)222 SysRes ML_(am_do_relocate_nooverlap_mapping_NO_NOTIFY)(
223 Addr old_addr, Addr old_len,
224 Addr new_addr, Addr new_len
225 )
226 {
227 /* Move the mapping old_addr .. old_addr+old_len-1 to the new
228 location and with the new length. Only needs to handle the case
229 where the two areas do not overlap, neither length is zero, and
230 all args are page aligned. */
231 # if defined(VGO_linux)
232 return VG_(do_syscall5)(
233 __NR_mremap,
234 old_addr, old_len, new_len,
235 VKI_MREMAP_MAYMOVE|VKI_MREMAP_FIXED/*move-or-fail*/,
236 new_addr
237 );
238 # elif defined(VGO_aix5)
239 ML_(am_barf)("ML_(am_do_relocate_nooverlap_mapping_NO_NOTIFY) on AIX5");
240 /* NOTREACHED, but gcc doesn't understand that */
241 return VG_(mk_SysRes_Error)(0);
242 # else
243 # error Unknown OS
244 # endif
245 }
246
247 #endif
248
249 /* --- Pertaining to files --- */
250
ML_(am_open)251 SysRes ML_(am_open) ( const Char* pathname, Int flags, Int mode )
252 {
253 SysRes res = VG_(do_syscall3)(__NR_open, (UWord)pathname, flags, mode);
254 return res;
255 }
256
ML_(am_read)257 Int ML_(am_read) ( Int fd, void* buf, Int count)
258 {
259 SysRes res = VG_(do_syscall3)(__NR_read, fd, (UWord)buf, count);
260 return sr_isError(res) ? -1 : sr_Res(res);
261 }
262
ML_(am_close)263 void ML_(am_close) ( Int fd )
264 {
265 (void)VG_(do_syscall1)(__NR_close, fd);
266 }
267
ML_(am_readlink)268 Int ML_(am_readlink)(HChar* path, HChar* buf, UInt bufsiz)
269 {
270 SysRes res;
271 res = VG_(do_syscall3)(__NR_readlink, (UWord)path, (UWord)buf, bufsiz);
272 return sr_isError(res) ? -1 : sr_Res(res);
273 }
274
ML_(am_fcntl)275 Int ML_(am_fcntl) ( Int fd, Int cmd, Addr arg )
276 {
277 # if defined(VGO_linux) || defined(VGO_aix5)
278 SysRes res = VG_(do_syscall3)(__NR_fcntl, fd, cmd, arg);
279 # elif defined(VGO_darwin)
280 SysRes res = VG_(do_syscall3)(__NR_fcntl_nocancel, fd, cmd, arg);
281 # else
282 # error "Unknown OS"
283 # endif
284 return sr_isError(res) ? -1 : sr_Res(res);
285 }
286
287 /* Get the dev, inode and mode info for a file descriptor, if
288 possible. Returns True on success. */
ML_(am_get_fd_d_i_m)289 Bool ML_(am_get_fd_d_i_m)( Int fd,
290 /*OUT*/ULong* dev,
291 /*OUT*/ULong* ino, /*OUT*/UInt* mode )
292 {
293 SysRes res;
294 struct vki_stat buf;
295 # if defined(VGO_linux) && defined(__NR_fstat64)
296 /* Try fstat64 first as it can cope with minor and major device
297 numbers outside the 0-255 range and it works properly for x86
298 binaries on amd64 systems where fstat seems to be broken. */
299 struct vki_stat64 buf64;
300 res = VG_(do_syscall2)(__NR_fstat64, fd, (UWord)&buf64);
301 if (!sr_isError(res)) {
302 *dev = (ULong)buf64.st_dev;
303 *ino = (ULong)buf64.st_ino;
304 *mode = (UInt) buf64.st_mode;
305 return True;
306 }
307 # endif
308 res = VG_(do_syscall2)(__NR_fstat, fd, (UWord)&buf);
309 if (!sr_isError(res)) {
310 *dev = (ULong)buf.st_dev;
311 *ino = (ULong)buf.st_ino;
312 *mode = (UInt) buf.st_mode;
313 return True;
314 }
315 return False;
316 }
317
ML_(am_resolve_filename)318 Bool ML_(am_resolve_filename) ( Int fd, /*OUT*/HChar* buf, Int nbuf )
319 {
320 #if defined(VGO_linux)
321 Int i;
322 HChar tmp[64];
323 for (i = 0; i < nbuf; i++) buf[i] = 0;
324 ML_(am_sprintf)(tmp, "/proc/self/fd/%d", fd);
325 if (ML_(am_readlink)(tmp, buf, nbuf) > 0 && buf[0] == '/')
326 return True;
327 else
328 return False;
329
330 #elif defined(VGO_aix5)
331 I_die_here; /* maybe just return False? */
332 return False;
333
334 #elif defined(VGO_darwin)
335 HChar tmp[VKI_MAXPATHLEN+1];
336 if (0 == ML_(am_fcntl)(fd, VKI_F_GETPATH, (UWord)tmp)) {
337 if (nbuf > 0) {
338 VG_(strncpy)( buf, tmp, nbuf < sizeof(tmp) ? nbuf : sizeof(tmp) );
339 buf[nbuf-1] = 0;
340 }
341 if (tmp[0] == '/') return True;
342 }
343 return False;
344
345 # else
346 # error Unknown OS
347 # endif
348 }
349
350
351
352
353 /*-----------------------------------------------------------------*/
354 /*--- ---*/
355 /*--- Manage stacks for Valgrind itself. ---*/
356 /*--- ---*/
357 /*-----------------------------------------------------------------*/
358
359 /* Allocate and initialise a VgStack (anonymous valgrind space).
360 Protect the stack active area and the guard areas appropriately.
361 Returns NULL on failure, else the address of the bottom of the
362 stack. On success, also sets *initial_sp to what the stack pointer
363 should be set to. */
364
VG_(am_alloc_VgStack)365 VgStack* VG_(am_alloc_VgStack)( /*OUT*/Addr* initial_sp )
366 {
367 Int szB;
368 SysRes sres;
369 VgStack* stack;
370 UInt* p;
371 Int i;
372
373 /* Allocate the stack. */
374 szB = VG_STACK_GUARD_SZB
375 + VG_STACK_ACTIVE_SZB + VG_STACK_GUARD_SZB;
376
377 sres = VG_(am_mmap_anon_float_valgrind)( szB );
378 if (sr_isError(sres))
379 return NULL;
380
381 stack = (VgStack*)(AddrH)sr_Res(sres);
382
383 aspacem_assert(VG_IS_PAGE_ALIGNED(szB));
384 aspacem_assert(VG_IS_PAGE_ALIGNED(stack));
385
386 /* Protect the guard areas. */
387 sres = local_do_mprotect_NO_NOTIFY(
388 (Addr) &stack[0],
389 VG_STACK_GUARD_SZB, VKI_PROT_NONE
390 );
391 if (sr_isError(sres)) goto protect_failed;
392 VG_(am_notify_mprotect)(
393 (Addr) &stack->bytes[0],
394 VG_STACK_GUARD_SZB, VKI_PROT_NONE
395 );
396
397 sres = local_do_mprotect_NO_NOTIFY(
398 (Addr) &stack->bytes[VG_STACK_GUARD_SZB + VG_STACK_ACTIVE_SZB],
399 VG_STACK_GUARD_SZB, VKI_PROT_NONE
400 );
401 if (sr_isError(sres)) goto protect_failed;
402 VG_(am_notify_mprotect)(
403 (Addr) &stack->bytes[VG_STACK_GUARD_SZB + VG_STACK_ACTIVE_SZB],
404 VG_STACK_GUARD_SZB, VKI_PROT_NONE
405 );
406
407 /* Looks good. Fill the active area with junk so we can later
408 tell how much got used. */
409
410 p = (UInt*)&stack->bytes[VG_STACK_GUARD_SZB];
411 for (i = 0; i < VG_STACK_ACTIVE_SZB/sizeof(UInt); i++)
412 p[i] = 0xDEADBEEF;
413
414 *initial_sp = (Addr)&stack->bytes[VG_STACK_GUARD_SZB + VG_STACK_ACTIVE_SZB];
415 *initial_sp -= 8;
416 *initial_sp &= ~((Addr)0x1F); /* 32-align it */
417
418 VG_(debugLog)( 1,"aspacem","allocated thread stack at 0x%llx size %d\n",
419 (ULong)(Addr)stack, szB);
420 ML_(am_do_sanity_check)();
421 return stack;
422
423 protect_failed:
424 /* The stack was allocated, but we can't protect it. Unmap it and
425 return NULL (failure). */
426 (void)ML_(am_do_munmap_NO_NOTIFY)( (Addr)stack, szB );
427 ML_(am_do_sanity_check)();
428 return NULL;
429 }
430
431
432 /* Figure out how many bytes of the stack's active area have not
433 been used. Used for estimating if we are close to overflowing it. */
434
VG_(am_get_VgStack_unused_szB)435 SizeT VG_(am_get_VgStack_unused_szB)( VgStack* stack, SizeT limit )
436 {
437 SizeT i;
438 UInt* p;
439
440 p = (UInt*)&stack->bytes[VG_STACK_GUARD_SZB];
441 for (i = 0; i < VG_STACK_ACTIVE_SZB/sizeof(UInt); i++) {
442 if (p[i] != 0xDEADBEEF)
443 break;
444 if (i * sizeof(UInt) >= limit)
445 break;
446 }
447
448 return i * sizeof(UInt);
449 }
450
451
452 /*--------------------------------------------------------------------*/
453 /*--- end ---*/
454 /*--------------------------------------------------------------------*/
455