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 |