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@mozilla.com> <jimb@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:
StringAssembler()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.
Add(const string & s)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.
StartCU()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.
EndCU()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.
StabsAssembler(StringAssembler * string_assembler)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) { }
~StabsAssembler()136 ~StabsAssembler() { assert(!cu_header_); }
137
138 // Accessor and setter for value_size_.
value_size() const139 size_t value_size() const { return value_size_; }
set_value_size(size_t 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.
Stab(uint8_t type,uint8_t other,Label descriptor,Label value,Label name)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.
Stab(uint8_t type,uint8_t other,Label descriptor,Label value,const string & name)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.
StartCU(const string & name)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.
EndCU()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));
Warning(const char * format,...)226 void Warning(const char *format, ...) { MockWarning(format); }
227 MOCK_METHOD1(MockWarning, void(const char *));
228 };
229
230 struct StabsFixture {
StabsFixture__anone52396750111::StabsFixture231 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.
ApplyHandlerToMockStabsData__anone52396750111::StabsFixture238 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
TEST_F(Stabs,MockStabsInput)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
TEST_F(Stabs,AbruptCU)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
TEST_F(Stabs,AbruptFunction)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
TEST_F(Stabs,NoCU)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
TEST_F(Stabs,NoCUEnd)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.
TEST_F(Stabs,Unitized)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.
TEST_F(Stabs,NonUnitized)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
TEST_F(Stabs,FunctionEnd)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.
TEST_F(Stabs,LeadingLine)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.
TEST_F(Stabs,OnePublicSymbol)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
TEST_F(Stabs,TwoPublicSymbols)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