/ src / common / dwarf / dwarf2reader_splitfunctions_unittest.cc
dwarf2reader_splitfunctions_unittest.cc
  1  // Copyright 2020 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: Snehasish Kumar <snehasishk@google.com>
 30  
 31  // dwarf2reader_splitfunctions_unittest.cc: Unit tests for with a focus on debug
 32  // information generated when with splitting optimizations such as
 33  // -fsplit-machine-functions (clang) -freorder-blocks-and-partition (gcc).
 34  
 35  #ifdef HAVE_CONFIG_H
 36  #include <config.h>  // Must come first
 37  #endif
 38  
 39  #include <stdint.h>
 40  #include <stdlib.h>
 41  
 42  #include <string>
 43  
 44  #include "breakpad_googletest_includes.h"
 45  #include "common/dwarf/bytereader.h"
 46  #include "common/dwarf/dwarf2reader.h"
 47  #include "google_breakpad/common/breakpad_types.h"
 48  
 49  using testing::_;
 50  using namespace google_breakpad;
 51  
 52  namespace {
 53  
 54  class MockLineInfoHandler: public LineInfoHandler {
 55   public:
 56    MOCK_METHOD(void, DefineFile, (const string& name, int32_t file_num,
 57                                   uint32_t dir_num, uint64_t mod_time,
 58                                   uint64_t length), (override));
 59    MOCK_METHOD(void, AddLine, (uint64_t address, uint64_t length,
 60                                uint32_t file_num, uint32_t line_num,
 61                                uint32_t column_num), (override));
 62  };
 63  
 64  struct LineProgram: public testing::Test {
 65    MockLineInfoHandler handler_;
 66  };
 67  
 68  // The debug information is generated from the following program --
 69  // $ cat -n split_functions.c
 70  //   1  #include <stdio.h>
 71  //   2
 72  //   3  __attribute__((noinline)) int foo(int i)  {
 73  //   4    if (i % 100) {
 74  //   5      return i + 1;
 75  //   6    } else {
 76  //   7      return i * 10 % 3;
 77  //   8    }
 78  //   9  }
 79  //  10
 80  //  11
 81  //  12  int main(int argc, char *argv[]) {
 82  //  13    int total = 0;
 83  //  14    for (int i = 0; i < 1000; ++i) {
 84  //  15      total += foo(i);
 85  //  16    }
 86  //  17    printf("%d\n", total);
 87  //  18  }
 88  //
 89  // $ bin/clang -fprofile-generate -O2 split_functions.c
 90  // $ ./a.out > /dev/null
 91  // $ bin/llvm-profdata merge -o default.profdata default_*.profraw
 92  // $ bin/clang -fprofile-use -O2 -gmlt -gdwarf-5 -fsplit-machine-functions \
 93  //             split_functions.c -o split.out
 94  //
 95  //  For the test we pick the first instruction in foo.cold which should be the
 96  //  else part of the function foo above.
 97  
 98  const uint8_t debug_line[] = {
 99    0xb0,0x0,0x0,0x0,0x5,0x0,0x8,0x0,0x37,0x0,0x0,0x0,0x1,0x1,0x1,0xfb,0xe,0xd,0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x1,0x1,0x1f,0x1,0x0,0x0,0x0,0x0,0x3,0x1,0x1f,0x2,0xf,0x5,0x1e,0x1,0x3d,0x0,0x0,0x0,0x0,0x24,0xb2,0xb6,0xb5,0xbb,0xf,0xf7,0x6d,0x27,0x92,0xab,0x55,0x3a,0x29,0x48,0x81,0x4,0x0,0x0,0x9,0x2,0x40,0x10,0x40,0x0,0x0,0x0,0x0,0x0,0x14,0x5,0x9,0xa,0x2f,0x5,0x7,0x6,0x8,0x4a,0x5,0xe,0x6,0x67,0x5,0x1,0x40,0x5,0x0,0xf5,0x5,0xe,0xa,0xf5,0x5,0xb,0x6,0x74,0x5,0x1d,0x6,0x2d,0x5,0x15,0x6,0x3c,0x5,0x3,0x66,0x2,0x7,0x0,0x1,0x1,0x4,0x0,0x5,0xe,0x0,0x9,0x2,0x84,0x11,0x40,0x0,0x0,0x0,0x0,0x0,0x18,0x5,0x13,0x6,0x58,0x5,0x1,0x6,0x8,0xa0,0x2,0x1,0x0,0x1,0x1,0x4,0x0,0x5,0x3,0x0,0x9,0x2,0xa5,0x11,0x40,0x0,0x0,0x0,0x0,0x0,0x3,0x10,0x1,0x5,0x1,0xd7,0x2,0x9,0x0,0x1,0x1
100  };
101  
102  const uint8_t debug_str[] = {
103    0x63,0x6c,0x61,0x6e,0x67,0x20,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x31,0x32,0x2e,0x30,0x2e,0x30,0x20,0x28,0x67,0x69,0x74,0x40,0x67,0x69,0x74,0x68,0x75,0x62,0x2e,0x63,0x6f,0x6d,0x3a,0x6c,0x6c,0x76,0x6d,0x2f,0x6c,0x6c,0x76,0x6d,0x2d,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x2e,0x67,0x69,0x74,0x20,0x63,0x37,0x35,0x61,0x30,0x61,0x31,0x65,0x39,0x64,0x63,0x32,0x39,0x62,0x65,0x34,0x65,0x30,0x30,0x64,0x33,0x37,0x64,0x30,0x64,0x30,0x30,0x32,0x38,0x38,0x61,0x66,0x63,0x31,0x61,0x36,0x31,0x35,0x33,0x66,0x29,0x0,0x73,0x70,0x6c,0x69,0x74,0x5f,0x66,0x75,0x6e,0x63,0x74,0x69,0x6f,0x6e,0x73,0x2e,0x63,0x0,0x2f,0x75,0x73,0x72,0x2f,0x6c,0x6f,0x63,0x61,0x6c,0x2f,0x67,0x6f,0x6f,0x67,0x6c,0x65,0x2f,0x68,0x6f,0x6d,0x65,0x2f,0x73,0x6e,0x65,0x68,0x61,0x73,0x69,0x73,0x68,0x6b,0x2f,0x77,0x6f,0x72,0x6b,0x69,0x6e,0x67,0x2f,0x6c,0x6c,0x76,0x6d,0x2d,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x2f,0x62,0x75,0x69,0x6c,0x64,0x0,0x66,0x6f,0x6f,0x0,0x69,0x6e,0x74,0x0,0x6d,0x61,0x69,0x6e,0x0,0x69,0x0,0x61,0x72,0x67,0x63,0x0,0x61,0x72,0x67,0x76,0x0,0x63,0x68,0x61,0x72,0x0,0x74,0x6f,0x74,0x61,0x6c,0x0
104  };
105  
106  const uint8_t debug_line_str[] = {
107    0x2f,0x75,0x73,0x72,0x2f,0x6c,0x6f,0x63,0x61,0x6c,0x2f,0x67,0x6f,0x6f,0x67,0x6c,0x65,0x2f,0x68,0x6f,0x6d,0x65,0x2f,0x73,0x6e,0x65,0x68,0x61,0x73,0x69,0x73,0x68,0x6b,0x2f,0x77,0x6f,0x72,0x6b,0x69,0x6e,0x67,0x2f,0x6c,0x6c,0x76,0x6d,0x2d,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x2f,0x62,0x75,0x69,0x6c,0x64,0x0,0x73,0x70,0x6c,0x69,0x74,0x5f,0x66,0x75,0x6e,0x63,0x74,0x69,0x6f,0x6e,0x73,0x2e,0x63,0x0
108  };
109  
110  TEST_F(LineProgram, ReadLinesSplitFunctions) {
111    ByteReader byte_reader(ENDIANNESS_LITTLE);
112    // LineTables don't specify the offset size like Compilation Units do.
113    byte_reader.SetOffsetSize(4);
114    LineInfo line_reader(debug_line,
115                         sizeof(debug_line),
116                         &byte_reader,
117                         debug_str,
118                         sizeof(debug_str),
119                         debug_line_str,
120                         sizeof(debug_line_str),
121                         &handler_);
122    EXPECT_CALL(handler_, DefineFile("split_functions.c", 0, 0, 0, 0)).Times(1);
123    EXPECT_CALL(handler_, AddLine(_, _, _, _, _)).Times(testing::AtLeast(1));
124    // Pick the first address from the foo.cold symbol and check the line number.
125    EXPECT_CALL(handler_, AddLine(testing::Eq(0x401184lu), _, _, /*line_num*/ 7, _)).Times(1);
126    EXPECT_EQ(line_reader.Start(), sizeof(debug_line));
127  }
128  
129  }  // anonymous namespace