|
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 // module_unittest.cc: Unit tests for google_breakpad::Module. |
|
33 |
|
34 #include <errno.h> |
|
35 #include <stdio.h> |
|
36 #include <stdlib.h> |
|
37 #include <string.h> |
|
38 |
|
39 #include <algorithm> |
|
40 #include <sstream> |
|
41 #include <string> |
|
42 |
|
43 #include "breakpad_googletest_includes.h" |
|
44 #include "common/module.h" |
|
45 #include "common/using_std_string.h" |
|
46 |
|
47 using google_breakpad::Module; |
|
48 using google_breakpad::ToUniqueString; |
|
49 using google_breakpad::ustr__ZDcfa; |
|
50 using std::stringstream; |
|
51 using std::vector; |
|
52 using testing::ContainerEq; |
|
53 |
|
54 static Module::Function *generate_duplicate_function(const string &name) { |
|
55 const Module::Address DUP_ADDRESS = 0xd35402aac7a7ad5cLL; |
|
56 const Module::Address DUP_SIZE = 0x200b26e605f99071LL; |
|
57 const Module::Address DUP_PARAMETER_SIZE = 0xf14ac4fed48c4a99LL; |
|
58 |
|
59 Module::Function *function = new(Module::Function); |
|
60 function->name = name; |
|
61 function->address = DUP_ADDRESS; |
|
62 function->size = DUP_SIZE; |
|
63 function->parameter_size = DUP_PARAMETER_SIZE; |
|
64 return function; |
|
65 } |
|
66 |
|
67 #define MODULE_NAME "name with spaces" |
|
68 #define MODULE_OS "os-name" |
|
69 #define MODULE_ARCH "architecture" |
|
70 #define MODULE_ID "id-string" |
|
71 |
|
72 TEST(Write, Header) { |
|
73 stringstream s; |
|
74 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
|
75 m.Write(s, ALL_SYMBOL_DATA); |
|
76 string contents = s.str(); |
|
77 EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n", |
|
78 contents.c_str()); |
|
79 } |
|
80 |
|
81 TEST(Write, OneLineFunc) { |
|
82 stringstream s; |
|
83 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
|
84 |
|
85 Module::File *file = m.FindFile("file_name.cc"); |
|
86 Module::Function *function = new(Module::Function); |
|
87 function->name = "function_name"; |
|
88 function->address = 0xe165bf8023b9d9abLL; |
|
89 function->size = 0x1e4bb0eb1cbf5b09LL; |
|
90 function->parameter_size = 0x772beee89114358aLL; |
|
91 Module::Line line = { 0xe165bf8023b9d9abLL, 0x1e4bb0eb1cbf5b09LL, |
|
92 file, 67519080 }; |
|
93 function->lines.push_back(line); |
|
94 m.AddFunction(function); |
|
95 |
|
96 m.Write(s, ALL_SYMBOL_DATA); |
|
97 string contents = s.str(); |
|
98 EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" |
|
99 "FILE 0 file_name.cc\n" |
|
100 "FUNC e165bf8023b9d9ab 1e4bb0eb1cbf5b09 772beee89114358a" |
|
101 " function_name\n" |
|
102 "e165bf8023b9d9ab 1e4bb0eb1cbf5b09 67519080 0\n", |
|
103 contents.c_str()); |
|
104 } |
|
105 |
|
106 TEST(Write, RelativeLoadAddress) { |
|
107 stringstream s; |
|
108 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
|
109 |
|
110 // Some source files. We will expect to see them in lexicographic order. |
|
111 Module::File *file1 = m.FindFile("filename-b.cc"); |
|
112 Module::File *file2 = m.FindFile("filename-a.cc"); |
|
113 |
|
114 // A function. |
|
115 Module::Function *function = new(Module::Function); |
|
116 function->name = "A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)"; |
|
117 function->address = 0xbec774ea5dd935f3LL; |
|
118 function->size = 0x2922088f98d3f6fcLL; |
|
119 function->parameter_size = 0xe5e9aa008bd5f0d0LL; |
|
120 |
|
121 // Some source lines. The module should not sort these. |
|
122 Module::Line line1 = { 0xbec774ea5dd935f3LL, 0x1c2be6d6c5af2611LL, |
|
123 file1, 41676901 }; |
|
124 Module::Line line2 = { 0xdaf35bc123885c04LL, 0xcf621b8d324d0ebLL, |
|
125 file2, 67519080 }; |
|
126 function->lines.push_back(line2); |
|
127 function->lines.push_back(line1); |
|
128 |
|
129 m.AddFunction(function); |
|
130 |
|
131 // Some stack information. |
|
132 Module::StackFrameEntry *entry = new Module::StackFrameEntry(); |
|
133 entry->address = 0x30f9e5c83323973dULL; |
|
134 entry->size = 0x49fc9ca7c7c13dc2ULL; |
|
135 entry->initial_rules[ustr__ZDcfa()] = Module::Expr("he was a handsome man"); |
|
136 entry->initial_rules[ToUniqueString("and")] = |
|
137 Module::Expr("what i want to know is"); |
|
138 entry->initial_rules[ToUniqueString("stallion")] = |
|
139 Module::Expr(ToUniqueString("and break"), 8, false); |
|
140 entry->initial_rules[ToUniqueString("onetwothreefourfive")] = |
|
141 Module::Expr(ToUniqueString("pigeonsjustlikethat"), 42, true); |
|
142 entry->rule_changes[0x30f9e5c83323973eULL][ToUniqueString("how")] = |
|
143 Module::Expr("do you like your blueeyed boy"); |
|
144 entry->rule_changes[0x30f9e5c83323973eULL][ToUniqueString("Mister")] = |
|
145 Module::Expr("Death"); |
|
146 m.AddStackFrameEntry(entry); |
|
147 |
|
148 // Set the load address. Doing this after adding all the data to |
|
149 // the module must work fine. |
|
150 m.SetLoadAddress(0x2ab698b0b6407073LL); |
|
151 |
|
152 m.Write(s, ALL_SYMBOL_DATA); |
|
153 string contents = s.str(); |
|
154 EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" |
|
155 "FILE 0 filename-a.cc\n" |
|
156 "FILE 1 filename-b.cc\n" |
|
157 "FUNC 9410dc39a798c580 2922088f98d3f6fc e5e9aa008bd5f0d0" |
|
158 " A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)\n" |
|
159 "b03cc3106d47eb91 cf621b8d324d0eb 67519080 0\n" |
|
160 "9410dc39a798c580 1c2be6d6c5af2611 41676901 1\n" |
|
161 "STACK CFI INIT 6434d177ce326ca 49fc9ca7c7c13dc2" |
|
162 " .cfa: he was a handsome man" |
|
163 " and: what i want to know is" |
|
164 " onetwothreefourfive: pigeonsjustlikethat 42 + ^" |
|
165 " stallion: and break 8 +\n" |
|
166 "STACK CFI 6434d177ce326cb" |
|
167 " Mister: Death" |
|
168 " how: do you like your blueeyed boy\n", |
|
169 contents.c_str()); |
|
170 } |
|
171 |
|
172 TEST(Write, OmitUnusedFiles) { |
|
173 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
|
174 |
|
175 // Create some source files. |
|
176 Module::File *file1 = m.FindFile("filename1"); |
|
177 m.FindFile("filename2"); // not used by any line |
|
178 Module::File *file3 = m.FindFile("filename3"); |
|
179 |
|
180 // Create a function. |
|
181 Module::Function *function = new(Module::Function); |
|
182 function->name = "function_name"; |
|
183 function->address = 0x9b926d464f0b9384LL; |
|
184 function->size = 0x4f524a4ba795e6a6LL; |
|
185 function->parameter_size = 0xbbe8133a6641c9b7LL; |
|
186 |
|
187 // Source files that refer to some files, but not others. |
|
188 Module::Line line1 = { 0x595fa44ebacc1086LL, 0x1e1e0191b066c5b3LL, |
|
189 file1, 137850127 }; |
|
190 Module::Line line2 = { 0x401ce8c8a12d25e3LL, 0x895751c41b8d2ce2LL, |
|
191 file3, 28113549 }; |
|
192 function->lines.push_back(line1); |
|
193 function->lines.push_back(line2); |
|
194 m.AddFunction(function); |
|
195 |
|
196 m.AssignSourceIds(); |
|
197 |
|
198 vector<Module::File *> vec; |
|
199 m.GetFiles(&vec); |
|
200 EXPECT_EQ((size_t) 3, vec.size()); |
|
201 EXPECT_STREQ("filename1", vec[0]->name.c_str()); |
|
202 EXPECT_NE(-1, vec[0]->source_id); |
|
203 // Expect filename2 not to be used. |
|
204 EXPECT_STREQ("filename2", vec[1]->name.c_str()); |
|
205 EXPECT_EQ(-1, vec[1]->source_id); |
|
206 EXPECT_STREQ("filename3", vec[2]->name.c_str()); |
|
207 EXPECT_NE(-1, vec[2]->source_id); |
|
208 |
|
209 stringstream s; |
|
210 m.Write(s, ALL_SYMBOL_DATA); |
|
211 string contents = s.str(); |
|
212 EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" |
|
213 "FILE 0 filename1\n" |
|
214 "FILE 1 filename3\n" |
|
215 "FUNC 9b926d464f0b9384 4f524a4ba795e6a6 bbe8133a6641c9b7" |
|
216 " function_name\n" |
|
217 "595fa44ebacc1086 1e1e0191b066c5b3 137850127 0\n" |
|
218 "401ce8c8a12d25e3 895751c41b8d2ce2 28113549 1\n", |
|
219 contents.c_str()); |
|
220 } |
|
221 |
|
222 TEST(Write, NoCFI) { |
|
223 stringstream s; |
|
224 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
|
225 |
|
226 // Some source files. We will expect to see them in lexicographic order. |
|
227 Module::File *file1 = m.FindFile("filename.cc"); |
|
228 |
|
229 // A function. |
|
230 Module::Function *function = new(Module::Function); |
|
231 function->name = "A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)"; |
|
232 function->address = 0xbec774ea5dd935f3LL; |
|
233 function->size = 0x2922088f98d3f6fcLL; |
|
234 function->parameter_size = 0xe5e9aa008bd5f0d0LL; |
|
235 |
|
236 // Some source lines. The module should not sort these. |
|
237 Module::Line line1 = { 0xbec774ea5dd935f3LL, 0x1c2be6d6c5af2611LL, |
|
238 file1, 41676901 }; |
|
239 function->lines.push_back(line1); |
|
240 |
|
241 m.AddFunction(function); |
|
242 |
|
243 // Some stack information. |
|
244 Module::StackFrameEntry *entry = new Module::StackFrameEntry(); |
|
245 entry->address = 0x30f9e5c83323973dULL; |
|
246 entry->size = 0x49fc9ca7c7c13dc2ULL; |
|
247 entry->initial_rules[ustr__ZDcfa()] = Module::Expr("he was a handsome man"); |
|
248 entry->initial_rules[ToUniqueString("and")] = |
|
249 Module::Expr("what i want to know is"); |
|
250 entry->rule_changes[0x30f9e5c83323973eULL][ToUniqueString("how")] = |
|
251 Module::Expr("do you like your blueeyed boy"); |
|
252 entry->rule_changes[0x30f9e5c83323973eULL][ToUniqueString("Mister")] = |
|
253 Module::Expr("Death"); |
|
254 m.AddStackFrameEntry(entry); |
|
255 |
|
256 // Set the load address. Doing this after adding all the data to |
|
257 // the module must work fine. |
|
258 m.SetLoadAddress(0x2ab698b0b6407073LL); |
|
259 |
|
260 m.Write(s, NO_CFI); |
|
261 string contents = s.str(); |
|
262 EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" |
|
263 "FILE 0 filename.cc\n" |
|
264 "FUNC 9410dc39a798c580 2922088f98d3f6fc e5e9aa008bd5f0d0" |
|
265 " A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)\n" |
|
266 "9410dc39a798c580 1c2be6d6c5af2611 41676901 0\n", |
|
267 contents.c_str()); |
|
268 } |
|
269 |
|
270 TEST(Construct, AddFunctions) { |
|
271 stringstream s; |
|
272 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
|
273 |
|
274 // Two functions. |
|
275 Module::Function *function1 = new(Module::Function); |
|
276 function1->name = "_without_form"; |
|
277 function1->address = 0xd35024aa7ca7da5cLL; |
|
278 function1->size = 0x200b26e605f99071LL; |
|
279 function1->parameter_size = 0xf14ac4fed48c4a99LL; |
|
280 |
|
281 Module::Function *function2 = new(Module::Function); |
|
282 function2->name = "_and_void"; |
|
283 function2->address = 0x2987743d0b35b13fLL; |
|
284 function2->size = 0xb369db048deb3010LL; |
|
285 function2->parameter_size = 0x938e556cb5a79988LL; |
|
286 |
|
287 // Put them in a vector. |
|
288 vector<Module::Function *> vec; |
|
289 vec.push_back(function1); |
|
290 vec.push_back(function2); |
|
291 |
|
292 m.AddFunctions(vec.begin(), vec.end()); |
|
293 |
|
294 m.Write(s, ALL_SYMBOL_DATA); |
|
295 string contents = s.str(); |
|
296 EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" |
|
297 "FUNC 2987743d0b35b13f b369db048deb3010 938e556cb5a79988" |
|
298 " _and_void\n" |
|
299 "FUNC d35024aa7ca7da5c 200b26e605f99071 f14ac4fed48c4a99" |
|
300 " _without_form\n", |
|
301 contents.c_str()); |
|
302 |
|
303 // Check that m.GetFunctions returns the functions we expect. |
|
304 vec.clear(); |
|
305 m.GetFunctions(&vec, vec.end()); |
|
306 EXPECT_TRUE(vec.end() != find(vec.begin(), vec.end(), function1)); |
|
307 EXPECT_TRUE(vec.end() != find(vec.begin(), vec.end(), function2)); |
|
308 EXPECT_EQ((size_t) 2, vec.size()); |
|
309 } |
|
310 |
|
311 TEST(Construct, AddFrames) { |
|
312 stringstream s; |
|
313 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
|
314 |
|
315 // First STACK CFI entry, with no initial rules or deltas. |
|
316 Module::StackFrameEntry *entry1 = new Module::StackFrameEntry(); |
|
317 entry1->address = 0xddb5f41285aa7757ULL; |
|
318 entry1->size = 0x1486493370dc5073ULL; |
|
319 m.AddStackFrameEntry(entry1); |
|
320 |
|
321 // Second STACK CFI entry, with initial rules but no deltas. |
|
322 Module::StackFrameEntry *entry2 = new Module::StackFrameEntry(); |
|
323 entry2->address = 0x8064f3af5e067e38ULL; |
|
324 entry2->size = 0x0de2a5ee55509407ULL; |
|
325 entry2->initial_rules[ustr__ZDcfa()] = |
|
326 Module::Expr("I think that I shall never see"); |
|
327 entry2->initial_rules[ToUniqueString("stromboli")] = |
|
328 Module::Expr("a poem lovely as a tree"); |
|
329 entry2->initial_rules[ToUniqueString("cannoli")] = |
|
330 Module::Expr("a tree whose hungry mouth is prest"); |
|
331 m.AddStackFrameEntry(entry2); |
|
332 |
|
333 // Third STACK CFI entry, with initial rules and deltas. |
|
334 Module::StackFrameEntry *entry3 = new Module::StackFrameEntry(); |
|
335 entry3->address = 0x5e8d0db0a7075c6cULL; |
|
336 entry3->size = 0x1c7edb12a7aea229ULL; |
|
337 entry3->initial_rules[ustr__ZDcfa()] = Module::Expr("Whose woods are these"); |
|
338 entry3->rule_changes[0x47ceb0f63c269d7fULL][ToUniqueString("calzone")] = |
|
339 Module::Expr("the village though"); |
|
340 entry3->rule_changes[0x47ceb0f63c269d7fULL][ToUniqueString("cannoli")] = |
|
341 Module::Expr("he will not see me stopping here"); |
|
342 entry3->rule_changes[0x36682fad3763ffffULL][ToUniqueString("stromboli")] = |
|
343 Module::Expr("his house is in"); |
|
344 entry3->rule_changes[0x36682fad3763ffffULL][ustr__ZDcfa()] = |
|
345 Module::Expr("I think I know"); |
|
346 m.AddStackFrameEntry(entry3); |
|
347 |
|
348 // Check that Write writes STACK CFI records properly. |
|
349 m.Write(s, ALL_SYMBOL_DATA); |
|
350 string contents = s.str(); |
|
351 EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" |
|
352 "STACK CFI INIT 5e8d0db0a7075c6c 1c7edb12a7aea229" |
|
353 " .cfa: Whose woods are these\n" |
|
354 "STACK CFI 36682fad3763ffff" |
|
355 " .cfa: I think I know" |
|
356 " stromboli: his house is in\n" |
|
357 "STACK CFI 47ceb0f63c269d7f" |
|
358 " calzone: the village though" |
|
359 " cannoli: he will not see me stopping here\n" |
|
360 "STACK CFI INIT 8064f3af5e067e38 de2a5ee55509407" |
|
361 " .cfa: I think that I shall never see" |
|
362 " cannoli: a tree whose hungry mouth is prest" |
|
363 " stromboli: a poem lovely as a tree\n" |
|
364 "STACK CFI INIT ddb5f41285aa7757 1486493370dc5073 \n", |
|
365 contents.c_str()); |
|
366 |
|
367 // Check that GetStackFrameEntries works. |
|
368 vector<Module::StackFrameEntry *> entries; |
|
369 m.GetStackFrameEntries(&entries); |
|
370 ASSERT_EQ(3U, entries.size()); |
|
371 // Check first entry. |
|
372 EXPECT_EQ(0x5e8d0db0a7075c6cULL, entries[0]->address); |
|
373 EXPECT_EQ(0x1c7edb12a7aea229ULL, entries[0]->size); |
|
374 Module::RuleMap entry1_initial; |
|
375 entry1_initial[ustr__ZDcfa()] = Module::Expr("Whose woods are these"); |
|
376 EXPECT_THAT(entries[0]->initial_rules, ContainerEq(entry1_initial)); |
|
377 Module::RuleChangeMap entry1_changes; |
|
378 entry1_changes[0x36682fad3763ffffULL][ustr__ZDcfa()] = |
|
379 Module::Expr("I think I know"); |
|
380 entry1_changes[0x36682fad3763ffffULL][ToUniqueString("stromboli")] = |
|
381 Module::Expr("his house is in"); |
|
382 entry1_changes[0x47ceb0f63c269d7fULL][ToUniqueString("calzone")] = |
|
383 Module::Expr("the village though"); |
|
384 entry1_changes[0x47ceb0f63c269d7fULL][ToUniqueString("cannoli")] = |
|
385 Module::Expr("he will not see me stopping here"); |
|
386 EXPECT_THAT(entries[0]->rule_changes, ContainerEq(entry1_changes)); |
|
387 // Check second entry. |
|
388 EXPECT_EQ(0x8064f3af5e067e38ULL, entries[1]->address); |
|
389 EXPECT_EQ(0x0de2a5ee55509407ULL, entries[1]->size); |
|
390 ASSERT_EQ(3U, entries[1]->initial_rules.size()); |
|
391 Module::RuleMap entry2_initial; |
|
392 entry2_initial[ustr__ZDcfa()] = |
|
393 Module::Expr("I think that I shall never see"); |
|
394 entry2_initial[ToUniqueString("stromboli")] = |
|
395 Module::Expr("a poem lovely as a tree"); |
|
396 entry2_initial[ToUniqueString("cannoli")] = |
|
397 Module::Expr("a tree whose hungry mouth is prest"); |
|
398 EXPECT_THAT(entries[1]->initial_rules, ContainerEq(entry2_initial)); |
|
399 ASSERT_EQ(0U, entries[1]->rule_changes.size()); |
|
400 // Check third entry. |
|
401 EXPECT_EQ(0xddb5f41285aa7757ULL, entries[2]->address); |
|
402 EXPECT_EQ(0x1486493370dc5073ULL, entries[2]->size); |
|
403 ASSERT_EQ(0U, entries[2]->initial_rules.size()); |
|
404 ASSERT_EQ(0U, entries[2]->rule_changes.size()); |
|
405 } |
|
406 |
|
407 TEST(Construct, UniqueFiles) { |
|
408 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
|
409 Module::File *file1 = m.FindFile("foo"); |
|
410 Module::File *file2 = m.FindFile(string("bar")); |
|
411 Module::File *file3 = m.FindFile(string("foo")); |
|
412 Module::File *file4 = m.FindFile("bar"); |
|
413 EXPECT_NE(file1, file2); |
|
414 EXPECT_EQ(file1, file3); |
|
415 EXPECT_EQ(file2, file4); |
|
416 EXPECT_EQ(file1, m.FindExistingFile("foo")); |
|
417 EXPECT_TRUE(m.FindExistingFile("baz") == NULL); |
|
418 } |
|
419 |
|
420 TEST(Construct, DuplicateFunctions) { |
|
421 stringstream s; |
|
422 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
|
423 |
|
424 // Two functions. |
|
425 Module::Function *function1 = generate_duplicate_function("_without_form"); |
|
426 Module::Function *function2 = generate_duplicate_function("_without_form"); |
|
427 |
|
428 m.AddFunction(function1); |
|
429 m.AddFunction(function2); |
|
430 |
|
431 m.Write(s, ALL_SYMBOL_DATA); |
|
432 string contents = s.str(); |
|
433 EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" |
|
434 "FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99" |
|
435 " _without_form\n", |
|
436 contents.c_str()); |
|
437 } |
|
438 |
|
439 TEST(Construct, FunctionsWithSameAddress) { |
|
440 stringstream s; |
|
441 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
|
442 |
|
443 // Two functions. |
|
444 Module::Function *function1 = generate_duplicate_function("_without_form"); |
|
445 Module::Function *function2 = generate_duplicate_function("_and_void"); |
|
446 |
|
447 m.AddFunction(function1); |
|
448 m.AddFunction(function2); |
|
449 |
|
450 m.Write(s, ALL_SYMBOL_DATA); |
|
451 string contents = s.str(); |
|
452 EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" |
|
453 "FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99" |
|
454 " _and_void\n" |
|
455 "FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99" |
|
456 " _without_form\n", |
|
457 contents.c_str()); |
|
458 } |
|
459 |
|
460 // Externs should be written out as PUBLIC records, sorted by |
|
461 // address. |
|
462 TEST(Construct, Externs) { |
|
463 stringstream s; |
|
464 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
|
465 |
|
466 // Two externs. |
|
467 Module::Extern *extern1 = new(Module::Extern); |
|
468 extern1->address = 0xffff; |
|
469 extern1->name = "_abc"; |
|
470 Module::Extern *extern2 = new(Module::Extern); |
|
471 extern2->address = 0xaaaa; |
|
472 extern2->name = "_xyz"; |
|
473 |
|
474 m.AddExtern(extern1); |
|
475 m.AddExtern(extern2); |
|
476 |
|
477 m.Write(s, ALL_SYMBOL_DATA); |
|
478 string contents = s.str(); |
|
479 |
|
480 EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " " |
|
481 MODULE_ID " " MODULE_NAME "\n" |
|
482 "PUBLIC aaaa 0 _xyz\n" |
|
483 "PUBLIC ffff 0 _abc\n", |
|
484 contents.c_str()); |
|
485 } |
|
486 |
|
487 // Externs with the same address should only keep the first entry |
|
488 // added. |
|
489 TEST(Construct, DuplicateExterns) { |
|
490 stringstream s; |
|
491 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
|
492 |
|
493 // Two externs. |
|
494 Module::Extern *extern1 = new(Module::Extern); |
|
495 extern1->address = 0xffff; |
|
496 extern1->name = "_xyz"; |
|
497 Module::Extern *extern2 = new(Module::Extern); |
|
498 extern2->address = 0xffff; |
|
499 extern2->name = "_abc"; |
|
500 |
|
501 m.AddExtern(extern1); |
|
502 m.AddExtern(extern2); |
|
503 |
|
504 m.Write(s, ALL_SYMBOL_DATA); |
|
505 string contents = s.str(); |
|
506 |
|
507 EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " " |
|
508 MODULE_ID " " MODULE_NAME "\n" |
|
509 "PUBLIC ffff 0 _xyz\n", |
|
510 contents.c_str()); |
|
511 } |
|
512 |
|
513 TEST(Lookup, Function) { |
|
514 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
|
515 |
|
516 Module::Function *function1 = new(Module::Function); |
|
517 function1->name = "_abc1"; |
|
518 function1->address = 0x1000; |
|
519 function1->size = 0x900; |
|
520 function1->parameter_size = 0x0; |
|
521 |
|
522 Module::Function *function2 = new(Module::Function); |
|
523 function2->name = "_xyz2"; |
|
524 function2->address = 0x2000; |
|
525 function2->size = 0x900; |
|
526 function2->parameter_size = 0x0; |
|
527 |
|
528 Module::Function *function3 = new(Module::Function); |
|
529 function3->name = "_def3"; |
|
530 function3->address = 0x3000; |
|
531 function3->size = 0x900; |
|
532 function3->parameter_size = 0x0; |
|
533 |
|
534 // Put them in a vector. |
|
535 vector<Module::Function *> vec; |
|
536 vec.push_back(function1); |
|
537 vec.push_back(function2); |
|
538 vec.push_back(function3); |
|
539 |
|
540 m.AddFunctions(vec.begin(), vec.end()); |
|
541 |
|
542 // Try looking up functions by address. |
|
543 Module::Function* f = m.FindFunctionByAddress(0x1000); |
|
544 EXPECT_EQ(function1, f); |
|
545 f = m.FindFunctionByAddress(0x18FF); |
|
546 EXPECT_EQ(function1, f); |
|
547 |
|
548 f = m.FindFunctionByAddress(0x1900); |
|
549 EXPECT_EQ((Module::Function*)NULL, f); |
|
550 f = m.FindFunctionByAddress(0x1A00); |
|
551 EXPECT_EQ((Module::Function*)NULL, f); |
|
552 |
|
553 f = m.FindFunctionByAddress(0x2000); |
|
554 EXPECT_EQ(function2, f); |
|
555 f = m.FindFunctionByAddress(0x28FF); |
|
556 EXPECT_EQ(function2, f); |
|
557 |
|
558 f = m.FindFunctionByAddress(0x3000); |
|
559 EXPECT_EQ(function3, f); |
|
560 f = m.FindFunctionByAddress(0x38FF); |
|
561 EXPECT_EQ(function3, f); |
|
562 |
|
563 f = m.FindFunctionByAddress(0x3900); |
|
564 EXPECT_EQ((Module::Function*)NULL, f); |
|
565 f = m.FindFunctionByAddress(0x3A00); |
|
566 EXPECT_EQ((Module::Function*)NULL, f); |
|
567 } |
|
568 |
|
569 TEST(Lookup, Externs) { |
|
570 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
|
571 |
|
572 // Two externs. |
|
573 Module::Extern* extern1 = new(Module::Extern); |
|
574 extern1->address = 0x1000; |
|
575 extern1->name = "_abc"; |
|
576 Module::Extern* extern2 = new(Module::Extern); |
|
577 extern2->address = 0x2000; |
|
578 extern2->name = "_xyz"; |
|
579 |
|
580 m.AddExtern(extern1); |
|
581 m.AddExtern(extern2); |
|
582 |
|
583 Module::Extern* e = m.FindExternByAddress(0xFFF); |
|
584 EXPECT_EQ((Module::Extern*)NULL, e); |
|
585 |
|
586 e = m.FindExternByAddress(0x1000); |
|
587 EXPECT_EQ(extern1, e); |
|
588 e = m.FindExternByAddress(0x1900); |
|
589 EXPECT_EQ(extern1, e); |
|
590 e = m.FindExternByAddress(0x1FFF); |
|
591 EXPECT_EQ(extern1, e); |
|
592 |
|
593 e = m.FindExternByAddress(0x2000); |
|
594 EXPECT_EQ(extern2, e); |
|
595 e = m.FindExternByAddress(0x2900); |
|
596 EXPECT_EQ(extern2, e); |
|
597 e = m.FindExternByAddress(0xFFFFFFFF); |
|
598 EXPECT_EQ(extern2, e); |
|
599 } |
|
600 |
|
601 TEST(Lookup, StackFrameEntries) { |
|
602 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
|
603 |
|
604 // First STACK CFI entry, with no initial rules or deltas. |
|
605 Module::StackFrameEntry *entry1 = new Module::StackFrameEntry(); |
|
606 entry1->address = 0x2000; |
|
607 entry1->size = 0x900; |
|
608 m.AddStackFrameEntry(entry1); |
|
609 |
|
610 // Second STACK CFI entry, with initial rules but no deltas. |
|
611 Module::StackFrameEntry *entry2 = new Module::StackFrameEntry(); |
|
612 entry2->address = 0x3000; |
|
613 entry2->size = 0x900; |
|
614 entry2->initial_rules[ustr__ZDcfa()] = |
|
615 Module::Expr("I think that I shall never see"); |
|
616 entry2->initial_rules[ToUniqueString("stromboli")] = |
|
617 Module::Expr("a poem lovely as a tree"); |
|
618 entry2->initial_rules[ToUniqueString("cannoli")] = |
|
619 Module::Expr("a tree whose hungry mouth is prest"); |
|
620 m.AddStackFrameEntry(entry2); |
|
621 |
|
622 // Third STACK CFI entry, with initial rules and deltas. |
|
623 Module::StackFrameEntry *entry3 = new Module::StackFrameEntry(); |
|
624 entry3->address = 0x1000; |
|
625 entry3->size = 0x900; |
|
626 entry3->initial_rules[ustr__ZDcfa()] = Module::Expr("Whose woods are these"); |
|
627 entry3->rule_changes[0x47ceb0f63c269d7fULL][ToUniqueString("calzone")] = |
|
628 Module::Expr("the village though"); |
|
629 entry3->rule_changes[0x47ceb0f63c269d7fULL][ToUniqueString("cannoli")] = |
|
630 Module::Expr("he will not see me stopping here"); |
|
631 entry3->rule_changes[0x36682fad3763ffffULL][ToUniqueString("stromboli")] = |
|
632 Module::Expr("his house is in"); |
|
633 entry3->rule_changes[0x36682fad3763ffffULL][ustr__ZDcfa()] = |
|
634 Module::Expr("I think I know"); |
|
635 m.AddStackFrameEntry(entry3); |
|
636 |
|
637 Module::StackFrameEntry* s = m.FindStackFrameEntryByAddress(0x1000); |
|
638 EXPECT_EQ(entry3, s); |
|
639 s = m.FindStackFrameEntryByAddress(0x18FF); |
|
640 EXPECT_EQ(entry3, s); |
|
641 |
|
642 s = m.FindStackFrameEntryByAddress(0x1900); |
|
643 EXPECT_EQ((Module::StackFrameEntry*)NULL, s); |
|
644 s = m.FindStackFrameEntryByAddress(0x1A00); |
|
645 EXPECT_EQ((Module::StackFrameEntry*)NULL, s); |
|
646 |
|
647 s = m.FindStackFrameEntryByAddress(0x2000); |
|
648 EXPECT_EQ(entry1, s); |
|
649 s = m.FindStackFrameEntryByAddress(0x28FF); |
|
650 EXPECT_EQ(entry1, s); |
|
651 |
|
652 s = m.FindStackFrameEntryByAddress(0x3000); |
|
653 EXPECT_EQ(entry2, s); |
|
654 s = m.FindStackFrameEntryByAddress(0x38FF); |
|
655 EXPECT_EQ(entry2, s); |
|
656 |
|
657 s = m.FindStackFrameEntryByAddress(0x3900); |
|
658 EXPECT_EQ((Module::StackFrameEntry*)NULL, s); |
|
659 s = m.FindStackFrameEntryByAddress(0x3A00); |
|
660 EXPECT_EQ((Module::StackFrameEntry*)NULL, s); |
|
661 } |