From f7566bd447f628d77152dc28fb70ab232c342b86 Mon Sep 17 00:00:00 2001 From: "thestig@chromium.org" Date: Wed, 24 Apr 2013 21:18:44 +0000 Subject: Add an option to not handle DWARF inter-compilation unit references in Linux dump_syms. This saves a lot of memory for dump_syms. Review URL: https://breakpad.appspot.com/565002 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1163 4c0a9323-5329-0410-9bdc-e9ce6186880e --- src/common/dwarf_cu_to_module_unittest.cc | 152 +++++++++++++++++++++--------- 1 file changed, 106 insertions(+), 46 deletions(-) (limited to 'src/common/dwarf_cu_to_module_unittest.cc') diff --git a/src/common/dwarf_cu_to_module_unittest.cc b/src/common/dwarf_cu_to_module_unittest.cc index 81e629b0..5f61a58e 100644 --- a/src/common/dwarf_cu_to_module_unittest.cc +++ b/src/common/dwarf_cu_to_module_unittest.cc @@ -81,6 +81,7 @@ class MockWarningReporter: public DwarfCUToModule::WarningReporter { MOCK_METHOD1(UncoveredFunction, void(const Module::Function &function)); MOCK_METHOD1(UncoveredLine, void(const Module::Line &line)); MOCK_METHOD1(UnnamedFunction, void(uint64 offset)); + MOCK_METHOD2(UnhandledInterCUReference, void(uint64 offset, uint64 target)); }; // A fixture class including all the objects needed to handle a @@ -88,7 +89,6 @@ class MockWarningReporter: public DwarfCUToModule::WarningReporter { // for doing common kinds of setup and tests. class CUFixtureBase { public: - // If we have: // // vector lines; @@ -108,7 +108,8 @@ class CUFixtureBase { // in which case calling l2m with some line vector will append lines. class AppendLinesFunctor { public: - AppendLinesFunctor(const vector *lines) : lines_(lines) { } + explicit AppendLinesFunctor( + const vector *lines) : lines_(lines) { } void operator()(const char *program, uint64 length, Module *module, vector *lines) { lines->insert(lines->end(), lines_->begin(), lines_->end()); @@ -119,7 +120,7 @@ class CUFixtureBase { CUFixtureBase() : module_("module-name", "module-os", "module-arch", "module-id"), - file_context_("dwarf-filename", &module_), + file_context_("dwarf-filename", &module_, true), language_(dwarf2reader::DW_LANG_none), language_signed_(false), appender_(&lines_), @@ -137,6 +138,7 @@ class CUFixtureBase { EXPECT_CALL(reporter_, UncoveredFunction(_)).Times(0); EXPECT_CALL(reporter_, UncoveredLine(_)).Times(0); EXPECT_CALL(reporter_, UnnamedFunction(_)).Times(0); + EXPECT_CALL(reporter_, UnhandledInterCUReference(_, _)).Times(0); // By default, expect the line program reader not to be invoked. We // may override this in StartCU. @@ -145,8 +147,9 @@ class CUFixtureBase { // The handler will consult this section map to decide what to // pass to our line reader. - file_context_.section_map[".debug_line"] = make_pair(dummy_line_program_, - dummy_line_size_); + file_context_.AddSectionToSectionMap(".debug_line", + dummy_line_program_, + dummy_line_size_); } // Add a line with the given address, size, filename, and line @@ -182,7 +185,7 @@ class CUFixtureBase { // not Finish. DIEHandler *StartNamedDIE(DIEHandler *parent, DwarfTag tag, const string &name); - + // Start a child DIE of PARENT with the given tag and a // DW_AT_specification attribute whose value is SPECIFICATION. Leave // the handler ready to hear about children: call EndAttributes, but @@ -190,7 +193,7 @@ class CUFixtureBase { // attribute. DIEHandler *StartSpecifiedDIE(DIEHandler *parent, DwarfTag tag, uint64 specification, const char *name = NULL); - + // Define a function as a child of PARENT with the given name, address, and // size. If high_pc_form is DW_FORM_addr then the DW_AT_high_pc attribute // will be written as an address; otherwise it will be written as the @@ -246,7 +249,7 @@ class CUFixtureBase { // parameter size is zero. void TestFunction(int i, const string &name, Module::Address address, Module::Address size); - + // Test that the number of source lines owned by the I'th function // in the module this.module_ is equal to EXPECTED. void TestLineCount(int i, size_t expected); @@ -283,7 +286,7 @@ class CUFixtureBase { AppendLinesFunctor appender_; static const char dummy_line_program_[]; static const size_t dummy_line_size_; - + MockWarningReporter reporter_; DwarfCUToModule root_handler_; @@ -299,8 +302,8 @@ class CUFixtureBase { }; const char CUFixtureBase::dummy_line_program_[] = "lots of fun data"; -const size_t CUFixtureBase::dummy_line_size_ = - sizeof (CUFixtureBase::dummy_line_program_); +const size_t CUFixtureBase::dummy_line_size_ = + sizeof(CUFixtureBase::dummy_line_program_); void CUFixtureBase::PushLine(Module::Address address, Module::Address size, const string &filename, int line_number) { @@ -320,7 +323,7 @@ void CUFixtureBase::StartCU() { // If we have lines, make the line reader expect to be invoked at // most once. (Hey, if the handler can pass its tests without // bothering to read the line number data, that's great.) - // Have it add the lines passed to PushLine. Otherwise, leave the + // Have it add the lines passed to PushLine. Otherwise, leave the // initial expectation (no calls) in force. if (!lines_.empty()) EXPECT_CALL(line_reader_, @@ -396,7 +399,7 @@ DIEHandler *CUFixtureBase::StartNamedDIE(DIEHandler *parent, delete handler; return NULL; } - + return handler; } @@ -420,7 +423,7 @@ DIEHandler *CUFixtureBase::StartSpecifiedDIE(DIEHandler *parent, delete handler; return NULL; } - + return handler; } @@ -541,7 +544,7 @@ void CUFixtureBase::AbstractInstanceDIE(DIEHandler *parent, void CUFixtureBase::DefineInlineInstanceDIE(DIEHandler *parent, const string &name, - uint64 origin, + uint64 origin, Module::Address address, Module::Address size) { dwarf2reader::DIEHandler *func @@ -708,7 +711,7 @@ TEST_F(SimpleCU, IrrelevantNamedScopeChildren) { // Verify that FileContexts can safely be deleted unused. TEST_F(SimpleCU, UnusedFileContext) { Module m("module-name", "module-os", "module-arch", "module-id"); - DwarfCUToModule::FileContext fc("dwarf-filename", &m); + DwarfCUToModule::FileContext fc("dwarf-filename", &m, true); // Kludge: satisfy reporter_'s expectation. reporter_.SetCUName("compilation-unit-name"); @@ -864,34 +867,33 @@ TEST_P(FuncLinePairing, Pairing) { StartCU(); DefineFunction(&root_handler_, "function1", - s.functions[0].start, + s.functions[0].start, s.functions[0].end - s.functions[0].start, NULL); DefineFunction(&root_handler_, "function2", - s.functions[1].start, + s.functions[1].start, s.functions[1].end - s.functions[1].start, NULL); root_handler_.Finish(); TestFunctionCount(2); TestFunction(0, "function1", - s.functions[0].start, + s.functions[0].start, s.functions[0].end - s.functions[0].start); TestLineCount(0, s.paired_count[0]); for (int i = 0; i < s.paired_count[0]; i++) - TestLine(0, i, s.paired[0][i].start, - s.paired[0][i].end - s.paired[0][i].start, + TestLine(0, i, s.paired[0][i].start, + s.paired[0][i].end - s.paired[0][i].start, "line-file", 67636963); TestFunction(1, "function2", - s.functions[1].start, + s.functions[1].start, s.functions[1].end - s.functions[1].start); TestLineCount(1, s.paired_count[1]); for (int i = 0; i < s.paired_count[1]; i++) - TestLine(1, i, s.paired[1][i].start, - s.paired[1][i].end - s.paired[1][i].start, + TestLine(1, i, s.paired[1][i].start, + s.paired[1][i].end - s.paired[1][i].start, "line-file", 67636963); } TEST_F(FuncLinePairing, EmptyCU) { - StartCU(); root_handler_.Finish(); @@ -913,7 +915,7 @@ TEST_F(FuncLinePairing, FuncsNoLines) { StartCU(); DefineFunction(&root_handler_, "function1", 0x127da12ffcf5c51fULL, 0x1000U, - NULL); + NULL); root_handler_.Finish(); TestFunctionCount(1); @@ -1064,11 +1066,11 @@ TEST_P(CXXQualifiedNames, FuncInEnclosureInNamespace) { PushLine(10, 1, "line-file", 69819327); StartCU(); - DIEHandler *namespace_handler + DIEHandler *namespace_handler = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, "Namespace"); EXPECT_TRUE(namespace_handler != NULL); - DIEHandler *enclosure_handler = StartNamedDIE(namespace_handler, tag, + DIEHandler *enclosure_handler = StartNamedDIE(namespace_handler, tag, "Enclosure"); EXPECT_TRUE(enclosure_handler != NULL); DefineFunction(enclosure_handler, "function", 10, 1, NULL); @@ -1127,10 +1129,10 @@ const LanguageAndQualifiedName LanguageAndQualifiedNameCases[] = { { dwarf2reader::DW_LANG_Mips_Assembler, NULL } }; -class QualifiedForLanguage: - public CUFixtureBase, - public TestWithParam { }; - +class QualifiedForLanguage + : public CUFixtureBase, + public TestWithParam { }; + INSTANTIATE_TEST_CASE_P(LanguageAndQualifiedName, QualifiedForLanguage, ValuesIn(LanguageAndQualifiedNameCases)); @@ -1254,7 +1256,7 @@ TEST_F(Specifications, FunctionDeclarationParent) { } DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, - 0x0e0e877c8404544aULL, "definition-name", + 0x0e0e877c8404544aULL, "definition-name", 0x463c9ddf405be227ULL, 0x6a47774af5049680ULL); root_handler_.Finish(); @@ -1287,14 +1289,14 @@ TEST_F(Specifications, NamedScopeDeclarationParent) { = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, 0x419bb1d12f9a73a2ULL, "class-definition-name"); ASSERT_TRUE(class_handler != NULL); - DefineFunction(class_handler, "function", + DefineFunction(class_handler, "function", 0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL, NULL); class_handler->Finish(); delete class_handler; } root_handler_.Finish(); - + TestFunctionCount(1); TestFunction(0, "space_A::class-definition-name::function", 0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL); @@ -1341,14 +1343,14 @@ TEST_F(Specifications, LongChain) { // class_H definition // func_I declaration // func_I definition - // - // So: + // + // So: // - space_A, struct_C, union_E, and class_G don't use specifications; // - space_B, struct_D, union_F, and class_H do. // - func_I uses a specification. - // + // // The full name for func_I is thus: - // + // // space_A::space_B::struct_C::struct_D::union_E::union_F:: // class_G::class_H::func_I { @@ -1429,7 +1431,7 @@ TEST_F(Specifications, LongChain) { TEST_F(Specifications, InterCU) { Module m("module-name", "module-os", "module-arch", "module-id"); - DwarfCUToModule::FileContext fc("dwarf-filename", &m); + DwarfCUToModule::FileContext fc("dwarf-filename", &m, true); EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return()); MockLineToModuleHandler lr; EXPECT_CALL(lr, ReadProgram(_,_,_,_)).Times(0); @@ -1449,7 +1451,7 @@ TEST_F(Specifications, InterCU) { dwarf2reader::DW_TAG_class_type, "class_A", ""); root1_handler.Finish(); } - + // Second CU. Defines class_A, declares member_func_B. { DwarfCUToModule root2_handler(&fc, &lr, &reporter_); @@ -1486,6 +1488,63 @@ TEST_F(Specifications, InterCU) { EXPECT_STREQ("class_A::member_func_B", functions[0]->name.c_str()); } +TEST_F(Specifications, UnhandledInterCU) { + Module m("module-name", "module-os", "module-arch", "module-id"); + DwarfCUToModule::FileContext fc("dwarf-filename", &m, false); + EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return()); + MockLineToModuleHandler lr; + EXPECT_CALL(lr, ReadProgram(_,_,_,_)).Times(0); + + // Kludge: satisfy reporter_'s expectation. + reporter_.SetCUName("compilation-unit-name"); + + // First CU. Declares class_A. + { + DwarfCUToModule root1_handler(&fc, &lr, &reporter_); + ASSERT_TRUE(root1_handler.StartCompilationUnit(0, 1, 2, 3, 3)); + ASSERT_TRUE(root1_handler.StartRootDIE(1, + dwarf2reader::DW_TAG_compile_unit)); + ProcessStrangeAttributes(&root1_handler); + ASSERT_TRUE(root1_handler.EndAttributes()); + DeclarationDIE(&root1_handler, 0xb8fbfdd5f0b26fceULL, + dwarf2reader::DW_TAG_class_type, "class_A", ""); + root1_handler.Finish(); + } + + // Second CU. Defines class_A, declares member_func_B. + { + DwarfCUToModule root2_handler(&fc, &lr, &reporter_); + ASSERT_TRUE(root2_handler.StartCompilationUnit(0, 1, 2, 3, 3)); + ASSERT_TRUE(root2_handler.StartRootDIE(1, + dwarf2reader::DW_TAG_compile_unit)); + ASSERT_TRUE(root2_handler.EndAttributes()); + EXPECT_CALL(reporter_, UnhandledInterCUReference(_, _)).Times(1); + DIEHandler *class_A_handler + = StartSpecifiedDIE(&root2_handler, dwarf2reader::DW_TAG_class_type, + 0xb8fbfdd5f0b26fceULL); + DeclarationDIE(class_A_handler, 0xb01fef8b380bd1a2ULL, + dwarf2reader::DW_TAG_subprogram, "member_func_B", ""); + class_A_handler->Finish(); + delete class_A_handler; + root2_handler.Finish(); + } + + // Third CU. Defines member_func_B. + { + DwarfCUToModule root3_handler(&fc, &lr, &reporter_); + ASSERT_TRUE(root3_handler.StartCompilationUnit(0, 1, 2, 3, 3)); + ASSERT_TRUE(root3_handler.StartRootDIE(1, + dwarf2reader::DW_TAG_compile_unit)); + ASSERT_TRUE(root3_handler.EndAttributes()); + EXPECT_CALL(reporter_, UnhandledInterCUReference(_, _)).Times(1); + EXPECT_CALL(reporter_, UnnamedFunction(_)).Times(1); + DefinitionDIE(&root3_handler, dwarf2reader::DW_TAG_subprogram, + 0xb01fef8b380bd1a2ULL, "", + 0x2618f00a1a711e53ULL, 0x4fd94b76d7c2caf5ULL); + root3_handler.Finish(); + } +} + TEST_F(Specifications, BadOffset) { PushLine(0xa0277efd7ce83771ULL, 0x149554a184c730c1ULL, "line-file", 56636272); EXPECT_CALL(reporter_, UnknownSpecification(_, 0x2be953efa6f9a996ULL)) @@ -1554,8 +1613,9 @@ TEST_F(Specifications, PreferSpecificationParents) { StartCU(); { - dwarf2reader::DIEHandler *declaration_class_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, "declaration-class"); + dwarf2reader::DIEHandler *declaration_class_handler = + StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, + "declaration-class"); DeclarationDIE(declaration_class_handler, 0x9ddb35517455ef7aULL, dwarf2reader::DW_TAG_subprogram, "function-declaration", ""); @@ -1603,7 +1663,7 @@ TEST_F(CUErrors, NoLineSection) { EXPECT_CALL(reporter_, MissingSection(".debug_line")).Times(1); PushLine(0x88507fb678052611ULL, 0x42c8e9de6bbaa0faULL, "line-file", 64472290); // Delete the entry for .debug_line added by the fixture class's constructor. - file_context_.section_map.clear(); + file_context_.ClearSectionMapForTest(); StartCU(); root_handler_.Finish(); @@ -1667,7 +1727,7 @@ struct Reporter: public Test { line.file = &file; line.number = 93400201; } - + DwarfCUToModule::WarningReporter reporter; Module::Function function; Module::File file; @@ -1714,7 +1774,7 @@ TEST_F(Reporter, UncoveredLineEnabled) { TEST_F(Reporter, UnnamedFunction) { reporter.UnnamedFunction(0x90c0baff9dedb2d9ULL); -} +} // Would be nice to also test: // - overlapping lines, functions -- cgit v1.2.1