| // Copyright (c) 2010 Google Inc. |
| // All rights reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above |
| // copyright notice, this list of conditions and the following disclaimer |
| // in the documentation and/or other materials provided with the |
| // distribution. |
| // * Neither the name of Google Inc. nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> |
| |
| // stabs_reader_unittest.cc: Unit tests for google_breakpad::StabsReader. |
| |
| #include <assert.h> |
| #include <errno.h> |
| #include <stab.h> |
| #include <stdarg.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include <fstream> |
| #include <iomanip> |
| #include <iostream> |
| #include <map> |
| #include <sstream> |
| #include <string> |
| |
| #include "breakpad_googletest_includes.h" |
| #include "common/stabs_reader.h" |
| #include "common/test_assembler.h" |
| #include "common/using_std_string.h" |
| |
| using ::testing::Eq; |
| using ::testing::InSequence; |
| using ::testing::Return; |
| using ::testing::StrEq; |
| using ::testing::Test; |
| using ::testing::_; |
| using google_breakpad::StabsHandler; |
| using google_breakpad::StabsReader; |
| using google_breakpad::test_assembler::Label; |
| using google_breakpad::test_assembler::Section; |
| using google_breakpad::test_assembler::kBigEndian; |
| using google_breakpad::test_assembler::kLittleEndian; |
| using std::map; |
| |
| namespace { |
| |
| // A StringAssembler is a class for generating .stabstr sections to present |
| // as input to the STABS parser. |
| class StringAssembler: public Section { |
| public: |
| StringAssembler() : in_cu_(false) { StartCU(); } |
| |
| // Add the string S to this StringAssembler, and return the string's |
| // offset within this compilation unit's strings. If S has been added |
| // already, this returns the offset of its first instance. |
| size_t Add(const string& s) { |
| map<string, size_t>::iterator it = added_.find(s); |
| if (it != added_.end()) |
| return it->second; |
| size_t offset = Size() - cu_start_; |
| AppendCString(s); |
| added_[s] = offset; |
| return offset; |
| } |
| |
| // Start a fresh compilation unit string collection. |
| void StartCU() { |
| // Ignore duplicate calls to StartCU. Our test data don't always call |
| // StartCU at all, meaning that our constructor has to take care of it, |
| // meaning that tests that *do* call StartCU call it twice at the |
| // beginning. This is not worth smoothing out. |
| if (in_cu_) return; |
| |
| added_.clear(); |
| cu_start_ = Size(); |
| |
| // Each compilation unit's strings start with an empty string. |
| AppendCString(""); |
| added_[""] = 0; |
| |
| in_cu_ = true; |
| } |
| |
| // Finish off the current CU's strings. |
| size_t EndCU() { |
| assert(in_cu_); |
| in_cu_ = false; |
| return Size() - cu_start_; |
| } |
| |
| private: |
| // The offset of the start of this compilation unit's strings. |
| size_t cu_start_; |
| |
| // True if we're in a CU. |
| bool in_cu_; |
| |
| // A map from the strings that have been added to this section to |
| // their starting indices within their compilation unit. |
| map<string, size_t> added_; |
| }; |
| |
| // A StabsAssembler is a class for generating .stab sections to present as |
| // test input for the STABS parser. |
| class StabsAssembler: public Section { |
| public: |
| // Create a StabsAssembler that uses StringAssembler for its strings. |
| StabsAssembler(StringAssembler* string_assembler) |
| : Section(string_assembler->endianness()), |
| string_assembler_(string_assembler), |
| value_size_(0), |
| entry_count_(0), |
| cu_header_(NULL) { } |
| ~StabsAssembler() { assert(!cu_header_); } |
| |
| // Accessor and setter for value_size_. |
| size_t value_size() const { return value_size_; } |
| StabsAssembler& set_value_size(size_t value_size) { |
| value_size_ = value_size; |
| return *this; |
| } |
| |
| // Append a STAB entry to the end of this section with the given |
| // characteristics. NAME is the offset of this entry's name string within |
| // its compilation unit's portion of the .stabstr section; this can be a |
| // value generated by a StringAssembler. Return a reference to this |
| // StabsAssembler. |
| StabsAssembler& Stab(uint8_t type, uint8_t other, Label descriptor, |
| Label value, Label name) { |
| D32(name); |
| D8(type); |
| D8(other); |
| D16(descriptor); |
| Append(endianness(), value_size_, value); |
| entry_count_++; |
| return *this; |
| } |
| |
| // As above, but automatically add NAME to our StringAssembler. |
| StabsAssembler& Stab(uint8_t type, uint8_t other, Label descriptor, |
| Label value, const string& name) { |
| return Stab(type, other, descriptor, value, string_assembler_->Add(name)); |
| } |
| |
| // Start a compilation unit named NAME, with an N_UNDF symbol to start |
| // it, and its own portion of the string section. Return a reference to |
| // this StabsAssembler. |
| StabsAssembler& StartCU(const string& name) { |
| assert(!cu_header_); |
| cu_header_ = new CUHeader; |
| string_assembler_->StartCU(); |
| entry_count_ = 0; |
| return Stab(N_UNDF, 0, |
| cu_header_->final_entry_count, |
| cu_header_->final_string_size, |
| string_assembler_->Add(name)); |
| } |
| |
| // Close off the current compilation unit. Return a reference to this |
| // StabsAssembler. |
| StabsAssembler& EndCU() { |
| assert(cu_header_); |
| cu_header_->final_entry_count = entry_count_; |
| cu_header_->final_string_size = string_assembler_->EndCU(); |
| delete cu_header_; |
| cu_header_ = NULL; |
| return *this; |
| } |
| |
| private: |
| // Data used in a compilation unit header STAB that we won't know until |
| // we've finished the compilation unit. |
| struct CUHeader { |
| // The final number of entries this compilation unit will hold. |
| Label final_entry_count; |
| |
| // The final size of this compilation unit's strings. |
| Label final_string_size; |
| }; |
| |
| // The strings for our STABS entries. |
| StringAssembler* string_assembler_; |
| |
| // The size of the 'value' field of stabs entries in this section. |
| size_t value_size_; |
| |
| // The number of entries in this compilation unit so far. |
| size_t entry_count_; |
| |
| // Header labels for this compilation unit, if we've started one but not |
| // finished it. |
| CUHeader* cu_header_; |
| }; |
| |
| class MockStabsReaderHandler: public StabsHandler { |
| public: |
| MOCK_METHOD3(StartCompilationUnit, |
| bool(const char*, uint64_t, const char*)); |
| MOCK_METHOD1(EndCompilationUnit, bool(uint64_t)); |
| MOCK_METHOD2(StartFunction, bool(const string&, uint64_t)); |
| MOCK_METHOD1(EndFunction, bool(uint64_t)); |
| MOCK_METHOD3(Line, bool(uint64_t, const char*, int)); |
| MOCK_METHOD2(Extern, bool(const string&, uint64_t)); |
| void Warning(const char* format, ...) { MockWarning(format); } |
| MOCK_METHOD1(MockWarning, void(const char*)); |
| }; |
| |
| struct StabsFixture { |
| StabsFixture() : stabs(&strings), unitized(true) { } |
| |
| // Create a StabsReader to parse the mock stabs data in stabs and |
| // strings, and pass the parsed information to mock_handler. Use the |
| // endianness and value size of stabs to parse the data. If all goes |
| // well, return the result of calling the reader's Process member |
| // function. Otherwise, return false. |
| bool ApplyHandlerToMockStabsData() { |
| string stabs_contents, stabstr_contents; |
| if (!stabs.GetContents(&stabs_contents) || |
| !strings.GetContents(&stabstr_contents)) |
| return false; |
| |
| // Run the parser on the test input, passing whatever we find to HANDLER. |
| StabsReader reader( |
| reinterpret_cast<const uint8_t*>(stabs_contents.data()), |
| stabs_contents.size(), |
| reinterpret_cast<const uint8_t*>(stabstr_contents.data()), |
| stabstr_contents.size(), |
| stabs.endianness() == kBigEndian, stabs.value_size(), unitized, |
| &mock_handler); |
| return reader.Process(); |
| } |
| |
| StringAssembler strings; |
| StabsAssembler stabs; |
| bool unitized; |
| MockStabsReaderHandler mock_handler; |
| }; |
| |
| class Stabs: public StabsFixture, public Test { }; |
| |
| TEST_F(Stabs, MockStabsInput) { |
| stabs.set_endianness(kLittleEndian); |
| stabs.set_value_size(4); |
| stabs |
| .Stab(N_SO, 149, 40232, 0x18a2a72bU, "builddir/") |
| .Stab(N_FUN, 83, 50010, 0x91a5353fU, |
| "not the SO with source file name we expected ") |
| .Stab(N_SO, 165, 24791, 0xfe69d23cU, "") |
| .Stab(N_SO, 184, 34178, 0xca4d883aU, "builddir1/") |
| .Stab(N_SO, 83, 40859, 0xd2fe5df3U, "file1.c") |
| .Stab(N_LSYM, 147, 39565, 0x60d4bb8aU, "not the FUN we're looking for") |
| .Stab(N_FUN, 120, 50271, 0xa049f4b1U, "fun1") |
| .Stab(N_BINCL, 150, 15694, 0xef65c659U, |
| "something to ignore in a FUN body") |
| .Stab(N_SLINE, 147, 4967, 0xd904b3f, "") |
| .Stab(N_SOL, 177, 56135, 0xbd97b1dcU, "header.h") |
| .Stab(N_SLINE, 130, 24610, 0x90f145b, "") |
| .Stab(N_FUN, 45, 32441, 0xbf27cf93U, |
| "fun2:some stabs type info here:to trim from the name") |
| .Stab(N_SLINE, 138, 39002, 0x8148b87, "") |
| .Stab(N_SOL, 60, 49318, 0x1d06e025U, "file1.c") |
| .Stab(N_SLINE, 29, 52163, 0x6eebbb7, "") |
| .Stab(N_SO, 167, 4647, 0xd04b7448U, "") |
| .Stab(N_LSYM, 58, 37837, 0xe6b14d37U, "") |
| .Stab(N_SO, 152, 7810, 0x11759f10U, "file3.c") |
| .Stab(N_SO, 218, 12447, 0x11cfe4b5U, ""); |
| |
| { |
| InSequence s; |
| |
| EXPECT_CALL(mock_handler, |
| StartCompilationUnit(StrEq("file1.c"), 0xd2fe5df3U, |
| StrEq("builddir1/"))) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, StartFunction(StrEq("fun1"), 0xa049f4b1U)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, |
| Line(0xa049f4b1U + 0xd904b3f, StrEq("file1.c"), 4967)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, |
| Line(0xa049f4b1U + 0x90f145b, StrEq("header.h"), 24610)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, EndFunction(0xbf27cf93U)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, StartFunction(StrEq("fun2"), 0xbf27cf93U)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, |
| Line(0xbf27cf93U + 0x8148b87, StrEq("header.h"), 39002)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, |
| Line(0xbf27cf93U + 0x6eebbb7, StrEq("file1.c"), 52163)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, EndFunction(0xd04b7448U)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, EndCompilationUnit(0xd04b7448U)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, StartCompilationUnit(StrEq("file3.c"), |
| 0x11759f10U, NULL)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, EndCompilationUnit(0x11cfe4b5U)) |
| .WillOnce(Return(true)); |
| } |
| |
| ASSERT_TRUE(ApplyHandlerToMockStabsData()); |
| } |
| |
| TEST_F(Stabs, AbruptCU) { |
| stabs.set_endianness(kBigEndian); |
| stabs.set_value_size(4); |
| stabs.Stab(N_SO, 177, 23446, 0xbf10d5e4, "file2-1.c"); |
| |
| { |
| InSequence s; |
| |
| EXPECT_CALL(mock_handler, |
| StartCompilationUnit(StrEq("file2-1.c"), 0xbf10d5e4, NULL)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, EndCompilationUnit(0)) |
| .WillOnce(Return(true)); |
| } |
| |
| ASSERT_TRUE(ApplyHandlerToMockStabsData()); |
| } |
| |
| TEST_F(Stabs, AbruptFunction) { |
| stabs.set_endianness(kLittleEndian); |
| stabs.set_value_size(8); |
| stabs |
| .Stab(N_SO, 218, 26631, 0xb83ddf10U, "file3-1.c") |
| .Stab(N_FUN, 113, 24765, 0xbbd4a145U, "fun3_1"); |
| |
| { |
| InSequence s; |
| |
| EXPECT_CALL(mock_handler, |
| StartCompilationUnit(StrEq("file3-1.c"), 0xb83ddf10U, NULL)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, StartFunction(StrEq("fun3_1"), 0xbbd4a145U)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, EndFunction(0)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, EndCompilationUnit(0)) |
| .WillOnce(Return(true)); |
| } |
| |
| ASSERT_TRUE(ApplyHandlerToMockStabsData()); |
| } |
| |
| TEST_F(Stabs, NoCU) { |
| stabs.set_endianness(kBigEndian); |
| stabs.set_value_size(8); |
| stabs.Stab(N_SO, 161, 25673, 0x8f676e7bU, "build-directory/"); |
| |
| EXPECT_CALL(mock_handler, StartCompilationUnit(_, _, _)) |
| .Times(0); |
| EXPECT_CALL(mock_handler, StartFunction(_, _)) |
| .Times(0); |
| |
| ASSERT_TRUE(ApplyHandlerToMockStabsData()); |
| } |
| |
| TEST_F(Stabs, NoCUEnd) { |
| stabs.set_endianness(kBigEndian); |
| stabs.set_value_size(8); |
| stabs |
| .Stab(N_SO, 116, 58280, 0x2f7493c9U, "file5-1.c") |
| .Stab(N_SO, 224, 23057, 0xf9f1d50fU, "file5-2.c"); |
| |
| { |
| InSequence s; |
| |
| EXPECT_CALL(mock_handler, |
| StartCompilationUnit(StrEq("file5-1.c"), 0x2f7493c9U, NULL)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, EndCompilationUnit(0)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, |
| StartCompilationUnit(StrEq("file5-2.c"), 0xf9f1d50fU, NULL)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, EndCompilationUnit(0)) |
| .WillOnce(Return(true)); |
| } |
| |
| ASSERT_TRUE(ApplyHandlerToMockStabsData()); |
| } |
| |
| // On systems that store STABS in sections, string offsets are relative to |
| // the beginning of that compilation unit's strings, marked with N_UNDF |
| // symbols; see the comments for StabsReader::StabsReader. |
| TEST_F(Stabs, Unitized) { |
| stabs.set_endianness(kBigEndian); |
| stabs.set_value_size(4); |
| stabs |
| .StartCU("antimony") |
| .Stab(N_SO, 49, 26043, 0x7e259f1aU, "antimony") |
| .Stab(N_FUN, 101, 63253, 0x7fbcccaeU, "arsenic") |
| .Stab(N_SO, 124, 37175, 0x80b0014cU, "") |
| .EndCU() |
| .StartCU("aluminum") |
| .Stab(N_SO, 72, 23084, 0x86756839U, "aluminum") |
| .Stab(N_FUN, 59, 3305, 0xa8e120b0U, "selenium") |
| .Stab(N_SO, 178, 56949, 0xbffff983U, "") |
| .EndCU(); |
| |
| { |
| InSequence s; |
| EXPECT_CALL(mock_handler, |
| StartCompilationUnit(StrEq("antimony"), 0x7e259f1aU, NULL)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, StartFunction(Eq("arsenic"), 0x7fbcccaeU)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, EndFunction(0x80b0014cU)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, EndCompilationUnit(0x80b0014cU)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, |
| StartCompilationUnit(StrEq("aluminum"), 0x86756839U, NULL)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, StartFunction(Eq("selenium"), 0xa8e120b0U)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, EndFunction(0xbffff983U)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, EndCompilationUnit(0xbffff983U)) |
| .WillOnce(Return(true)); |
| } |
| |
| ASSERT_TRUE(ApplyHandlerToMockStabsData()); |
| } |
| |
| // On systems that store STABS entries in the real symbol table, the N_UNDF |
| // entries have no special meaning, and shouldn't mess up the string |
| // indices. |
| TEST_F(Stabs, NonUnitized) { |
| stabs.set_endianness(kLittleEndian); |
| stabs.set_value_size(4); |
| unitized = false; |
| stabs |
| .Stab(N_UNDF, 21, 11551, 0x9bad2b2e, "") |
| .Stab(N_UNDF, 21, 11551, 0x9bad2b2e, "") |
| .Stab(N_SO, 71, 45139, 0x11a97352, "Tanzania") |
| .Stab(N_SO, 221, 41976, 0x21a97352, ""); |
| |
| { |
| InSequence s; |
| EXPECT_CALL(mock_handler, |
| StartCompilationUnit(StrEq("Tanzania"), |
| 0x11a97352, NULL)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, EndCompilationUnit(0x21a97352)) |
| .WillOnce(Return(true)); |
| } |
| |
| ASSERT_TRUE(ApplyHandlerToMockStabsData()); |
| } |
| |
| TEST_F(Stabs, FunctionEnd) { |
| stabs.set_endianness(kLittleEndian); |
| stabs.set_value_size(8); |
| stabs |
| .Stab(N_SO, 102, 62362, 0x52a830d644cd6942ULL, "compilation unit") |
| // This function is terminated by the start of the next function. |
| .Stab(N_FUN, 216, 38405, 0xbb5ab70ecdd23bfeULL, "function 1") |
| // This function is terminated by an explicit end-of-function stab, |
| // whose value is a size in bytes. |
| .Stab(N_FUN, 240, 10973, 0xc954de9b8fb3e5e2ULL, "function 2") |
| .Stab(N_FUN, 14, 36749, 0xc1ab, "") |
| // This function is terminated by the end of the compilation unit. |
| .Stab(N_FUN, 143, 64514, 0xdff98c9a35386e1fULL, "function 3") |
| .Stab(N_SO, 164, 60142, 0xfdacb856e78bbf57ULL, ""); |
| |
| { |
| InSequence s; |
| EXPECT_CALL(mock_handler, |
| StartCompilationUnit(StrEq("compilation unit"), |
| 0x52a830d644cd6942ULL, NULL)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, |
| StartFunction(Eq("function 1"), 0xbb5ab70ecdd23bfeULL)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, EndFunction(0xc954de9b8fb3e5e2ULL)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, |
| StartFunction(Eq("function 2"), 0xc954de9b8fb3e5e2ULL)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, EndFunction(0xc954de9b8fb3e5e2ULL + 0xc1ab)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, |
| StartFunction(Eq("function 3"), 0xdff98c9a35386e1fULL)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, EndFunction(0xfdacb856e78bbf57ULL)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, EndCompilationUnit(0xfdacb856e78bbf57ULL)) |
| .WillOnce(Return(true)); |
| } |
| |
| ASSERT_TRUE(ApplyHandlerToMockStabsData()); |
| } |
| |
| // On Mac OS X, SLINE records can appear before the FUN stab to which they |
| // belong, and their values are absolute addresses, not offsets. |
| TEST_F(Stabs, LeadingLine) { |
| stabs.set_endianness(kBigEndian); |
| stabs.set_value_size(4); |
| stabs |
| .Stab(N_SO, 179, 27357, 0x8adabc15, "build directory/") |
| .Stab(N_SO, 52, 53058, 0x4c7e3bf4, "compilation unit") |
| .Stab(N_SOL, 165, 12086, 0x6a797ca3, "source file name") |
| .Stab(N_SLINE, 229, 20015, 0x4cb3d7e0, "") |
| .Stab(N_SLINE, 89, 43802, 0x4cba8b88, "") |
| .Stab(N_FUN, 251, 51639, 0xce1b98fa, "rutabaga") |
| .Stab(N_FUN, 218, 16113, 0x5798, "") |
| .Stab(N_SO, 52, 53058, 0xd4af4415, ""); |
| |
| { |
| InSequence s; |
| EXPECT_CALL(mock_handler, |
| StartCompilationUnit(StrEq("compilation unit"), |
| 0x4c7e3bf4, StrEq("build directory/"))) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, |
| StartFunction(Eq("rutabaga"), 0xce1b98fa)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, |
| Line(0x4cb3d7e0, StrEq("source file name"), 20015)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, |
| Line(0x4cba8b88, StrEq("source file name"), 43802)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, EndFunction(0xce1b98fa + 0x5798)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, EndCompilationUnit(0xd4af4415)) |
| .WillOnce(Return(true)); |
| } |
| |
| ASSERT_TRUE(ApplyHandlerToMockStabsData()); |
| } |
| |
| |
| #if defined(HAVE_MACH_O_NLIST_H) |
| // These tests have no meaning on non-Mach-O-based systems, as |
| // only Mach-O uses N_SECT to represent public symbols. |
| TEST_F(Stabs, OnePublicSymbol) { |
| stabs.set_endianness(kLittleEndian); |
| stabs.set_value_size(4); |
| |
| const uint32_t kExpectedAddress = 0x9000; |
| const string kExpectedFunctionName("public_function"); |
| stabs |
| .Stab(N_SECT, 1, 0, kExpectedAddress, kExpectedFunctionName); |
| |
| { |
| InSequence s; |
| EXPECT_CALL(mock_handler, |
| Extern(StrEq(kExpectedFunctionName), |
| kExpectedAddress)) |
| .WillOnce(Return(true)); |
| } |
| ASSERT_TRUE(ApplyHandlerToMockStabsData()); |
| } |
| |
| TEST_F(Stabs, TwoPublicSymbols) { |
| stabs.set_endianness(kLittleEndian); |
| stabs.set_value_size(4); |
| |
| const uint32_t kExpectedAddress1 = 0xB0B0B0B0; |
| const string kExpectedFunctionName1("public_function"); |
| const uint32_t kExpectedAddress2 = 0xF0F0F0F0; |
| const string kExpectedFunctionName2("something else"); |
| stabs |
| .Stab(N_SECT, 1, 0, kExpectedAddress1, kExpectedFunctionName1) |
| .Stab(N_SECT, 1, 0, kExpectedAddress2, kExpectedFunctionName2); |
| |
| { |
| InSequence s; |
| EXPECT_CALL(mock_handler, |
| Extern(StrEq(kExpectedFunctionName1), |
| kExpectedAddress1)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(mock_handler, |
| Extern(StrEq(kExpectedFunctionName2), |
| kExpectedAddress2)) |
| .WillOnce(Return(true)); |
| } |
| ASSERT_TRUE(ApplyHandlerToMockStabsData()); |
| } |
| |
| #endif |
| |
| } // anonymous namespace |