Home | History | Annotate | Download | only in common
      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 (at) mozilla.com> <jimb (at) red-bean.com>
     31 
     32 // stabs_reader_unittest.cc: Unit tests for google_breakpad::StabsReader.
     33 
     34 #include <assert.h>
     35 #include <errno.h>
     36 #include <stab.h>
     37 #include <stdarg.h>
     38 #include <stdlib.h>
     39 #include <string.h>
     40 
     41 #include <fstream>
     42 #include <iomanip>
     43 #include <iostream>
     44 #include <map>
     45 #include <sstream>
     46 #include <string>
     47 
     48 #include "breakpad_googletest_includes.h"
     49 #include "common/stabs_reader.h"
     50 #include "common/test_assembler.h"
     51 #include "common/using_std_string.h"
     52 
     53 using ::testing::Eq;
     54 using ::testing::InSequence;
     55 using ::testing::Return;
     56 using ::testing::StrEq;
     57 using ::testing::Test;
     58 using ::testing::_;
     59 using google_breakpad::StabsHandler;
     60 using google_breakpad::StabsReader;
     61 using google_breakpad::test_assembler::Label;
     62 using google_breakpad::test_assembler::Section;
     63 using google_breakpad::test_assembler::kBigEndian;
     64 using google_breakpad::test_assembler::kLittleEndian;
     65 using std::map;
     66 
     67 namespace {
     68 
     69 // A StringAssembler is a class for generating .stabstr sections to present
     70 // as input to the STABS parser.
     71 class StringAssembler: public Section {
     72  public:
     73   StringAssembler() : in_cu_(false) { StartCU(); }
     74 
     75   // Add the string S to this StringAssembler, and return the string's
     76   // offset within this compilation unit's strings. If S has been added
     77   // already, this returns the offset of its first instance.
     78   size_t Add(const string &s) {
     79     map<string, size_t>::iterator it = added_.find(s);
     80     if (it != added_.end())
     81       return it->second;
     82     size_t offset = Size() - cu_start_;
     83     AppendCString(s);
     84     added_[s] = offset;
     85     return offset;
     86   }
     87 
     88   // Start a fresh compilation unit string collection.
     89   void StartCU() {
     90     // Ignore duplicate calls to StartCU. Our test data don't always call
     91     // StartCU at all, meaning that our constructor has to take care of it,
     92     // meaning that tests that *do* call StartCU call it twice at the
     93     // beginning.  This is not worth smoothing out.
     94     if (in_cu_) return;
     95 
     96     added_.clear();
     97     cu_start_ = Size();
     98 
     99     // Each compilation unit's strings start with an empty string.
    100     AppendCString("");
    101     added_[""] = 0;
    102 
    103     in_cu_ = true;
    104   }
    105 
    106   // Finish off the current CU's strings.
    107   size_t EndCU() {
    108     assert(in_cu_);
    109     in_cu_ = false;
    110     return Size() - cu_start_;
    111   }
    112 
    113  private:
    114   // The offset of the start of this compilation unit's strings.
    115   size_t cu_start_;
    116 
    117   // True if we're in a CU.
    118   bool in_cu_;
    119 
    120   // A map from the strings that have been added to this section to
    121   // their starting indices within their compilation unit.
    122   map<string, size_t> added_;
    123 };
    124 
    125 // A StabsAssembler is a class for generating .stab sections to present as
    126 // test input for the STABS parser.
    127 class StabsAssembler: public Section {
    128  public:
    129   // Create a StabsAssembler that uses StringAssembler for its strings.
    130   StabsAssembler(StringAssembler *string_assembler)
    131       : Section(string_assembler->endianness()),
    132         string_assembler_(string_assembler),
    133         value_size_(0),
    134         entry_count_(0),
    135         cu_header_(NULL) { }
    136   ~StabsAssembler() { assert(!cu_header_); }
    137 
    138   // Accessor and setter for value_size_.
    139   size_t value_size() const { return value_size_; }
    140   StabsAssembler &set_value_size(size_t value_size) {
    141     value_size_ = value_size;
    142     return *this;
    143   }
    144 
    145   // Append a STAB entry to the end of this section with the given
    146   // characteristics. NAME is the offset of this entry's name string within
    147   // its compilation unit's portion of the .stabstr section; this can be a
    148   // value generated by a StringAssembler. Return a reference to this
    149   // StabsAssembler.
    150   StabsAssembler &Stab(uint8_t type, uint8_t other, Label descriptor,
    151                        Label value, Label name) {
    152     D32(name);
    153     D8(type);
    154     D8(other);
    155     D16(descriptor);
    156     Append(endianness(), value_size_, value);
    157     entry_count_++;
    158     return *this;
    159   }
    160 
    161   // As above, but automatically add NAME to our StringAssembler.
    162   StabsAssembler &Stab(uint8_t type, uint8_t other, Label descriptor,
    163                        Label value, const string &name) {
    164     return Stab(type, other, descriptor, value, string_assembler_->Add(name));
    165   }
    166 
    167   // Start a compilation unit named NAME, with an N_UNDF symbol to start
    168   // it, and its own portion of the string section. Return a reference to
    169   // this StabsAssembler.
    170   StabsAssembler &StartCU(const string &name) {
    171     assert(!cu_header_);
    172     cu_header_ = new CUHeader;
    173     string_assembler_->StartCU();
    174     entry_count_ = 0;
    175     return Stab(N_UNDF, 0,
    176                 cu_header_->final_entry_count,
    177                 cu_header_->final_string_size,
    178                 string_assembler_->Add(name));
    179   }
    180 
    181   // Close off the current compilation unit. Return a reference to this
    182   // StabsAssembler.
    183   StabsAssembler &EndCU() {
    184     assert(cu_header_);
    185     cu_header_->final_entry_count = entry_count_;
    186     cu_header_->final_string_size = string_assembler_->EndCU();
    187     delete cu_header_;
    188     cu_header_ = NULL;
    189     return *this;
    190   }
    191 
    192  private:
    193   // Data used in a compilation unit header STAB that we won't know until
    194   // we've finished the compilation unit.
    195   struct CUHeader {
    196     // The final number of entries this compilation unit will hold.
    197     Label final_entry_count;
    198 
    199     // The final size of this compilation unit's strings.
    200     Label final_string_size;
    201   };
    202 
    203   // The strings for our STABS entries.
    204   StringAssembler *string_assembler_;
    205 
    206   // The size of the 'value' field of stabs entries in this section.
    207   size_t value_size_;
    208 
    209   // The number of entries in this compilation unit so far.
    210   size_t entry_count_;
    211 
    212   // Header labels for this compilation unit, if we've started one but not
    213   // finished it.
    214   CUHeader *cu_header_;
    215 };
    216 
    217 class MockStabsReaderHandler: public StabsHandler {
    218  public:
    219   MOCK_METHOD3(StartCompilationUnit,
    220                bool(const char *, uint64_t, const char *));
    221   MOCK_METHOD1(EndCompilationUnit, bool(uint64_t));
    222   MOCK_METHOD2(StartFunction, bool(const string &, uint64_t));
    223   MOCK_METHOD1(EndFunction, bool(uint64_t));
    224   MOCK_METHOD3(Line, bool(uint64_t, const char *, int));
    225   MOCK_METHOD2(Extern, bool(const string &, uint64_t));
    226   void Warning(const char *format, ...) { MockWarning(format); }
    227   MOCK_METHOD1(MockWarning, void(const char *));
    228 };
    229 
    230 struct StabsFixture {
    231   StabsFixture() : stabs(&strings), unitized(true) { }
    232 
    233   // Create a StabsReader to parse the mock stabs data in stabs and
    234   // strings, and pass the parsed information to mock_handler. Use the
    235   // endianness and value size of stabs to parse the data. If all goes
    236   // well, return the result of calling the reader's Process member
    237   // function. Otherwise, return false.
    238   bool ApplyHandlerToMockStabsData() {
    239     string stabs_contents, stabstr_contents;
    240     if (!stabs.GetContents(&stabs_contents) ||
    241         !strings.GetContents(&stabstr_contents))
    242       return false;
    243 
    244     // Run the parser on the test input, passing whatever we find to HANDLER.
    245     StabsReader reader(
    246         reinterpret_cast<const uint8_t *>(stabs_contents.data()),
    247         stabs_contents.size(),
    248         reinterpret_cast<const uint8_t *>(stabstr_contents.data()),
    249         stabstr_contents.size(),
    250         stabs.endianness() == kBigEndian, stabs.value_size(), unitized,
    251         &mock_handler);
    252     return reader.Process();
    253   }
    254 
    255   StringAssembler strings;
    256   StabsAssembler stabs;
    257   bool unitized;
    258   MockStabsReaderHandler mock_handler;
    259 };
    260 
    261 class Stabs: public StabsFixture, public Test { };
    262 
    263 TEST_F(Stabs, MockStabsInput) {
    264   stabs.set_endianness(kLittleEndian);
    265   stabs.set_value_size(4);
    266   stabs
    267       .Stab(N_SO,      149, 40232, 0x18a2a72bU, "builddir/")
    268       .Stab(N_FUN,      83, 50010, 0x91a5353fU,
    269             "not the SO with source file name we expected ")
    270       .Stab(N_SO,      165, 24791, 0xfe69d23cU, "")
    271       .Stab(N_SO,      184, 34178, 0xca4d883aU, "builddir1/")
    272       .Stab(N_SO,       83, 40859, 0xd2fe5df3U, "file1.c")
    273       .Stab(N_LSYM,    147, 39565, 0x60d4bb8aU, "not the FUN we're looking for")
    274       .Stab(N_FUN,     120, 50271, 0xa049f4b1U, "fun1")
    275       .Stab(N_BINCL,   150, 15694, 0xef65c659U,
    276             "something to ignore in a FUN body")
    277       .Stab(N_SLINE,   147,  4967, 0xd904b3f, "")
    278       .Stab(N_SOL,     177, 56135, 0xbd97b1dcU, "header.h")
    279       .Stab(N_SLINE,   130, 24610, 0x90f145b, "")
    280       .Stab(N_FUN,      45, 32441, 0xbf27cf93U,
    281             "fun2:some stabs type info here:to trim from the name")
    282       .Stab(N_SLINE,   138, 39002, 0x8148b87, "")
    283       .Stab(N_SOL,      60, 49318, 0x1d06e025U, "file1.c")
    284       .Stab(N_SLINE,    29, 52163, 0x6eebbb7, "")
    285       .Stab(N_SO,      167,  4647, 0xd04b7448U, "")
    286       .Stab(N_LSYM,     58, 37837, 0xe6b14d37U, "")
    287       .Stab(N_SO,      152,  7810, 0x11759f10U, "file3.c")
    288       .Stab(N_SO,      218, 12447, 0x11cfe4b5U, "");
    289 
    290   {
    291     InSequence s;
    292 
    293     EXPECT_CALL(mock_handler,
    294                 StartCompilationUnit(StrEq("file1.c"), 0xd2fe5df3U,
    295                                      StrEq("builddir1/")))
    296         .WillOnce(Return(true));
    297     EXPECT_CALL(mock_handler, StartFunction(StrEq("fun1"), 0xa049f4b1U))
    298         .WillOnce(Return(true));
    299     EXPECT_CALL(mock_handler,
    300                 Line(0xa049f4b1U + 0xd904b3f, StrEq("file1.c"), 4967))
    301         .WillOnce(Return(true));
    302     EXPECT_CALL(mock_handler,
    303                 Line(0xa049f4b1U + 0x90f145b, StrEq("header.h"), 24610))
    304         .WillOnce(Return(true));
    305     EXPECT_CALL(mock_handler, EndFunction(0xbf27cf93U))
    306         .WillOnce(Return(true));
    307     EXPECT_CALL(mock_handler, StartFunction(StrEq("fun2"), 0xbf27cf93U))
    308         .WillOnce(Return(true));
    309     EXPECT_CALL(mock_handler,
    310                 Line(0xbf27cf93U + 0x8148b87, StrEq("header.h"), 39002))
    311         .WillOnce(Return(true));
    312     EXPECT_CALL(mock_handler,
    313                 Line(0xbf27cf93U + 0x6eebbb7, StrEq("file1.c"), 52163))
    314         .WillOnce(Return(true));
    315     EXPECT_CALL(mock_handler, EndFunction(0xd04b7448U))
    316         .WillOnce(Return(true));
    317     EXPECT_CALL(mock_handler, EndCompilationUnit(0xd04b7448U))
    318         .WillOnce(Return(true));
    319     EXPECT_CALL(mock_handler, StartCompilationUnit(StrEq("file3.c"),
    320                                                    0x11759f10U, NULL))
    321         .WillOnce(Return(true));
    322     EXPECT_CALL(mock_handler, EndCompilationUnit(0x11cfe4b5U))
    323         .WillOnce(Return(true));
    324   }
    325 
    326   ASSERT_TRUE(ApplyHandlerToMockStabsData());
    327 }
    328 
    329 TEST_F(Stabs, AbruptCU) {
    330   stabs.set_endianness(kBigEndian);
    331   stabs.set_value_size(4);
    332   stabs.Stab(N_SO, 177, 23446, 0xbf10d5e4, "file2-1.c");
    333 
    334   {
    335     InSequence s;
    336 
    337     EXPECT_CALL(mock_handler,
    338                 StartCompilationUnit(StrEq("file2-1.c"), 0xbf10d5e4, NULL))
    339         .WillOnce(Return(true));
    340     EXPECT_CALL(mock_handler, EndCompilationUnit(0))
    341         .WillOnce(Return(true));
    342   }
    343 
    344   ASSERT_TRUE(ApplyHandlerToMockStabsData());
    345 }
    346 
    347 TEST_F(Stabs, AbruptFunction) {
    348   stabs.set_endianness(kLittleEndian);
    349   stabs.set_value_size(8);
    350   stabs
    351       .Stab(N_SO,      218,   26631,   0xb83ddf10U, "file3-1.c")
    352       .Stab(N_FUN,     113,   24765,   0xbbd4a145U, "fun3_1");
    353 
    354   {
    355     InSequence s;
    356 
    357     EXPECT_CALL(mock_handler,
    358                 StartCompilationUnit(StrEq("file3-1.c"), 0xb83ddf10U, NULL))
    359         .WillOnce(Return(true));
    360     EXPECT_CALL(mock_handler, StartFunction(StrEq("fun3_1"), 0xbbd4a145U))
    361         .WillOnce(Return(true));
    362     EXPECT_CALL(mock_handler, EndFunction(0))
    363         .WillOnce(Return(true));
    364     EXPECT_CALL(mock_handler, EndCompilationUnit(0))
    365         .WillOnce(Return(true));
    366   }
    367 
    368   ASSERT_TRUE(ApplyHandlerToMockStabsData());
    369 }
    370 
    371 TEST_F(Stabs, NoCU) {
    372   stabs.set_endianness(kBigEndian);
    373   stabs.set_value_size(8);
    374   stabs.Stab(N_SO, 161, 25673, 0x8f676e7bU, "build-directory/");
    375 
    376   EXPECT_CALL(mock_handler, StartCompilationUnit(_, _, _))
    377       .Times(0);
    378   EXPECT_CALL(mock_handler, StartFunction(_, _))
    379       .Times(0);
    380 
    381   ASSERT_TRUE(ApplyHandlerToMockStabsData());
    382 }
    383 
    384 TEST_F(Stabs, NoCUEnd) {
    385   stabs.set_endianness(kBigEndian);
    386   stabs.set_value_size(8);
    387   stabs
    388       .Stab(N_SO,      116,   58280,   0x2f7493c9U, "file5-1.c")
    389       .Stab(N_SO,      224,   23057,   0xf9f1d50fU, "file5-2.c");
    390 
    391   {
    392     InSequence s;
    393 
    394     EXPECT_CALL(mock_handler,
    395                 StartCompilationUnit(StrEq("file5-1.c"), 0x2f7493c9U, NULL))
    396         .WillOnce(Return(true));
    397     EXPECT_CALL(mock_handler, EndCompilationUnit(0))
    398         .WillOnce(Return(true));
    399     EXPECT_CALL(mock_handler,
    400                 StartCompilationUnit(StrEq("file5-2.c"), 0xf9f1d50fU, NULL))
    401         .WillOnce(Return(true));
    402     EXPECT_CALL(mock_handler, EndCompilationUnit(0))
    403         .WillOnce(Return(true));
    404   }
    405 
    406   ASSERT_TRUE(ApplyHandlerToMockStabsData());
    407 }
    408 
    409 // On systems that store STABS in sections, string offsets are relative to
    410 // the beginning of that compilation unit's strings, marked with N_UNDF
    411 // symbols; see the comments for StabsReader::StabsReader.
    412 TEST_F(Stabs, Unitized) {
    413   stabs.set_endianness(kBigEndian);
    414   stabs.set_value_size(4);
    415   stabs
    416       .StartCU("antimony")
    417       .Stab(N_SO,   49, 26043, 0x7e259f1aU, "antimony")
    418       .Stab(N_FUN, 101, 63253, 0x7fbcccaeU, "arsenic")
    419       .Stab(N_SO,  124, 37175, 0x80b0014cU, "")
    420       .EndCU()
    421       .StartCU("aluminum")
    422       .Stab(N_SO,   72, 23084, 0x86756839U, "aluminum")
    423       .Stab(N_FUN,  59,  3305, 0xa8e120b0U, "selenium")
    424       .Stab(N_SO,  178, 56949, 0xbffff983U, "")
    425       .EndCU();
    426 
    427   {
    428     InSequence s;
    429     EXPECT_CALL(mock_handler,
    430                 StartCompilationUnit(StrEq("antimony"), 0x7e259f1aU, NULL))
    431         .WillOnce(Return(true));
    432     EXPECT_CALL(mock_handler, StartFunction(Eq("arsenic"), 0x7fbcccaeU))
    433         .WillOnce(Return(true));
    434     EXPECT_CALL(mock_handler, EndFunction(0x80b0014cU))
    435         .WillOnce(Return(true));
    436     EXPECT_CALL(mock_handler, EndCompilationUnit(0x80b0014cU))
    437         .WillOnce(Return(true));
    438     EXPECT_CALL(mock_handler,
    439                 StartCompilationUnit(StrEq("aluminum"), 0x86756839U, NULL))
    440         .WillOnce(Return(true));
    441     EXPECT_CALL(mock_handler, StartFunction(Eq("selenium"), 0xa8e120b0U))
    442         .WillOnce(Return(true));
    443     EXPECT_CALL(mock_handler, EndFunction(0xbffff983U))
    444         .WillOnce(Return(true));
    445     EXPECT_CALL(mock_handler, EndCompilationUnit(0xbffff983U))
    446         .WillOnce(Return(true));
    447   }
    448 
    449   ASSERT_TRUE(ApplyHandlerToMockStabsData());
    450 }
    451 
    452 // On systems that store STABS entries in the real symbol table, the N_UNDF
    453 // entries have no special meaning, and shouldn't mess up the string
    454 // indices.
    455 TEST_F(Stabs, NonUnitized) {
    456   stabs.set_endianness(kLittleEndian);
    457   stabs.set_value_size(4);
    458   unitized = false;
    459   stabs
    460       .Stab(N_UNDF,    21, 11551, 0x9bad2b2e, "")
    461       .Stab(N_UNDF,    21, 11551, 0x9bad2b2e, "")
    462       .Stab(N_SO,      71, 45139, 0x11a97352, "Tanzania")
    463       .Stab(N_SO,     221, 41976, 0x21a97352, "");
    464 
    465   {
    466     InSequence s;
    467     EXPECT_CALL(mock_handler,
    468                 StartCompilationUnit(StrEq("Tanzania"),
    469                                      0x11a97352, NULL))
    470         .WillOnce(Return(true));
    471     EXPECT_CALL(mock_handler, EndCompilationUnit(0x21a97352))
    472         .WillOnce(Return(true));
    473   }
    474 
    475   ASSERT_TRUE(ApplyHandlerToMockStabsData());
    476 }
    477 
    478 TEST_F(Stabs, FunctionEnd) {
    479   stabs.set_endianness(kLittleEndian);
    480   stabs.set_value_size(8);
    481   stabs
    482       .Stab(N_SO,    102, 62362, 0x52a830d644cd6942ULL, "compilation unit")
    483       // This function is terminated by the start of the next function.
    484       .Stab(N_FUN,   216, 38405, 0xbb5ab70ecdd23bfeULL, "function 1")
    485       // This function is terminated by an explicit end-of-function stab,
    486       // whose value is a size in bytes.
    487       .Stab(N_FUN,   240, 10973, 0xc954de9b8fb3e5e2ULL, "function 2")
    488       .Stab(N_FUN,    14, 36749, 0xc1ab,     "")
    489       // This function is terminated by the end of the compilation unit.
    490       .Stab(N_FUN,   143, 64514, 0xdff98c9a35386e1fULL, "function 3")
    491       .Stab(N_SO,    164, 60142, 0xfdacb856e78bbf57ULL, "");
    492 
    493   {
    494     InSequence s;
    495     EXPECT_CALL(mock_handler,
    496                 StartCompilationUnit(StrEq("compilation unit"),
    497                                      0x52a830d644cd6942ULL, NULL))
    498         .WillOnce(Return(true));
    499     EXPECT_CALL(mock_handler,
    500                 StartFunction(Eq("function 1"), 0xbb5ab70ecdd23bfeULL))
    501         .WillOnce(Return(true));
    502     EXPECT_CALL(mock_handler, EndFunction(0xc954de9b8fb3e5e2ULL))
    503         .WillOnce(Return(true));
    504     EXPECT_CALL(mock_handler,
    505                 StartFunction(Eq("function 2"), 0xc954de9b8fb3e5e2ULL))
    506         .WillOnce(Return(true));
    507     EXPECT_CALL(mock_handler, EndFunction(0xc954de9b8fb3e5e2ULL + 0xc1ab))
    508         .WillOnce(Return(true));
    509     EXPECT_CALL(mock_handler,
    510                 StartFunction(Eq("function 3"), 0xdff98c9a35386e1fULL))
    511         .WillOnce(Return(true));
    512     EXPECT_CALL(mock_handler, EndFunction(0xfdacb856e78bbf57ULL))
    513         .WillOnce(Return(true));
    514     EXPECT_CALL(mock_handler, EndCompilationUnit(0xfdacb856e78bbf57ULL))
    515         .WillOnce(Return(true));
    516   }
    517 
    518   ASSERT_TRUE(ApplyHandlerToMockStabsData());
    519 }
    520 
    521 // On Mac OS X, SLINE records can appear before the FUN stab to which they
    522 // belong, and their values are absolute addresses, not offsets.
    523 TEST_F(Stabs, LeadingLine) {
    524   stabs.set_endianness(kBigEndian);
    525   stabs.set_value_size(4);
    526   stabs
    527       .Stab(N_SO,    179, 27357, 0x8adabc15, "build directory/")
    528       .Stab(N_SO,     52, 53058, 0x4c7e3bf4, "compilation unit")
    529       .Stab(N_SOL,   165, 12086, 0x6a797ca3, "source file name")
    530       .Stab(N_SLINE, 229, 20015, 0x4cb3d7e0, "")
    531       .Stab(N_SLINE,  89, 43802, 0x4cba8b88, "")
    532       .Stab(N_FUN,   251, 51639, 0xce1b98fa, "rutabaga")
    533       .Stab(N_FUN,   218, 16113, 0x5798,     "")
    534       .Stab(N_SO,     52, 53058, 0xd4af4415, "");
    535 
    536   {
    537     InSequence s;
    538     EXPECT_CALL(mock_handler,
    539                 StartCompilationUnit(StrEq("compilation unit"),
    540                                      0x4c7e3bf4, StrEq("build directory/")))
    541         .WillOnce(Return(true));
    542     EXPECT_CALL(mock_handler,
    543                 StartFunction(Eq("rutabaga"), 0xce1b98fa))
    544         .WillOnce(Return(true));
    545     EXPECT_CALL(mock_handler,
    546                 Line(0x4cb3d7e0, StrEq("source file name"), 20015))
    547         .WillOnce(Return(true));
    548     EXPECT_CALL(mock_handler,
    549                 Line(0x4cba8b88, StrEq("source file name"), 43802))
    550         .WillOnce(Return(true));
    551     EXPECT_CALL(mock_handler, EndFunction(0xce1b98fa + 0x5798))
    552         .WillOnce(Return(true));
    553     EXPECT_CALL(mock_handler, EndCompilationUnit(0xd4af4415))
    554         .WillOnce(Return(true));
    555   }
    556 
    557   ASSERT_TRUE(ApplyHandlerToMockStabsData());
    558 }
    559 
    560 
    561 #if defined(HAVE_MACH_O_NLIST_H)
    562 // These tests have no meaning on non-Mach-O-based systems, as
    563 // only Mach-O uses N_SECT to represent public symbols.
    564 TEST_F(Stabs, OnePublicSymbol) {
    565   stabs.set_endianness(kLittleEndian);
    566   stabs.set_value_size(4);
    567 
    568   const uint32_t kExpectedAddress = 0x9000;
    569   const string kExpectedFunctionName("public_function");
    570   stabs
    571     .Stab(N_SECT, 1, 0, kExpectedAddress, kExpectedFunctionName);
    572 
    573   {
    574     InSequence s;
    575     EXPECT_CALL(mock_handler,
    576                 Extern(StrEq(kExpectedFunctionName),
    577                        kExpectedAddress))
    578         .WillOnce(Return(true));
    579   }
    580   ASSERT_TRUE(ApplyHandlerToMockStabsData());
    581 }
    582 
    583 TEST_F(Stabs, TwoPublicSymbols) {
    584   stabs.set_endianness(kLittleEndian);
    585   stabs.set_value_size(4);
    586 
    587   const uint32_t kExpectedAddress1 = 0xB0B0B0B0;
    588   const string kExpectedFunctionName1("public_function");
    589   const uint32_t kExpectedAddress2 = 0xF0F0F0F0;
    590   const string kExpectedFunctionName2("something else");
    591   stabs
    592     .Stab(N_SECT, 1, 0, kExpectedAddress1, kExpectedFunctionName1)
    593     .Stab(N_SECT, 1, 0, kExpectedAddress2, kExpectedFunctionName2);
    594 
    595   {
    596     InSequence s;
    597     EXPECT_CALL(mock_handler,
    598                 Extern(StrEq(kExpectedFunctionName1),
    599                        kExpectedAddress1))
    600         .WillOnce(Return(true));
    601     EXPECT_CALL(mock_handler,
    602                 Extern(StrEq(kExpectedFunctionName2),
    603                        kExpectedAddress2))
    604         .WillOnce(Return(true));
    605   }
    606   ASSERT_TRUE(ApplyHandlerToMockStabsData());
    607 }
    608 
    609 #endif
    610 
    611 } // anonymous namespace
    612