| // Copyright (c) 2020, Google Inc. |
| // All rights reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above |
| // copyright notice, this list of conditions and the following disclaimer |
| // in the documentation and/or other materials provided with the |
| // distribution. |
| // * Neither the name of Google Inc. nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| // Original author: Snehasish Kumar <snehasishk@google.com> |
| |
| // dwarf2reader_splitfunctions_unittest.cc: Unit tests for with a focus on debug |
| // information generated when with splitting optimizations such as |
| // -fsplit-machine-functions (clang) -freorder-blocks-and-partition (gcc). |
| |
| #include <stdint.h> |
| #include <stdlib.h> |
| |
| #include <string> |
| |
| #include "breakpad_googletest_includes.h" |
| #include "common/dwarf/bytereader.h" |
| #include "common/dwarf/dwarf2reader.h" |
| #include "google_breakpad/common/breakpad_types.h" |
| |
| using testing::_; |
| using namespace dwarf2reader; |
| |
| namespace { |
| |
| class MockLineInfoHandler: public LineInfoHandler { |
| public: |
| MOCK_METHOD(void, DefineFile, (const string& name, int32_t file_num, |
| uint32_t dir_num, uint64_t mod_time, |
| uint64_t length), (override)); |
| MOCK_METHOD(void, AddLine, (uint64_t address, uint64_t length, |
| uint32_t file_num, uint32_t line_num, |
| uint32_t column_num), (override)); |
| }; |
| |
| struct LineProgram: public testing::Test { |
| MockLineInfoHandler handler_; |
| }; |
| |
| // The debug information is generated from the following program -- |
| // $ cat -n split_functions.c |
| // 1 #include <stdio.h> |
| // 2 |
| // 3 __attribute__((noinline)) int foo(int i) { |
| // 4 if (i % 100) { |
| // 5 return i + 1; |
| // 6 } else { |
| // 7 return i * 10 % 3; |
| // 8 } |
| // 9 } |
| // 10 |
| // 11 |
| // 12 int main(int argc, char *argv[]) { |
| // 13 int total = 0; |
| // 14 for (int i = 0; i < 1000; ++i) { |
| // 15 total += foo(i); |
| // 16 } |
| // 17 printf("%d\n", total); |
| // 18 } |
| // |
| // $ bin/clang -fprofile-generate -O2 split_functions.c |
| // $ ./a.out > /dev/null |
| // $ bin/llvm-profdata merge -o default.profdata default_*.profraw |
| // $ bin/clang -fprofile-use -O2 -gmlt -gdwarf-5 -fsplit-machine-functions \ |
| // split_functions.c -o split.out |
| // |
| // For the test we pick the first instruction in foo.cold which should be the |
| // else part of the function foo above. |
| |
| const uint8_t debug_line[] = { |
| 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 |
| }; |
| |
| const uint8_t debug_str[] = { |
| 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 |
| }; |
| |
| const uint8_t debug_line_str[] = { |
| 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 |
| }; |
| |
| TEST_F(LineProgram, ReadLinesSplitFunctions) { |
| ByteReader byte_reader(ENDIANNESS_LITTLE); |
| // LineTables don't specify the offset size like Compilation Units do. |
| byte_reader.SetOffsetSize(4); |
| LineInfo line_reader(debug_line, |
| sizeof(debug_line), |
| &byte_reader, |
| debug_str, |
| sizeof(debug_str), |
| debug_line_str, |
| sizeof(debug_line_str), |
| &handler_); |
| EXPECT_CALL(handler_, DefineFile("split_functions.c", 0, 0, 0, 0)).Times(1); |
| EXPECT_CALL(handler_, AddLine(_, _, _, _, _)).Times(testing::AtLeast(1)); |
| // Pick the first address from the foo.cold symbol and check the line number. |
| EXPECT_CALL(handler_, AddLine(testing::Eq(0x401184lu), _, _, /*line_num*/ 7, _)).Times(1); |
| EXPECT_EQ(line_reader.Start(), sizeof(debug_line)); |
| } |
| |
| } // anonymous namespace |