xref: /aosp_15_r20/external/google-breakpad/src/common/stabs_reader_unittest.cc (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
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 <[email protected]> <[email protected]>
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:
StringAssembler()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.
Add(const string & s)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.
StartCU()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.
EndCU()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.
StabsAssembler(StringAssembler * string_assembler)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) { }
~StabsAssembler()139   ~StabsAssembler() { assert(!cu_header_); }
140 
141   // Accessor and setter for value_size_.
value_size() const142   size_t value_size() const { return value_size_; }
set_value_size(size_t 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.
Stab(uint8_t type,uint8_t other,Label descriptor,Label value,Label name)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.
Stab(uint8_t type,uint8_t other,Label descriptor,Label value,const string & name)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.
StartCU(const string & name)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.
EndCU()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));
Warning(const char * format,...)229   void Warning(const char* format, ...) { MockWarning(format); }
230   MOCK_METHOD1(MockWarning, void(const char*));
231 };
232 
233 struct StabsFixture {
StabsFixture__anon9175f6ab0111::StabsFixture234   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.
ApplyHandlerToMockStabsData__anon9175f6ab0111::StabsFixture241   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 
TEST_F(Stabs,MockStabsInput)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 
TEST_F(Stabs,AbruptCU)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 
TEST_F(Stabs,AbruptFunction)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 
TEST_F(Stabs,NoCU)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 
TEST_F(Stabs,NoCUEnd)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.
TEST_F(Stabs,Unitized)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.
TEST_F(Stabs,NonUnitized)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 
TEST_F(Stabs,FunctionEnd)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.
TEST_F(Stabs,LeadingLine)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.
TEST_F(Stabs,OnePublicSymbol)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 
TEST_F(Stabs,TwoPublicSymbols)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
615