michael@0: // Copyright (c) 2010 Google Inc. michael@0: // 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: // stabs_reader_unittest.cc: Unit tests for google_breakpad::StabsReader. michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "breakpad_googletest_includes.h" michael@0: #include "common/stabs_reader.h" michael@0: #include "common/test_assembler.h" michael@0: #include "common/using_std_string.h" michael@0: michael@0: using ::testing::Eq; michael@0: using ::testing::InSequence; michael@0: using ::testing::Return; michael@0: using ::testing::StrEq; michael@0: using ::testing::Test; michael@0: using ::testing::_; michael@0: using google_breakpad::StabsHandler; michael@0: using google_breakpad::StabsReader; michael@0: using google_breakpad::test_assembler::Label; michael@0: using google_breakpad::test_assembler::Section; michael@0: using google_breakpad::test_assembler::kBigEndian; michael@0: using google_breakpad::test_assembler::kLittleEndian; michael@0: using std::map; michael@0: michael@0: namespace { michael@0: michael@0: // A StringAssembler is a class for generating .stabstr sections to present michael@0: // as input to the STABS parser. michael@0: class StringAssembler: public Section { michael@0: public: michael@0: StringAssembler() : in_cu_(false) { StartCU(); } michael@0: michael@0: // Add the string S to this StringAssembler, and return the string's michael@0: // offset within this compilation unit's strings. If S has been added michael@0: // already, this returns the offset of its first instance. michael@0: size_t Add(const string &s) { michael@0: map::iterator it = added_.find(s); michael@0: if (it != added_.end()) michael@0: return it->second; michael@0: size_t offset = Size() - cu_start_; michael@0: AppendCString(s); michael@0: added_[s] = offset; michael@0: return offset; michael@0: } michael@0: michael@0: // Start a fresh compilation unit string collection. michael@0: void StartCU() { michael@0: // Ignore duplicate calls to StartCU. Our test data don't always call michael@0: // StartCU at all, meaning that our constructor has to take care of it, michael@0: // meaning that tests that *do* call StartCU call it twice at the michael@0: // beginning. This is not worth smoothing out. michael@0: if (in_cu_) return; michael@0: michael@0: added_.clear(); michael@0: cu_start_ = Size(); michael@0: michael@0: // Each compilation unit's strings start with an empty string. michael@0: AppendCString(""); michael@0: added_[""] = 0; michael@0: michael@0: in_cu_ = true; michael@0: } michael@0: michael@0: // Finish off the current CU's strings. michael@0: size_t EndCU() { michael@0: assert(in_cu_); michael@0: in_cu_ = false; michael@0: return Size() - cu_start_; michael@0: } michael@0: michael@0: private: michael@0: // The offset of the start of this compilation unit's strings. michael@0: size_t cu_start_; michael@0: michael@0: // True if we're in a CU. michael@0: bool in_cu_; michael@0: michael@0: // A map from the strings that have been added to this section to michael@0: // their starting indices within their compilation unit. michael@0: map added_; michael@0: }; michael@0: michael@0: // A StabsAssembler is a class for generating .stab sections to present as michael@0: // test input for the STABS parser. michael@0: class StabsAssembler: public Section { michael@0: public: michael@0: // Create a StabsAssembler that uses StringAssembler for its strings. michael@0: StabsAssembler(StringAssembler *string_assembler) michael@0: : Section(string_assembler->endianness()), michael@0: string_assembler_(string_assembler), michael@0: value_size_(0), michael@0: entry_count_(0), michael@0: cu_header_(NULL) { } michael@0: ~StabsAssembler() { assert(!cu_header_); } michael@0: michael@0: // Accessor and setter for value_size_. michael@0: size_t value_size() const { return value_size_; } michael@0: StabsAssembler &set_value_size(size_t value_size) { michael@0: value_size_ = value_size; michael@0: return *this; michael@0: } michael@0: michael@0: // Append a STAB entry to the end of this section with the given michael@0: // characteristics. NAME is the offset of this entry's name string within michael@0: // its compilation unit's portion of the .stabstr section; this can be a michael@0: // value generated by a StringAssembler. Return a reference to this michael@0: // StabsAssembler. michael@0: StabsAssembler &Stab(uint8_t type, uint8_t other, Label descriptor, michael@0: Label value, Label name) { michael@0: D32(name); michael@0: D8(type); michael@0: D8(other); michael@0: D16(descriptor); michael@0: Append(endianness(), value_size_, value); michael@0: entry_count_++; michael@0: return *this; michael@0: } michael@0: michael@0: // As above, but automatically add NAME to our StringAssembler. michael@0: StabsAssembler &Stab(uint8_t type, uint8_t other, Label descriptor, michael@0: Label value, const string &name) { michael@0: return Stab(type, other, descriptor, value, string_assembler_->Add(name)); michael@0: } michael@0: michael@0: // Start a compilation unit named NAME, with an N_UNDF symbol to start michael@0: // it, and its own portion of the string section. Return a reference to michael@0: // this StabsAssembler. michael@0: StabsAssembler &StartCU(const string &name) { michael@0: assert(!cu_header_); michael@0: cu_header_ = new CUHeader; michael@0: string_assembler_->StartCU(); michael@0: entry_count_ = 0; michael@0: return Stab(N_UNDF, 0, michael@0: cu_header_->final_entry_count, michael@0: cu_header_->final_string_size, michael@0: string_assembler_->Add(name)); michael@0: } michael@0: michael@0: // Close off the current compilation unit. Return a reference to this michael@0: // StabsAssembler. michael@0: StabsAssembler &EndCU() { michael@0: assert(cu_header_); michael@0: cu_header_->final_entry_count = entry_count_; michael@0: cu_header_->final_string_size = string_assembler_->EndCU(); michael@0: delete cu_header_; michael@0: cu_header_ = NULL; michael@0: return *this; michael@0: } michael@0: michael@0: private: michael@0: // Data used in a compilation unit header STAB that we won't know until michael@0: // we've finished the compilation unit. michael@0: struct CUHeader { michael@0: // The final number of entries this compilation unit will hold. michael@0: Label final_entry_count; michael@0: michael@0: // The final size of this compilation unit's strings. michael@0: Label final_string_size; michael@0: }; michael@0: michael@0: // The strings for our STABS entries. michael@0: StringAssembler *string_assembler_; michael@0: michael@0: // The size of the 'value' field of stabs entries in this section. michael@0: size_t value_size_; michael@0: michael@0: // The number of entries in this compilation unit so far. michael@0: size_t entry_count_; michael@0: michael@0: // Header labels for this compilation unit, if we've started one but not michael@0: // finished it. michael@0: CUHeader *cu_header_; michael@0: }; michael@0: michael@0: class MockStabsReaderHandler: public StabsHandler { michael@0: public: michael@0: MOCK_METHOD3(StartCompilationUnit, michael@0: bool(const char *, uint64_t, const char *)); michael@0: MOCK_METHOD1(EndCompilationUnit, bool(uint64_t)); michael@0: MOCK_METHOD2(StartFunction, bool(const string &, uint64_t)); michael@0: MOCK_METHOD1(EndFunction, bool(uint64_t)); michael@0: MOCK_METHOD3(Line, bool(uint64_t, const char *, int)); michael@0: MOCK_METHOD2(Extern, bool(const string &, uint64_t)); michael@0: void Warning(const char *format, ...) { MockWarning(format); } michael@0: MOCK_METHOD1(MockWarning, void(const char *)); michael@0: }; michael@0: michael@0: struct StabsFixture { michael@0: StabsFixture() : stabs(&strings), unitized(true) { } michael@0: michael@0: // Create a StabsReader to parse the mock stabs data in stabs and michael@0: // strings, and pass the parsed information to mock_handler. Use the michael@0: // endianness and value size of stabs to parse the data. If all goes michael@0: // well, return the result of calling the reader's Process member michael@0: // function. Otherwise, return false. michael@0: bool ApplyHandlerToMockStabsData() { michael@0: string stabs_contents, stabstr_contents; michael@0: if (!stabs.GetContents(&stabs_contents) || michael@0: !strings.GetContents(&stabstr_contents)) michael@0: return false; michael@0: michael@0: // Run the parser on the test input, passing whatever we find to HANDLER. michael@0: StabsReader reader( michael@0: reinterpret_cast(stabs_contents.data()), michael@0: stabs_contents.size(), michael@0: reinterpret_cast(stabstr_contents.data()), michael@0: stabstr_contents.size(), michael@0: stabs.endianness() == kBigEndian, stabs.value_size(), unitized, michael@0: &mock_handler); michael@0: return reader.Process(); michael@0: } michael@0: michael@0: StringAssembler strings; michael@0: StabsAssembler stabs; michael@0: bool unitized; michael@0: MockStabsReaderHandler mock_handler; michael@0: }; michael@0: michael@0: class Stabs: public StabsFixture, public Test { }; michael@0: michael@0: TEST_F(Stabs, MockStabsInput) { michael@0: stabs.set_endianness(kLittleEndian); michael@0: stabs.set_value_size(4); michael@0: stabs michael@0: .Stab(N_SO, 149, 40232, 0x18a2a72bU, "builddir/") michael@0: .Stab(N_FUN, 83, 50010, 0x91a5353fU, michael@0: "not the SO with source file name we expected ") michael@0: .Stab(N_SO, 165, 24791, 0xfe69d23cU, "") michael@0: .Stab(N_SO, 184, 34178, 0xca4d883aU, "builddir1/") michael@0: .Stab(N_SO, 83, 40859, 0xd2fe5df3U, "file1.c") michael@0: .Stab(N_LSYM, 147, 39565, 0x60d4bb8aU, "not the FUN we're looking for") michael@0: .Stab(N_FUN, 120, 50271, 0xa049f4b1U, "fun1") michael@0: .Stab(N_BINCL, 150, 15694, 0xef65c659U, michael@0: "something to ignore in a FUN body") michael@0: .Stab(N_SLINE, 147, 4967, 0xd904b3f, "") michael@0: .Stab(N_SOL, 177, 56135, 0xbd97b1dcU, "header.h") michael@0: .Stab(N_SLINE, 130, 24610, 0x90f145b, "") michael@0: .Stab(N_FUN, 45, 32441, 0xbf27cf93U, michael@0: "fun2:some stabs type info here:to trim from the name") michael@0: .Stab(N_SLINE, 138, 39002, 0x8148b87, "") michael@0: .Stab(N_SOL, 60, 49318, 0x1d06e025U, "file1.c") michael@0: .Stab(N_SLINE, 29, 52163, 0x6eebbb7, "") michael@0: .Stab(N_SO, 167, 4647, 0xd04b7448U, "") michael@0: .Stab(N_LSYM, 58, 37837, 0xe6b14d37U, "") michael@0: .Stab(N_SO, 152, 7810, 0x11759f10U, "file3.c") michael@0: .Stab(N_SO, 218, 12447, 0x11cfe4b5U, ""); michael@0: michael@0: { michael@0: InSequence s; michael@0: michael@0: EXPECT_CALL(mock_handler, michael@0: StartCompilationUnit(StrEq("file1.c"), 0xd2fe5df3U, michael@0: StrEq("builddir1/"))) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, StartFunction(StrEq("fun1"), 0xa049f4b1U)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, michael@0: Line(0xa049f4b1U + 0xd904b3f, StrEq("file1.c"), 4967)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, michael@0: Line(0xa049f4b1U + 0x90f145b, StrEq("header.h"), 24610)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, EndFunction(0xbf27cf93U)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, StartFunction(StrEq("fun2"), 0xbf27cf93U)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, michael@0: Line(0xbf27cf93U + 0x8148b87, StrEq("header.h"), 39002)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, michael@0: Line(0xbf27cf93U + 0x6eebbb7, StrEq("file1.c"), 52163)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, EndFunction(0xd04b7448U)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, EndCompilationUnit(0xd04b7448U)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, StartCompilationUnit(StrEq("file3.c"), michael@0: 0x11759f10U, NULL)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, EndCompilationUnit(0x11cfe4b5U)) michael@0: .WillOnce(Return(true)); michael@0: } michael@0: michael@0: ASSERT_TRUE(ApplyHandlerToMockStabsData()); michael@0: } michael@0: michael@0: TEST_F(Stabs, AbruptCU) { michael@0: stabs.set_endianness(kBigEndian); michael@0: stabs.set_value_size(4); michael@0: stabs.Stab(N_SO, 177, 23446, 0xbf10d5e4, "file2-1.c"); michael@0: michael@0: { michael@0: InSequence s; michael@0: michael@0: EXPECT_CALL(mock_handler, michael@0: StartCompilationUnit(StrEq("file2-1.c"), 0xbf10d5e4, NULL)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, EndCompilationUnit(0)) michael@0: .WillOnce(Return(true)); michael@0: } michael@0: michael@0: ASSERT_TRUE(ApplyHandlerToMockStabsData()); michael@0: } michael@0: michael@0: TEST_F(Stabs, AbruptFunction) { michael@0: stabs.set_endianness(kLittleEndian); michael@0: stabs.set_value_size(8); michael@0: stabs michael@0: .Stab(N_SO, 218, 26631, 0xb83ddf10U, "file3-1.c") michael@0: .Stab(N_FUN, 113, 24765, 0xbbd4a145U, "fun3_1"); michael@0: michael@0: { michael@0: InSequence s; michael@0: michael@0: EXPECT_CALL(mock_handler, michael@0: StartCompilationUnit(StrEq("file3-1.c"), 0xb83ddf10U, NULL)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, StartFunction(StrEq("fun3_1"), 0xbbd4a145U)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, EndFunction(0)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, EndCompilationUnit(0)) michael@0: .WillOnce(Return(true)); michael@0: } michael@0: michael@0: ASSERT_TRUE(ApplyHandlerToMockStabsData()); michael@0: } michael@0: michael@0: TEST_F(Stabs, NoCU) { michael@0: stabs.set_endianness(kBigEndian); michael@0: stabs.set_value_size(8); michael@0: stabs.Stab(N_SO, 161, 25673, 0x8f676e7bU, "build-directory/"); michael@0: michael@0: EXPECT_CALL(mock_handler, StartCompilationUnit(_, _, _)) michael@0: .Times(0); michael@0: EXPECT_CALL(mock_handler, StartFunction(_, _)) michael@0: .Times(0); michael@0: michael@0: ASSERT_TRUE(ApplyHandlerToMockStabsData()); michael@0: } michael@0: michael@0: TEST_F(Stabs, NoCUEnd) { michael@0: stabs.set_endianness(kBigEndian); michael@0: stabs.set_value_size(8); michael@0: stabs michael@0: .Stab(N_SO, 116, 58280, 0x2f7493c9U, "file5-1.c") michael@0: .Stab(N_SO, 224, 23057, 0xf9f1d50fU, "file5-2.c"); michael@0: michael@0: { michael@0: InSequence s; michael@0: michael@0: EXPECT_CALL(mock_handler, michael@0: StartCompilationUnit(StrEq("file5-1.c"), 0x2f7493c9U, NULL)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, EndCompilationUnit(0)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, michael@0: StartCompilationUnit(StrEq("file5-2.c"), 0xf9f1d50fU, NULL)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, EndCompilationUnit(0)) michael@0: .WillOnce(Return(true)); michael@0: } michael@0: michael@0: ASSERT_TRUE(ApplyHandlerToMockStabsData()); michael@0: } michael@0: michael@0: // On systems that store STABS in sections, string offsets are relative to michael@0: // the beginning of that compilation unit's strings, marked with N_UNDF michael@0: // symbols; see the comments for StabsReader::StabsReader. michael@0: TEST_F(Stabs, Unitized) { michael@0: stabs.set_endianness(kBigEndian); michael@0: stabs.set_value_size(4); michael@0: stabs michael@0: .StartCU("antimony") michael@0: .Stab(N_SO, 49, 26043, 0x7e259f1aU, "antimony") michael@0: .Stab(N_FUN, 101, 63253, 0x7fbcccaeU, "arsenic") michael@0: .Stab(N_SO, 124, 37175, 0x80b0014cU, "") michael@0: .EndCU() michael@0: .StartCU("aluminum") michael@0: .Stab(N_SO, 72, 23084, 0x86756839U, "aluminum") michael@0: .Stab(N_FUN, 59, 3305, 0xa8e120b0U, "selenium") michael@0: .Stab(N_SO, 178, 56949, 0xbffff983U, "") michael@0: .EndCU(); michael@0: michael@0: { michael@0: InSequence s; michael@0: EXPECT_CALL(mock_handler, michael@0: StartCompilationUnit(StrEq("antimony"), 0x7e259f1aU, NULL)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, StartFunction(Eq("arsenic"), 0x7fbcccaeU)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, EndFunction(0x80b0014cU)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, EndCompilationUnit(0x80b0014cU)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, michael@0: StartCompilationUnit(StrEq("aluminum"), 0x86756839U, NULL)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, StartFunction(Eq("selenium"), 0xa8e120b0U)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, EndFunction(0xbffff983U)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, EndCompilationUnit(0xbffff983U)) michael@0: .WillOnce(Return(true)); michael@0: } michael@0: michael@0: ASSERT_TRUE(ApplyHandlerToMockStabsData()); michael@0: } michael@0: michael@0: // On systems that store STABS entries in the real symbol table, the N_UNDF michael@0: // entries have no special meaning, and shouldn't mess up the string michael@0: // indices. michael@0: TEST_F(Stabs, NonUnitized) { michael@0: stabs.set_endianness(kLittleEndian); michael@0: stabs.set_value_size(4); michael@0: unitized = false; michael@0: stabs michael@0: .Stab(N_UNDF, 21, 11551, 0x9bad2b2e, "") michael@0: .Stab(N_UNDF, 21, 11551, 0x9bad2b2e, "") michael@0: .Stab(N_SO, 71, 45139, 0x11a97352, "Tanzania") michael@0: .Stab(N_SO, 221, 41976, 0x21a97352, ""); michael@0: michael@0: { michael@0: InSequence s; michael@0: EXPECT_CALL(mock_handler, michael@0: StartCompilationUnit(StrEq("Tanzania"), michael@0: 0x11a97352, NULL)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, EndCompilationUnit(0x21a97352)) michael@0: .WillOnce(Return(true)); michael@0: } michael@0: michael@0: ASSERT_TRUE(ApplyHandlerToMockStabsData()); michael@0: } michael@0: michael@0: TEST_F(Stabs, FunctionEnd) { michael@0: stabs.set_endianness(kLittleEndian); michael@0: stabs.set_value_size(8); michael@0: stabs michael@0: .Stab(N_SO, 102, 62362, 0x52a830d644cd6942ULL, "compilation unit") michael@0: // This function is terminated by the start of the next function. michael@0: .Stab(N_FUN, 216, 38405, 0xbb5ab70ecdd23bfeULL, "function 1") michael@0: // This function is terminated by an explicit end-of-function stab, michael@0: // whose value is a size in bytes. michael@0: .Stab(N_FUN, 240, 10973, 0xc954de9b8fb3e5e2ULL, "function 2") michael@0: .Stab(N_FUN, 14, 36749, 0xc1ab, "") michael@0: // This function is terminated by the end of the compilation unit. michael@0: .Stab(N_FUN, 143, 64514, 0xdff98c9a35386e1fULL, "function 3") michael@0: .Stab(N_SO, 164, 60142, 0xfdacb856e78bbf57ULL, ""); michael@0: michael@0: { michael@0: InSequence s; michael@0: EXPECT_CALL(mock_handler, michael@0: StartCompilationUnit(StrEq("compilation unit"), michael@0: 0x52a830d644cd6942ULL, NULL)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, michael@0: StartFunction(Eq("function 1"), 0xbb5ab70ecdd23bfeULL)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, EndFunction(0xc954de9b8fb3e5e2ULL)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, michael@0: StartFunction(Eq("function 2"), 0xc954de9b8fb3e5e2ULL)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, EndFunction(0xc954de9b8fb3e5e2ULL + 0xc1ab)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, michael@0: StartFunction(Eq("function 3"), 0xdff98c9a35386e1fULL)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, EndFunction(0xfdacb856e78bbf57ULL)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, EndCompilationUnit(0xfdacb856e78bbf57ULL)) michael@0: .WillOnce(Return(true)); michael@0: } michael@0: michael@0: ASSERT_TRUE(ApplyHandlerToMockStabsData()); michael@0: } michael@0: michael@0: // On Mac OS X, SLINE records can appear before the FUN stab to which they michael@0: // belong, and their values are absolute addresses, not offsets. michael@0: TEST_F(Stabs, LeadingLine) { michael@0: stabs.set_endianness(kBigEndian); michael@0: stabs.set_value_size(4); michael@0: stabs michael@0: .Stab(N_SO, 179, 27357, 0x8adabc15, "build directory/") michael@0: .Stab(N_SO, 52, 53058, 0x4c7e3bf4, "compilation unit") michael@0: .Stab(N_SOL, 165, 12086, 0x6a797ca3, "source file name") michael@0: .Stab(N_SLINE, 229, 20015, 0x4cb3d7e0, "") michael@0: .Stab(N_SLINE, 89, 43802, 0x4cba8b88, "") michael@0: .Stab(N_FUN, 251, 51639, 0xce1b98fa, "rutabaga") michael@0: .Stab(N_FUN, 218, 16113, 0x5798, "") michael@0: .Stab(N_SO, 52, 53058, 0xd4af4415, ""); michael@0: michael@0: { michael@0: InSequence s; michael@0: EXPECT_CALL(mock_handler, michael@0: StartCompilationUnit(StrEq("compilation unit"), michael@0: 0x4c7e3bf4, StrEq("build directory/"))) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, michael@0: StartFunction(Eq("rutabaga"), 0xce1b98fa)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, michael@0: Line(0x4cb3d7e0, StrEq("source file name"), 20015)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, michael@0: Line(0x4cba8b88, StrEq("source file name"), 43802)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, EndFunction(0xce1b98fa + 0x5798)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, EndCompilationUnit(0xd4af4415)) michael@0: .WillOnce(Return(true)); michael@0: } michael@0: michael@0: ASSERT_TRUE(ApplyHandlerToMockStabsData()); michael@0: } michael@0: michael@0: michael@0: #if defined(HAVE_MACH_O_NLIST_H) michael@0: // These tests have no meaning on non-Mach-O-based systems, as michael@0: // only Mach-O uses N_SECT to represent public symbols. michael@0: TEST_F(Stabs, OnePublicSymbol) { michael@0: stabs.set_endianness(kLittleEndian); michael@0: stabs.set_value_size(4); michael@0: michael@0: const uint32_t kExpectedAddress = 0x9000; michael@0: const string kExpectedFunctionName("public_function"); michael@0: stabs michael@0: .Stab(N_SECT, 1, 0, kExpectedAddress, kExpectedFunctionName); michael@0: michael@0: { michael@0: InSequence s; michael@0: EXPECT_CALL(mock_handler, michael@0: Extern(StrEq(kExpectedFunctionName), michael@0: kExpectedAddress)) michael@0: .WillOnce(Return(true)); michael@0: } michael@0: ASSERT_TRUE(ApplyHandlerToMockStabsData()); michael@0: } michael@0: michael@0: TEST_F(Stabs, TwoPublicSymbols) { michael@0: stabs.set_endianness(kLittleEndian); michael@0: stabs.set_value_size(4); michael@0: michael@0: const uint32_t kExpectedAddress1 = 0xB0B0B0B0; michael@0: const string kExpectedFunctionName1("public_function"); michael@0: const uint32_t kExpectedAddress2 = 0xF0F0F0F0; michael@0: const string kExpectedFunctionName2("something else"); michael@0: stabs michael@0: .Stab(N_SECT, 1, 0, kExpectedAddress1, kExpectedFunctionName1) michael@0: .Stab(N_SECT, 1, 0, kExpectedAddress2, kExpectedFunctionName2); michael@0: michael@0: { michael@0: InSequence s; michael@0: EXPECT_CALL(mock_handler, michael@0: Extern(StrEq(kExpectedFunctionName1), michael@0: kExpectedAddress1)) michael@0: .WillOnce(Return(true)); michael@0: EXPECT_CALL(mock_handler, michael@0: Extern(StrEq(kExpectedFunctionName2), michael@0: kExpectedAddress2)) michael@0: .WillOnce(Return(true)); michael@0: } michael@0: ASSERT_TRUE(ApplyHandlerToMockStabsData()); michael@0: } michael@0: michael@0: #endif michael@0: michael@0: } // anonymous namespace