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_cu_to_module.cc: Unit tests for google_breakpad::DwarfCUToModule. | |
33 | |
34 #include <vector> | |
35 | |
36 #include "breakpad_googletest_includes.h" | |
37 #include "common/dwarf_cu_to_module.h" | |
38 | |
39 using std::vector; | |
40 | |
41 using dwarf2reader::AttributeList; | |
42 using dwarf2reader::DIEHandler; | |
43 using dwarf2reader::DwarfTag; | |
44 using dwarf2reader::DwarfAttribute; | |
45 using dwarf2reader::DwarfForm; | |
46 using dwarf2reader::DwarfInline; | |
47 using dwarf2reader::RootDIEHandler; | |
48 using google_breakpad::DwarfCUToModule; | |
49 using google_breakpad::Module; | |
50 | |
51 using ::testing::_; | |
52 using ::testing::AtMost; | |
53 using ::testing::Invoke; | |
54 using ::testing::Return; | |
55 using ::testing::Test; | |
56 using ::testing::TestWithParam; | |
57 using ::testing::Values; | |
58 using ::testing::ValuesIn; | |
59 | |
60 // Mock classes. | |
61 | |
62 class MockLineToModuleFunctor: public DwarfCUToModule::LineToModuleFunctor { | |
63 public: | |
64 MOCK_METHOD4(mock_apply, void(const char *program, uint64 length, | |
65 Module *module, vector<Module::Line> *lines)); | |
66 void operator()(const char *program, uint64 length, | |
67 Module *module, vector<Module::Line> *lines) { | |
68 mock_apply(program, length, module, lines); | |
69 } | |
70 }; | |
71 | |
72 class MockWarningReporter: public DwarfCUToModule::WarningReporter { | |
73 public: | |
74 MockWarningReporter(const string &filename, uint64 cu_offset) | |
75 : DwarfCUToModule::WarningReporter(filename, cu_offset) { } | |
76 MOCK_METHOD1(SetCUName, void(const string &name)); | |
77 MOCK_METHOD2(UnknownSpecification, void(uint64 offset, uint64 target)); | |
78 MOCK_METHOD2(UnknownAbstractOrigin, void(uint64 offset, uint64 target)); | |
79 MOCK_METHOD1(MissingSection, void(const string §ion_name)); | |
80 MOCK_METHOD1(BadLineInfoOffset, void(uint64 offset)); | |
81 MOCK_METHOD1(UncoveredFunction, void(const Module::Function &function)); | |
82 MOCK_METHOD1(UncoveredLine, void(const Module::Line &line)); | |
83 }; | |
84 | |
85 // A fixture class including all the objects needed to handle a | |
86 // compilation unit, and their entourage. It includes member functions | |
87 // for doing common kinds of setup and tests. | |
88 class CUFixtureBase { | |
89 public: | |
90 | |
91 // If we have: | |
92 // | |
93 // vector<Module::Line> lines; | |
94 // AppendLinesFunctor appender(lines); | |
95 // | |
96 // then doing: | |
97 // | |
98 // appender(line_program, length, module, line_vector); | |
99 // | |
100 // will append lines to the end of line_vector. We can use this with | |
101 // MockLineToModuleFunctor like this: | |
102 // | |
103 // MockLineToModuleFunctor l2m; | |
104 // EXPECT_CALL(l2m, mock_apply(_,_,_,_)) | |
105 // .WillOnce(DoAll(Invoke(appender), Return())); | |
106 // | |
107 // in which case calling l2m with some line vector will append lines. | |
108 class AppendLinesFunctor { | |
109 public: | |
110 AppendLinesFunctor(const vector<Module::Line> *lines) : lines_(lines) { } | |
111 void operator()(const char *program, uint64 length, | |
112 Module *module, vector<Module::Line> *lines) { | |
113 lines->insert(lines->end(), lines_->begin(), lines_->end()); | |
114 } | |
115 private: | |
116 const vector<Module::Line> *lines_; | |
117 }; | |
118 | |
119 CUFixtureBase() | |
120 : module_("module-name", "module-os", "module-arch", "module-id"), | |
121 file_context_("dwarf-filename", &module_), | |
122 language_(dwarf2reader::DW_LANG_none), | |
123 language_signed_(false), | |
124 appender_(&lines_), | |
125 reporter_("dwarf-filename", 0xcf8f9bb6443d29b5LL), | |
126 root_handler_(&file_context_, &line_reader_, &reporter_), | |
127 functions_filled_(false) { | |
128 // By default, expect no warnings to be reported, and expect the | |
129 // compilation unit's name to be provided. The test can override | |
130 // these expectations. | |
131 EXPECT_CALL(reporter_, SetCUName("compilation-unit-name")).Times(1); | |
132 EXPECT_CALL(reporter_, UnknownSpecification(_, _)).Times(0); | |
133 EXPECT_CALL(reporter_, UnknownAbstractOrigin(_, _)).Times(0); | |
134 EXPECT_CALL(reporter_, MissingSection(_)).Times(0); | |
135 EXPECT_CALL(reporter_, BadLineInfoOffset(_)).Times(0); | |
136 EXPECT_CALL(reporter_, UncoveredFunction(_)).Times(0); | |
137 EXPECT_CALL(reporter_, UncoveredLine(_)).Times(0); | |
138 | |
139 // By default, expect the line program reader not to be invoked. We | |
140 // may override this in StartCU. | |
141 EXPECT_CALL(line_reader_, mock_apply(_,_,_,_)).Times(0); | |
142 | |
143 // The handler will consult this section map to decide what to | |
144 // pass to our line reader. | |
145 file_context_.section_map[".debug_line"] = std::make_pair(dummy_line_program
_, | |
146 dummy_line_size_); | |
147 } | |
148 | |
149 // Add a line with the given address, size, filename, and line | |
150 // number to the end of the statement list the handler will receive | |
151 // when it invokes its LineToModuleFunctor. Call this before calling | |
152 // StartCU. | |
153 void PushLine(Module::Address address, Module::Address size, | |
154 const string &filename, int line_number); | |
155 | |
156 // Use LANGUAGE for the compilation unit. More precisely, arrange | |
157 // for StartCU to pass the compilation unit's root DIE a | |
158 // DW_AT_language attribute whose value is LANGUAGE. | |
159 void SetLanguage(dwarf2reader::DwarfLanguage language) { | |
160 language_ = language; | |
161 } | |
162 | |
163 // If SIGNED true, have StartCU report DW_AT_language as a signed | |
164 // attribute; if false, have it report it as unsigned. | |
165 void SetLanguageSigned(bool is_signed) { language_signed_ = is_signed; } | |
166 | |
167 // Call the handler this.root_handler_'s StartCompilationUnit and | |
168 // StartRootDIE member functions, passing it appropriate attributes as | |
169 // determined by prior calls to PushLine and SetLanguage. Leave | |
170 // this.root_handler_ ready to hear about children: call | |
171 // this.root_handler_.EndAttributes, but not this.root_handler_.Finish. | |
172 void StartCU(); | |
173 | |
174 // Add some strange attributes/form pairs to the end of ATTRS. | |
175 void PushBackStrangeAttributes(dwarf2reader::AttributeList *attrs); | |
176 | |
177 // Have HANDLER process some strange attribute/form/value triples. | |
178 // These will match those promised by PushBackStrangeAttributes. | |
179 void ProcessStrangeAttributes(dwarf2reader::DIEHandler *handler); | |
180 | |
181 // Start a child DIE of PARENT with the given tag and name. Leave | |
182 // the handler ready to hear about children: call EndAttributes, but | |
183 // not Finish. | |
184 DIEHandler *StartNamedDIE(DIEHandler *parent, DwarfTag tag, | |
185 const string &name); | |
186 | |
187 // Start a child DIE of PARENT with the given tag and a | |
188 // DW_AT_specification attribute whose value is SPECIFICATION. Leave | |
189 // the handler ready to hear about children: call EndAttributes, but | |
190 // not Finish. If NAME is non-zero, use it as the DW_AT_name | |
191 // attribute. | |
192 DIEHandler *StartSpecifiedDIE(DIEHandler *parent, DwarfTag tag, | |
193 uint64 offset, const char *name = NULL); | |
194 | |
195 // Define a function as a child of PARENT with the given name, | |
196 // address, and size. Call EndAttributes and Finish; one cannot | |
197 // define children of the defined function's DIE. | |
198 void DefineFunction(DIEHandler *parent, const string &name, | |
199 Module::Address address, Module::Address size); | |
200 | |
201 // Create a declaration DIE as a child of PARENT with the given | |
202 // offset, tag and name. If NAME is the empty string, don't provide | |
203 // a DW_AT_name attribute. Call EndAttributes and Finish. | |
204 void DeclarationDIE(DIEHandler *parent, uint64 offset, | |
205 DwarfTag tag, const string &name); | |
206 | |
207 // Create a definition DIE as a child of PARENT with the given tag | |
208 // that refers to the declaration DIE at offset SPECIFICATION as its | |
209 // specification. If NAME is non-empty, pass it as the DW_AT_name | |
210 // attribute. If SIZE is non-zero, record ADDRESS and SIZE as | |
211 // low_pc/high_pc attributes. | |
212 void DefinitionDIE(DIEHandler *parent, DwarfTag tag, | |
213 uint64 specification, const string &name, | |
214 Module::Address address = 0, Module::Address size = 0); | |
215 | |
216 // Create an inline DW_TAG_subprogram DIE as a child of PARENT. If | |
217 // SPECIFICATION is non-zero, then the DIE refers to the declaration DIE at | |
218 // offset SPECIFICATION as its specification. If Name is non-empty, pass it | |
219 // as the DW_AT_name attribute. | |
220 void AbstractInstanceDIE(DIEHandler *parent, uint64 offset, | |
221 DwarfInline type, uint64 specification, | |
222 const string &name, | |
223 DwarfForm form = dwarf2reader::DW_FORM_data1); | |
224 | |
225 // Create a DW_TAG_subprogram DIE as a child of PARENT that refers to | |
226 // ORIGIN in its DW_AT_abstract_origin attribute. If NAME is the empty | |
227 // string, don't provide a DW_AT_name attribute. | |
228 void DefineInlineInstanceDIE(DIEHandler *parent, const string &name, | |
229 uint64 origin, Module::Address address, | |
230 Module::Address size); | |
231 | |
232 // The following Test* functions should be called after calling | |
233 // this.root_handler_.Finish. After that point, no further calls | |
234 // should be made on the handler. | |
235 | |
236 // Test that the number of functions defined in the module this.module_ is | |
237 // equal to EXPECTED. | |
238 void TestFunctionCount(size_t expected); | |
239 | |
240 // Test that the I'th function (ordered by address) in the module | |
241 // this.module_ has the given name, address, and size, and that its | |
242 // parameter size is zero. | |
243 void TestFunction(int i, const string &name, | |
244 Module::Address address, Module::Address size); | |
245 | |
246 // Test that the number of source lines owned by the I'th function | |
247 // in the module this.module_ is equal to EXPECTED. | |
248 void TestLineCount(int i, size_t expected); | |
249 | |
250 // Test that the J'th line (ordered by address) of the I'th function | |
251 // (again, by address) has the given address, size, filename, and | |
252 // line number. | |
253 void TestLine(int i, int j, Module::Address address, Module::Address size, | |
254 const string &filename, int number); | |
255 | |
256 // Actual objects under test. | |
257 Module module_; | |
258 DwarfCUToModule::FileContext file_context_; | |
259 | |
260 // If this is not DW_LANG_none, we'll pass it as a DW_AT_language | |
261 // attribute to the compilation unit. This defaults to DW_LANG_none. | |
262 dwarf2reader::DwarfLanguage language_; | |
263 | |
264 // If this is true, report DW_AT_language as a signed value; if false, | |
265 // report it as an unsigned value. | |
266 bool language_signed_; | |
267 | |
268 // If this is not empty, we'll give the CU a DW_AT_stmt_list | |
269 // attribute that, when passed to line_reader_, adds these lines to the | |
270 // provided lines array. | |
271 vector<Module::Line> lines_; | |
272 | |
273 // Mock line program reader. | |
274 MockLineToModuleFunctor line_reader_; | |
275 AppendLinesFunctor appender_; | |
276 static const char dummy_line_program_[]; | |
277 static const size_t dummy_line_size_; | |
278 | |
279 MockWarningReporter reporter_; | |
280 DwarfCUToModule root_handler_; | |
281 | |
282 private: | |
283 // Fill functions_, if we haven't already. | |
284 void FillFunctions(); | |
285 | |
286 // If functions_filled_ is true, this is a table of functions we've | |
287 // extracted from module_, sorted by address. | |
288 vector<Module::Function *> functions_; | |
289 // True if we have filled the above vector with this.module_'s function list. | |
290 bool functions_filled_; | |
291 }; | |
292 | |
293 const char CUFixtureBase::dummy_line_program_[] = "lots of fun data"; | |
294 const size_t CUFixtureBase::dummy_line_size_ = | |
295 sizeof (CUFixtureBase::dummy_line_program_); | |
296 | |
297 void CUFixtureBase::PushLine(Module::Address address, Module::Address size, | |
298 const string &filename, int line_number) { | |
299 Module::Line l; | |
300 l.address = address; | |
301 l.size = size; | |
302 l.file = module_.FindFile(filename); | |
303 l.number = line_number; | |
304 lines_.push_back(l); | |
305 } | |
306 | |
307 void CUFixtureBase::StartCU() { | |
308 // If we have lines, make the line reader expect to be invoked at | |
309 // most once. (Hey, if the handler can pass its tests without | |
310 // bothering to read the line number data, that's great.) | |
311 // Have it add the lines passed to PushLine. Otherwise, leave the | |
312 // initial expectation (no calls) in force. | |
313 if (!lines_.empty()) | |
314 EXPECT_CALL(line_reader_, | |
315 mock_apply(&dummy_line_program_[0], dummy_line_size_, | |
316 &module_, _)) | |
317 .Times(AtMost(1)) | |
318 .WillOnce(DoAll(Invoke(appender_), Return())); | |
319 | |
320 ASSERT_TRUE(root_handler_ | |
321 .StartCompilationUnit(0x51182ec307610b51ULL, 0x81, 0x44, | |
322 0x4241b4f33720dd5cULL, 3)); | |
323 { | |
324 dwarf2reader::AttributeList attrs; | |
325 attrs.push_back(make_pair(dwarf2reader::DW_AT_name, | |
326 dwarf2reader::DW_FORM_strp)); | |
327 if (!lines_.empty()) | |
328 attrs.push_back(make_pair(dwarf2reader::DW_AT_stmt_list, | |
329 dwarf2reader::DW_FORM_ref4)); | |
330 if (language_ != dwarf2reader::DW_LANG_none) | |
331 attrs.push_back(make_pair(dwarf2reader::DW_AT_language, | |
332 language_signed_ | |
333 ? dwarf2reader::DW_FORM_sdata | |
334 : dwarf2reader::DW_FORM_udata)); | |
335 ASSERT_TRUE(root_handler_.StartRootDIE(0x02e56bfbda9e7337ULL, | |
336 dwarf2reader::DW_TAG_compile_unit, | |
337 attrs)); | |
338 } | |
339 root_handler_.ProcessAttributeString(dwarf2reader::DW_AT_name, | |
340 dwarf2reader::DW_FORM_strp, | |
341 "compilation-unit-name"); | |
342 if (!lines_.empty()) | |
343 root_handler_.ProcessAttributeUnsigned(dwarf2reader::DW_AT_stmt_list, | |
344 dwarf2reader::DW_FORM_ref4, | |
345 0); | |
346 if (language_ != dwarf2reader::DW_LANG_none) { | |
347 if (language_signed_) | |
348 root_handler_.ProcessAttributeSigned(dwarf2reader::DW_AT_language, | |
349 dwarf2reader::DW_FORM_sdata, | |
350 language_); | |
351 else | |
352 root_handler_.ProcessAttributeUnsigned(dwarf2reader::DW_AT_language, | |
353 dwarf2reader::DW_FORM_udata, | |
354 language_); | |
355 } | |
356 ASSERT_TRUE(root_handler_.EndAttributes()); | |
357 } | |
358 | |
359 void CUFixtureBase::PushBackStrangeAttributes( | |
360 dwarf2reader::AttributeList *attrs) { | |
361 attrs->push_back(make_pair((DwarfAttribute) 0xf560dead, | |
362 (DwarfForm) 0x4106e4db)); | |
363 attrs->push_back(make_pair((DwarfAttribute) 0x85380095, | |
364 (DwarfForm) 0x0f16fe87)); | |
365 attrs->push_back(make_pair((DwarfAttribute) 0xf7f7480f, | |
366 (DwarfForm) 0x829e038a)); | |
367 attrs->push_back(make_pair((DwarfAttribute) 0xa55ffb51, | |
368 (DwarfForm) 0x2f43b041)); | |
369 attrs->push_back(make_pair((DwarfAttribute) 0x2fde304a, | |
370 (DwarfForm) 0x895ffa23)); | |
371 } | |
372 | |
373 void CUFixtureBase::ProcessStrangeAttributes( | |
374 dwarf2reader::DIEHandler *handler) { | |
375 handler->ProcessAttributeUnsigned((DwarfAttribute) 0xf560dead, | |
376 (DwarfForm) 0x4106e4db, | |
377 0xa592571997facda1ULL); | |
378 handler->ProcessAttributeSigned((DwarfAttribute) 0x85380095, | |
379 (DwarfForm) 0x0f16fe87, | |
380 0x12602a4e3bf1f446LL); | |
381 handler->ProcessAttributeReference((DwarfAttribute) 0xf7f7480f, | |
382 (DwarfForm) 0x829e038a, | |
383 0x50fddef44734fdecULL); | |
384 static const char buffer[10] = "frobynode"; | |
385 handler->ProcessAttributeBuffer((DwarfAttribute) 0xa55ffb51, | |
386 (DwarfForm) 0x2f43b041, | |
387 buffer, sizeof(buffer)); | |
388 handler->ProcessAttributeString((DwarfAttribute) 0x2f43b041, | |
389 (DwarfForm) 0x895ffa23, | |
390 "strange string"); | |
391 } | |
392 | |
393 DIEHandler *CUFixtureBase::StartNamedDIE(DIEHandler *parent, | |
394 DwarfTag tag, | |
395 const string &name) { | |
396 dwarf2reader::AttributeList attrs; | |
397 attrs.push_back(make_pair(dwarf2reader::DW_AT_name, | |
398 dwarf2reader::DW_FORM_strp)); | |
399 PushBackStrangeAttributes(&attrs); | |
400 dwarf2reader::DIEHandler *handler | |
401 = parent->FindChildHandler(0x8f4c783c0467c989ULL, tag, attrs); | |
402 if (!handler) | |
403 return NULL; | |
404 handler->ProcessAttributeString(dwarf2reader::DW_AT_name, | |
405 dwarf2reader::DW_FORM_strp, | |
406 name); | |
407 ProcessStrangeAttributes(handler); | |
408 if (!handler->EndAttributes()) { | |
409 handler->Finish(); | |
410 delete handler; | |
411 return NULL; | |
412 } | |
413 | |
414 return handler; | |
415 } | |
416 | |
417 DIEHandler *CUFixtureBase::StartSpecifiedDIE(DIEHandler *parent, | |
418 DwarfTag tag, | |
419 uint64 specification, | |
420 const char *name) { | |
421 dwarf2reader::AttributeList attrs; | |
422 if (name) | |
423 attrs.push_back(make_pair(dwarf2reader::DW_AT_name, | |
424 dwarf2reader::DW_FORM_strp)); | |
425 attrs.push_back(make_pair(dwarf2reader::DW_AT_specification, | |
426 dwarf2reader::DW_FORM_ref4)); | |
427 dwarf2reader::DIEHandler *handler | |
428 = parent->FindChildHandler(0x8f4c783c0467c989ULL, tag, attrs); | |
429 if (!handler) | |
430 return NULL; | |
431 if (name) | |
432 handler->ProcessAttributeString(dwarf2reader::DW_AT_name, | |
433 dwarf2reader::DW_FORM_strp, | |
434 name); | |
435 handler->ProcessAttributeReference(dwarf2reader::DW_AT_specification, | |
436 dwarf2reader::DW_FORM_ref4, | |
437 specification); | |
438 if (!handler->EndAttributes()) { | |
439 handler->Finish(); | |
440 delete handler; | |
441 return NULL; | |
442 } | |
443 | |
444 return handler; | |
445 } | |
446 | |
447 void CUFixtureBase::DefineFunction(dwarf2reader::DIEHandler *parent, | |
448 const string &name, Module::Address address, | |
449 Module::Address size) { | |
450 dwarf2reader::AttributeList func_attrs; | |
451 func_attrs.push_back(make_pair(dwarf2reader::DW_AT_name, | |
452 dwarf2reader::DW_FORM_strp)); | |
453 func_attrs.push_back(make_pair(dwarf2reader::DW_AT_low_pc, | |
454 dwarf2reader::DW_FORM_addr)); | |
455 func_attrs.push_back(make_pair(dwarf2reader::DW_AT_high_pc, | |
456 dwarf2reader::DW_FORM_addr)); | |
457 PushBackStrangeAttributes(&func_attrs); | |
458 dwarf2reader::DIEHandler *func | |
459 = parent->FindChildHandler(0xe34797c7e68590a8LL, | |
460 dwarf2reader::DW_TAG_subprogram, | |
461 func_attrs); | |
462 ASSERT_TRUE(func != NULL); | |
463 func->ProcessAttributeString(dwarf2reader::DW_AT_name, | |
464 dwarf2reader::DW_FORM_strp, | |
465 name); | |
466 func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_low_pc, | |
467 dwarf2reader::DW_FORM_addr, | |
468 address); | |
469 func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc, | |
470 dwarf2reader::DW_FORM_addr, | |
471 address + size); | |
472 ProcessStrangeAttributes(func); | |
473 EXPECT_TRUE(func->EndAttributes()); | |
474 func->Finish(); | |
475 delete func; | |
476 } | |
477 | |
478 void CUFixtureBase::DeclarationDIE(DIEHandler *parent, uint64 offset, | |
479 DwarfTag tag, | |
480 const string &name) { | |
481 dwarf2reader::AttributeList attrs; | |
482 if (!name.empty()) | |
483 attrs.push_back(make_pair(dwarf2reader::DW_AT_name, | |
484 dwarf2reader::DW_FORM_strp)); | |
485 attrs.push_back(make_pair(dwarf2reader::DW_AT_declaration, | |
486 dwarf2reader::DW_FORM_flag)); | |
487 dwarf2reader::DIEHandler *die = parent->FindChildHandler(offset, tag, attrs); | |
488 ASSERT_TRUE(die != NULL); | |
489 if (!name.empty()) | |
490 die->ProcessAttributeString(dwarf2reader::DW_AT_name, | |
491 dwarf2reader::DW_FORM_strp, | |
492 name); | |
493 die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_declaration, | |
494 dwarf2reader::DW_FORM_flag, | |
495 1); | |
496 EXPECT_TRUE(die->EndAttributes()); | |
497 die->Finish(); | |
498 delete die; | |
499 } | |
500 | |
501 void CUFixtureBase::DefinitionDIE(DIEHandler *parent, | |
502 DwarfTag tag, | |
503 uint64 specification, | |
504 const string &name, | |
505 Module::Address address, | |
506 Module::Address size) { | |
507 dwarf2reader::AttributeList attrs; | |
508 attrs.push_back(make_pair(dwarf2reader::DW_AT_specification, | |
509 dwarf2reader::DW_FORM_ref4)); | |
510 if (!name.empty()) | |
511 attrs.push_back(make_pair(dwarf2reader::DW_AT_name, | |
512 dwarf2reader::DW_FORM_strp)); | |
513 if (size) { | |
514 attrs.push_back(make_pair(dwarf2reader::DW_AT_low_pc, | |
515 dwarf2reader::DW_FORM_addr)); | |
516 attrs.push_back(make_pair(dwarf2reader::DW_AT_high_pc, | |
517 dwarf2reader::DW_FORM_addr)); | |
518 } | |
519 dwarf2reader::DIEHandler *die | |
520 = parent->FindChildHandler(0x6ccfea031a9e6cc9ULL, tag, attrs); | |
521 ASSERT_TRUE(die != NULL); | |
522 die->ProcessAttributeReference(dwarf2reader::DW_AT_specification, | |
523 dwarf2reader::DW_FORM_ref4, | |
524 specification); | |
525 if (!name.empty()) | |
526 die->ProcessAttributeString(dwarf2reader::DW_AT_name, | |
527 dwarf2reader::DW_FORM_strp, | |
528 name); | |
529 if (size) { | |
530 die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_low_pc, | |
531 dwarf2reader::DW_FORM_addr, | |
532 address); | |
533 die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc, | |
534 dwarf2reader::DW_FORM_addr, | |
535 address + size); | |
536 } | |
537 EXPECT_TRUE(die->EndAttributes()); | |
538 die->Finish(); | |
539 delete die; | |
540 } | |
541 | |
542 void CUFixtureBase::AbstractInstanceDIE(DIEHandler *parent, | |
543 uint64 offset, | |
544 DwarfInline type, | |
545 uint64 specification, | |
546 const string &name, | |
547 DwarfForm form) { | |
548 dwarf2reader::AttributeList attrs; | |
549 if (specification != 0ULL) | |
550 attrs.push_back(make_pair(dwarf2reader::DW_AT_specification, | |
551 dwarf2reader::DW_FORM_ref4)); | |
552 attrs.push_back(make_pair(dwarf2reader::DW_AT_inline, form)); | |
553 if (!name.empty()) | |
554 attrs.push_back(make_pair(dwarf2reader::DW_AT_name, | |
555 dwarf2reader::DW_FORM_strp)); | |
556 dwarf2reader::DIEHandler *die | |
557 = parent->FindChildHandler(offset, dwarf2reader::DW_TAG_subprogram, attrs); | |
558 ASSERT_TRUE(die != NULL); | |
559 if (specification != 0ULL) | |
560 die->ProcessAttributeReference(dwarf2reader::DW_AT_specification, | |
561 dwarf2reader::DW_FORM_ref4, | |
562 specification); | |
563 if (form == dwarf2reader::DW_FORM_sdata) { | |
564 die->ProcessAttributeSigned(dwarf2reader::DW_AT_inline, form, type); | |
565 } else { | |
566 die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_inline, form, type); | |
567 } | |
568 if (!name.empty()) | |
569 die->ProcessAttributeString(dwarf2reader::DW_AT_name, | |
570 dwarf2reader::DW_FORM_strp, | |
571 name); | |
572 | |
573 EXPECT_TRUE(die->EndAttributes()); | |
574 die->Finish(); | |
575 delete die; | |
576 } | |
577 | |
578 void CUFixtureBase::DefineInlineInstanceDIE(DIEHandler *parent, | |
579 const string &name, | |
580 uint64 origin, | |
581 Module::Address address, | |
582 Module::Address size) { | |
583 dwarf2reader::AttributeList func_attrs; | |
584 if (!name.empty()) | |
585 func_attrs.push_back(make_pair(dwarf2reader::DW_AT_name, | |
586 dwarf2reader::DW_FORM_strp)); | |
587 func_attrs.push_back(make_pair(dwarf2reader::DW_AT_low_pc, | |
588 dwarf2reader::DW_FORM_addr)); | |
589 func_attrs.push_back(make_pair(dwarf2reader::DW_AT_high_pc, | |
590 dwarf2reader::DW_FORM_addr)); | |
591 func_attrs.push_back(make_pair(dwarf2reader::DW_AT_abstract_origin, | |
592 dwarf2reader::DW_FORM_ref4)); | |
593 PushBackStrangeAttributes(&func_attrs); | |
594 dwarf2reader::DIEHandler *func | |
595 = parent->FindChildHandler(0x11c70f94c6e87ccdLL, | |
596 dwarf2reader::DW_TAG_subprogram, | |
597 func_attrs); | |
598 ASSERT_TRUE(func != NULL); | |
599 if (!name.empty()) { | |
600 func->ProcessAttributeString(dwarf2reader::DW_AT_name, | |
601 dwarf2reader::DW_FORM_strp, | |
602 name); | |
603 } | |
604 func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_low_pc, | |
605 dwarf2reader::DW_FORM_addr, | |
606 address); | |
607 func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc, | |
608 dwarf2reader::DW_FORM_addr, | |
609 address + size); | |
610 func->ProcessAttributeReference(dwarf2reader::DW_AT_abstract_origin, | |
611 dwarf2reader::DW_FORM_ref4, | |
612 origin); | |
613 ProcessStrangeAttributes(func); | |
614 EXPECT_TRUE(func->EndAttributes()); | |
615 func->Finish(); | |
616 delete func; | |
617 } | |
618 | |
619 void CUFixtureBase::FillFunctions() { | |
620 if (functions_filled_) | |
621 return; | |
622 module_.GetFunctions(&functions_, functions_.end()); | |
623 sort(functions_.begin(), functions_.end(), | |
624 Module::Function::CompareByAddress); | |
625 functions_filled_ = true; | |
626 } | |
627 | |
628 void CUFixtureBase::TestFunctionCount(size_t expected) { | |
629 FillFunctions(); | |
630 ASSERT_EQ(expected, functions_.size()); | |
631 } | |
632 | |
633 void CUFixtureBase::TestFunction(int i, const string &name, | |
634 Module::Address address, | |
635 Module::Address size) { | |
636 FillFunctions(); | |
637 ASSERT_LT((size_t) i, functions_.size()); | |
638 | |
639 Module::Function *function = functions_[i]; | |
640 EXPECT_EQ(name, function->name); | |
641 EXPECT_EQ(address, function->address); | |
642 EXPECT_EQ(size, function->size); | |
643 EXPECT_EQ(0U, function->parameter_size); | |
644 } | |
645 | |
646 void CUFixtureBase::TestLineCount(int i, size_t expected) { | |
647 FillFunctions(); | |
648 ASSERT_LT((size_t) i, functions_.size()); | |
649 | |
650 ASSERT_EQ(expected, functions_[i]->lines.size()); | |
651 } | |
652 | |
653 void CUFixtureBase::TestLine(int i, int j, | |
654 Module::Address address, Module::Address size, | |
655 const string &filename, int number) { | |
656 FillFunctions(); | |
657 ASSERT_LT((size_t) i, functions_.size()); | |
658 ASSERT_LT((size_t) j, functions_[i]->lines.size()); | |
659 | |
660 Module::Line *line = &functions_[i]->lines[j]; | |
661 EXPECT_EQ(address, line->address); | |
662 EXPECT_EQ(size, line->size); | |
663 EXPECT_EQ(filename, line->file->name.c_str()); | |
664 EXPECT_EQ(number, line->number); | |
665 } | |
666 | |
667 // Include caller locations for our test subroutines. | |
668 #define TRACE(call) do { SCOPED_TRACE("called from here"); call; } while (0) | |
669 #define PushLine(a,b,c,d) TRACE(PushLine((a),(b),(c),(d))) | |
670 #define SetLanguage(a) TRACE(SetLanguage(a)) | |
671 #define StartCU() TRACE(StartCU()) | |
672 #define DefineFunction(a,b,c,d) TRACE(DefineFunction((a),(b),(c),(d))) | |
673 #define DeclarationDIE(a,b,c,d) TRACE(DeclarationDIE((a),(b),(c),(d))) | |
674 #define DefinitionDIE(a,b,c,d,e,f) TRACE(DefinitionDIE((a),(b),(c),(d),(e),(f))) | |
675 #define TestFunctionCount(a) TRACE(TestFunctionCount(a)) | |
676 #define TestFunction(a,b,c,d) TRACE(TestFunction((a),(b),(c),(d))) | |
677 #define TestLineCount(a,b) TRACE(TestLineCount((a),(b))) | |
678 #define TestLine(a,b,c,d,e,f) TRACE(TestLine((a),(b),(c),(d),(e),(f))) | |
679 | |
680 class Simple: public CUFixtureBase, public Test { | |
681 }; | |
682 | |
683 TEST_F(Simple, OneFunc) { | |
684 PushLine(0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file", 246571772); | |
685 | |
686 StartCU(); | |
687 DefineFunction(&root_handler_, "function1", | |
688 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL); | |
689 root_handler_.Finish(); | |
690 | |
691 TestFunctionCount(1); | |
692 TestFunction(0, "function1", 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL); | |
693 TestLineCount(0, 1); | |
694 TestLine(0, 0, 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file", | |
695 246571772); | |
696 } | |
697 | |
698 TEST_F(Simple, IrrelevantRootChildren) { | |
699 StartCU(); | |
700 dwarf2reader::AttributeList no_attrs; | |
701 EXPECT_FALSE(root_handler_ | |
702 .FindChildHandler(0x7db32bff4e2dcfb1ULL, | |
703 dwarf2reader::DW_TAG_lexical_block, no_attrs)); | |
704 } | |
705 | |
706 TEST_F(Simple, IrrelevantNamedScopeChildren) { | |
707 StartCU(); | |
708 dwarf2reader::AttributeList no_attrs; | |
709 DIEHandler *class_A_handler | |
710 = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, "class_A"); | |
711 EXPECT_TRUE(class_A_handler != NULL); | |
712 EXPECT_FALSE(class_A_handler | |
713 ->FindChildHandler(0x02e55999b865e4e9ULL, | |
714 dwarf2reader::DW_TAG_lexical_block, | |
715 no_attrs)); | |
716 delete class_A_handler; | |
717 } | |
718 | |
719 // Verify that FileContexts can safely be deleted unused. | |
720 TEST_F(Simple, UnusedFileContext) { | |
721 Module m("module-name", "module-os", "module-arch", "module-id"); | |
722 DwarfCUToModule::FileContext fc("dwarf-filename", &m); | |
723 | |
724 // Kludge: satisfy reporter_'s expectation. | |
725 reporter_.SetCUName("compilation-unit-name"); | |
726 } | |
727 | |
728 TEST_F(Simple, InlineFunction) { | |
729 PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118); | |
730 | |
731 StartCU(); | |
732 AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL, | |
733 dwarf2reader::DW_INL_inlined, 0, "inline-name"); | |
734 DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL, | |
735 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); | |
736 root_handler_.Finish(); | |
737 | |
738 TestFunctionCount(1); | |
739 TestFunction(0, "inline-name", | |
740 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); | |
741 } | |
742 | |
743 TEST_F(Simple, InlineFunctionSignedAttribute) { | |
744 PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118); | |
745 | |
746 StartCU(); | |
747 AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL, | |
748 dwarf2reader::DW_INL_inlined, 0, "inline-name", | |
749 dwarf2reader::DW_FORM_sdata); | |
750 DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL, | |
751 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); | |
752 root_handler_.Finish(); | |
753 | |
754 TestFunctionCount(1); | |
755 TestFunction(0, "inline-name", | |
756 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); | |
757 } | |
758 | |
759 // Any DIE with an DW_AT_inline attribute can be cited by | |
760 // DW_AT_abstract_origin attributes --- even if the value of the | |
761 // DW_AT_inline attribute is DW_INL_not_inlined. | |
762 TEST_F(Simple, AbstractOriginNotInlined) { | |
763 PushLine(0x2805c4531be6ca0eULL, 0x686b52155a8d4d2cULL, "line-file", 6111581); | |
764 | |
765 StartCU(); | |
766 AbstractInstanceDIE(&root_handler_, 0x93e9cdad52826b39ULL, | |
767 dwarf2reader::DW_INL_not_inlined, 0, "abstract-instance"); | |
768 DefineInlineInstanceDIE(&root_handler_, "", 0x93e9cdad52826b39ULL, | |
769 0x2805c4531be6ca0eULL, 0x686b52155a8d4d2cULL); | |
770 root_handler_.Finish(); | |
771 | |
772 TestFunctionCount(1); | |
773 TestFunction(0, "abstract-instance", | |
774 0x2805c4531be6ca0eULL, 0x686b52155a8d4d2cULL); | |
775 } | |
776 | |
777 TEST_F(Simple, UnknownAbstractOrigin) { | |
778 EXPECT_CALL(reporter_, UnknownAbstractOrigin(_, 1ULL)).WillOnce(Return()); | |
779 PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118); | |
780 | |
781 StartCU(); | |
782 AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL, | |
783 dwarf2reader::DW_INL_inlined, 0, "inline-name"); | |
784 DefineInlineInstanceDIE(&root_handler_, "", 1ULL, | |
785 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); | |
786 root_handler_.Finish(); | |
787 | |
788 TestFunctionCount(1); | |
789 TestFunction(0, "", | |
790 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); | |
791 } | |
792 | |
793 // An address range. | |
794 struct Range { | |
795 Module::Address start, end; | |
796 }; | |
797 | |
798 // Test data for pairing functions and lines. | |
799 struct Situation { | |
800 // Two function intervals, and two line intervals. | |
801 Range functions[2], lines[2]; | |
802 | |
803 // The number of lines we expect to be assigned to each of the | |
804 // functions, and the address ranges. | |
805 int paired_count[2]; | |
806 Range paired[2][2]; | |
807 | |
808 // The number of functions that are not entirely covered by lines, | |
809 // and vice versa. | |
810 int uncovered_functions, uncovered_lines; | |
811 }; | |
812 | |
813 #define PAIRING(func1_start, func1_end, func2_start, func2_end, \ | |
814 line1_start, line1_end, line2_start, line2_end, \ | |
815 func1_num_lines, func2_num_lines, \ | |
816 func1_line1_start, func1_line1_end, \ | |
817 func1_line2_start, func1_line2_end, \ | |
818 func2_line1_start, func2_line1_end, \ | |
819 func2_line2_start, func2_line2_end, \ | |
820 uncovered_functions, uncovered_lines) \ | |
821 { { { func1_start, func1_end }, { func2_start, func2_end } }, \ | |
822 { { line1_start, line1_end }, { line2_start, line2_end } }, \ | |
823 { func1_num_lines, func2_num_lines }, \ | |
824 { { { func1_line1_start, func1_line1_end }, \ | |
825 { func1_line2_start, func1_line2_end } }, \ | |
826 { { func2_line1_start, func2_line1_end }, \ | |
827 { func2_line2_start, func2_line2_end } } }, \ | |
828 uncovered_functions, uncovered_lines }, | |
829 | |
830 Situation situations[] = { | |
831 #include "common/testdata/func-line-pairing.h" | |
832 }; | |
833 | |
834 #undef PAIRING | |
835 | |
836 class FuncLinePairing: public CUFixtureBase, | |
837 public TestWithParam<Situation> { }; | |
838 | |
839 INSTANTIATE_TEST_CASE_P(AllSituations, FuncLinePairing, | |
840 ValuesIn(situations)); | |
841 | |
842 TEST_P(FuncLinePairing, Pairing) { | |
843 const Situation &s = GetParam(); | |
844 PushLine(s.lines[0].start, | |
845 s.lines[0].end - s.lines[0].start, | |
846 "line-file", 67636963); | |
847 PushLine(s.lines[1].start, | |
848 s.lines[1].end - s.lines[1].start, | |
849 "line-file", 67636963); | |
850 if (s.uncovered_functions) | |
851 EXPECT_CALL(reporter_, UncoveredFunction(_)) | |
852 .Times(s.uncovered_functions) | |
853 .WillRepeatedly(Return()); | |
854 if (s.uncovered_lines) | |
855 EXPECT_CALL(reporter_, UncoveredLine(_)) | |
856 .Times(s.uncovered_lines) | |
857 .WillRepeatedly(Return()); | |
858 | |
859 StartCU(); | |
860 DefineFunction(&root_handler_, "function1", | |
861 s.functions[0].start, | |
862 s.functions[0].end - s.functions[0].start); | |
863 DefineFunction(&root_handler_, "function2", | |
864 s.functions[1].start, | |
865 s.functions[1].end - s.functions[1].start); | |
866 root_handler_.Finish(); | |
867 | |
868 TestFunctionCount(2); | |
869 TestFunction(0, "function1", | |
870 s.functions[0].start, | |
871 s.functions[0].end - s.functions[0].start); | |
872 TestLineCount(0, s.paired_count[0]); | |
873 for (int i = 0; i < s.paired_count[0]; i++) | |
874 TestLine(0, i, s.paired[0][i].start, | |
875 s.paired[0][i].end - s.paired[0][i].start, | |
876 "line-file", 67636963); | |
877 TestFunction(1, "function2", | |
878 s.functions[1].start, | |
879 s.functions[1].end - s.functions[1].start); | |
880 TestLineCount(1, s.paired_count[1]); | |
881 for (int i = 0; i < s.paired_count[1]; i++) | |
882 TestLine(1, i, s.paired[1][i].start, | |
883 s.paired[1][i].end - s.paired[1][i].start, | |
884 "line-file", 67636963); | |
885 } | |
886 | |
887 TEST_F(FuncLinePairing, EmptyCU) { | |
888 | |
889 StartCU(); | |
890 root_handler_.Finish(); | |
891 | |
892 TestFunctionCount(0); | |
893 } | |
894 | |
895 TEST_F(FuncLinePairing, LinesNoFuncs) { | |
896 PushLine(40, 2, "line-file", 82485646); | |
897 EXPECT_CALL(reporter_, UncoveredLine(_)).WillOnce(Return()); | |
898 | |
899 StartCU(); | |
900 root_handler_.Finish(); | |
901 | |
902 TestFunctionCount(0); | |
903 } | |
904 | |
905 TEST_F(FuncLinePairing, FuncsNoLines) { | |
906 EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return()); | |
907 | |
908 StartCU(); | |
909 DefineFunction(&root_handler_, "function1", 0x127da12ffcf5c51fULL, 0x1000U); | |
910 root_handler_.Finish(); | |
911 | |
912 TestFunctionCount(1); | |
913 TestFunction(0, "function1", 0x127da12ffcf5c51fULL, 0x1000U); | |
914 } | |
915 | |
916 TEST_F(FuncLinePairing, GapThenFunction) { | |
917 PushLine(20, 2, "line-file-2", 174314698); | |
918 PushLine(10, 2, "line-file-1", 263008005); | |
919 | |
920 StartCU(); | |
921 DefineFunction(&root_handler_, "function1", 10, 2); | |
922 DefineFunction(&root_handler_, "function2", 20, 2); | |
923 root_handler_.Finish(); | |
924 | |
925 TestFunctionCount(2); | |
926 TestFunction(0, "function1", 10, 2); | |
927 TestLineCount(0, 1); | |
928 TestLine(0, 0, 10, 2, "line-file-1", 263008005); | |
929 TestFunction(1, "function2", 20, 2); | |
930 TestLineCount(1, 1); | |
931 TestLine(1, 0, 20, 2, "line-file-2", 174314698); | |
932 } | |
933 | |
934 // If GCC emits padding after one function to align the start of | |
935 // the next, then it will attribute the padding instructions to | |
936 // the last source line of function (to reduce the size of the | |
937 // line number info), but omit it from the DW_AT_{low,high}_pc | |
938 // range given in .debug_info (since it costs nothing to be | |
939 // precise there). If we did use at least some of the line | |
940 // we're about to skip, then assume this is what happened, and | |
941 // don't warn. | |
942 TEST_F(FuncLinePairing, GCCAlignmentStretch) { | |
943 PushLine(10, 10, "line-file", 63351048); | |
944 PushLine(20, 10, "line-file", 61661044); | |
945 | |
946 StartCU(); | |
947 DefineFunction(&root_handler_, "function1", 10, 5); | |
948 // five-byte gap between functions, covered by line 63351048. | |
949 // This should not elicit a warning. | |
950 DefineFunction(&root_handler_, "function2", 20, 10); | |
951 root_handler_.Finish(); | |
952 | |
953 TestFunctionCount(2); | |
954 TestFunction(0, "function1", 10, 5); | |
955 TestLineCount(0, 1); | |
956 TestLine(0, 0, 10, 5, "line-file", 63351048); | |
957 TestFunction(1, "function2", 20, 10); | |
958 TestLineCount(1, 1); | |
959 TestLine(1, 0, 20, 10, "line-file", 61661044); | |
960 } | |
961 | |
962 // Unfortunately, neither the DWARF parser's handler interface nor the | |
963 // DIEHandler interface is capable of expressing a function that abuts | |
964 // the end of the address space: the high_pc value looks like zero. | |
965 | |
966 TEST_F(FuncLinePairing, LineAtEndOfAddressSpace) { | |
967 PushLine(0xfffffffffffffff0ULL, 16, "line-file", 63351048); | |
968 EXPECT_CALL(reporter_, UncoveredLine(_)).WillOnce(Return()); | |
969 | |
970 StartCU(); | |
971 DefineFunction(&root_handler_, "function1", 0xfffffffffffffff0ULL, 6); | |
972 DefineFunction(&root_handler_, "function2", 0xfffffffffffffffaULL, 5); | |
973 root_handler_.Finish(); | |
974 | |
975 TestFunctionCount(2); | |
976 TestFunction(0, "function1", 0xfffffffffffffff0ULL, 6); | |
977 TestLineCount(0, 1); | |
978 TestLine(0, 0, 0xfffffffffffffff0ULL, 6, "line-file", 63351048); | |
979 TestFunction(1, "function2", 0xfffffffffffffffaULL, 5); | |
980 TestLineCount(1, 1); | |
981 TestLine(1, 0, 0xfffffffffffffffaULL, 5, "line-file", 63351048); | |
982 } | |
983 | |
984 // A function with more than one uncovered area should only be warned | |
985 // about once. | |
986 TEST_F(FuncLinePairing, WarnOnceFunc) { | |
987 PushLine(20, 1, "line-file-2", 262951329); | |
988 PushLine(11, 1, "line-file-1", 219964021); | |
989 EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return()); | |
990 | |
991 StartCU(); | |
992 DefineFunction(&root_handler_, "function", 10, 11); | |
993 root_handler_.Finish(); | |
994 | |
995 TestFunctionCount(1); | |
996 TestFunction(0, "function", 10, 11); | |
997 TestLineCount(0, 2); | |
998 TestLine(0, 0, 11, 1, "line-file-1", 219964021); | |
999 TestLine(0, 1, 20, 1, "line-file-2", 262951329); | |
1000 } | |
1001 | |
1002 // A line with more than one uncovered area should only be warned | |
1003 // about once. | |
1004 TEST_F(FuncLinePairing, WarnOnceLine) { | |
1005 PushLine(10, 20, "filename1", 118581871); | |
1006 EXPECT_CALL(reporter_, UncoveredLine(_)).WillOnce(Return()); | |
1007 | |
1008 StartCU(); | |
1009 DefineFunction(&root_handler_, "function1", 11, 1); | |
1010 DefineFunction(&root_handler_, "function2", 13, 1); | |
1011 root_handler_.Finish(); | |
1012 | |
1013 TestFunctionCount(2); | |
1014 TestFunction(0, "function1", 11, 1); | |
1015 TestLineCount(0, 1); | |
1016 TestLine(0, 0, 11, 1, "filename1", 118581871); | |
1017 TestFunction(1, "function2", 13, 1); | |
1018 TestLineCount(1, 1); | |
1019 TestLine(1, 0, 13, 1, "filename1", 118581871); | |
1020 } | |
1021 | |
1022 class CXXQualifiedNames: public CUFixtureBase, | |
1023 public TestWithParam<DwarfTag> { }; | |
1024 | |
1025 INSTANTIATE_TEST_CASE_P(VersusEnclosures, CXXQualifiedNames, | |
1026 Values(dwarf2reader::DW_TAG_class_type, | |
1027 dwarf2reader::DW_TAG_structure_type, | |
1028 dwarf2reader::DW_TAG_union_type, | |
1029 dwarf2reader::DW_TAG_namespace)); | |
1030 | |
1031 TEST_P(CXXQualifiedNames, TwoFunctions) { | |
1032 DwarfTag tag = GetParam(); | |
1033 | |
1034 SetLanguage(dwarf2reader::DW_LANG_C_plus_plus); | |
1035 PushLine(10, 1, "filename1", 69819327); | |
1036 PushLine(20, 1, "filename2", 95115701); | |
1037 | |
1038 StartCU(); | |
1039 DIEHandler *enclosure_handler = StartNamedDIE(&root_handler_, tag, | |
1040 "Enclosure"); | |
1041 EXPECT_TRUE(enclosure_handler != NULL); | |
1042 DefineFunction(enclosure_handler, "func_B", 10, 1); | |
1043 DefineFunction(enclosure_handler, "func_C", 20, 1); | |
1044 enclosure_handler->Finish(); | |
1045 delete enclosure_handler; | |
1046 root_handler_.Finish(); | |
1047 | |
1048 TestFunctionCount(2); | |
1049 TestFunction(0, "Enclosure::func_B", 10, 1); | |
1050 TestFunction(1, "Enclosure::func_C", 20, 1); | |
1051 } | |
1052 | |
1053 TEST_P(CXXQualifiedNames, FuncInEnclosureInNamespace) { | |
1054 DwarfTag tag = GetParam(); | |
1055 | |
1056 SetLanguage(dwarf2reader::DW_LANG_C_plus_plus); | |
1057 PushLine(10, 1, "line-file", 69819327); | |
1058 | |
1059 StartCU(); | |
1060 DIEHandler *namespace_handler | |
1061 = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, | |
1062 "Namespace"); | |
1063 EXPECT_TRUE(namespace_handler != NULL); | |
1064 DIEHandler *enclosure_handler = StartNamedDIE(namespace_handler, tag, | |
1065 "Enclosure"); | |
1066 EXPECT_TRUE(enclosure_handler != NULL); | |
1067 DefineFunction(enclosure_handler, "function", 10, 1); | |
1068 enclosure_handler->Finish(); | |
1069 delete enclosure_handler; | |
1070 namespace_handler->Finish(); | |
1071 delete namespace_handler; | |
1072 root_handler_.Finish(); | |
1073 | |
1074 TestFunctionCount(1); | |
1075 TestFunction(0, "Namespace::Enclosure::function", 10, 1); | |
1076 } | |
1077 | |
1078 TEST_F(CXXQualifiedNames, FunctionInClassInStructInNamespace) { | |
1079 SetLanguage(dwarf2reader::DW_LANG_C_plus_plus); | |
1080 PushLine(10, 1, "filename1", 69819327); | |
1081 | |
1082 StartCU(); | |
1083 DIEHandler *namespace_handler | |
1084 = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, | |
1085 "namespace_A"); | |
1086 EXPECT_TRUE(namespace_handler != NULL); | |
1087 DIEHandler *struct_handler | |
1088 = StartNamedDIE(namespace_handler, dwarf2reader::DW_TAG_structure_type, | |
1089 "struct_B"); | |
1090 EXPECT_TRUE(struct_handler != NULL); | |
1091 DIEHandler *class_handler | |
1092 = StartNamedDIE(struct_handler, dwarf2reader::DW_TAG_class_type, | |
1093 "class_C"); | |
1094 DefineFunction(class_handler, "function_D", 10, 1); | |
1095 class_handler->Finish(); | |
1096 delete class_handler; | |
1097 struct_handler->Finish(); | |
1098 delete struct_handler; | |
1099 namespace_handler->Finish(); | |
1100 delete namespace_handler; | |
1101 root_handler_.Finish(); | |
1102 | |
1103 TestFunctionCount(1); | |
1104 TestFunction(0, "namespace_A::struct_B::class_C::function_D", 10, 1); | |
1105 } | |
1106 | |
1107 struct LanguageAndQualifiedName { | |
1108 dwarf2reader::DwarfLanguage language; | |
1109 const char *name; | |
1110 }; | |
1111 | |
1112 const LanguageAndQualifiedName LanguageAndQualifiedNameCases[] = { | |
1113 { dwarf2reader::DW_LANG_none, "class_A::function_B" }, | |
1114 { dwarf2reader::DW_LANG_C, "class_A::function_B" }, | |
1115 { dwarf2reader::DW_LANG_C89, "class_A::function_B" }, | |
1116 { dwarf2reader::DW_LANG_C99, "class_A::function_B" }, | |
1117 { dwarf2reader::DW_LANG_C_plus_plus, "class_A::function_B" }, | |
1118 { dwarf2reader::DW_LANG_Java, "class_A.function_B" }, | |
1119 { dwarf2reader::DW_LANG_Cobol74, "class_A::function_B" }, | |
1120 { dwarf2reader::DW_LANG_Mips_Assembler, NULL } | |
1121 }; | |
1122 | |
1123 class QualifiedForLanguage: | |
1124 public CUFixtureBase, | |
1125 public TestWithParam<LanguageAndQualifiedName> { }; | |
1126 | |
1127 INSTANTIATE_TEST_CASE_P(LanguageAndQualifiedName, QualifiedForLanguage, | |
1128 ValuesIn(LanguageAndQualifiedNameCases)); | |
1129 | |
1130 TEST_P(QualifiedForLanguage, MemberFunction) { | |
1131 const LanguageAndQualifiedName ¶m = GetParam(); | |
1132 | |
1133 PushLine(10, 1, "line-file", 212966758); | |
1134 SetLanguage(param.language); | |
1135 | |
1136 StartCU(); | |
1137 DIEHandler *class_handler | |
1138 = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, | |
1139 "class_A"); | |
1140 DefineFunction(class_handler, "function_B", 10, 1); | |
1141 class_handler->Finish(); | |
1142 delete class_handler; | |
1143 root_handler_.Finish(); | |
1144 | |
1145 if (param.name) { | |
1146 TestFunctionCount(1); | |
1147 TestFunction(0, param.name, 10, 1); | |
1148 } else { | |
1149 TestFunctionCount(0); | |
1150 } | |
1151 } | |
1152 | |
1153 TEST_P(QualifiedForLanguage, MemberFunctionSignedLanguage) { | |
1154 const LanguageAndQualifiedName ¶m = GetParam(); | |
1155 | |
1156 PushLine(10, 1, "line-file", 212966758); | |
1157 SetLanguage(param.language); | |
1158 SetLanguageSigned(true); | |
1159 | |
1160 StartCU(); | |
1161 DIEHandler *class_handler | |
1162 = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, | |
1163 "class_A"); | |
1164 DefineFunction(class_handler, "function_B", 10, 1); | |
1165 class_handler->Finish(); | |
1166 delete class_handler; | |
1167 root_handler_.Finish(); | |
1168 | |
1169 if (param.name) { | |
1170 TestFunctionCount(1); | |
1171 TestFunction(0, param.name, 10, 1); | |
1172 } else { | |
1173 TestFunctionCount(0); | |
1174 } | |
1175 } | |
1176 | |
1177 class Specifications: public CUFixtureBase, public Test { }; | |
1178 | |
1179 TEST_F(Specifications, Function) { | |
1180 PushLine(0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL, "line-file", 54883661); | |
1181 | |
1182 StartCU(); | |
1183 DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL, | |
1184 dwarf2reader::DW_TAG_subprogram, "declaration-name"); | |
1185 DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, | |
1186 0xcd3c51b946fb1eeeLL, "", | |
1187 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL); | |
1188 root_handler_.Finish(); | |
1189 | |
1190 TestFunctionCount(1); | |
1191 TestFunction(0, "declaration-name", | |
1192 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL); | |
1193 } | |
1194 | |
1195 TEST_F(Specifications, MemberFunction) { | |
1196 PushLine(0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL, "line-file", 18116691); | |
1197 | |
1198 StartCU(); | |
1199 DIEHandler *class_handler | |
1200 = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, "class_A"); | |
1201 DeclarationDIE(class_handler, 0x7d83028c431406e8ULL, | |
1202 dwarf2reader::DW_TAG_subprogram, "declaration-name"); | |
1203 class_handler->Finish(); | |
1204 delete class_handler; | |
1205 DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, | |
1206 0x7d83028c431406e8ULL, "", | |
1207 0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL); | |
1208 root_handler_.Finish(); | |
1209 | |
1210 TestFunctionCount(1); | |
1211 TestFunction(0, "class_A::declaration-name", | |
1212 0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL); | |
1213 } | |
1214 | |
1215 // This case should gather the name from both the definition and the | |
1216 // declaration's parent. | |
1217 TEST_F(Specifications, FunctionDeclarationParent) { | |
1218 PushLine(0x463c9ddf405be227ULL, 0x6a47774af5049680ULL, "line-file", 70254922); | |
1219 | |
1220 StartCU(); | |
1221 { | |
1222 DIEHandler *class_handler | |
1223 = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, | |
1224 "class_A"); | |
1225 ASSERT_TRUE(class_handler != NULL); | |
1226 DeclarationDIE(class_handler, 0x0e0e877c8404544aULL, | |
1227 dwarf2reader::DW_TAG_subprogram, "declaration-name"); | |
1228 class_handler->Finish(); | |
1229 delete class_handler; | |
1230 } | |
1231 | |
1232 DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, | |
1233 0x0e0e877c8404544aULL, "definition-name", | |
1234 0x463c9ddf405be227ULL, 0x6a47774af5049680ULL); | |
1235 | |
1236 root_handler_.Finish(); | |
1237 | |
1238 TestFunctionCount(1); | |
1239 TestFunction(0, "class_A::definition-name", | |
1240 0x463c9ddf405be227ULL, 0x6a47774af5049680ULL); | |
1241 } | |
1242 | |
1243 // Named scopes should also gather enclosing name components from | |
1244 // their declarations. | |
1245 TEST_F(Specifications, NamedScopeDeclarationParent) { | |
1246 PushLine(0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL, "line-file", 77392604); | |
1247 | |
1248 StartCU(); | |
1249 { | |
1250 DIEHandler *space_handler | |
1251 = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, | |
1252 "space_A"); | |
1253 ASSERT_TRUE(space_handler != NULL); | |
1254 DeclarationDIE(space_handler, 0x419bb1d12f9a73a2ULL, | |
1255 dwarf2reader::DW_TAG_class_type, "class-declaration-name"); | |
1256 space_handler->Finish(); | |
1257 delete space_handler; | |
1258 } | |
1259 | |
1260 { | |
1261 DIEHandler *class_handler | |
1262 = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, | |
1263 0x419bb1d12f9a73a2ULL, "class-definition-name"); | |
1264 ASSERT_TRUE(class_handler != NULL); | |
1265 DefineFunction(class_handler, "function", | |
1266 0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL); | |
1267 class_handler->Finish(); | |
1268 delete class_handler; | |
1269 } | |
1270 | |
1271 root_handler_.Finish(); | |
1272 | |
1273 TestFunctionCount(1); | |
1274 TestFunction(0, "space_A::class-definition-name::function", | |
1275 0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL); | |
1276 } | |
1277 | |
1278 // This test recreates bug 364. | |
1279 TEST_F(Specifications, InlineFunction) { | |
1280 PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118); | |
1281 | |
1282 StartCU(); | |
1283 DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL, | |
1284 dwarf2reader::DW_TAG_subprogram, "inline-name"); | |
1285 AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL, | |
1286 dwarf2reader::DW_INL_inlined, 0xcd3c51b946fb1eeeLL, ""); | |
1287 DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL, | |
1288 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); | |
1289 root_handler_.Finish(); | |
1290 | |
1291 TestFunctionCount(1); | |
1292 TestFunction(0, "inline-name", | |
1293 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); | |
1294 } | |
1295 | |
1296 // Check name construction for a long chain containing each combination of: | |
1297 // - struct, union, class, namespace | |
1298 // - direct and definition | |
1299 TEST_F(Specifications, LongChain) { | |
1300 PushLine(0x5a0dd6bb85db754cULL, 0x3bccb213d08c7fd3ULL, "line-file", 21192926); | |
1301 SetLanguage(dwarf2reader::DW_LANG_C_plus_plus); | |
1302 | |
1303 StartCU(); | |
1304 // The structure we're building here is: | |
1305 // space_A full definition | |
1306 // space_B declaration | |
1307 // space_B definition | |
1308 // struct_C full definition | |
1309 // struct_D declaration | |
1310 // struct_D definition | |
1311 // union_E full definition | |
1312 // union_F declaration | |
1313 // union_F definition | |
1314 // class_G full definition | |
1315 // class_H declaration | |
1316 // class_H definition | |
1317 // func_I declaration | |
1318 // func_I definition | |
1319 // | |
1320 // So: | |
1321 // - space_A, struct_C, union_E, and class_G don't use specifications; | |
1322 // - space_B, struct_D, union_F, and class_H do. | |
1323 // - func_I uses a specification. | |
1324 // | |
1325 // The full name for func_I is thus: | |
1326 // | |
1327 // space_A::space_B::struct_C::struct_D::union_E::union_F:: | |
1328 // class_G::class_H::func_I | |
1329 { | |
1330 DIEHandler *space_A_handler | |
1331 = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, | |
1332 "space_A"); | |
1333 DeclarationDIE(space_A_handler, 0x2e111126496596e2ULL, | |
1334 dwarf2reader::DW_TAG_namespace, "space_B"); | |
1335 space_A_handler->Finish(); | |
1336 delete space_A_handler; | |
1337 } | |
1338 | |
1339 { | |
1340 DIEHandler *space_B_handler | |
1341 = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, | |
1342 0x2e111126496596e2ULL); | |
1343 DIEHandler *struct_C_handler | |
1344 = StartNamedDIE(space_B_handler, dwarf2reader::DW_TAG_structure_type, | |
1345 "struct_C"); | |
1346 DeclarationDIE(struct_C_handler, 0x20cd423bf2a25a4cULL, | |
1347 dwarf2reader::DW_TAG_structure_type, "struct_D"); | |
1348 struct_C_handler->Finish(); | |
1349 delete struct_C_handler; | |
1350 space_B_handler->Finish(); | |
1351 delete space_B_handler; | |
1352 } | |
1353 | |
1354 { | |
1355 DIEHandler *struct_D_handler | |
1356 = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_structure_type, | |
1357 0x20cd423bf2a25a4cULL); | |
1358 DIEHandler *union_E_handler | |
1359 = StartNamedDIE(struct_D_handler, dwarf2reader::DW_TAG_union_type, | |
1360 "union_E"); | |
1361 DeclarationDIE(union_E_handler, 0xe25c84805aa58c32ULL, | |
1362 dwarf2reader::DW_TAG_union_type, "union_F"); | |
1363 union_E_handler->Finish(); | |
1364 delete union_E_handler; | |
1365 struct_D_handler->Finish(); | |
1366 delete struct_D_handler; | |
1367 } | |
1368 | |
1369 { | |
1370 DIEHandler *union_F_handler | |
1371 = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_union_type, | |
1372 0xe25c84805aa58c32ULL); | |
1373 DIEHandler *class_G_handler | |
1374 = StartNamedDIE(union_F_handler, dwarf2reader::DW_TAG_class_type, | |
1375 "class_G"); | |
1376 DeclarationDIE(class_G_handler, 0xb70d960dcc173b6eULL, | |
1377 dwarf2reader::DW_TAG_class_type, "class_H"); | |
1378 class_G_handler->Finish(); | |
1379 delete class_G_handler; | |
1380 union_F_handler->Finish(); | |
1381 delete union_F_handler; | |
1382 } | |
1383 | |
1384 { | |
1385 DIEHandler *class_H_handler | |
1386 = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, | |
1387 0xb70d960dcc173b6eULL); | |
1388 DeclarationDIE(class_H_handler, 0x27ff829e3bf69f37ULL, | |
1389 dwarf2reader::DW_TAG_subprogram, "func_I"); | |
1390 class_H_handler->Finish(); | |
1391 delete class_H_handler; | |
1392 } | |
1393 | |
1394 DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, | |
1395 0x27ff829e3bf69f37ULL, "", | |
1396 0x5a0dd6bb85db754cULL, 0x3bccb213d08c7fd3ULL); | |
1397 root_handler_.Finish(); | |
1398 | |
1399 TestFunctionCount(1); | |
1400 TestFunction(0, "space_A::space_B::struct_C::struct_D::union_E::union_F" | |
1401 "::class_G::class_H::func_I", | |
1402 0x5a0dd6bb85db754cULL, 0x3bccb213d08c7fd3ULL); | |
1403 } | |
1404 | |
1405 TEST_F(Specifications, InterCU) { | |
1406 Module m("module-name", "module-os", "module-arch", "module-id"); | |
1407 DwarfCUToModule::FileContext fc("dwarf-filename", &m); | |
1408 EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return()); | |
1409 MockLineToModuleFunctor lr; | |
1410 EXPECT_CALL(lr, mock_apply(_,_,_,_)).Times(0); | |
1411 dwarf2reader::AttributeList no_attrs; | |
1412 | |
1413 // Kludge: satisfy reporter_'s expectation. | |
1414 reporter_.SetCUName("compilation-unit-name"); | |
1415 | |
1416 // First CU. Declares class_A. | |
1417 { | |
1418 DwarfCUToModule root1_handler(&fc, &lr, &reporter_); | |
1419 ASSERT_TRUE(root1_handler.StartCompilationUnit(0, 1, 2, 3, 3)); | |
1420 dwarf2reader::AttributeList attrs; | |
1421 PushBackStrangeAttributes(&attrs); | |
1422 ASSERT_TRUE(root1_handler.StartRootDIE(1, dwarf2reader::DW_TAG_compile_unit, | |
1423 attrs)); | |
1424 ProcessStrangeAttributes(&root1_handler); | |
1425 ASSERT_TRUE(root1_handler.EndAttributes()); | |
1426 DeclarationDIE(&root1_handler, 0xb8fbfdd5f0b26fceULL, | |
1427 dwarf2reader::DW_TAG_class_type, "class_A"); | |
1428 root1_handler.Finish(); | |
1429 } | |
1430 | |
1431 // Second CU. Defines class_A, declares member_func_B. | |
1432 { | |
1433 DwarfCUToModule root2_handler(&fc, &lr, &reporter_); | |
1434 ASSERT_TRUE(root2_handler.StartCompilationUnit(0, 1, 2, 3, 3)); | |
1435 ASSERT_TRUE(root2_handler.StartRootDIE(1, dwarf2reader::DW_TAG_compile_unit, | |
1436 no_attrs)); | |
1437 ASSERT_TRUE(root2_handler.EndAttributes()); | |
1438 DIEHandler *class_A_handler | |
1439 = StartSpecifiedDIE(&root2_handler, dwarf2reader::DW_TAG_class_type, | |
1440 0xb8fbfdd5f0b26fceULL); | |
1441 DeclarationDIE(class_A_handler, 0xb01fef8b380bd1a2ULL, | |
1442 dwarf2reader::DW_TAG_subprogram, "member_func_B"); | |
1443 class_A_handler->Finish(); | |
1444 delete class_A_handler; | |
1445 root2_handler.Finish(); | |
1446 } | |
1447 | |
1448 // Third CU. Defines member_func_B. | |
1449 { | |
1450 DwarfCUToModule root3_handler(&fc, &lr, &reporter_); | |
1451 ASSERT_TRUE(root3_handler.StartCompilationUnit(0, 1, 2, 3, 3)); | |
1452 ASSERT_TRUE(root3_handler.StartRootDIE(1, dwarf2reader::DW_TAG_compile_unit, | |
1453 no_attrs)); | |
1454 ASSERT_TRUE(root3_handler.EndAttributes()); | |
1455 DefinitionDIE(&root3_handler, dwarf2reader::DW_TAG_subprogram, | |
1456 0xb01fef8b380bd1a2ULL, "", | |
1457 0x2618f00a1a711e53ULL, 0x4fd94b76d7c2caf5ULL); | |
1458 root3_handler.Finish(); | |
1459 } | |
1460 | |
1461 vector<Module::Function *> functions; | |
1462 m.GetFunctions(&functions, functions.end()); | |
1463 EXPECT_EQ(1U, functions.size()); | |
1464 EXPECT_STREQ("class_A::member_func_B", functions[0]->name.c_str()); | |
1465 } | |
1466 | |
1467 TEST_F(Specifications, BadOffset) { | |
1468 PushLine(0xa0277efd7ce83771ULL, 0x149554a184c730c1ULL, "line-file", 56636272); | |
1469 EXPECT_CALL(reporter_, UnknownSpecification(_, 0x2be953efa6f9a996ULL)) | |
1470 .WillOnce(Return()); | |
1471 | |
1472 StartCU(); | |
1473 DeclarationDIE(&root_handler_, 0xefd7f7752c27b7e4ULL, | |
1474 dwarf2reader::DW_TAG_subprogram, "function"); | |
1475 DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, | |
1476 0x2be953efa6f9a996ULL, "", | |
1477 0xa0277efd7ce83771ULL, 0x149554a184c730c1ULL); | |
1478 root_handler_.Finish(); | |
1479 } | |
1480 | |
1481 TEST_F(Specifications, FunctionDefinitionHasOwnName) { | |
1482 PushLine(0xced50b3eea81022cULL, 0x08dd4d301cc7a7d2ULL, "line-file", 56792403); | |
1483 | |
1484 StartCU(); | |
1485 DeclarationDIE(&root_handler_, 0xc34ff4786cae78bdULL, | |
1486 dwarf2reader::DW_TAG_subprogram, "declaration-name"); | |
1487 DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, | |
1488 0xc34ff4786cae78bdULL, "definition-name", | |
1489 0xced50b3eea81022cULL, 0x08dd4d301cc7a7d2ULL); | |
1490 root_handler_.Finish(); | |
1491 | |
1492 TestFunctionCount(1); | |
1493 TestFunction(0, "definition-name", | |
1494 0xced50b3eea81022cULL, 0x08dd4d301cc7a7d2ULL); | |
1495 } | |
1496 | |
1497 TEST_F(Specifications, ClassDefinitionHasOwnName) { | |
1498 PushLine(0x1d0f5e0f6ce309bdULL, 0x654e1852ec3599e7ULL, "line-file", 57119241); | |
1499 | |
1500 StartCU(); | |
1501 DeclarationDIE(&root_handler_, 0xd0fe467ec2f1a58cULL, | |
1502 dwarf2reader::DW_TAG_class_type, "class-declaration-name"); | |
1503 | |
1504 dwarf2reader::DIEHandler *class_definition | |
1505 = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, | |
1506 0xd0fe467ec2f1a58cULL, "class-definition-name"); | |
1507 ASSERT_TRUE(class_definition); | |
1508 DeclarationDIE(class_definition, 0x6d028229c15623dbULL, | |
1509 dwarf2reader::DW_TAG_subprogram, | |
1510 "function-declaration-name"); | |
1511 class_definition->Finish(); | |
1512 delete class_definition; | |
1513 | |
1514 DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, | |
1515 0x6d028229c15623dbULL, "function-definition-name", | |
1516 0x1d0f5e0f6ce309bdULL, 0x654e1852ec3599e7ULL); | |
1517 | |
1518 root_handler_.Finish(); | |
1519 | |
1520 TestFunctionCount(1); | |
1521 TestFunction(0, "class-definition-name::function-definition-name", | |
1522 0x1d0f5e0f6ce309bdULL, 0x654e1852ec3599e7ULL); | |
1523 } | |
1524 | |
1525 // DIEs that cite a specification should prefer the specification's | |
1526 // parents over their own when choosing qualified names. In this test, | |
1527 // we take the name from our definition but the enclosing scope name | |
1528 // from our declaration. I don't see why they'd ever be different, but | |
1529 // we want to verify what DwarfCUToModule is looking at. | |
1530 TEST_F(Specifications, PreferSpecificationParents) { | |
1531 PushLine(0xbbd9d54dce3b95b7ULL, 0x39188b7b52b0899fULL, "line-file", 79488694); | |
1532 | |
1533 StartCU(); | |
1534 { | |
1535 dwarf2reader::DIEHandler *declaration_class_handler | |
1536 = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, "declarat
ion-class"); | |
1537 DeclarationDIE(declaration_class_handler, 0x9ddb35517455ef7aULL, | |
1538 dwarf2reader::DW_TAG_subprogram, "function-declaration"); | |
1539 declaration_class_handler->Finish(); | |
1540 delete declaration_class_handler; | |
1541 } | |
1542 { | |
1543 dwarf2reader::DIEHandler *definition_class_handler | |
1544 = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, | |
1545 "definition-class"); | |
1546 DefinitionDIE(definition_class_handler, dwarf2reader::DW_TAG_subprogram, | |
1547 0x9ddb35517455ef7aULL, "function-definition", | |
1548 0xbbd9d54dce3b95b7ULL, 0x39188b7b52b0899fULL); | |
1549 definition_class_handler->Finish(); | |
1550 delete definition_class_handler; | |
1551 } | |
1552 root_handler_.Finish(); | |
1553 | |
1554 TestFunctionCount(1); | |
1555 TestFunction(0, "declaration-class::function-definition", | |
1556 0xbbd9d54dce3b95b7ULL, 0x39188b7b52b0899fULL); | |
1557 } | |
1558 | |
1559 class Errors: public CUFixtureBase, public Test { }; | |
1560 | |
1561 TEST_F(Errors, BadStmtList) { | |
1562 EXPECT_CALL(reporter_, BadLineInfoOffset(dummy_line_size_ + 10)).Times(1); | |
1563 | |
1564 ASSERT_TRUE(root_handler_ | |
1565 .StartCompilationUnit(0xc591d5b037543d7cULL, 0x11, 0xcd, | |
1566 0x2d7d19546cf6590cULL, 3)); | |
1567 dwarf2reader::AttributeList attrs; | |
1568 attrs.push_back(make_pair(dwarf2reader::DW_AT_name, | |
1569 dwarf2reader::DW_FORM_strp)); | |
1570 attrs.push_back(make_pair(dwarf2reader::DW_AT_stmt_list, | |
1571 dwarf2reader::DW_FORM_ref4)); | |
1572 ASSERT_TRUE(root_handler_.StartRootDIE(0xae789dc102cfca54ULL, | |
1573 dwarf2reader::DW_TAG_compile_unit, | |
1574 attrs)); | |
1575 root_handler_.ProcessAttributeString(dwarf2reader::DW_AT_name, | |
1576 dwarf2reader::DW_FORM_strp, | |
1577 "compilation-unit-name"); | |
1578 root_handler_.ProcessAttributeUnsigned(dwarf2reader::DW_AT_stmt_list, | |
1579 dwarf2reader::DW_FORM_ref4, | |
1580 dummy_line_size_ + 10); | |
1581 root_handler_.EndAttributes(); | |
1582 root_handler_.Finish(); | |
1583 } | |
1584 | |
1585 TEST_F(Errors, NoLineSection) { | |
1586 EXPECT_CALL(reporter_, MissingSection(".debug_line")).Times(1); | |
1587 PushLine(0x88507fb678052611ULL, 0x42c8e9de6bbaa0faULL, "line-file", 64472290); | |
1588 // Delete the entry for .debug_line added by the fixture class's constructor. | |
1589 file_context_.section_map.clear(); | |
1590 | |
1591 StartCU(); | |
1592 root_handler_.Finish(); | |
1593 } | |
1594 | |
1595 TEST_F(Errors, BadDwarfVersion1) { | |
1596 // Kludge: satisfy reporter_'s expectation. | |
1597 reporter_.SetCUName("compilation-unit-name"); | |
1598 | |
1599 ASSERT_FALSE(root_handler_ | |
1600 .StartCompilationUnit(0xadf6e0eb71e2b0d9ULL, 0x4d, 0x90, | |
1601 0xc9de224ccb99ac3eULL, 1)); | |
1602 } | |
1603 | |
1604 TEST_F(Errors, GoodDwarfVersion2) { | |
1605 // Kludge: satisfy reporter_'s expectation. | |
1606 reporter_.SetCUName("compilation-unit-name"); | |
1607 | |
1608 ASSERT_TRUE(root_handler_ | |
1609 .StartCompilationUnit(0xadf6e0eb71e2b0d9ULL, 0x4d, 0x90, | |
1610 0xc9de224ccb99ac3eULL, 2)); | |
1611 } | |
1612 | |
1613 TEST_F(Errors, GoodDwarfVersion3) { | |
1614 // Kludge: satisfy reporter_'s expectation. | |
1615 reporter_.SetCUName("compilation-unit-name"); | |
1616 | |
1617 ASSERT_TRUE(root_handler_ | |
1618 .StartCompilationUnit(0xadf6e0eb71e2b0d9ULL, 0x4d, 0x90, | |
1619 0xc9de224ccb99ac3eULL, 3)); | |
1620 } | |
1621 | |
1622 TEST_F(Errors, BadCURootDIETag) { | |
1623 // Kludge: satisfy reporter_'s expectation. | |
1624 reporter_.SetCUName("compilation-unit-name"); | |
1625 | |
1626 ASSERT_TRUE(root_handler_ | |
1627 .StartCompilationUnit(0xadf6e0eb71e2b0d9ULL, 0x4d, 0x90, | |
1628 0xc9de224ccb99ac3eULL, 3)); | |
1629 | |
1630 dwarf2reader::AttributeList no_attrs; | |
1631 ASSERT_FALSE(root_handler_.StartRootDIE(0x02e56bfbda9e7337ULL, | |
1632 dwarf2reader::DW_TAG_subprogram, | |
1633 no_attrs)); | |
1634 } | |
1635 | |
1636 // Tests for DwarfCUToModule::Reporter. These just produce (or fail to | |
1637 // produce) output, so their results need to be checked by hand. | |
1638 struct Reporter: public Test { | |
1639 Reporter() | |
1640 : reporter("filename", 0x123456789abcdef0ULL) { | |
1641 reporter.SetCUName("compilation-unit-name"); | |
1642 | |
1643 function.name = "function name"; | |
1644 function.address = 0x19c45c30770c1eb0ULL; | |
1645 function.size = 0x89808a5bdfa0a6a3ULL; | |
1646 function.parameter_size = 0x6a329f18683dcd51ULL; | |
1647 | |
1648 file.name = "source file name"; | |
1649 | |
1650 line.address = 0x3606ac6267aebeccULL; | |
1651 line.size = 0x5de482229f32556aULL; | |
1652 line.file = &file; | |
1653 line.number = 93400201; | |
1654 } | |
1655 | |
1656 DwarfCUToModule::WarningReporter reporter; | |
1657 Module::Function function; | |
1658 Module::File file; | |
1659 Module::Line line; | |
1660 }; | |
1661 | |
1662 TEST_F(Reporter, UnknownSpecification) { | |
1663 reporter.UnknownSpecification(0x123456789abcdef1ULL, 0x323456789abcdef2ULL); | |
1664 } | |
1665 | |
1666 TEST_F(Reporter, UnknownAbstractOrigin) { | |
1667 reporter.UnknownAbstractOrigin(0x123456789abcdef1ULL, 0x323456789abcdef2ULL); | |
1668 } | |
1669 | |
1670 TEST_F(Reporter, MissingSection) { | |
1671 reporter.MissingSection("section name"); | |
1672 } | |
1673 | |
1674 TEST_F(Reporter, BadLineInfoOffset) { | |
1675 reporter.BadLineInfoOffset(0x123456789abcdef1ULL); | |
1676 } | |
1677 | |
1678 TEST_F(Reporter, UncoveredFunctionDisabled) { | |
1679 reporter.UncoveredFunction(function); | |
1680 EXPECT_FALSE(reporter.uncovered_warnings_enabled()); | |
1681 } | |
1682 | |
1683 TEST_F(Reporter, UncoveredFunctionEnabled) { | |
1684 reporter.set_uncovered_warnings_enabled(true); | |
1685 reporter.UncoveredFunction(function); | |
1686 EXPECT_TRUE(reporter.uncovered_warnings_enabled()); | |
1687 } | |
1688 | |
1689 TEST_F(Reporter, UncoveredLineDisabled) { | |
1690 reporter.UncoveredLine(line); | |
1691 EXPECT_FALSE(reporter.uncovered_warnings_enabled()); | |
1692 } | |
1693 | |
1694 TEST_F(Reporter, UncoveredLineEnabled) { | |
1695 reporter.set_uncovered_warnings_enabled(true); | |
1696 reporter.UncoveredLine(line); | |
1697 EXPECT_TRUE(reporter.uncovered_warnings_enabled()); | |
1698 } | |
1699 | |
1700 // Would be nice to also test: | |
1701 // - overlapping lines, functions | |
OLD | NEW |