1#define _GNU_SOURCE
2#include <stdio.h>
3#include <stdlib.h>
4#include <unistd.h>
5#include "../memcheck.h"
6#include "leak.h"
7#include <sys/mman.h>
8#include <sys/syscall.h>
9
10typedef unsigned long            UWord;
11typedef unsigned long long int   ULong;
12// Below code is copied from m_syscall.c
13// Refer to this file for syscall convention.
14#if defined(VGP_x86_linux)
15extern UWord do_syscall_WRK (UWord syscall_no,
16                             UWord a1, UWord a2, UWord a3,
17                             UWord a4, UWord a5, UWord a6
18                             );
19asm(
20".text\n"
21".globl do_syscall_WRK\n"
22"do_syscall_WRK:\n"
23"	push	%esi\n"
24"	push	%edi\n"
25"	push	%ebx\n"
26"	push	%ebp\n"
27"	movl	16+ 4(%esp),%eax\n"
28"	movl	16+ 8(%esp),%ebx\n"
29"	movl	16+12(%esp),%ecx\n"
30"	movl	16+16(%esp),%edx\n"
31"	movl	16+20(%esp),%esi\n"
32"	movl	16+24(%esp),%edi\n"
33"	movl	16+28(%esp),%ebp\n"
34"	int	$0x80\n"
35"	popl	%ebp\n"
36"	popl	%ebx\n"
37"	popl	%edi\n"
38"	popl	%esi\n"
39"	ret\n"
40".previous\n"
41);
42#elif defined(VGP_amd64_linux)
43extern UWord do_syscall_WRK (
44          UWord syscall_no,
45          UWord a1, UWord a2, UWord a3,
46          UWord a4, UWord a5, UWord a6
47       );
48asm(
49".text\n"
50".globl do_syscall_WRK\n"
51"do_syscall_WRK:\n"
52"	movq	%rdi, %rax\n"
53"	movq	%rsi, %rdi\n"
54"	movq	%rdx, %rsi\n"
55"	movq	%rcx, %rdx\n"
56"	movq	%r8,  %r10\n"
57"	movq	%r9,  %r8\n"
58"	movq    8(%rsp), %r9\n"	 /* last arg from stack */
59"	syscall\n"
60"	ret\n"
61".previous\n"
62);
63
64#elif defined(VGP_ppc32_linux)
65extern ULong do_syscall_WRK (
66          UWord syscall_no,
67          UWord a1, UWord a2, UWord a3,
68          UWord a4, UWord a5, UWord a6
69       );
70asm(
71".text\n"
72".globl do_syscall_WRK\n"
73"do_syscall_WRK:\n"
74"        mr      0,3\n"
75"        mr      3,4\n"
76"        mr      4,5\n"
77"        mr      5,6\n"
78"        mr      6,7\n"
79"        mr      7,8\n"
80"        mr      8,9\n"
81"        sc\n"                  /* syscall: sets %cr0.so on error         */
82"        mfcr    4\n"           /* %cr -> low word of return var          */
83"        rlwinm  4,4,4,31,31\n" /* rotate flag bit so to lsb, and mask it */
84"        blr\n"                 /* and return                             */
85".previous\n"
86);
87
88#elif defined(VGP_arm_linux)
89extern UWord do_syscall_WRK (
90          UWord a1, UWord a2, UWord a3,
91          UWord a4, UWord a5, UWord a6,
92          UWord syscall_no
93       );
94asm(
95".text\n"
96".globl do_syscall_WRK\n"
97"do_syscall_WRK:\n"
98"         push    {r4, r5, r7}\n"
99"         ldr     r4, [sp, #12]\n"
100"         ldr     r5, [sp, #16]\n"
101"         ldr     r7, [sp, #20]\n"
102"         svc     0x0\n"
103"         pop     {r4, r5, r7}\n"
104"         bx      lr\n"
105".previous\n"
106);
107#elif defined(VGP_s390x_linux)
108UWord do_syscall_WRK (
109   UWord syscall_no,
110   UWord arg1, UWord arg2, UWord arg3,
111   UWord arg4, UWord arg5, UWord arg6
112   )
113{
114   register UWord __arg1 asm("2") = arg1;
115   register UWord __arg2 asm("3") = arg2;
116   register UWord __arg3 asm("4") = arg3;
117   register UWord __arg4 asm("5") = arg4;
118   register UWord __arg5 asm("6") = arg5;
119   register UWord __arg6 asm("7") = arg6;
120   register ULong __svcres asm("2");
121
122   __asm__ __volatile__ (
123                 "lgr %%r1,%1\n\t"
124                 "svc 0\n\t"
125		: "=d" (__svcres)
126		: "a" (syscall_no),
127		  "0" (__arg1),
128		  "d" (__arg2),
129		  "d" (__arg3),
130		  "d" (__arg4),
131		  "d" (__arg5),
132		  "d" (__arg6)
133		: "1", "cc", "memory");
134
135   return (UWord) (__svcres);
136}
137
138#elif defined(VGP_mips64_linux)
139extern UWord do_syscall_WRK (
140          UWord syscall_no,
141          UWord a1, UWord a2, UWord a3,
142          UWord a4, UWord a5, UWord a6
143       )
144{
145   UWord out;
146   __asm__ __volatile__ (
147                 "move $v0, %1\n\t"
148                 "move $a0, %2\n\t"
149                 "move $a1, %3\n\t"
150                 "move $a2, %4\n\t"
151                 "move $a3, %5\n\t"
152                 "move $8,  %6\n\t"  /* We use numbers because some compilers */
153                 "move $9,  %7\n\t"  /* don't recognize $a4 and $a5 */
154                 "syscall\n"
155                 "move %0, $v0\n\t"
156                 : /*out*/ "=r" (out)
157                 : "r"(syscall_no), "r"(a1), "r"(a2), "r"(a3),
158                   "r"(a4), "r"(a5), "r"(a6)
159                 : "v0", "v1", "a0", "a1", "a2", "a3", "$8", "$9");
160   return out;
161}
162
163#else
164// Ensure the file compiles even if the syscall nr is not defined.
165#ifndef __NR_mprotect
166#define __NR_mprotect 0
167#endif
168UWord do_syscall_WRK (UWord syscall_no,
169                      UWord a1, UWord a2, UWord a3,
170                      UWord a4, UWord a5, UWord a6
171                      )
172{
173   // not implemented. vgtest prereq should avoid this to be called.
174   return -1;
175}
176#endif
177
178
179
180char **b10;
181int mprotect_result = 0;
182static void non_simd_mprotect (long tid, void* addr, long len)
183{
184   mprotect_result = do_syscall_WRK(__NR_mprotect,
185                                    (UWord) addr, len, PROT_NONE,
186                                    0, 0, 0);
187}
188
189void f(void)
190{
191   long pagesize;
192#define RNDPAGEDOWN(a) ((long)a & ~(pagesize-1))
193   int i;
194   const int nr_ptr = (10000 * 4)/sizeof(char*);
195
196   b10 = calloc (nr_ptr * sizeof(char*), 1);
197   for (i = 0; i < nr_ptr; i++)
198      b10[i] = (char*)b10;
199   b10[4000] = malloc (1000);
200
201   fprintf(stderr, "expecting no leaks\n");
202   fflush(stderr);
203   VALGRIND_DO_LEAK_CHECK;
204
205   // make b10[4000] undefined. This should create a leak.
206   (void) VALGRIND_MAKE_MEM_UNDEFINED (&b10[4000], sizeof(char*));
207   fprintf(stderr, "expecting a leak\n");
208   fflush(stderr);
209   VALGRIND_DO_LEAK_CHECK;
210
211   // make  b10[4000] defined again.
212   (void) VALGRIND_MAKE_MEM_DEFINED (&b10[4000], sizeof(char*));
213
214   // now make some bricolage to have some pages around b10[4000]
215   // unreadable. The leak check should recover from that
216   // thanks to a SEGV handler and a setjmp/longjmp.
217   // This setjmp/longjmp is useful if there is a desync between
218   // the aspacemgr and the real pages mapping.
219   // To have such a discrepancy, we resort on a non SIMD call
220   // to mprotect the pages : as this syscall will not be seen
221   // by Valgrind core, the aspacemgr will not get a chance
222   // to stay synchronised.
223   pagesize = sysconf(_SC_PAGE_SIZE);
224   if (pagesize == -1)
225      perror ("sysconf failed");
226
227   if (RUNNING_ON_VALGRIND)
228     (void) VALGRIND_NON_SIMD_CALL2(non_simd_mprotect, RNDPAGEDOWN(&b10[4000]), 2 * pagesize);
229   else
230      mprotect_result = mprotect((void*) RNDPAGEDOWN(&b10[4000]), 2 * pagesize, PROT_NONE);
231   fprintf(stderr, "mprotect result %d\n", mprotect_result);
232
233   fprintf(stderr, "expecting a leak again\n");
234   fflush(stderr);
235   VALGRIND_DO_LEAK_CHECK;
236
237   if (RUNNING_ON_VALGRIND)
238     (void) VALGRIND_NON_SIMD_CALL2(non_simd_mprotect,
239                                    RNDPAGEDOWN(&b10[0]),
240                                    RNDPAGEDOWN(&(b10[nr_ptr-1]))
241                                    - RNDPAGEDOWN(&(b10[0])));
242   else
243      mprotect_result = mprotect((void*) RNDPAGEDOWN(&b10[0]),
244                                 RNDPAGEDOWN(&(b10[nr_ptr-1]))
245                                 - RNDPAGEDOWN(&(b10[0])),
246                                 PROT_NONE);
247   fprintf(stderr, "full mprotect result %d\n", mprotect_result);
248
249   fprintf(stderr, "expecting a leak again after full mprotect\n");
250   fflush(stderr);
251   VALGRIND_DO_LEAK_CHECK;
252
253   fprintf(stderr, "finished\n");
254}
255
256int main(void)
257{
258   DECLARE_LEAK_COUNTERS;
259
260   GET_INITIAL_LEAK_COUNTS;
261
262   f();   // see leak-cases.c
263
264
265   GET_FINAL_LEAK_COUNTS;
266
267   PRINT_LEAK_COUNTS(stderr);
268
269   return 0;
270}
271