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 "native_client/src/trusted/validator_arm/validator_tests.h"
8 :
9 : namespace nacl_val_arm_test {
10 :
11 3480 : void ProblemSpy::ReportProblemMessage(Violation violation,
12 : uint32_t vaddr,
13 : const char* message) {
14 3480 : ProblemRecord prob(violation, vaddr, message);
15 3480 : problems_.push_back(prob);
16 3480 : }
17 :
18 51 : ValidatorTests::ValidatorTests()
19 : : _validator(NULL),
20 51 : _is_valid_single_instruction_destination_register() {
21 : _is_valid_single_instruction_destination_register.
22 51 : Add(Register::Tp()).Add(Register::Sp()).Add(Register::Pc());
23 51 : }
24 :
25 1365 : const nacl_arm_dec::ClassDecoder& ValidatorTests::decode(
26 : nacl_arm_dec::Instruction inst) const {
27 1365 : return _validator->decode(inst);
28 : }
29 :
30 261882 : bool ValidatorTests::validate(const arm_inst *pattern,
31 : size_t inst_count,
32 : uint32_t start_addr,
33 : ProblemSink *sink) {
34 : // We think in instructions; CodeSegment thinks in bytes.
35 261882 : const uint8_t *bytes = reinterpret_cast<const uint8_t *>(pattern);
36 261882 : CodeSegment segment(bytes, start_addr, inst_count * sizeof(arm_inst));
37 :
38 261882 : vector<CodeSegment> segments;
39 261882 : segments.push_back(segment);
40 :
41 261882 : return _validator->validate(segments, sink);
42 : }
43 :
44 372203 : ViolationSet ValidatorTests::find_violations(
45 : const arm_inst *pattern,
46 : size_t inst_count,
47 : uint32_t start_addr,
48 : ProblemSink *sink) {
49 : // We think in instructions; CodeSegment thinks in bytes.
50 372203 : const uint8_t *bytes = reinterpret_cast<const uint8_t *>(pattern);
51 372203 : CodeSegment segment(bytes, start_addr, inst_count * sizeof(arm_inst));
52 :
53 372203 : vector<CodeSegment> segments;
54 372203 : segments.push_back(segment);
55 :
56 372203 : return _validator->find_violations(segments, sink);
57 : }
58 :
59 119969 : void ValidatorTests::validation_should_pass(const arm_inst *pattern,
60 : size_t inst_count,
61 : uint32_t base_addr,
62 : const string &msg) {
63 119969 : ProblemSpy spy;
64 119969 : bool validation_result = validate(pattern, inst_count, base_addr, &spy);
65 :
66 119969 : std::string errors;
67 119969 : vector<ProblemRecord> &problems = spy.get_problems();
68 239938 : for (vector<ProblemRecord>::const_iterator it = problems.begin();
69 119969 : it != problems.end();
70 : ++it) {
71 0 : if (it != problems.begin()) {
72 0 : errors += "\n";
73 : }
74 0 : errors += std::string("\t") + it->message();
75 : }
76 :
77 119969 : ASSERT_TRUE(validation_result) << msg << " should pass at " << base_addr <<
78 119969 : ":\n" << errors;
79 : }
80 :
81 1587 : void ValidatorTests::validation_should_pass2(const arm_inst *pattern,
82 : size_t inst_count,
83 : uint32_t base_addr,
84 : const string &msg) {
85 : // A couple sanity checks for correct usage.
86 1587 : ASSERT_EQ(2U, inst_count)
87 0 : << "This routine only supports 2-instruction patterns.";
88 1587 : ASSERT_TRUE(
89 : _validator->bundle_for_address(base_addr).begin_addr() == base_addr)
90 0 : << "base_addr parameter must be bundle-aligned";
91 :
92 : // Try error case where second instruction occurs as first instruction.
93 : arm_inst second_as_program[] = {
94 1587 : pattern[1]
95 1587 : };
96 1587 : ostringstream bad_first_message;
97 1587 : bad_first_message << msg << ": without first instruction";
98 : validation_should_fail(second_as_program,
99 : NACL_ARRAY_SIZE(second_as_program),
100 : base_addr,
101 1587 : bad_first_message.str());
102 :
103 : // Try the legitimate (non-overlapping) variations:
104 1587 : uint32_t last_addr = base_addr + (kBytesPerBundle - 4);
105 6348 : for (uint32_t addr = base_addr; addr < last_addr; addr += 4) {
106 4761 : validation_should_pass(pattern, inst_count, addr, msg);
107 : }
108 :
109 : // Make sure it fails over bundle boundaries.
110 1587 : ProblemSpy spy;
111 : ViolationSet violations = find_violations(
112 1587 : pattern, inst_count, last_addr, &spy);
113 :
114 1587 : EXPECT_NE(violations, kNoViolations)
115 0 : << msg << " should fail at overlapping address " << last_addr;
116 1587 : EXPECT_TRUE(nacl_arm_dec::ContainsCrossesBundleViolation(violations))
117 0 : << msg << " should contain crosses bundle violation";
118 :
119 1587 : vector<ProblemRecord> &problems = spy.get_problems();
120 1587 : ASSERT_EQ(1U, problems.size())
121 0 : << msg << " should have 1 problem at overlapping address " << last_addr;
122 :
123 1587 : ProblemRecord first = problems[0];
124 :
125 1587 : if (first.violation() !=
126 : nacl_arm_dec::DATA_REGISTER_UPDATE_CROSSES_BUNDLE_VIOLATION) {
127 1587 : last_addr += 4;
128 : }
129 1587 : EXPECT_EQ(last_addr, first.vaddr())
130 0 : << "Problem in valid but mis-aligned pseudo-instruction ("
131 0 : << msg
132 1587 : << ") must be reported at end of bundle";
133 1587 : EXPECT_FALSE(nacl_arm_dec::IsSafetyViolation(first.violation()))
134 0 : << "Just crossing a bundle should not make a safe instruction unsafe: "
135 1587 : << msg;
136 :
137 : // Be sure that we get one of the crosses bundle error messages.
138 1587 : EXPECT_TRUE(nacl_arm_dec::IsCrossesBundleViolation(first.violation()));
139 : }
140 :
141 370616 : ViolationSet ValidatorTests::validation_should_fail(
142 : const arm_inst *pattern,
143 : size_t inst_count,
144 : uint32_t base_addr,
145 : const string &msg,
146 : ProblemSpy* spy) {
147 : // TODO(cbiffle): test at various overlapping and non-overlapping addresses,
148 : // like above. Not that this is a spectacularly likely failure case, but
149 : // it's worth exercising.
150 : ViolationSet violations =
151 370616 : find_violations(pattern, inst_count, base_addr, spy);
152 370616 : EXPECT_NE(violations, kNoViolations) << "Expected to fail: " << msg;
153 :
154 370616 : if (spy != NULL) {
155 : // There should be at least one problem.
156 1893 : vector<ProblemRecord> &problems = spy->get_problems();
157 1893 : EXPECT_LT(static_cast<size_t>(0), problems.size());
158 :
159 : // Violations found in problems should match violations returned by
160 : // find_violations.
161 1893 : ViolationSet problem_violations = kNoViolations;
162 7572 : for (vector<ProblemRecord>::iterator iter = problems.begin();
163 3786 : iter != problems.end();
164 : ++iter) {
165 : problem_violations = nacl_arm_dec::ViolationUnion(
166 : problem_violations,
167 1893 : nacl_arm_dec::ViolationBit(iter->violation()));
168 : }
169 1893 : EXPECT_EQ(violations, problem_violations)
170 0 : << "Violation differences: " << msg;
171 : }
172 :
173 : // The rest of the checking is done in the caller.
174 370616 : return violations;
175 : }
176 :
177 0 : void ValidatorTests::all_cond_values_pass(const arm_inst prototype,
178 : uint32_t base_addr,
179 : const string &msg) {
180 0 : arm_inst test_inst = prototype;
181 0 : for (Instruction::Condition cond = Instruction::EQ;
182 : cond < Instruction::UNCONDITIONAL;
183 : cond = Instruction::Next(cond)) {
184 0 : test_inst = ChangeCond(test_inst, cond);
185 0 : EXPECT_TRUE(validate(&test_inst, 1, base_addr))
186 0 : << "Fails on cond " << Instruction::ToString(cond) << ": " << msg;
187 : }
188 0 : }
189 :
190 721 : void ValidatorTests::all_cond_values_fail(const arm_inst prototype,
191 : uint32_t base_addr,
192 : const string &msg) {
193 721 : arm_inst test_inst = prototype;
194 11536 : for (Instruction::Condition cond = Instruction::EQ;
195 : cond < Instruction::UNCONDITIONAL;
196 : cond = Instruction::Next(cond)) {
197 10815 : test_inst = ChangeCond(test_inst, cond);
198 10815 : EXPECT_FALSE(validate(&test_inst, 1, base_addr))
199 0 : << std::hex << test_inst
200 10815 : << ": Passes on cond " << Instruction::ToString(cond) << ": " << msg;
201 : }
202 721 : }
203 :
204 3 : } // namespace nacl_val_arm_test
|