1// -*- mode: c++ -*-
2
3// Copyright (c) 2010 Google Inc. All Rights Reserved.
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9//     * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11//     * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15//     * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
32
33// dwarf2diehander_unittest.cc: Unit tests for google_breakpad::DIEDispatcher.
34
35#include <string>
36#include <utility>
37
38#include "breakpad_googletest_includes.h"
39
40#include "common/dwarf/dwarf2diehandler.h"
41#include "common/using_std_string.h"
42
43using std::make_pair;
44
45using ::testing::_;
46using ::testing::ContainerEq;
47using ::testing::ElementsAreArray;
48using ::testing::Eq;
49using ::testing::InSequence;
50using ::testing::Return;
51using ::testing::Sequence;
52using ::testing::StrEq;
53
54using dwarf2reader::DIEDispatcher;
55using dwarf2reader::DIEHandler;
56using dwarf2reader::DwarfAttribute;
57using dwarf2reader::DwarfForm;
58using dwarf2reader::DwarfTag;
59using dwarf2reader::RootDIEHandler;
60
61class MockDIEHandler: public DIEHandler {
62 public:
63  MOCK_METHOD3(ProcessAttributeUnsigned,
64               void(DwarfAttribute, DwarfForm, uint64));
65  MOCK_METHOD3(ProcessAttributeSigned,
66               void(DwarfAttribute, DwarfForm, int64));
67  MOCK_METHOD3(ProcessAttributeReference,
68               void(DwarfAttribute, DwarfForm, uint64));
69  MOCK_METHOD4(ProcessAttributeBuffer,
70               void(DwarfAttribute, DwarfForm, const char *, uint64));
71  MOCK_METHOD3(ProcessAttributeString,
72               void(DwarfAttribute, DwarfForm, const string &));
73  MOCK_METHOD3(ProcessAttributeSignature,
74               void(DwarfAttribute, DwarfForm, uint64));
75  MOCK_METHOD0(EndAttributes, bool());
76  MOCK_METHOD2(FindChildHandler, DIEHandler *(uint64, DwarfTag));
77  MOCK_METHOD0(Finish, void());
78};
79
80class MockRootDIEHandler: public RootDIEHandler {
81 public:
82  MOCK_METHOD3(ProcessAttributeUnsigned,
83               void(DwarfAttribute, DwarfForm, uint64));
84  MOCK_METHOD3(ProcessAttributeSigned,
85               void(DwarfAttribute, DwarfForm, int64));
86  MOCK_METHOD3(ProcessAttributeReference,
87               void(DwarfAttribute, DwarfForm, uint64));
88  MOCK_METHOD4(ProcessAttributeBuffer,
89               void(DwarfAttribute, DwarfForm, const char *, uint64));
90  MOCK_METHOD3(ProcessAttributeString,
91               void(DwarfAttribute, DwarfForm, const string &));
92  MOCK_METHOD3(ProcessAttributeSignature,
93               void(DwarfAttribute, DwarfForm, uint64));
94  MOCK_METHOD0(EndAttributes, bool());
95  MOCK_METHOD2(FindChildHandler, DIEHandler *(uint64, DwarfTag));
96  MOCK_METHOD0(Finish, void());
97  MOCK_METHOD5(StartCompilationUnit, bool(uint64, uint8, uint8, uint64, uint8));
98  MOCK_METHOD2(StartRootDIE, bool(uint64, DwarfTag));
99};
100
101// If the handler elects to skip the compilation unit, the dispatcher
102// should tell the reader so.
103TEST(Dwarf2DIEHandler, SkipCompilationUnit) {
104  Sequence s;
105  MockRootDIEHandler mock_root_handler;
106  DIEDispatcher die_dispatcher(&mock_root_handler);
107
108  EXPECT_CALL(mock_root_handler,
109              StartCompilationUnit(0x8d42aed77cfccf3eLL,
110                                   0x89, 0xdc,
111                                   0x2ecb4dc778a80f21LL,
112                                   0x66))
113      .InSequence(s)
114      .WillOnce(Return(false));
115
116  EXPECT_FALSE(die_dispatcher.StartCompilationUnit(0x8d42aed77cfccf3eLL,
117                                                   0x89, 0xdc,
118                                                   0x2ecb4dc778a80f21LL,
119                                                   0x66));
120}
121
122// If the handler elects to skip the root DIE, the dispatcher should
123// tell the reader so.
124TEST(Dwarf2DIEHandler, SkipRootDIE) {
125  Sequence s;
126  MockRootDIEHandler mock_root_handler;
127  DIEDispatcher die_dispatcher(&mock_root_handler);
128
129  EXPECT_CALL(mock_root_handler,
130              StartCompilationUnit(0xde8994029fc8b999LL, 0xf4, 0x02,
131                                   0xb00febffa76e2b2bLL, 0x5c))
132      .InSequence(s)
133      .WillOnce(Return(true));
134  EXPECT_CALL(mock_root_handler,
135              StartRootDIE(0x7d08242b4b510cf2LL, (DwarfTag) 0xb4f98da6))
136      .InSequence(s)
137      .WillOnce(Return(false));
138
139  EXPECT_TRUE(die_dispatcher.StartCompilationUnit(0xde8994029fc8b999LL,
140                                                  0xf4, 0x02,
141                                                  0xb00febffa76e2b2bLL, 0x5c));
142  EXPECT_FALSE(die_dispatcher.StartDIE(0x7d08242b4b510cf2LL,
143                                       (DwarfTag) 0xb4f98da6));
144  die_dispatcher.EndDIE(0x7d08242b4b510cf2LL);
145}
146
147// If the handler elects to skip the root DIE's children, the
148// dispatcher should tell the reader so --- and avoid deleting the
149// root handler.
150TEST(Dwarf2DIEHandler, SkipRootDIEChildren) {
151  MockRootDIEHandler mock_root_handler;
152  DIEDispatcher die_dispatcher(&mock_root_handler);
153
154  {
155    InSequence s;
156
157    EXPECT_CALL(mock_root_handler,
158                StartCompilationUnit(0x15d6897480cc65a7LL, 0x26, 0xa0,
159                                     0x09f8bf0767f91675LL, 0xdb))
160      .WillOnce(Return(true));
161    EXPECT_CALL(mock_root_handler,
162                StartRootDIE(0x7d08242b4b510cf2LL, (DwarfTag) 0xb4f98da6))
163      .WillOnce(Return(true));
164    // Please don't tell me about my children.
165    EXPECT_CALL(mock_root_handler, EndAttributes())
166      .WillOnce(Return(false));
167    EXPECT_CALL(mock_root_handler, Finish())
168      .WillOnce(Return());
169  }
170
171  EXPECT_TRUE(die_dispatcher.StartCompilationUnit(0x15d6897480cc65a7LL,
172                                                  0x26, 0xa0,
173                                                  0x09f8bf0767f91675LL, 0xdb));
174  EXPECT_TRUE(die_dispatcher.StartDIE(0x7d08242b4b510cf2LL,
175                                      (DwarfTag) 0xb4f98da6));
176  EXPECT_FALSE(die_dispatcher.StartDIE(0x435150ceedccda18LL,
177                                       (DwarfTag) 0xc3a17bba));
178  die_dispatcher.EndDIE(0x435150ceedccda18LL);
179  die_dispatcher.EndDIE(0x7d08242b4b510cf2LL);
180}
181
182// The dispatcher should pass attribute values through to the die
183// handler accurately.
184TEST(Dwarf2DIEHandler, PassAttributeValues) {
185  MockRootDIEHandler mock_root_handler;
186  DIEDispatcher die_dispatcher(&mock_root_handler);
187
188  const char buffer[10] = { 0x24, 0x24, 0x35, 0x9a, 0xca,
189                            0xcf, 0xa8, 0x84, 0xa7, 0x18 };
190  string str = "\xc8\x26\x2e\x0d\xa4\x9c\x37\xd6\xfb\x1d";
191
192  // Set expectations.
193  {
194    InSequence s;
195
196    // We'll like the compilation unit header.
197    EXPECT_CALL(mock_root_handler,
198                StartCompilationUnit(0x8d42aed77cfccf3eLL, 0x89, 0xdc,
199                                     0x2ecb4dc778a80f21LL, 0x66))
200      .WillOnce(Return(true));
201
202    // We'll like the root DIE.
203    EXPECT_CALL(mock_root_handler,
204                StartRootDIE(0xe2222da01e29f2a9LL, (DwarfTag) 0x9829445c))
205      .WillOnce(Return(true));
206
207    // Expect some attribute values.
208    EXPECT_CALL(mock_root_handler,
209                ProcessAttributeUnsigned((DwarfAttribute) 0x1cc0bfed,
210                                         (DwarfForm) 0x424f1468,
211                                         0xa592571997facda1ULL))
212      .WillOnce(Return());
213    EXPECT_CALL(mock_root_handler,
214                ProcessAttributeSigned((DwarfAttribute) 0x43694dc9,
215                                       (DwarfForm) 0xf6f78901L,
216                                       0x92602a4e3bf1f446LL))
217      .WillOnce(Return());
218    EXPECT_CALL(mock_root_handler,
219                ProcessAttributeReference((DwarfAttribute) 0x4033e8cL,
220                                          (DwarfForm) 0xf66fbe0bL,
221                                          0x50fddef44734fdecULL))
222      .WillOnce(Return());
223    EXPECT_CALL(mock_root_handler,
224                ProcessAttributeBuffer((DwarfAttribute) 0x25d7e0af,
225                                       (DwarfForm) 0xe99a539a,
226                                       buffer, sizeof(buffer)))
227      .WillOnce(Return());
228    EXPECT_CALL(mock_root_handler,
229                ProcessAttributeString((DwarfAttribute) 0x310ed065,
230                                       (DwarfForm) 0x15762fec,
231                                       StrEq(str)))
232      .WillOnce(Return());
233    EXPECT_CALL(mock_root_handler,
234                ProcessAttributeSignature((DwarfAttribute) 0x58790d72,
235                                          (DwarfForm) 0x4159f138,
236                                          0x94682463613e6a5fULL))
237      .WillOnce(Return());
238    EXPECT_CALL(mock_root_handler, EndAttributes())
239      .WillOnce(Return(true));
240    EXPECT_CALL(mock_root_handler, FindChildHandler(_, _))
241      .Times(0);
242    EXPECT_CALL(mock_root_handler, Finish())
243      .WillOnce(Return());
244  }
245
246  // Drive the dispatcher.
247
248  // Report the CU header.
249  EXPECT_TRUE(die_dispatcher.StartCompilationUnit(0x8d42aed77cfccf3eLL,
250                                                  0x89, 0xdc,
251                                                  0x2ecb4dc778a80f21LL,
252                                                  0x66));
253  // Report the root DIE.
254  EXPECT_TRUE(die_dispatcher.StartDIE(0xe2222da01e29f2a9LL,
255                                      (DwarfTag) 0x9829445c));
256
257  // Report some attribute values.
258  die_dispatcher.ProcessAttributeUnsigned(0xe2222da01e29f2a9LL,
259                                          (DwarfAttribute) 0x1cc0bfed,
260                                          (DwarfForm) 0x424f1468,
261                                          0xa592571997facda1ULL);
262  die_dispatcher.ProcessAttributeSigned(0xe2222da01e29f2a9LL,
263                                        (DwarfAttribute) 0x43694dc9,
264                                        (DwarfForm) 0xf6f78901,
265                                        0x92602a4e3bf1f446LL);
266  die_dispatcher.ProcessAttributeReference(0xe2222da01e29f2a9LL,
267                                           (DwarfAttribute) 0x4033e8c,
268                                           (DwarfForm) 0xf66fbe0b,
269                                           0x50fddef44734fdecULL);
270  die_dispatcher.ProcessAttributeBuffer(0xe2222da01e29f2a9LL,
271                                        (DwarfAttribute) 0x25d7e0af,
272                                        (DwarfForm) 0xe99a539a,
273                                        buffer, sizeof(buffer));
274  die_dispatcher.ProcessAttributeString(0xe2222da01e29f2a9LL,
275                                        (DwarfAttribute) 0x310ed065,
276                                        (DwarfForm) 0x15762fec,
277                                        str);
278  die_dispatcher.ProcessAttributeSignature(0xe2222da01e29f2a9LL,
279                                           (DwarfAttribute) 0x58790d72,
280                                           (DwarfForm) 0x4159f138,
281                                           0x94682463613e6a5fULL);
282
283  // Finish the root DIE (and thus the CU).
284  die_dispatcher.EndDIE(0xe2222da01e29f2a9LL);
285}
286
287TEST(Dwarf2DIEHandler, FindAndSkipChildren) {
288  MockRootDIEHandler mock_root_handler;
289  MockDIEHandler *mock_child1_handler = new(MockDIEHandler);
290  MockDIEHandler *mock_child3_handler = new(MockDIEHandler);
291  DIEDispatcher die_dispatcher(&mock_root_handler);
292
293  {
294    InSequence s;
295
296    // We'll like the compilation unit header.
297    EXPECT_CALL(mock_root_handler,
298                StartCompilationUnit(0x9ec1e6d05e434a0eLL, 0xeb, 0x21,
299                                     0x47dd3c764275a216LL, 0xa5))
300      .WillOnce(Return(true));
301
302    // Root DIE.
303    {
304      EXPECT_CALL(mock_root_handler,
305                  StartRootDIE(0x15f0e06bdfe3c372LL, (DwarfTag) 0xf5d60c59))
306        .WillOnce(Return(true));
307      EXPECT_CALL(mock_root_handler,
308                  ProcessAttributeSigned((DwarfAttribute) 0xf779a642,
309                                         (DwarfForm) 0x2cb63027,
310                                         0x18e744661769d08fLL))
311        .WillOnce(Return());
312      EXPECT_CALL(mock_root_handler, EndAttributes())
313        .WillOnce(Return(true));
314
315      // First child DIE.
316      EXPECT_CALL(mock_root_handler,
317                  FindChildHandler(0x149f644f8116fe8cLL,
318                                   (DwarfTag) 0xac2cbd8c))
319        .WillOnce(Return(mock_child1_handler));
320      {
321        EXPECT_CALL(*mock_child1_handler,
322                    ProcessAttributeSigned((DwarfAttribute) 0xa6fd6f65,
323                                           (DwarfForm) 0xe4f64c41,
324                                           0x1b04e5444a55fe67LL))
325          .WillOnce(Return());
326        EXPECT_CALL(*mock_child1_handler, EndAttributes())
327          .WillOnce(Return(false));
328        // Skip first grandchild DIE and first great-grandchild DIE.
329        EXPECT_CALL(*mock_child1_handler, Finish())
330          .WillOnce(Return());
331      }
332
333      // Second child DIE.  Root handler will decline to return a handler
334      // for this child.
335      EXPECT_CALL(mock_root_handler,
336                  FindChildHandler(0x97412be24875de9dLL,
337                                   (DwarfTag) 0x505a068b))
338        .WillOnce(Return((DIEHandler *) NULL));
339
340      // Third child DIE.
341      EXPECT_CALL(mock_root_handler,
342                  FindChildHandler(0x753c964c8ab538aeLL,
343                                   (DwarfTag) 0x8c22970e))
344        .WillOnce(Return(mock_child3_handler));
345      {
346        EXPECT_CALL(*mock_child3_handler,
347                    ProcessAttributeSigned((DwarfAttribute) 0x4e2b7cfb,
348                                           (DwarfForm) 0x610b7ae1,
349                                           0x3ea5c609d7d7560fLL))
350          .WillOnce(Return());
351        EXPECT_CALL(*mock_child3_handler, EndAttributes())
352          .WillOnce(Return(true));
353        EXPECT_CALL(*mock_child3_handler, Finish())
354          .WillOnce(Return());
355      }
356
357      EXPECT_CALL(mock_root_handler, Finish())
358        .WillOnce(Return());
359    }
360  }
361
362
363  // Drive the dispatcher.
364
365  // Report the CU header.
366  EXPECT_TRUE(die_dispatcher
367              .StartCompilationUnit(0x9ec1e6d05e434a0eLL, 0xeb, 0x21,
368                                    0x47dd3c764275a216LL, 0xa5));
369  // Report the root DIE.
370  {
371    EXPECT_TRUE(die_dispatcher.StartDIE(0x15f0e06bdfe3c372LL,
372                                        (DwarfTag) 0xf5d60c59));
373    die_dispatcher.ProcessAttributeSigned(0x15f0e06bdfe3c372LL,
374                                          (DwarfAttribute) 0xf779a642,
375                                          (DwarfForm) 0x2cb63027,
376                                          0x18e744661769d08fLL);
377
378    // First child DIE.
379    {
380      EXPECT_TRUE(die_dispatcher.StartDIE(0x149f644f8116fe8cLL,
381                                          (DwarfTag) 0xac2cbd8c));
382      die_dispatcher.ProcessAttributeSigned(0x149f644f8116fe8cLL,
383                                            (DwarfAttribute) 0xa6fd6f65,
384                                            (DwarfForm) 0xe4f64c41,
385                                            0x1b04e5444a55fe67LL);
386
387      // First grandchild DIE.  Will be skipped.
388      {
389        EXPECT_FALSE(die_dispatcher.StartDIE(0xd68de1ee0bd29419LL,
390                                            (DwarfTag) 0x22f05a15));
391        // First great-grandchild DIE.  Will be skipped without being
392        // mentioned to any handler.
393        {
394          EXPECT_FALSE(die_dispatcher
395                       .StartDIE(0xb3076285d25cac25LL,
396                                 (DwarfTag) 0xcff4061b));
397          die_dispatcher.EndDIE(0xb3076285d25cac25LL);
398        }
399        die_dispatcher.EndDIE(0xd68de1ee0bd29419LL);
400      }
401      die_dispatcher.EndDIE(0x149f644f8116fe8cLL);
402    }
403
404    // Second child DIE.  Root handler will decline to find a handler for it.
405    {
406      EXPECT_FALSE(die_dispatcher.StartDIE(0x97412be24875de9dLL,
407                                           (DwarfTag) 0x505a068b));
408      die_dispatcher.EndDIE(0x97412be24875de9dLL);
409    }
410
411    // Third child DIE.
412    {
413      EXPECT_TRUE(die_dispatcher.StartDIE(0x753c964c8ab538aeLL,
414                                          (DwarfTag) 0x8c22970e));
415      die_dispatcher.ProcessAttributeSigned(0x753c964c8ab538aeLL,
416                                            (DwarfAttribute) 0x4e2b7cfb,
417                                            (DwarfForm) 0x610b7ae1,
418                                            0x3ea5c609d7d7560fLL);
419      die_dispatcher.EndDIE(0x753c964c8ab538aeLL);
420    }
421
422    // Finish the root DIE (and thus the CU).
423    die_dispatcher.EndDIE(0x15f0e06bdfe3c372LL);
424  }
425}
426
427// The DIEDispatcher destructor is supposed to delete all handlers on
428// the stack, except for the root.
429TEST(Dwarf2DIEHandler, FreeHandlersOnStack) {
430  MockRootDIEHandler mock_root_handler;
431  MockDIEHandler *mock_child_handler = new(MockDIEHandler);
432  MockDIEHandler *mock_grandchild_handler = new(MockDIEHandler);
433
434  {
435    InSequence s;
436
437    // We'll like the compilation unit header.
438    EXPECT_CALL(mock_root_handler,
439                StartCompilationUnit(0x87b41ba8381cd71cLL, 0xff, 0x89,
440                                     0x76d392ff393ddda2LL, 0xbf))
441      .WillOnce(Return(true));
442
443    // Root DIE.
444    {
445      EXPECT_CALL(mock_root_handler,
446                  StartRootDIE(0xbf13b761691ddc91LL, (DwarfTag) 0x98980361))
447        .WillOnce(Return(true));
448      EXPECT_CALL(mock_root_handler, EndAttributes())
449        .WillOnce(Return(true));
450
451      // Child DIE.
452      EXPECT_CALL(mock_root_handler,
453                  FindChildHandler(0x058f09240c5fc8c9LL,
454                                   (DwarfTag) 0x898bf0d0))
455        .WillOnce(Return(mock_child_handler));
456      {
457        EXPECT_CALL(*mock_child_handler, EndAttributes())
458          .WillOnce(Return(true));
459
460        // Grandchild DIE.
461        EXPECT_CALL(*mock_child_handler,
462                    FindChildHandler(0x32dc00c9945dc0c8LL,
463                                     (DwarfTag) 0x2802d007))
464          .WillOnce(Return(mock_grandchild_handler));
465        {
466          EXPECT_CALL(*mock_grandchild_handler,
467                      ProcessAttributeSigned((DwarfAttribute) 0x4e2b7cfb,
468                                             (DwarfForm) 0x610b7ae1,
469                                             0x3ea5c609d7d7560fLL))
470            .WillOnce(Return());
471
472          // At this point, we abandon the traversal, so none of the
473          // usual stuff should get called.
474          EXPECT_CALL(*mock_grandchild_handler, EndAttributes())
475            .Times(0);
476          EXPECT_CALL(*mock_grandchild_handler, Finish())
477            .Times(0);
478        }
479
480        EXPECT_CALL(*mock_child_handler, Finish())
481          .Times(0);
482      }
483
484      EXPECT_CALL(mock_root_handler, Finish())
485        .Times(0);
486    }
487  }
488
489  // The dispatcher.
490  DIEDispatcher die_dispatcher(&mock_root_handler);
491
492  // Report the CU header.
493  EXPECT_TRUE(die_dispatcher
494              .StartCompilationUnit(0x87b41ba8381cd71cLL, 0xff, 0x89,
495                                    0x76d392ff393ddda2LL, 0xbf));
496  // Report the root DIE.
497  {
498    EXPECT_TRUE(die_dispatcher.StartDIE(0xbf13b761691ddc91LL,
499                                        (DwarfTag) 0x98980361));
500
501    // Child DIE.
502    {
503      EXPECT_TRUE(die_dispatcher.StartDIE(0x058f09240c5fc8c9LL,
504                                          (DwarfTag) 0x898bf0d0));
505
506      // Grandchild DIE.
507      {
508        EXPECT_TRUE(die_dispatcher.StartDIE(0x32dc00c9945dc0c8LL,
509                                            (DwarfTag) 0x2802d007));
510        die_dispatcher.ProcessAttributeSigned(0x32dc00c9945dc0c8LL,
511                                              (DwarfAttribute) 0x4e2b7cfb,
512                                              (DwarfForm) 0x610b7ae1,
513                                              0x3ea5c609d7d7560fLL);
514
515        // Stop the traversal abruptly, so that there will still be
516        // handlers on the stack when the dispatcher is destructed.
517
518        // No EndDIE call...
519      }
520      // No EndDIE call...
521    }
522    // No EndDIE call...
523  }
524}
525