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