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"
101 " push {r4, r5, r7}\n"
102 " ldr r4, [sp, #12]\n"
103 " ldr r5, [sp, #16]\n"
104 " ldr r7, [sp, #20]\n"
106 " pop {r4, r5, r7}\n"
111 #elif defined(VGP_arm64_linux)
112 extern UWord
do_syscall_WRK (
113 UWord a1
, UWord a2
, UWord a3
,
114 UWord a4
, UWord a5
, UWord a6
,
119 ".globl do_syscall_WRK\n"
129 #elif defined(VGP_s390x_linux)
130 UWord
do_syscall_WRK (
132 UWord arg1
, UWord arg2
, UWord arg3
,
133 UWord arg4
, UWord arg5
, UWord arg6
136 register UWord __arg1
asm("2") = arg1
;
137 register UWord __arg2
asm("3") = arg2
;
138 register UWord __arg3
asm("4") = arg3
;
139 register UWord __arg4
asm("5") = arg4
;
140 register UWord __arg5
asm("6") = arg5
;
141 register UWord __arg6
asm("7") = arg6
;
142 register ULong __svcres
asm("2");
144 __asm__
__volatile__ (
155 : "1", "cc", "memory");
157 return (UWord
) (__svcres
);
160 #elif defined(VGP_mips64_linux)
161 extern UWord
do_syscall_WRK (
163 UWord a1
, UWord a2
, UWord a3
,
164 UWord a4
, UWord a5
, UWord a6
168 __asm__
__volatile__ (
174 "move $8, %6\n\t" /* We use numbers because some compilers */
175 "move $9, %7\n\t" /* don't recognize $a4 and $a5 */
179 : "r"(syscall_no
), "r"(a1
), "r"(a2
), "r"(a3
),
180 "r"(a4
), "r"(a5
), "r"(a6
)
181 : "v0", "v1", "a0", "a1", "a2", "a3", "$8", "$9");
185 #elif defined(VGP_x86_solaris)
187 do_syscall_WRK(UWord a1
, UWord a2
, UWord a3
,
188 UWord a4
, UWord a5
, UWord a6
,
194 ".globl do_syscall_WRK\n"
196 " movl 40(%esp), %ecx\n" /* assume syscall success */
198 " movl 36(%esp), %eax\n"
200 " jnc 1f\n" /* jump if success */
201 " movl 40(%esp), %ecx\n" /* syscall failed - set *errflag */
207 #elif defined(VGP_amd64_solaris)
209 do_syscall_WRK(UWord a1
, UWord a2
, UWord a3
,
210 UWord a4
, UWord a5
, UWord a6
,
216 ".globl do_syscall_WRK\n"
218 " movq %rcx, %r10\n" /* pass rcx in r10 instead */
219 " movq 32(%rsp), %rcx\n" /* assume syscall success */
221 " movq 24(%rsp), %rax\n"
223 " jnc 1f\n" /* jump if success */
224 " movq 32(%rsp), %rcx\n" /* syscall failed - set *errflag */
230 #elif defined(VGP_x86_freebsd)
232 #define __NR_mprotect 74
234 /* Incoming args (syscall number + up to 8 args) are on the stack.
235 FreeBSD has a syscall called 'syscall' that takes all args (including
236 the syscall number) off the stack. Since we're called, the return
237 address is on the stack as expected, so we can just call syscall(2)
238 and it Just Works. Error is when carry is set.
240 extern ULong
do_syscall_WRK (
242 UWord a1
, UWord a2
, UWord a3
,
243 UWord a4
, UWord a5
, UWord a6
,
244 UWord a7
, UWord a8
, UInt
*flags
249 " movl $0,%eax\n" /* syscall number = "syscall" (0) to avoid stack frobbing
254 "1: movl 40(%esp),%ecx\n" /* store carry in *flags */
260 #elif defined(VGP_amd64_freebsd)
262 #define __NR_mprotect 74
264 extern UWord
do_syscall_WRK (
265 UWord syscall_no
, /* %rdi */
271 UWord a6
, /* 8(%rsp) */
272 UWord a7
, /* 16(%rsp) */
273 UWord a8
, /* 24(%rsp) */
274 UInt
*flags
, /* 32(%rsp) */
275 UWord
*rv2
/* 40(%rsp) */
280 /* Convert function calling convention --> syscall calling
284 " movq %rdi, %rax\n" /* syscall_no */
285 " movq %rsi, %rdi\n" /* a1 */
286 " movq %rdx, %rsi\n" /* a2 */
287 " movq %rcx, %rdx\n" /* a3 */
288 " movq %r8, %r10\n" /* a4 */
289 " movq %r9, %r8\n" /* a5 */
290 " movq 16(%rbp), %r9\n" /* a6 last arg from stack, account for %rbp */
291 " movq 24(%rbp), %r11\n" /* a7 from stack */
293 " movq 32(%rbp), %r11\n" /* a8 from stack */
295 " subq $8,%rsp\n" /* fake return addr */
298 " movq 48(%rbp),%rsi\n"
299 " movq %rdx, (%rsi)\n"
304 " movq 40(%rbp), %rsi\n"
313 // Ensure the file compiles even if the syscall nr is not defined.
314 #ifndef __NR_mprotect
315 #define __NR_mprotect 0
317 UWord
do_syscall_WRK (UWord syscall_no
,
318 UWord a1
, UWord a2
, UWord a3
,
319 UWord a4
, UWord a5
, UWord a6
322 // not implemented. vgtest prereq should avoid this to be called.
330 char *interior_ptrs
[3];
331 int mprotect_result
= 0;
332 static void non_simd_mprotect (long tid
, void* addr
, long len
)
334 #if defined(VGP_x86_solaris) || defined(VGP_amd64_solaris)
336 mprotect_result
= do_syscall_WRK((UWord
) addr
, len
, PROT_NONE
,
337 0, 0, 0, 0, 0, SYS_mprotect
,
340 mprotect_result
= -1;
341 #elif defined(VGP_arm64_linux)
342 mprotect_result
= do_syscall_WRK((UWord
) addr
, len
, PROT_NONE
,
345 #elif defined(VGP_x86_freebsd)
348 mprotect_result
= do_syscall_WRK(__NR_mprotect
,
349 (UWord
) addr
, len
, PROT_NONE
,
350 0, 0, 0, 0, 0, &flags
);
351 #elif defined(VGP_amd64_freebsd)
355 mprotect_result
= do_syscall_WRK(__NR_mprotect
,
356 (UWord
) addr
, len
, PROT_NONE
,
357 0, 0, 0, 0, 0, &flags
, &rv2
);
360 mprotect_result
= do_syscall_WRK(__NR_mprotect
,
361 (UWord
) addr
, len
, PROT_NONE
,
366 // can this work without global variable for return value?
367 static void my_mprotect_none(void* addr
, long len
)
369 if (RUNNING_ON_VALGRIND
)
370 (void) VALGRIND_NON_SIMD_CALL2(non_simd_mprotect
,
374 mprotect_result
= mprotect(addr
,
382 #define RNDPAGEDOWN(a) ((long)a & ~(pagesize-1))
384 const int nr_ptr
= (10000 * 20)/sizeof(char*);
386 b10
= calloc (nr_ptr
* sizeof(char*), 1);
387 for (i
= 0; i
< nr_ptr
; i
++)
389 b10
[4000] = malloc (1000);
391 fprintf(stderr
, "expecting no leaks\n");
393 VALGRIND_DO_LEAK_CHECK
;
395 // make b10[4000] undefined. This should create a leak.
396 (void) VALGRIND_MAKE_MEM_UNDEFINED (&b10
[4000], sizeof(char*));
397 fprintf(stderr
, "expecting a leak\n");
399 VALGRIND_DO_LEAK_CHECK
;
401 // make b10[4000] defined again.
402 (void) VALGRIND_MAKE_MEM_DEFINED (&b10
[4000], sizeof(char*));
404 // now make some bricolage to have some pages around b10[4000]
405 // unreadable. The leak check should recover from that
406 // thanks to a SEGV handler and a setjmp/longjmp.
407 // This setjmp/longjmp is useful if there is a desync between
408 // the aspacemgr and the real pages mapping.
409 // To have such a discrepancy, we resort on a non SIMD call
410 // to mprotect the pages : as this syscall will not be seen
411 // by Valgrind core, the aspacemgr will not get a chance
412 // to stay synchronised.
413 pagesize
= sysconf(_SC_PAGE_SIZE
);
415 perror ("sysconf failed");
417 my_mprotect_none((void*) RNDPAGEDOWN(&b10
[4000]), 2 * pagesize
);
418 fprintf(stderr
, "mprotect result %d\n", mprotect_result
);
420 fprintf(stderr
, "expecting a leak again\n");
422 VALGRIND_DO_LEAK_CHECK
;
424 my_mprotect_none((void*) RNDPAGEDOWN(&b10
[0]),
425 RNDPAGEDOWN(&(b10
[nr_ptr
-1]))
426 - RNDPAGEDOWN(&(b10
[0])));
427 fprintf(stderr
, "full mprotect result %d\n", mprotect_result
);
429 fprintf(stderr
, "expecting a leak again after full mprotect\n");
431 VALGRIND_DO_LEAK_CHECK
;
433 // allocate memory but keep only interior pointers to trigger various
435 // Allocate some memory:
436 interior_ptrs
[0] = calloc (nr_ptr
* sizeof(char*), 1);
438 // Inner pointer after 3 sizeT: triggers the stdstring heuristic:
439 interior_ptrs
[2] = interior_ptrs
[0] + 3 * sizeof(size_t);
441 // Inner pointer after 1 ULong: triggers the length64 heuristic:
442 interior_ptrs
[1] = interior_ptrs
[0] + sizeof(unsigned long);
444 // Inner pointer after a size: triggers the newarray heuristics.
445 interior_ptrs
[0] += sizeof(size_t);
447 my_mprotect_none( (void*) RNDPAGEDOWN((interior_ptrs
[0] - sizeof(size_t))),
448 RNDPAGEDOWN(nr_ptr
* sizeof(char*)));
449 fprintf(stderr
, "mprotect result %d\n", mprotect_result
);
451 fprintf(stderr
, "expecting heuristic not to crash after full mprotect\n");
453 VALGRIND_DO_LEAK_CHECK
;
455 fprintf(stderr
, "finished\n");
460 DECLARE_LEAK_COUNTERS
;
462 GET_INITIAL_LEAK_COUNTS
;
464 f(); // see leak-cases.c
467 GET_FINAL_LEAK_COUNTS
;
469 PRINT_LEAK_COUNTS(stderr
);