michael@0: // -*- mode: c++ -*- michael@0: michael@0: // Copyright (c) 2010 Google Inc. All Rights Reserved. michael@0: // michael@0: // Redistribution and use in source and binary forms, with or without michael@0: // modification, are permitted provided that the following conditions are michael@0: // met: michael@0: // michael@0: // * Redistributions of source code must retain the above copyright michael@0: // notice, this list of conditions and the following disclaimer. michael@0: // * Redistributions in binary form must reproduce the above michael@0: // copyright notice, this list of conditions and the following disclaimer michael@0: // in the documentation and/or other materials provided with the michael@0: // distribution. michael@0: // * Neither the name of Google Inc. nor the names of its michael@0: // contributors may be used to endorse or promote products derived from michael@0: // this software without specific prior written permission. michael@0: // michael@0: // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR michael@0: // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT michael@0: // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, michael@0: // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT michael@0: // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, michael@0: // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY michael@0: // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE michael@0: // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: michael@0: // Original author: Jim Blandy michael@0: michael@0: // dwarf2diehander_unittest.cc: Unit tests for google_breakpad::DIEDispatcher. michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include "breakpad_googletest_includes.h" michael@0: michael@0: #include "common/dwarf/dwarf2diehandler.h" michael@0: #include "common/using_std_string.h" michael@0: michael@0: using std::make_pair; michael@0: michael@0: using ::testing::_; michael@0: using ::testing::ContainerEq; michael@0: using ::testing::ElementsAreArray; michael@0: using ::testing::Eq; michael@0: using ::testing::InSequence; michael@0: using ::testing::Return; michael@0: using ::testing::Sequence; michael@0: using ::testing::StrEq; michael@0: michael@0: using dwarf2reader::DIEDispatcher; michael@0: using dwarf2reader::DIEHandler; michael@0: using dwarf2reader::DwarfAttribute; michael@0: using dwarf2reader::DwarfForm; michael@0: using dwarf2reader::DwarfTag; michael@0: using dwarf2reader::RootDIEHandler; michael@0: michael@0: class MockDIEHandler: public DIEHandler { michael@0: public: michael@0: MOCK_METHOD3(ProcessAttributeUnsigned, michael@0: void(DwarfAttribute, DwarfForm, uint64)); michael@0: MOCK_METHOD3(ProcessAttributeSigned, michael@0: void(DwarfAttribute, DwarfForm, int64)); michael@0: MOCK_METHOD3(ProcessAttributeReference, michael@0: void(DwarfAttribute, DwarfForm, uint64)); michael@0: MOCK_METHOD4(ProcessAttributeBuffer, michael@0: void(DwarfAttribute, DwarfForm, const char *, uint64)); michael@0: MOCK_METHOD3(ProcessAttributeString, michael@0: void(DwarfAttribute, DwarfForm, const string &)); michael@0: MOCK_METHOD3(ProcessAttributeSignature, michael@0: void(DwarfAttribute, DwarfForm, uint64)); michael@0: MOCK_METHOD0(EndAttributes, bool()); michael@0: MOCK_METHOD2(FindChildHandler, DIEHandler *(uint64, DwarfTag)); michael@0: MOCK_METHOD0(Finish, void()); michael@0: }; michael@0: michael@0: class MockRootDIEHandler: public RootDIEHandler { michael@0: public: michael@0: MOCK_METHOD3(ProcessAttributeUnsigned, michael@0: void(DwarfAttribute, DwarfForm, uint64)); michael@0: MOCK_METHOD3(ProcessAttributeSigned, michael@0: void(DwarfAttribute, DwarfForm, int64)); michael@0: MOCK_METHOD3(ProcessAttributeReference, michael@0: void(DwarfAttribute, DwarfForm, uint64)); michael@0: MOCK_METHOD4(ProcessAttributeBuffer, michael@0: void(DwarfAttribute, DwarfForm, const char *, uint64)); michael@0: MOCK_METHOD3(ProcessAttributeString, michael@0: void(DwarfAttribute, DwarfForm, const string &)); michael@0: MOCK_METHOD3(ProcessAttributeSignature, michael@0: void(DwarfAttribute, DwarfForm, uint64)); michael@0: MOCK_METHOD0(EndAttributes, bool()); michael@0: MOCK_METHOD2(FindChildHandler, DIEHandler *(uint64, DwarfTag)); michael@0: MOCK_METHOD0(Finish, void()); michael@0: MOCK_METHOD5(StartCompilationUnit, bool(uint64, uint8, uint8, uint64, uint8)); michael@0: MOCK_METHOD2(StartRootDIE, bool(uint64, DwarfTag)); michael@0: }; michael@0: michael@0: // If the handler elects to skip the compilation unit, the dispatcher michael@0: // should tell the reader so. michael@0: TEST(Dwarf2DIEHandler, SkipCompilationUnit) { michael@0: Sequence s; michael@0: MockRootDIEHandler mock_root_handler; michael@0: DIEDispatcher die_dispatcher(&mock_root_handler); michael@0: michael@0: EXPECT_CALL(mock_root_handler, michael@0: StartCompilationUnit(0x8d42aed77cfccf3eLL, michael@0: 0x89, 0xdc, michael@0: 0x2ecb4dc778a80f21LL, michael@0: 0x66)) michael@0: .InSequence(s) michael@0: .WillOnce(Return(false)); michael@0: michael@0: EXPECT_FALSE(die_dispatcher.StartCompilationUnit(0x8d42aed77cfccf3eLL, michael@0: 0x89, 0xdc, michael@0: 0x2ecb4dc778a80f21LL, michael@0: 0x66)); michael@0: } michael@0: michael@0: // If the handler elects to skip the root DIE, the dispatcher should michael@0: // tell the reader so. michael@0: TEST(Dwarf2DIEHandler, SkipRootDIE) { michael@0: Sequence s; michael@0: MockRootDIEHandler mock_root_handler; michael@0: DIEDispatcher die_dispatcher(&mock_root_handler); michael@0: michael@0: EXPECT_CALL(mock_root_handler, michael@0: StartCompilationUnit(0xde8994029fc8b999LL, 0xf4, 0x02, michael@0: 0xb00febffa76e2b2bLL, 0x5c)) michael@0: .InSequence(s) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_root_handler, michael@0: StartRootDIE(0x7d08242b4b510cf2LL, (DwarfTag) 0xb4f98da6)) michael@0: .InSequence(s) michael@0: .WillOnce(Return(false)); michael@0: michael@0: EXPECT_TRUE(die_dispatcher.StartCompilationUnit(0xde8994029fc8b999LL, michael@0: 0xf4, 0x02, michael@0: 0xb00febffa76e2b2bLL, 0x5c)); michael@0: EXPECT_FALSE(die_dispatcher.StartDIE(0x7d08242b4b510cf2LL, michael@0: (DwarfTag) 0xb4f98da6)); michael@0: die_dispatcher.EndDIE(0x7d08242b4b510cf2LL); michael@0: } michael@0: michael@0: // If the handler elects to skip the root DIE's children, the michael@0: // dispatcher should tell the reader so --- and avoid deleting the michael@0: // root handler. michael@0: TEST(Dwarf2DIEHandler, SkipRootDIEChildren) { michael@0: MockRootDIEHandler mock_root_handler; michael@0: DIEDispatcher die_dispatcher(&mock_root_handler); michael@0: michael@0: { michael@0: InSequence s; michael@0: michael@0: EXPECT_CALL(mock_root_handler, michael@0: StartCompilationUnit(0x15d6897480cc65a7LL, 0x26, 0xa0, michael@0: 0x09f8bf0767f91675LL, 0xdb)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_root_handler, michael@0: StartRootDIE(0x7d08242b4b510cf2LL, (DwarfTag) 0xb4f98da6)) michael@0: .WillOnce(Return(true)); michael@0: // Please don't tell me about my children. michael@0: EXPECT_CALL(mock_root_handler, EndAttributes()) michael@0: .WillOnce(Return(false)); michael@0: EXPECT_CALL(mock_root_handler, Finish()) michael@0: .WillOnce(Return()); michael@0: } michael@0: michael@0: EXPECT_TRUE(die_dispatcher.StartCompilationUnit(0x15d6897480cc65a7LL, michael@0: 0x26, 0xa0, michael@0: 0x09f8bf0767f91675LL, 0xdb)); michael@0: EXPECT_TRUE(die_dispatcher.StartDIE(0x7d08242b4b510cf2LL, michael@0: (DwarfTag) 0xb4f98da6)); michael@0: EXPECT_FALSE(die_dispatcher.StartDIE(0x435150ceedccda18LL, michael@0: (DwarfTag) 0xc3a17bba)); michael@0: die_dispatcher.EndDIE(0x435150ceedccda18LL); michael@0: die_dispatcher.EndDIE(0x7d08242b4b510cf2LL); michael@0: } michael@0: michael@0: // The dispatcher should pass attribute values through to the die michael@0: // handler accurately. michael@0: TEST(Dwarf2DIEHandler, PassAttributeValues) { michael@0: MockRootDIEHandler mock_root_handler; michael@0: DIEDispatcher die_dispatcher(&mock_root_handler); michael@0: michael@0: const char buffer[10] = { 0x24, 0x24, 0x35, 0x9a, 0xca, michael@0: 0xcf, 0xa8, 0x84, 0xa7, 0x18 }; michael@0: string str = "\xc8\x26\x2e\x0d\xa4\x9c\x37\xd6\xfb\x1d"; michael@0: michael@0: // Set expectations. michael@0: { michael@0: InSequence s; michael@0: michael@0: // We'll like the compilation unit header. michael@0: EXPECT_CALL(mock_root_handler, michael@0: StartCompilationUnit(0x8d42aed77cfccf3eLL, 0x89, 0xdc, michael@0: 0x2ecb4dc778a80f21LL, 0x66)) michael@0: .WillOnce(Return(true)); michael@0: michael@0: // We'll like the root DIE. michael@0: EXPECT_CALL(mock_root_handler, michael@0: StartRootDIE(0xe2222da01e29f2a9LL, (DwarfTag) 0x9829445c)) michael@0: .WillOnce(Return(true)); michael@0: michael@0: // Expect some attribute values. michael@0: EXPECT_CALL(mock_root_handler, michael@0: ProcessAttributeUnsigned((DwarfAttribute) 0x1cc0bfed, michael@0: (DwarfForm) 0x424f1468, michael@0: 0xa592571997facda1ULL)) michael@0: .WillOnce(Return()); michael@0: EXPECT_CALL(mock_root_handler, michael@0: ProcessAttributeSigned((DwarfAttribute) 0x43694dc9, michael@0: (DwarfForm) 0xf6f78901L, michael@0: 0x92602a4e3bf1f446LL)) michael@0: .WillOnce(Return()); michael@0: EXPECT_CALL(mock_root_handler, michael@0: ProcessAttributeReference((DwarfAttribute) 0x4033e8cL, michael@0: (DwarfForm) 0xf66fbe0bL, michael@0: 0x50fddef44734fdecULL)) michael@0: .WillOnce(Return()); michael@0: EXPECT_CALL(mock_root_handler, michael@0: ProcessAttributeBuffer((DwarfAttribute) 0x25d7e0af, michael@0: (DwarfForm) 0xe99a539a, michael@0: buffer, sizeof(buffer))) michael@0: .WillOnce(Return()); michael@0: EXPECT_CALL(mock_root_handler, michael@0: ProcessAttributeString((DwarfAttribute) 0x310ed065, michael@0: (DwarfForm) 0x15762fec, michael@0: StrEq(str))) michael@0: .WillOnce(Return()); michael@0: EXPECT_CALL(mock_root_handler, michael@0: ProcessAttributeSignature((DwarfAttribute) 0x58790d72, michael@0: (DwarfForm) 0x4159f138, michael@0: 0x94682463613e6a5fULL)) michael@0: .WillOnce(Return()); michael@0: EXPECT_CALL(mock_root_handler, EndAttributes()) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_root_handler, FindChildHandler(_, _)) michael@0: .Times(0); michael@0: EXPECT_CALL(mock_root_handler, Finish()) michael@0: .WillOnce(Return()); michael@0: } michael@0: michael@0: // Drive the dispatcher. michael@0: michael@0: // Report the CU header. michael@0: EXPECT_TRUE(die_dispatcher.StartCompilationUnit(0x8d42aed77cfccf3eLL, michael@0: 0x89, 0xdc, michael@0: 0x2ecb4dc778a80f21LL, michael@0: 0x66)); michael@0: // Report the root DIE. michael@0: EXPECT_TRUE(die_dispatcher.StartDIE(0xe2222da01e29f2a9LL, michael@0: (DwarfTag) 0x9829445c)); michael@0: michael@0: // Report some attribute values. michael@0: die_dispatcher.ProcessAttributeUnsigned(0xe2222da01e29f2a9LL, michael@0: (DwarfAttribute) 0x1cc0bfed, michael@0: (DwarfForm) 0x424f1468, michael@0: 0xa592571997facda1ULL); michael@0: die_dispatcher.ProcessAttributeSigned(0xe2222da01e29f2a9LL, michael@0: (DwarfAttribute) 0x43694dc9, michael@0: (DwarfForm) 0xf6f78901, michael@0: 0x92602a4e3bf1f446LL); michael@0: die_dispatcher.ProcessAttributeReference(0xe2222da01e29f2a9LL, michael@0: (DwarfAttribute) 0x4033e8c, michael@0: (DwarfForm) 0xf66fbe0b, michael@0: 0x50fddef44734fdecULL); michael@0: die_dispatcher.ProcessAttributeBuffer(0xe2222da01e29f2a9LL, michael@0: (DwarfAttribute) 0x25d7e0af, michael@0: (DwarfForm) 0xe99a539a, michael@0: buffer, sizeof(buffer)); michael@0: die_dispatcher.ProcessAttributeString(0xe2222da01e29f2a9LL, michael@0: (DwarfAttribute) 0x310ed065, michael@0: (DwarfForm) 0x15762fec, michael@0: str); michael@0: die_dispatcher.ProcessAttributeSignature(0xe2222da01e29f2a9LL, michael@0: (DwarfAttribute) 0x58790d72, michael@0: (DwarfForm) 0x4159f138, michael@0: 0x94682463613e6a5fULL); michael@0: michael@0: // Finish the root DIE (and thus the CU). michael@0: die_dispatcher.EndDIE(0xe2222da01e29f2a9LL); michael@0: } michael@0: michael@0: TEST(Dwarf2DIEHandler, FindAndSkipChildren) { michael@0: MockRootDIEHandler mock_root_handler; michael@0: MockDIEHandler *mock_child1_handler = new(MockDIEHandler); michael@0: MockDIEHandler *mock_child3_handler = new(MockDIEHandler); michael@0: DIEDispatcher die_dispatcher(&mock_root_handler); michael@0: michael@0: { michael@0: InSequence s; michael@0: michael@0: // We'll like the compilation unit header. michael@0: EXPECT_CALL(mock_root_handler, michael@0: StartCompilationUnit(0x9ec1e6d05e434a0eLL, 0xeb, 0x21, michael@0: 0x47dd3c764275a216LL, 0xa5)) michael@0: .WillOnce(Return(true)); michael@0: michael@0: // Root DIE. michael@0: { michael@0: EXPECT_CALL(mock_root_handler, michael@0: StartRootDIE(0x15f0e06bdfe3c372LL, (DwarfTag) 0xf5d60c59)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_root_handler, michael@0: ProcessAttributeSigned((DwarfAttribute) 0xf779a642, michael@0: (DwarfForm) 0x2cb63027, michael@0: 0x18e744661769d08fLL)) michael@0: .WillOnce(Return()); michael@0: EXPECT_CALL(mock_root_handler, EndAttributes()) michael@0: .WillOnce(Return(true)); michael@0: michael@0: // First child DIE. michael@0: EXPECT_CALL(mock_root_handler, michael@0: FindChildHandler(0x149f644f8116fe8cLL, michael@0: (DwarfTag) 0xac2cbd8c)) michael@0: .WillOnce(Return(mock_child1_handler)); michael@0: { michael@0: EXPECT_CALL(*mock_child1_handler, michael@0: ProcessAttributeSigned((DwarfAttribute) 0xa6fd6f65, michael@0: (DwarfForm) 0xe4f64c41, michael@0: 0x1b04e5444a55fe67LL)) michael@0: .WillOnce(Return()); michael@0: EXPECT_CALL(*mock_child1_handler, EndAttributes()) michael@0: .WillOnce(Return(false)); michael@0: // Skip first grandchild DIE and first great-grandchild DIE. michael@0: EXPECT_CALL(*mock_child1_handler, Finish()) michael@0: .WillOnce(Return()); michael@0: } michael@0: michael@0: // Second child DIE. Root handler will decline to return a handler michael@0: // for this child. michael@0: EXPECT_CALL(mock_root_handler, michael@0: FindChildHandler(0x97412be24875de9dLL, michael@0: (DwarfTag) 0x505a068b)) michael@0: .WillOnce(Return((DIEHandler *) NULL)); michael@0: michael@0: // Third child DIE. michael@0: EXPECT_CALL(mock_root_handler, michael@0: FindChildHandler(0x753c964c8ab538aeLL, michael@0: (DwarfTag) 0x8c22970e)) michael@0: .WillOnce(Return(mock_child3_handler)); michael@0: { michael@0: EXPECT_CALL(*mock_child3_handler, michael@0: ProcessAttributeSigned((DwarfAttribute) 0x4e2b7cfb, michael@0: (DwarfForm) 0x610b7ae1, michael@0: 0x3ea5c609d7d7560fLL)) michael@0: .WillOnce(Return()); michael@0: EXPECT_CALL(*mock_child3_handler, EndAttributes()) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(*mock_child3_handler, Finish()) michael@0: .WillOnce(Return()); michael@0: } michael@0: michael@0: EXPECT_CALL(mock_root_handler, Finish()) michael@0: .WillOnce(Return()); michael@0: } michael@0: } michael@0: michael@0: michael@0: // Drive the dispatcher. michael@0: michael@0: // Report the CU header. michael@0: EXPECT_TRUE(die_dispatcher michael@0: .StartCompilationUnit(0x9ec1e6d05e434a0eLL, 0xeb, 0x21, michael@0: 0x47dd3c764275a216LL, 0xa5)); michael@0: // Report the root DIE. michael@0: { michael@0: EXPECT_TRUE(die_dispatcher.StartDIE(0x15f0e06bdfe3c372LL, michael@0: (DwarfTag) 0xf5d60c59)); michael@0: die_dispatcher.ProcessAttributeSigned(0x15f0e06bdfe3c372LL, michael@0: (DwarfAttribute) 0xf779a642, michael@0: (DwarfForm) 0x2cb63027, michael@0: 0x18e744661769d08fLL); michael@0: michael@0: // First child DIE. michael@0: { michael@0: EXPECT_TRUE(die_dispatcher.StartDIE(0x149f644f8116fe8cLL, michael@0: (DwarfTag) 0xac2cbd8c)); michael@0: die_dispatcher.ProcessAttributeSigned(0x149f644f8116fe8cLL, michael@0: (DwarfAttribute) 0xa6fd6f65, michael@0: (DwarfForm) 0xe4f64c41, michael@0: 0x1b04e5444a55fe67LL); michael@0: michael@0: // First grandchild DIE. Will be skipped. michael@0: { michael@0: EXPECT_FALSE(die_dispatcher.StartDIE(0xd68de1ee0bd29419LL, michael@0: (DwarfTag) 0x22f05a15)); michael@0: // First great-grandchild DIE. Will be skipped without being michael@0: // mentioned to any handler. michael@0: { michael@0: EXPECT_FALSE(die_dispatcher michael@0: .StartDIE(0xb3076285d25cac25LL, michael@0: (DwarfTag) 0xcff4061b)); michael@0: die_dispatcher.EndDIE(0xb3076285d25cac25LL); michael@0: } michael@0: die_dispatcher.EndDIE(0xd68de1ee0bd29419LL); michael@0: } michael@0: die_dispatcher.EndDIE(0x149f644f8116fe8cLL); michael@0: } michael@0: michael@0: // Second child DIE. Root handler will decline to find a handler for it. michael@0: { michael@0: EXPECT_FALSE(die_dispatcher.StartDIE(0x97412be24875de9dLL, michael@0: (DwarfTag) 0x505a068b)); michael@0: die_dispatcher.EndDIE(0x97412be24875de9dLL); michael@0: } michael@0: michael@0: // Third child DIE. michael@0: { michael@0: EXPECT_TRUE(die_dispatcher.StartDIE(0x753c964c8ab538aeLL, michael@0: (DwarfTag) 0x8c22970e)); michael@0: die_dispatcher.ProcessAttributeSigned(0x753c964c8ab538aeLL, michael@0: (DwarfAttribute) 0x4e2b7cfb, michael@0: (DwarfForm) 0x610b7ae1, michael@0: 0x3ea5c609d7d7560fLL); michael@0: die_dispatcher.EndDIE(0x753c964c8ab538aeLL); michael@0: } michael@0: michael@0: // Finish the root DIE (and thus the CU). michael@0: die_dispatcher.EndDIE(0x15f0e06bdfe3c372LL); michael@0: } michael@0: } michael@0: michael@0: // The DIEDispatcher destructor is supposed to delete all handlers on michael@0: // the stack, except for the root. michael@0: TEST(Dwarf2DIEHandler, FreeHandlersOnStack) { michael@0: MockRootDIEHandler mock_root_handler; michael@0: MockDIEHandler *mock_child_handler = new(MockDIEHandler); michael@0: MockDIEHandler *mock_grandchild_handler = new(MockDIEHandler); michael@0: michael@0: { michael@0: InSequence s; michael@0: michael@0: // We'll like the compilation unit header. michael@0: EXPECT_CALL(mock_root_handler, michael@0: StartCompilationUnit(0x87b41ba8381cd71cLL, 0xff, 0x89, michael@0: 0x76d392ff393ddda2LL, 0xbf)) michael@0: .WillOnce(Return(true)); michael@0: michael@0: // Root DIE. michael@0: { michael@0: EXPECT_CALL(mock_root_handler, michael@0: StartRootDIE(0xbf13b761691ddc91LL, (DwarfTag) 0x98980361)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_root_handler, EndAttributes()) michael@0: .WillOnce(Return(true)); michael@0: michael@0: // Child DIE. michael@0: EXPECT_CALL(mock_root_handler, michael@0: FindChildHandler(0x058f09240c5fc8c9LL, michael@0: (DwarfTag) 0x898bf0d0)) michael@0: .WillOnce(Return(mock_child_handler)); michael@0: { michael@0: EXPECT_CALL(*mock_child_handler, EndAttributes()) michael@0: .WillOnce(Return(true)); michael@0: michael@0: // Grandchild DIE. michael@0: EXPECT_CALL(*mock_child_handler, michael@0: FindChildHandler(0x32dc00c9945dc0c8LL, michael@0: (DwarfTag) 0x2802d007)) michael@0: .WillOnce(Return(mock_grandchild_handler)); michael@0: { michael@0: EXPECT_CALL(*mock_grandchild_handler, michael@0: ProcessAttributeSigned((DwarfAttribute) 0x4e2b7cfb, michael@0: (DwarfForm) 0x610b7ae1, michael@0: 0x3ea5c609d7d7560fLL)) michael@0: .WillOnce(Return()); michael@0: michael@0: // At this point, we abandon the traversal, so none of the michael@0: // usual stuff should get called. michael@0: EXPECT_CALL(*mock_grandchild_handler, EndAttributes()) michael@0: .Times(0); michael@0: EXPECT_CALL(*mock_grandchild_handler, Finish()) michael@0: .Times(0); michael@0: } michael@0: michael@0: EXPECT_CALL(*mock_child_handler, Finish()) michael@0: .Times(0); michael@0: } michael@0: michael@0: EXPECT_CALL(mock_root_handler, Finish()) michael@0: .Times(0); michael@0: } michael@0: } michael@0: michael@0: // The dispatcher. michael@0: DIEDispatcher die_dispatcher(&mock_root_handler); michael@0: michael@0: // Report the CU header. michael@0: EXPECT_TRUE(die_dispatcher michael@0: .StartCompilationUnit(0x87b41ba8381cd71cLL, 0xff, 0x89, michael@0: 0x76d392ff393ddda2LL, 0xbf)); michael@0: // Report the root DIE. michael@0: { michael@0: EXPECT_TRUE(die_dispatcher.StartDIE(0xbf13b761691ddc91LL, michael@0: (DwarfTag) 0x98980361)); michael@0: michael@0: // Child DIE. michael@0: { michael@0: EXPECT_TRUE(die_dispatcher.StartDIE(0x058f09240c5fc8c9LL, michael@0: (DwarfTag) 0x898bf0d0)); michael@0: michael@0: // Grandchild DIE. michael@0: { michael@0: EXPECT_TRUE(die_dispatcher.StartDIE(0x32dc00c9945dc0c8LL, michael@0: (DwarfTag) 0x2802d007)); michael@0: die_dispatcher.ProcessAttributeSigned(0x32dc00c9945dc0c8LL, michael@0: (DwarfAttribute) 0x4e2b7cfb, michael@0: (DwarfForm) 0x610b7ae1, michael@0: 0x3ea5c609d7d7560fLL); michael@0: michael@0: // Stop the traversal abruptly, so that there will still be michael@0: // handlers on the stack when the dispatcher is destructed. michael@0: michael@0: // No EndDIE call... michael@0: } michael@0: // No EndDIE call... michael@0: } michael@0: // No EndDIE call... michael@0: } michael@0: }