| 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 |