OLD | NEW |
| (Empty) |
1 // Copyright (c) 2010, Google Inc. | |
2 // All rights reserved. | |
3 // | |
4 // Redistribution and use in source and binary forms, with or without | |
5 // modification, are permitted provided that the following conditions are | |
6 // met: | |
7 // | |
8 // * Redistributions of source code must retain the above copyright | |
9 // notice, this list of conditions and the following disclaimer. | |
10 // * Redistributions in binary form must reproduce the above | |
11 // copyright notice, this list of conditions and the following disclaimer | |
12 // in the documentation and/or other materials provided with the | |
13 // distribution. | |
14 // * Neither the name of Google Inc. nor the names of its | |
15 // contributors may be used to endorse or promote products derived from | |
16 // this software without specific prior written permission. | |
17 // | |
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 | |
30 // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> | |
31 | |
32 // dwarf_cfi_to_module_unittest.cc: Tests for google_breakpad::DwarfCFIToModule. | |
33 | |
34 #include "breakpad_googletest_includes.h" | |
35 #include "common/dwarf_cfi_to_module.h" | |
36 | |
37 using google_breakpad::Module; | |
38 using google_breakpad::DwarfCFIToModule; | |
39 using testing::ContainerEq; | |
40 using testing::Test; | |
41 using testing::_; | |
42 | |
43 struct MockCFIReporter: public DwarfCFIToModule::Reporter { | |
44 MockCFIReporter(const string &file, const string §ion) | |
45 : Reporter(file, section) { } | |
46 MOCK_METHOD2(UnnamedRegister, void(size_t offset, int reg)); | |
47 MOCK_METHOD2(UndefinedNotSupported, void(size_t offset, const string ®)); | |
48 MOCK_METHOD2(ExpressionsNotSupported, void(size_t offset, const string ®)); | |
49 }; | |
50 | |
51 struct DwarfCFIToModuleFixture { | |
52 DwarfCFIToModuleFixture() | |
53 : module("module name", "module os", "module arch", "module id"), | |
54 reporter("reporter file", "reporter section"), | |
55 handler(&module, register_names, &reporter) { | |
56 register_names.push_back("reg0"); | |
57 register_names.push_back("reg1"); | |
58 register_names.push_back("reg2"); | |
59 register_names.push_back("reg3"); | |
60 register_names.push_back("reg4"); | |
61 register_names.push_back("reg5"); | |
62 register_names.push_back("reg6"); | |
63 register_names.push_back("reg7"); | |
64 register_names.push_back("sp"); | |
65 register_names.push_back("pc"); | |
66 | |
67 EXPECT_CALL(reporter, UnnamedRegister(_, _)).Times(0); | |
68 EXPECT_CALL(reporter, UndefinedNotSupported(_, _)).Times(0); | |
69 EXPECT_CALL(reporter, ExpressionsNotSupported(_, _)).Times(0); | |
70 } | |
71 | |
72 Module module; | |
73 vector<string> register_names; | |
74 MockCFIReporter reporter; | |
75 DwarfCFIToModule handler; | |
76 vector<Module::StackFrameEntry *> entries; | |
77 }; | |
78 | |
79 class Entry: public DwarfCFIToModuleFixture, public Test { }; | |
80 | |
81 TEST_F(Entry, Accept) { | |
82 ASSERT_TRUE(handler.Entry(0x3b8961b8, 0xa21069698096fc98ULL, | |
83 0xb440ce248169c8d6ULL, 3, "", 0xea93c106)); | |
84 ASSERT_TRUE(handler.End()); | |
85 module.GetStackFrameEntries(&entries); | |
86 EXPECT_EQ(1U, entries.size()); | |
87 EXPECT_EQ(0xa21069698096fc98ULL, entries[0]->address); | |
88 EXPECT_EQ(0xb440ce248169c8d6ULL, entries[0]->size); | |
89 EXPECT_EQ(0U, entries[0]->initial_rules.size()); | |
90 EXPECT_EQ(0U, entries[0]->rule_changes.size()); | |
91 } | |
92 | |
93 TEST_F(Entry, AcceptOldVersion) { | |
94 ASSERT_TRUE(handler.Entry(0xeb60e0fc, 0x75b8806bb09eab78ULL, | |
95 0xc771f44958d40bbcULL, 1, "", 0x093c945e)); | |
96 ASSERT_TRUE(handler.End()); | |
97 module.GetStackFrameEntries(&entries); | |
98 EXPECT_EQ(1U, entries.size()); | |
99 EXPECT_EQ(0x75b8806bb09eab78ULL, entries[0]->address); | |
100 EXPECT_EQ(0xc771f44958d40bbcULL, entries[0]->size); | |
101 EXPECT_EQ(0U, entries[0]->initial_rules.size()); | |
102 EXPECT_EQ(0U, entries[0]->rule_changes.size()); | |
103 } | |
104 | |
105 struct RuleFixture: public DwarfCFIToModuleFixture { | |
106 RuleFixture() : DwarfCFIToModuleFixture() { | |
107 entry_address = 0x89327ebf86b47492ULL; | |
108 entry_size = 0x2f8cd573072fe02aULL; | |
109 return_reg = 0x7886a346; | |
110 } | |
111 void StartEntry() { | |
112 ASSERT_TRUE(handler.Entry(0x4445c05c, entry_address, entry_size, | |
113 3, "", return_reg)); | |
114 } | |
115 void CheckEntry() { | |
116 module.GetStackFrameEntries(&entries); | |
117 EXPECT_EQ(1U, entries.size()); | |
118 EXPECT_EQ(entry_address, entries[0]->address); | |
119 EXPECT_EQ(entry_size, entries[0]->size); | |
120 } | |
121 uint64 entry_address, entry_size; | |
122 unsigned return_reg; | |
123 }; | |
124 | |
125 class Rule: public RuleFixture, public Test { }; | |
126 | |
127 TEST_F(Rule, UndefinedRule) { | |
128 EXPECT_CALL(reporter, UndefinedNotSupported(_, "reg7")); | |
129 StartEntry(); | |
130 ASSERT_TRUE(handler.UndefinedRule(entry_address, 7)); | |
131 ASSERT_TRUE(handler.End()); | |
132 CheckEntry(); | |
133 EXPECT_EQ(0U, entries[0]->initial_rules.size()); | |
134 EXPECT_EQ(0U, entries[0]->rule_changes.size()); | |
135 } | |
136 | |
137 TEST_F(Rule, SameValueRule) { | |
138 StartEntry(); | |
139 ASSERT_TRUE(handler.SameValueRule(entry_address, 6)); | |
140 ASSERT_TRUE(handler.End()); | |
141 CheckEntry(); | |
142 Module::RuleMap expected_initial; | |
143 expected_initial["reg6"] = "reg6"; | |
144 EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial)); | |
145 EXPECT_EQ(0U, entries[0]->rule_changes.size()); | |
146 } | |
147 | |
148 TEST_F(Rule, OffsetRule) { | |
149 StartEntry(); | |
150 ASSERT_TRUE(handler.OffsetRule(entry_address + 1, return_reg, | |
151 DwarfCFIToModule::kCFARegister, | |
152 16927065)); | |
153 ASSERT_TRUE(handler.End()); | |
154 CheckEntry(); | |
155 EXPECT_EQ(0U, entries[0]->initial_rules.size()); | |
156 Module::RuleChangeMap expected_changes; | |
157 expected_changes[entry_address + 1][".ra"] = ".cfa 16927065 + ^"; | |
158 EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes)); | |
159 } | |
160 | |
161 TEST_F(Rule, OffsetRuleNegative) { | |
162 StartEntry(); | |
163 ASSERT_TRUE(handler.OffsetRule(entry_address + 1, | |
164 DwarfCFIToModule::kCFARegister, 4, -34530721)); | |
165 ASSERT_TRUE(handler.End()); | |
166 CheckEntry(); | |
167 EXPECT_EQ(0U, entries[0]->initial_rules.size()); | |
168 Module::RuleChangeMap expected_changes; | |
169 expected_changes[entry_address + 1][".cfa"] = "reg4 -34530721 + ^"; | |
170 EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes)); | |
171 } | |
172 | |
173 TEST_F(Rule, ValOffsetRule) { | |
174 // Use an unnamed register number, to exercise that branch of RegisterName. | |
175 EXPECT_CALL(reporter, UnnamedRegister(_, 10)); | |
176 StartEntry(); | |
177 ASSERT_TRUE(handler.ValOffsetRule(entry_address + 0x5ab7, | |
178 DwarfCFIToModule::kCFARegister, | |
179 10, 61812979)); | |
180 ASSERT_TRUE(handler.End()); | |
181 CheckEntry(); | |
182 EXPECT_EQ(0U, entries[0]->initial_rules.size()); | |
183 Module::RuleChangeMap expected_changes; | |
184 expected_changes[entry_address + 0x5ab7][".cfa"] = | |
185 "unnamed_register10 61812979 +"; | |
186 EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes)); | |
187 } | |
188 | |
189 TEST_F(Rule, RegisterRule) { | |
190 StartEntry(); | |
191 ASSERT_TRUE(handler.RegisterRule(entry_address, return_reg, 3)); | |
192 ASSERT_TRUE(handler.End()); | |
193 CheckEntry(); | |
194 Module::RuleMap expected_initial; | |
195 expected_initial[".ra"] = "reg3"; | |
196 EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial)); | |
197 EXPECT_EQ(0U, entries[0]->rule_changes.size()); | |
198 } | |
199 | |
200 TEST_F(Rule, ExpressionRule) { | |
201 EXPECT_CALL(reporter, ExpressionsNotSupported(_, "reg2")); | |
202 StartEntry(); | |
203 ASSERT_TRUE(handler.ExpressionRule(entry_address + 0xf326, 2, | |
204 "it takes two to tango")); | |
205 ASSERT_TRUE(handler.End()); | |
206 CheckEntry(); | |
207 EXPECT_EQ(0U, entries[0]->initial_rules.size()); | |
208 EXPECT_EQ(0U, entries[0]->rule_changes.size()); | |
209 } | |
210 | |
211 TEST_F(Rule, ValExpressionRule) { | |
212 EXPECT_CALL(reporter, ExpressionsNotSupported(_, "reg0")); | |
213 StartEntry(); | |
214 ASSERT_TRUE(handler.ValExpressionRule(entry_address + 0x6367, 0, | |
215 "bit off more than he could chew")); | |
216 ASSERT_TRUE(handler.End()); | |
217 CheckEntry(); | |
218 EXPECT_EQ(0U, entries[0]->initial_rules.size()); | |
219 EXPECT_EQ(0U, entries[0]->rule_changes.size()); | |
220 } | |
221 | |
222 TEST_F(Rule, DefaultReturnAddressRule) { | |
223 return_reg = 2; | |
224 StartEntry(); | |
225 ASSERT_TRUE(handler.RegisterRule(entry_address, 0, 1)); | |
226 ASSERT_TRUE(handler.End()); | |
227 CheckEntry(); | |
228 Module::RuleMap expected_initial; | |
229 expected_initial[".ra"] = "reg2"; | |
230 expected_initial["reg0"] = "reg1"; | |
231 EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial)); | |
232 EXPECT_EQ(0U, entries[0]->rule_changes.size()); | |
233 } | |
234 | |
235 TEST_F(Rule, DefaultReturnAddressRuleOverride) { | |
236 return_reg = 2; | |
237 StartEntry(); | |
238 ASSERT_TRUE(handler.RegisterRule(entry_address, return_reg, 1)); | |
239 ASSERT_TRUE(handler.End()); | |
240 CheckEntry(); | |
241 Module::RuleMap expected_initial; | |
242 expected_initial[".ra"] = "reg1"; | |
243 EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial)); | |
244 EXPECT_EQ(0U, entries[0]->rule_changes.size()); | |
245 } | |
246 | |
247 TEST_F(Rule, DefaultReturnAddressRuleLater) { | |
248 return_reg = 2; | |
249 StartEntry(); | |
250 ASSERT_TRUE(handler.RegisterRule(entry_address + 1, return_reg, 1)); | |
251 ASSERT_TRUE(handler.End()); | |
252 CheckEntry(); | |
253 Module::RuleMap expected_initial; | |
254 expected_initial[".ra"] = "reg2"; | |
255 EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial)); | |
256 Module::RuleChangeMap expected_changes; | |
257 expected_changes[entry_address + 1][".ra"] = "reg1"; | |
258 EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes)); | |
259 } | |
260 | |
OLD | NEW |