5 #include "../memcheck.h"
8 #include <sys/syscall.h>
10 typedef unsigned int UInt
;
11 typedef unsigned long UWord
;
12 typedef unsigned long long int ULong
;
14 // Below code is copied from m_syscall.c
15 // Refer to this file for syscall convention.
16 #if defined(VGP_x86_linux)
17 extern UWord
do_syscall_WRK (UWord syscall_no
,
18 UWord a1
, UWord a2
, UWord a3
,
19 UWord a4
, UWord a5
, UWord a6
23 ".globl do_syscall_WRK\n"
29 " movl 16+ 4(%esp),%eax\n"
30 " movl 16+ 8(%esp),%ebx\n"
31 " movl 16+12(%esp),%ecx\n"
32 " movl 16+16(%esp),%edx\n"
33 " movl 16+20(%esp),%esi\n"
34 " movl 16+24(%esp),%edi\n"
35 " movl 16+28(%esp),%ebp\n"
45 #elif defined(VGP_amd64_linux)
46 extern UWord
do_syscall_WRK (
48 UWord a1
, UWord a2
, UWord a3
,
49 UWord a4
, UWord a5
, UWord a6
53 ".globl do_syscall_WRK\n"
61 " movq 8(%rsp), %r9\n" /* last arg from stack */
67 #elif defined(VGP_ppc32_linux)
68 extern ULong
do_syscall_WRK (
70 UWord a1
, UWord a2
, UWord a3
,
71 UWord a4
, UWord a5
, UWord a6
75 ".globl do_syscall_WRK\n"
84 " sc\n" /* syscall: sets %cr0.so on error */
85 " mfcr 4\n" /* %cr -> low word of return var */
86 " rlwinm 4,4,4,31,31\n" /* rotate flag bit so to lsb, and mask it */
87 " blr\n" /* and return */
91 #elif defined(VGP_arm_linux)
92 extern UWord
do_syscall_WRK (
93 UWord a1
, UWord a2
, UWord a3
,
94 UWord a4
, UWord a5
, UWord a6
,
99 ".globl do_syscall_WRK\n"
112 #elif defined(VGP_arm64_linux)
113 extern UWord
do_syscall_WRK (
114 UWord a1
, UWord a2
, UWord a3
,
115 UWord a4
, UWord a5
, UWord a6
,
120 ".globl do_syscall_WRK\n"
130 #elif defined(VGP_s390x_linux)
131 UWord
do_syscall_WRK (
133 UWord arg1
, UWord arg2
, UWord arg3
,
134 UWord arg4
, UWord arg5
, UWord arg6
137 register UWord __arg1
asm("2") = arg1
;
138 register UWord __arg2
asm("3") = arg2
;
139 register UWord __arg3
asm("4") = arg3
;
140 register UWord __arg4
asm("5") = arg4
;
141 register UWord __arg5
asm("6") = arg5
;
142 register UWord __arg6
asm("7") = arg6
;
143 register ULong __svcres
asm("2");
145 __asm__
__volatile__ (
156 : "1", "cc", "memory");
158 return (UWord
) (__svcres
);
161 #elif defined(VGP_mips64_linux)
162 extern UWord
do_syscall_WRK (
164 UWord a1
, UWord a2
, UWord a3
,
165 UWord a4
, UWord a5
, UWord a6
169 __asm__
__volatile__ (
175 "move $8, %6\n\t" /* We use numbers because some compilers */
176 "move $9, %7\n\t" /* don't recognize $a4 and $a5 */
180 : "r"(syscall_no
), "r"(a1
), "r"(a2
), "r"(a3
),
181 "r"(a4
), "r"(a5
), "r"(a6
)
182 : "v0", "v1", "a0", "a1", "a2", "a3", "$8", "$9");
186 #elif defined(VGP_x86_solaris)
188 do_syscall_WRK(UWord a1
, UWord a2
, UWord a3
,
189 UWord a4
, UWord a5
, UWord a6
,
195 ".globl do_syscall_WRK\n"
197 " movl 40(%esp), %ecx\n" /* assume syscall success */
199 " movl 36(%esp), %eax\n"
201 " jnc 1f\n" /* jump if success */
202 " movl 40(%esp), %ecx\n" /* syscall failed - set *errflag */
208 #elif defined(VGP_amd64_solaris)
210 do_syscall_WRK(UWord a1
, UWord a2
, UWord a3
,
211 UWord a4
, UWord a5
, UWord a6
,
217 ".globl do_syscall_WRK\n"
219 " movq %rcx, %r10\n" /* pass rcx in r10 instead */
220 " movq 32(%rsp), %rcx\n" /* assume syscall success */
222 " movq 24(%rsp), %rax\n"
224 " jnc 1f\n" /* jump if success */
225 " movq 32(%rsp), %rcx\n" /* syscall failed - set *errflag */
231 #elif defined(VGP_x86_freebsd)
233 #define __NR_mprotect 74
235 /* Incoming args (syscall number + up to 8 args) are on the stack.
236 FreeBSD has a syscall called 'syscall' that takes all args (including
237 the syscall number) off the stack. Since we're called, the return
238 address is on the stack as expected, so we can just call syscall(2)
239 and it Just Works. Error is when carry is set.
241 extern ULong
do_syscall_WRK (
243 UWord a1
, UWord a2
, UWord a3
,
244 UWord a4
, UWord a5
, UWord a6
,
245 UWord a7
, UWord a8
, UInt
*flags
250 " movl $0,%eax\n" /* syscall number = "syscall" (0) to avoid stack frobbing
255 "1: movl 40(%esp),%ecx\n" /* store carry in *flags */
261 #elif defined(VGP_amd64_freebsd)
263 #define __NR_mprotect 74
265 extern UWord
do_syscall_WRK (
266 UWord syscall_no
, /* %rdi */
272 UWord a6
, /* 8(%rsp) */
273 UWord a7
, /* 16(%rsp) */
274 UWord a8
, /* 24(%rsp) */
275 UInt
*flags
, /* 32(%rsp) */
276 UWord
*rv2
/* 40(%rsp) */
281 /* Convert function calling convention --> syscall calling
285 " movq %rdi, %rax\n" /* syscall_no */
286 " movq %rsi, %rdi\n" /* a1 */
287 " movq %rdx, %rsi\n" /* a2 */
288 " movq %rcx, %rdx\n" /* a3 */
289 " movq %r8, %r10\n" /* a4 */
290 " movq %r9, %r8\n" /* a5 */
291 " movq 16(%rbp), %r9\n" /* a6 last arg from stack, account for %rbp */
292 " movq 24(%rbp), %r11\n" /* a7 from stack */
294 " movq 32(%rbp), %r11\n" /* a8 from stack */
296 " subq $8,%rsp\n" /* fake return addr */
299 " movq 48(%rbp),%rsi\n"
300 " movq %rdx, (%rsi)\n"
305 " movq 40(%rbp), %rsi\n"
313 #elif defined(VGP_arm64_freebsd)
315 #define __NR_mprotect 74
317 extern UWord
do_syscall_WRK (
319 UWord a1
, UWord a2
, UWord a3
,
320 UWord a4
, UWord a5
, UWord a6
,
327 ".globl do_syscall_WRK\n"
329 " ldr x8, [sp, #8] \n" /* assume syscall success */
331 " ldr x8, [sp, #0] \n" /* load syscall_no */
333 " bcc 1f \n" /* jump if success */
334 " ldr x9, [sp, #8] \n" /* syscall failed - set *errflag */
337 " 1: ldr x9, [sp, #16] \n" /* save 2nd result word */
339 " ret \n" /* return 1st result word */
344 // Ensure the file compiles even if the syscall nr is not defined.
345 #ifndef __NR_mprotect
346 #define __NR_mprotect 0
348 UWord
do_syscall_WRK (UWord syscall_no
,
349 UWord a1
, UWord a2
, UWord a3
,
350 UWord a4
, UWord a5
, UWord a6
353 // not implemented. vgtest prereq should avoid this to be called.
361 char *interior_ptrs
[3];
362 int mprotect_result
= 0;
363 static void non_simd_mprotect (long tid
, void* addr
, long len
)
365 #if defined(VGP_x86_solaris) || defined(VGP_amd64_solaris)
367 mprotect_result
= do_syscall_WRK((UWord
) addr
, len
, PROT_NONE
,
368 0, 0, 0, 0, 0, SYS_mprotect
,
371 mprotect_result
= -1;
372 #elif defined(VGP_arm64_linux)
373 mprotect_result
= do_syscall_WRK((UWord
) addr
, len
, PROT_NONE
,
376 #elif defined(VGP_x86_freebsd)
379 mprotect_result
= do_syscall_WRK(__NR_mprotect
,
380 (UWord
) addr
, len
, PROT_NONE
,
381 0, 0, 0, 0, 0, &flags
);
382 #elif defined(VGP_amd64_freebsd) || defined(VGP_arm64_freebsd)
386 mprotect_result
= do_syscall_WRK(__NR_mprotect
,
387 (UWord
) addr
, len
, PROT_NONE
,
388 0, 0, 0, 0, 0, &flags
, &rv2
);
391 mprotect_result
= do_syscall_WRK(__NR_mprotect
,
392 (UWord
) addr
, len
, PROT_NONE
,
397 // can this work without global variable for return value?
398 static void my_mprotect_none(void* addr
, long len
)
400 if (RUNNING_ON_VALGRIND
)
401 (void) VALGRIND_NON_SIMD_CALL2(non_simd_mprotect
,
405 mprotect_result
= mprotect(addr
,
413 #define RNDPAGEDOWN(a) ((long)a & ~(pagesize-1))
415 const int nr_ptr
= (10000 * 20)/sizeof(char*);
417 b10
= calloc (nr_ptr
* sizeof(char*), 1);
418 for (i
= 0; i
< nr_ptr
; i
++)
420 b10
[4000] = malloc (1000);
422 fprintf(stderr
, "expecting no leaks\n");
424 VALGRIND_DO_LEAK_CHECK
;
426 // make b10[4000] undefined. This should create a leak.
427 (void) VALGRIND_MAKE_MEM_UNDEFINED (&b10
[4000], sizeof(char*));
428 fprintf(stderr
, "expecting a leak\n");
430 VALGRIND_DO_LEAK_CHECK
;
432 // make b10[4000] defined again.
433 (void) VALGRIND_MAKE_MEM_DEFINED (&b10
[4000], sizeof(char*));
435 // now make some bricolage to have some pages around b10[4000]
436 // unreadable. The leak check should recover from that
437 // thanks to a SEGV handler and a setjmp/longjmp.
438 // This setjmp/longjmp is useful if there is a desync between
439 // the aspacemgr and the real pages mapping.
440 // To have such a discrepancy, we resort on a non SIMD call
441 // to mprotect the pages : as this syscall will not be seen
442 // by Valgrind core, the aspacemgr will not get a chance
443 // to stay synchronised.
444 pagesize
= sysconf(_SC_PAGE_SIZE
);
446 perror ("sysconf failed");
448 my_mprotect_none((void*) RNDPAGEDOWN(&b10
[4000]), 2 * pagesize
);
449 fprintf(stderr
, "mprotect result %d\n", mprotect_result
);
451 fprintf(stderr
, "expecting a leak again\n");
453 VALGRIND_DO_LEAK_CHECK
;
455 my_mprotect_none((void*) RNDPAGEDOWN(&b10
[0]),
456 RNDPAGEDOWN(&(b10
[nr_ptr
-1]))
457 - RNDPAGEDOWN(&(b10
[0])));
458 fprintf(stderr
, "full mprotect result %d\n", mprotect_result
);
460 fprintf(stderr
, "expecting a leak again after full mprotect\n");
462 VALGRIND_DO_LEAK_CHECK
;
464 // allocate memory but keep only interior pointers to trigger various
466 // Allocate some memory:
467 interior_ptrs
[0] = calloc (nr_ptr
* sizeof(char*), 1);
469 // Inner pointer after 3 sizeT: triggers the stdstring heuristic:
470 interior_ptrs
[2] = interior_ptrs
[0] + 3 * sizeof(size_t);
472 // Inner pointer after 1 ULong: triggers the length64 heuristic:
473 interior_ptrs
[1] = interior_ptrs
[0] + sizeof(unsigned long);
475 // Inner pointer after a size: triggers the newarray heuristics.
476 interior_ptrs
[0] += sizeof(size_t);
478 my_mprotect_none( (void*) RNDPAGEDOWN((interior_ptrs
[0] - sizeof(size_t))),
479 RNDPAGEDOWN(nr_ptr
* sizeof(char*)));
480 fprintf(stderr
, "mprotect result %d\n", mprotect_result
);
482 fprintf(stderr
, "expecting heuristic not to crash after full mprotect\n");
484 VALGRIND_DO_LEAK_CHECK
;
486 fprintf(stderr
, "finished\n");
491 DECLARE_LEAK_COUNTERS
;
493 GET_INITIAL_LEAK_COUNTS
;
495 f(); // see leak-cases.c
498 GET_FINAL_LEAK_COUNTS
;
500 PRINT_LEAK_COUNTS(stderr
);