| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2012 The Native Client Authors. All rights reserved. | 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 | 3 * Use of this source code is governed by a BSD-style license that can be |
| 4 * be found in the LICENSE file. | 4 * found in the LICENSE file. |
| 5 */ | 5 */ |
| 6 | 6 |
| 7 /* | 7 /* |
| 8 * Unit tests for the MIPS validator | 8 * Unit tests for the MIPS validator |
| 9 * | 9 * |
| 10 * These tests use the google-test framework (gtest for short) to exercise the | 10 * These tests use the google-test framework (gtest for short) to exercise the |
| 11 * MIPS validator. The tests currently fall into two rough categories: | 11 * MIPS validator. The tests currently fall into two rough categories: |
| 12 * 1. Simple method-level tests that exercise the validator's primitive | 12 * 1. Simple method-level tests that exercise the validator's primitive |
| 13 * capabilities, and | 13 * capabilities, and |
| 14 * 2. Instruction pattern tests that run the entire validator. | 14 * 2. Instruction pattern tests that run the entire validator. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 36 using std::string; | 36 using std::string; |
| 37 using std::ostringstream; | 37 using std::ostringstream; |
| 38 | 38 |
| 39 using nacl_mips_dec::Register; | 39 using nacl_mips_dec::Register; |
| 40 using nacl_mips_dec::RegisterList; | 40 using nacl_mips_dec::RegisterList; |
| 41 using nacl_mips_dec::Instruction; | 41 using nacl_mips_dec::Instruction; |
| 42 | 42 |
| 43 using nacl_mips_val::SfiValidator; | 43 using nacl_mips_val::SfiValidator; |
| 44 using nacl_mips_val::ProblemSink; | 44 using nacl_mips_val::ProblemSink; |
| 45 using nacl_mips_val::CodeSegment; | 45 using nacl_mips_val::CodeSegment; |
| 46 using nacl_mips_dec::kInstrSize; |
| 47 using nacl_mips_dec::kNop; |
| 48 using nacl_mips_dec::kRegisterStack; |
| 49 using nacl_mips_dec::kRegListReserved; |
| 46 | 50 |
| 47 namespace { | 51 namespace { |
| 48 | 52 |
| 49 typedef uint32_t mips_inst; | 53 typedef uint32_t mips_inst; |
| 50 | 54 |
| 51 /* | 55 /* |
| 52 * We use these parameters to initialize the validator, below. They are | 56 * We use these parameters to initialize the validator, below. They are |
| 53 * somewhat different from the parameters used in real NaCl systems, to test | 57 * somewhat different from the parameters used in real NaCl systems, to test |
| 54 * degrees of validator freedom that we don't currently exercise in prod. | 58 * degrees of validator freedom that we don't currently exercise in prod. |
| 55 */ | 59 */ |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 243 static const AnnotatedInstruction examples_of_safe_jump_masks[] = { | 247 static const AnnotatedInstruction examples_of_safe_jump_masks[] = { |
| 244 { (10 << 21 | 14 << 16 | 10 << 11 | 36), | 248 { (10 << 21 | 14 << 16 | 10 << 11 | 36), |
| 245 "and t2,t2,t6 : simple jump masking" }, | 249 "and t2,t2,t6 : simple jump masking" }, |
| 246 }; | 250 }; |
| 247 | 251 |
| 248 static const AnnotatedInstruction examples_of_safe_jumps[] = { | 252 static const AnnotatedInstruction examples_of_safe_jumps[] = { |
| 249 { ((10<<21| 31 << 11 |9) ), "simple jump jalr t2" }, | 253 { ((10<<21| 31 << 11 |9) ), "simple jump jalr t2" }, |
| 250 { (10<<21|8), "simple jump jr t2" }, | 254 { (10<<21|8), "simple jump jr t2" }, |
| 251 }; | 255 }; |
| 252 | 256 |
| 253 static const AnnotatedInstruction nop_instruction[] = { | |
| 254 { 0, "nop"}, | |
| 255 }; | |
| 256 | |
| 257 TEST_F(ValidatorTests, SafeMaskedJumps) { | 257 TEST_F(ValidatorTests, SafeMaskedJumps) { |
| 258 /* | 258 /* |
| 259 * Produces examples of masked jumps using the safe jump table | 259 * Produces examples of masked jumps using the safe jump table |
| 260 * (above) and the list of possible masking instructions (above). | 260 * (above) and the list of possible masking instructions (above). |
| 261 */ | 261 */ |
| 262 for (unsigned m = 0; m < NACL_ARRAY_SIZE(examples_of_safe_jump_masks); m++) { | 262 for (unsigned m = 0; m < NACL_ARRAY_SIZE(examples_of_safe_jump_masks); m++) { |
| 263 for (unsigned s = 0; s < NACL_ARRAY_SIZE(examples_of_safe_jumps); s++) { | 263 for (unsigned s = 0; s < NACL_ARRAY_SIZE(examples_of_safe_jumps); s++) { |
| 264 ostringstream message; | 264 ostringstream message; |
| 265 message << examples_of_safe_jump_masks[m].about | 265 message << examples_of_safe_jump_masks[m].about |
| 266 << ", " | 266 << ", " |
| 267 << examples_of_safe_jumps[s].about; | 267 << examples_of_safe_jumps[s].about; |
| 268 mips_inst program[] = { | 268 mips_inst program[] = { |
| 269 nop_instruction[0].inst, | 269 kNop, |
| 270 examples_of_safe_jump_masks[m].inst, | 270 examples_of_safe_jump_masks[m].inst, |
| 271 examples_of_safe_jumps[s].inst, | 271 examples_of_safe_jumps[s].inst, |
| 272 }; | 272 }; |
| 273 ValidationShouldPass(program, | 273 ValidationShouldPass(program, |
| 274 3, | 274 3, |
| 275 kDefaultBaseAddr, | 275 kDefaultBaseAddr, |
| 276 message.str()); | 276 message.str()); |
| 277 } | 277 } |
| 278 } | 278 } |
| 279 } | 279 } |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 350 */ | 350 */ |
| 351 for (unsigned m = 0; m < NACL_ARRAY_SIZE(examples_of_safe_stack_masks); m++) { | 351 for (unsigned m = 0; m < NACL_ARRAY_SIZE(examples_of_safe_stack_masks); m++) { |
| 352 for (unsigned s = 0; s < NACL_ARRAY_SIZE(examples_of_safe_stack_ops); s++) { | 352 for (unsigned s = 0; s < NACL_ARRAY_SIZE(examples_of_safe_stack_ops); s++) { |
| 353 ostringstream bad_message; | 353 ostringstream bad_message; |
| 354 bad_message << examples_of_safe_stack_masks[m].about | 354 bad_message << examples_of_safe_stack_masks[m].about |
| 355 << ", " | 355 << ", " |
| 356 << examples_of_safe_stack_ops[s].about; | 356 << examples_of_safe_stack_ops[s].about; |
| 357 mips_inst bad_program[] = { | 357 mips_inst bad_program[] = { |
| 358 examples_of_safe_stack_masks[m].inst, | 358 examples_of_safe_stack_masks[m].inst, |
| 359 examples_of_safe_stack_ops[s].inst, | 359 examples_of_safe_stack_ops[s].inst, |
| 360 nop_instruction[0].inst | 360 kNop |
| 361 }; | 361 }; |
| 362 | 362 |
| 363 ValidationShouldFail(bad_program, | 363 ValidationShouldFail(bad_program, |
| 364 3, | 364 3, |
| 365 kDefaultBaseAddr, | 365 kDefaultBaseAddr, |
| 366 bad_message.str()); | 366 bad_message.str()); |
| 367 } | 367 } |
| 368 } | 368 } |
| 369 } | 369 } |
| 370 | 370 |
| 371 TEST_F(ValidatorTests, NopBundle) { |
| 372 vector<mips_inst> code(_validator.bytes_per_bundle() / kInstrSize, kNop); |
| 373 ValidationShouldPass(&code[0], code.size(), kDefaultBaseAddr, |
| 374 "NOP bundle"); |
| 375 } |
| 376 |
| 377 TEST_F(ValidatorTests, UnmaskedSpUpdate) { |
| 378 vector<mips_inst> code(_validator.bytes_per_bundle() / kInstrSize, kNop); |
| 379 for (vector<mips_inst>::size_type i = 0; i < code.size(); ++i) { |
| 380 std::fill(code.begin(), code.end(), kNop); |
| 381 code[i] = 0x8fbd0000; // lw $sp, 0($sp) |
| 382 ValidationShouldFail(&code[0], code.size(), kDefaultBaseAddr, |
| 383 "unmasked SP update"); |
| 384 } |
| 385 } |
| 386 |
| 387 TEST_F(ValidatorTests, MaskedSpUpdate) { |
| 388 vector<mips_inst> code((_validator.bytes_per_bundle() / kInstrSize) * 2, |
| 389 kNop); |
| 390 for (vector<mips_inst>::size_type i = 0; i < code.size() - 1; ++i) { |
| 391 std::fill(code.begin(), code.end(), kNop); |
| 392 code[i] = examples_of_safe_stack_ops[0].inst; |
| 393 code[i + 1] = examples_of_safe_stack_masks[0].inst; |
| 394 ValidationShouldPass(&code[0], code.size(), kDefaultBaseAddr, |
| 395 "masked SP update"); |
| 396 } |
| 397 } |
| 398 |
| 371 /* | 399 /* |
| 372 * Implementation of the ValidatorTests utility methods. These are documented | 400 * Implementation of the ValidatorTests utility methods. These are documented |
| 373 * toward the top of this file. | 401 * toward the top of this file. |
| 374 */ | 402 */ |
| 375 ValidatorTests::ValidatorTests() | 403 ValidatorTests::ValidatorTests() |
| 376 : _validator(kBytesPerBundle, | 404 : _validator(kBytesPerBundle, |
| 377 kCodeRegionSize, | 405 kCodeRegionSize, |
| 378 kDataRegionSize, | 406 kDataRegionSize, |
| 379 nacl_mips_dec::kRegListReserved, | 407 kRegListReserved, |
| 380 nacl_mips_dec::kRegisterStack) {} | 408 RegisterList(kRegisterStack)) {} |
| 381 | 409 |
| 382 bool ValidatorTests::Validate(const mips_inst *pattern, | 410 bool ValidatorTests::Validate(const mips_inst *pattern, |
| 383 size_t inst_count, | 411 size_t inst_count, |
| 384 uint32_t start_addr, | 412 uint32_t start_addr, |
| 385 ProblemSink *sink) { | 413 ProblemSink *sink) { |
| 386 // We think in instructions; CodeSegment thinks in bytes. | 414 // We think in instructions; CodeSegment thinks in bytes. |
| 387 const uint8_t *bytes = reinterpret_cast<const uint8_t *>(pattern); | 415 const uint8_t *bytes = reinterpret_cast<const uint8_t *>(pattern); |
| 388 CodeSegment segment(bytes, start_addr, inst_count * sizeof(mips_inst)); | 416 CodeSegment segment(bytes, start_addr, inst_count * sizeof(mips_inst)); |
| 389 | 417 |
| 390 vector<CodeSegment> segments; | 418 vector<CodeSegment> segments; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 429 return problems; | 457 return problems; |
| 430 } | 458 } |
| 431 | 459 |
| 432 }; // anonymous namespace | 460 }; // anonymous namespace |
| 433 | 461 |
| 434 // Test driver function. | 462 // Test driver function. |
| 435 int main(int argc, char *argv[]) { | 463 int main(int argc, char *argv[]) { |
| 436 testing::InitGoogleTest(&argc, argv); | 464 testing::InitGoogleTest(&argc, argv); |
| 437 return RUN_ALL_TESTS(); | 465 return RUN_ALL_TESTS(); |
| 438 } | 466 } |
| OLD | NEW |