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