OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2012 The Native Client Authors. All rights reserved. | |
3 * Use of this source code is governed by a BSD-style license that can be | |
4 * found in the LICENSE file. | |
5 */ | |
6 | |
7 #include <stdio.h> | |
8 #include <stdlib.h> | |
9 | |
10 #include "native_client/src/include/portability.h" | |
11 | |
12 #include "native_client/src/shared/platform/nacl_check.h" | |
13 | |
14 #include "native_client/src/trusted/desc/nacl_desc_base.h" | |
15 #include "native_client/src/trusted/desc/nacl_desc_imc_shm.h" | |
16 #include "native_client/src/trusted/desc/nacl_desc_effector_trusted_mem.h" | |
17 | |
18 #include "native_client/src/trusted/service_runtime/include/bits/mman.h" | |
19 #include "native_client/src/trusted/service_runtime/include/sys/errno.h" | |
20 #include "native_client/src/trusted/service_runtime/include/sys/stat.h" | |
21 #include "native_client/src/trusted/gio/gio_shm.h" | |
22 #include "native_client/src/trusted/desc/nrd_all_modules.h" | |
23 #include "native_client/src/trusted/service_runtime/nacl_config.h" | |
24 | |
25 #define NCHUNKS 3 | |
26 | |
27 #define MAX_CHECK (4096) | |
28 | |
29 int gVerbose = 0; | |
30 unsigned int gRandomSeed = 0x31415926; | |
31 size_t gNumSamples = 2048; | |
32 | |
33 uint32_t patgen(uint32_t offset) { | |
34 return (((offset + 3) << (3 * 8)) ^ | |
35 ((offset + 2) << (2 * 8)) ^ | |
36 ((offset + 1) << (1 * 8)) ^ | |
37 ((offset + 0) << (0 * 8))); | |
38 } | |
39 | |
40 | |
41 size_t ZeroFiller(uint32_t *mem, size_t offset) { | |
42 UNREFERENCED_PARAMETER(offset); | |
43 *mem = 0; | |
44 return 0; | |
45 } | |
46 | |
47 size_t ZeroChecker(uint32_t *mem, size_t offset) { | |
48 UNREFERENCED_PARAMETER(offset); | |
49 return *mem != 0; | |
50 } | |
51 | |
52 size_t MemFiller(uint32_t *mem, size_t offset) { | |
53 *mem = patgen((uint32_t) offset); | |
54 return 0; | |
55 } | |
56 | |
57 size_t MemChecker(uint32_t *mem, size_t offset) { | |
58 uint32_t pat = patgen((uint32_t) offset); | |
59 return *mem != pat; | |
60 } | |
61 | |
62 size_t MemWalk(size_t (*visitor)(uint32_t *, uintptr_t), | |
63 uint32_t *buf, | |
64 size_t nwords) { | |
65 size_t ix = 0; | |
66 size_t err_count = 0; | |
67 | |
68 for (ix = 0; ix < nwords; ++ix) { | |
69 err_count += (*visitor)(&buf[ix], ix); | |
70 } | |
71 return err_count; | |
72 } | |
73 | |
74 struct Prober { | |
75 /* inline vtbl */ | |
76 ssize_t (*NextIx)(struct Prober *self, size_t *nbytes); | |
77 }; | |
78 | |
79 struct LinearProber { | |
80 struct Prober base; | |
81 size_t cur_ix; | |
82 size_t nbytes; | |
83 }; | |
84 | |
85 ssize_t LinearProberIndex(struct Prober *vself, size_t *checkbytes) { | |
86 struct LinearProber *self = (struct LinearProber *) vself; | |
87 if (self->cur_ix == self->nbytes) return -1; | |
88 *checkbytes = 1; | |
89 return self->cur_ix++; | |
90 } | |
91 | |
92 void LinearProberCtor(struct LinearProber *self, size_t nbytes) { | |
93 self->base.NextIx = LinearProberIndex; | |
94 self->cur_ix = 0; | |
95 self->nbytes = nbytes; | |
96 } | |
97 | |
98 struct ReverseProber { | |
99 struct Prober base; | |
100 size_t nbytes; | |
101 }; | |
102 | |
103 ssize_t ReverseProberIndex(struct Prober *vself, size_t *checkbytes) { | |
104 struct ReverseProber *self = (struct ReverseProber *) vself; | |
105 | |
106 *checkbytes = 1; | |
107 return --self->nbytes; | |
108 } | |
109 | |
110 void ReverseProberCtor(struct ReverseProber *self, size_t nbytes) { | |
111 self->base.NextIx = ReverseProberIndex; | |
112 self->nbytes = nbytes; | |
113 } | |
114 | |
115 struct RandomProber { | |
116 struct Prober base; | |
117 size_t nbytes; | |
118 /* windows does not have rand_r, so this test must be single threaded */ | |
119 size_t count; | |
120 }; | |
121 | |
122 ssize_t RandomProberIndex(struct Prober *vself, size_t *checkbytes) { | |
123 struct RandomProber *self = (struct RandomProber *) vself; | |
124 int r; | |
125 size_t remain; | |
126 | |
127 if (0 == self->count) { | |
128 return -1; | |
129 } | |
130 --self->count; | |
131 r = (int) ((size_t) rand() % self->nbytes); | |
132 CHECK(r >= 0); | |
133 remain = self->nbytes - r; | |
134 if (remain > MAX_CHECK) { | |
135 remain = MAX_CHECK; | |
136 } | |
137 *checkbytes = rand() % remain; | |
138 CHECK(*checkbytes <= remain); | |
139 return r; | |
140 } | |
141 | |
142 void RandomProberCtor(struct RandomProber *self, | |
143 size_t nbytes, | |
144 size_t nsamples) { | |
145 self->base.NextIx = RandomProberIndex; | |
146 self->nbytes = nbytes; | |
147 self->count = nsamples; | |
148 } | |
149 | |
150 /* | |
151 * Op is sort of a funny virtual function pointer -- it's not an | |
152 * offset in the vtbl, so changing the object is bad (esp w/ | |
153 * subclasses that might have overridden the virtual function), but | |
154 * the extracted function pointer. | |
155 */ | |
156 size_t CheckGioOpWithProber(struct Prober *pp, | |
157 struct Gio *gp, | |
158 uint8_t *addr, | |
159 size_t nbytes, | |
160 ssize_t (*Op)(struct Gio *, void *, size_t)) { | |
161 size_t errs = 0; | |
162 ssize_t ix; | |
163 size_t checkbytes; | |
164 uint8_t val[MAX_CHECK]; | |
165 size_t valix; | |
166 | |
167 while (-1 != (ix = (*pp->NextIx)(pp, &checkbytes))) { | |
168 if (nbytes <= (size_t) ix) { | |
169 break; | |
170 } | |
171 if (gVerbose > 1) { | |
172 printf("0x%"NACL_PRIxS", 0x%"NACL_PRIxS"\n", ix, checkbytes); | |
173 } | |
174 if (checkbytes > sizeof val) { | |
175 checkbytes = sizeof val; | |
176 } | |
177 | |
178 /* fill with something we don't expect to be in real data */ | |
179 for (valix = 0; valix < checkbytes; ++valix) { | |
180 val[valix] = (uint8_t) (~valix); | |
181 } | |
182 | |
183 if (gVerbose > 2) { | |
184 printf("Seeking to 0x%"NACL_PRIxS"\n", ix); | |
185 } | |
186 | |
187 if (-1 == (*gp->vtbl->Seek)(gp, (off_t) ix, SEEK_SET)) { | |
188 if (gVerbose) { | |
189 printf("Seek to %"NACL_PRIdS" failed\n", ix); | |
190 } | |
191 ++errs; | |
192 continue; | |
193 } | |
194 if (gVerbose > 2) { | |
195 printf("Operating on 0x%"NACL_PRIxS" bytes\n", checkbytes); | |
196 } | |
197 | |
198 if (-1 == (*Op)(gp, val, checkbytes)) { | |
199 if (gVerbose) { | |
200 printf("Apply Op at %"NACL_PRIdS" failed\n", ix); | |
201 } | |
202 ++errs; | |
203 continue; | |
204 } | |
205 | |
206 if (gVerbose > 2) { | |
207 printf("Comparing against plain mmap view\n"); | |
208 } | |
209 for (valix = 0; valix < checkbytes; ++valix) { | |
210 if (1 < gVerbose) { | |
211 printf(("Value from gio is 0x%08"NACL_PRIx8"," | |
212 " from memory is 0x%08"NACL_PRIx8"\n"), | |
213 val[valix], | |
214 addr[ix + valix]); | |
215 } | |
216 if (val[valix] != addr[ix + valix]) { | |
217 ++errs; | |
218 } | |
219 } | |
220 } | |
221 return errs; | |
222 } | |
223 | |
224 size_t CheckGioReadWithProber(struct Prober *pp, | |
225 struct Gio *gp, | |
226 uint8_t *addr, | |
227 size_t nbytes) { | |
228 return CheckGioOpWithProber(pp, gp, addr, nbytes, gp->vtbl->Read); | |
229 } | |
230 | |
231 size_t CheckGioWriteWithProber(struct Prober *pp, | |
232 struct Gio *gp, | |
233 uint8_t *addr, | |
234 size_t nbytes) { | |
235 return CheckGioOpWithProber(pp, gp, addr, nbytes, | |
236 (ssize_t (*)(struct Gio *, void *, size_t)) | |
237 gp->vtbl->Write); | |
238 } | |
239 | |
240 | |
241 size_t CheckGioOp(struct Gio *gp, | |
242 uint8_t *addr, | |
243 size_t nbytes, | |
244 size_t (*Op)(struct Prober *, | |
245 struct Gio *, | |
246 uint8_t *, | |
247 size_t)) { | |
248 struct LinearProber lp; | |
249 struct ReverseProber rp; | |
250 struct RandomProber rand_probe; | |
251 ssize_t num_err = 0; | |
252 | |
253 LinearProberCtor(&lp, nbytes); | |
254 printf("Testing w/ LinearProber\n"); | |
255 num_err += (*Op)((struct Prober *) &lp, gp, addr, nbytes); | |
256 | |
257 ReverseProberCtor(&rp, nbytes); | |
258 printf("Testing w/ ReverseProber\n"); | |
259 num_err += (*Op)((struct Prober *) &rp, gp, addr, nbytes); | |
260 | |
261 RandomProberCtor(&rand_probe, nbytes, gNumSamples); | |
262 printf("Testing w/ RandomProber\n"); | |
263 num_err += (*Op)((struct Prober *) &rand_probe, gp, addr, nbytes); | |
264 | |
265 return num_err; | |
266 } | |
267 | |
268 size_t CheckGioRead(struct Gio *gp, | |
269 uint8_t *addr, | |
270 size_t nbytes) { | |
271 return CheckGioOp(gp, addr, nbytes, CheckGioReadWithProber); | |
272 } | |
273 | |
274 size_t CheckGioWrite(struct Gio *gp, | |
275 uint8_t *addr, | |
276 size_t nbytes) { | |
277 return CheckGioOp(gp, addr, nbytes, CheckGioWriteWithProber); | |
278 } | |
279 | |
280 size_t CheckGioZeros(struct Gio *gp, | |
281 size_t nbytes) { | |
282 unsigned char byte; | |
283 ssize_t rv; | |
284 size_t nerrors = 0; | |
285 size_t ix; | |
286 uint64_t temp_nbytes = nbytes; | |
287 | |
288 if (temp_nbytes > OFF_T_MAX) { | |
289 return 1; | |
290 } | |
291 | |
292 for (ix = 0; ix < nbytes; ++ix) { | |
293 byte = 0xff; | |
294 if (-1 == (*gp->vtbl->Seek)(gp, (off_t) ix, SEEK_SET)) { | |
295 printf("Seek to byt %"NACL_PRIuS" failed\n", ix); | |
296 ++nerrors; | |
297 continue; | |
298 } | |
299 if (1 != (rv = (*gp->vtbl->Read)(gp, &byte, 1))) { | |
300 printf("Read of byte %"NACL_PRIuS" failed\n", ix); | |
301 ++nerrors; | |
302 continue; | |
303 } | |
304 if (0 != byte) { | |
305 printf("Byte %"NACL_PRIuS" not zero: 0x%02x\n", ix, 0xff & byte); | |
306 ++nerrors; | |
307 } | |
308 } | |
309 return nerrors; | |
310 } | |
311 | |
312 | |
313 int main(int ac, | |
314 char **av) { | |
315 int opt; | |
316 | |
317 struct NaClDescImcShm *shmp; | |
318 struct NaClDesc *dp; | |
319 uintptr_t addr; | |
320 uintptr_t addr2; | |
321 size_t nbytes; | |
322 size_t errs; | |
323 struct NaClGioShm gio_shm; | |
324 size_t map_chunks = NCHUNKS; | |
325 | |
326 while (EOF != (opt = getopt(ac, av, "m:n:s:v"))) { | |
327 switch (opt) { | |
328 case 'm': | |
329 map_chunks = strtoul(optarg, (char **) NULL, 0); | |
330 break; | |
331 case 'n': | |
332 gNumSamples = strtoul(optarg, (char **) NULL, 0); | |
333 break; | |
334 case 's': | |
335 gRandomSeed = strtoul(optarg, (char **) NULL, 0); | |
336 break; | |
337 case 'v': | |
338 ++gVerbose; | |
339 break; | |
340 default: | |
341 fprintf(stderr, | |
342 ("Usage: gio_shm_test [-v] [-m map_chunks]" | |
343 " [-n num_samples] [-s seed]\n")); | |
344 return EXIT_FAILURE; | |
345 } | |
346 } | |
347 | |
348 printf("Using seed %d (0x%x)\n", gRandomSeed, gRandomSeed); | |
349 srand(gRandomSeed); | |
350 | |
351 NaClNrdAllModulesInit(); | |
352 | |
353 shmp = malloc(sizeof *shmp); | |
354 if (NULL == shmp) { | |
355 printf("No memory\n"); | |
356 printf("FAILED\n"); | |
357 return EXIT_FAILURE; | |
358 } | |
359 | |
360 nbytes = map_chunks * NACL_MAP_PAGESIZE; | |
361 if (!NaClDescImcShmAllocCtor(shmp, nbytes, /* executable= */ 0)) { | |
362 printf("NaClDescImcShmAllocCtor failed\n"); | |
363 printf("FAILED\n"); | |
364 return EXIT_FAILURE; | |
365 } | |
366 dp = &shmp->base; | |
367 | |
368 addr = (*((struct NaClDescVtbl const *) dp->base.vtbl)-> | |
369 Map)(dp, | |
370 NaClDescEffectorTrustedMem(), | |
371 NULL, | |
372 nbytes, | |
373 NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE, | |
374 NACL_ABI_MAP_SHARED, | |
375 0); | |
376 if (NaClPtrIsNegErrno(&addr)) { | |
377 printf("Map failed\n"); | |
378 return EXIT_FAILURE; | |
379 } | |
380 | |
381 MemWalk(MemFiller, (uint32_t *) addr, nbytes / sizeof(uint32_t)); | |
382 printf("Checking basic consistency\n"); | |
383 if (0 != MemWalk(MemChecker, (uint32_t *) addr, nbytes / sizeof(uint32_t))) { | |
384 printf("Initial consistency check failed\n"); | |
385 printf("FAILED\n"); | |
386 return EXIT_FAILURE; | |
387 } | |
388 | |
389 addr2 = (*((struct NaClDescVtbl const *) dp->base.vtbl)-> | |
390 Map)(dp, | |
391 NaClDescEffectorTrustedMem(), | |
392 NULL, | |
393 nbytes, | |
394 NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE, | |
395 NACL_ABI_MAP_SHARED, | |
396 0); | |
397 if (NaClPtrIsNegErrno(&addr2)) { | |
398 printf("Second Map failed\n"); | |
399 return EXIT_FAILURE; | |
400 } | |
401 printf("Checking second view consistency\n"); | |
402 if (0 != MemWalk(MemChecker, (uint32_t *) addr2, nbytes / sizeof(uint32_t))) { | |
403 printf("Second view consistency check failed\n"); | |
404 printf("FAILED\n"); | |
405 return EXIT_FAILURE; | |
406 } | |
407 NaClDescUnmapUnsafe(dp, (void *) addr2, nbytes); | |
408 | |
409 if (!NaClGioShmCtor(&gio_shm, dp, nbytes)) { | |
410 printf("NaClGioShmCtor failed\n"); | |
411 printf("FAILED\n"); | |
412 return EXIT_FAILURE; | |
413 } | |
414 | |
415 printf("Checking Gio vs direct shm consistency, read\n"); | |
416 if (0 != (errs = CheckGioRead((struct Gio *) &gio_shm, | |
417 (uint8_t *) addr, | |
418 nbytes))) { | |
419 printf("ERROR: CheckGioRead failed, found %"NACL_PRIdS" errors\n", errs); | |
420 } | |
421 | |
422 printf("Zeroing shared memory\n"); | |
423 MemWalk(ZeroFiller, (uint32_t *) addr, nbytes / sizeof(uint32_t)); | |
424 printf("Reading for zeros\n"); | |
425 if (0 != (errs = CheckGioZeros((struct Gio *) &gio_shm, | |
426 nbytes))) { | |
427 printf("ERROR: Gio found non-zero bytes!\n"); | |
428 } | |
429 | |
430 printf("Checking Gio vs direct shm consistency, write\n"); | |
431 if (0 != (errs = CheckGioWrite((struct Gio *) &gio_shm, | |
432 (uint8_t *) addr, | |
433 nbytes))) { | |
434 printf("ERROR: CheckGioWrite failed, found %"NACL_PRIdS" errors\n", errs); | |
435 } | |
436 | |
437 (*gio_shm.base.vtbl->Dtor)((struct Gio *) &gio_shm); | |
438 | |
439 NaClDescUnref(dp); | |
440 | |
441 NaClNrdAllModulesFini(); | |
442 if (0 != errs) { | |
443 printf("FAILED\n"); | |
444 return EXIT_FAILURE; | |
445 } else { | |
446 printf("PASSED\n"); | |
447 return EXIT_SUCCESS; | |
448 } | |
449 } | |
OLD | NEW |