// 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: Sterling Augustine // dwarf2reader_lineinfo_unittest.cc: Unit tests for dwarf2reader::LineInfo #include #include #include #include #include "breakpad_googletest_includes.h" #include "common/dwarf/bytereader.h" #include "common/dwarf/dwarf2reader.h" #include "google_breakpad/common/breakpad_types.h" using std::vector; using testing::InSequence; using testing::Return; using testing::Sequence; using testing::Test; using testing::_; using namespace dwarf2reader; namespace { const uint8_t dwarf5_line_program[] = { 0x40, 0x0, 0x0, 0x0, // unit_length (end - begin) // begin 0x05, 0x0, // version 0x8, // address_size 0x0, // segment_selector_size 0x26, 0x0, 0x0, 0x0, // header_length (end_header_end - begin_header) // begin_header: 0x1, // minimum_instruction_length 0x1, // maximum_operations_per_instruction 0x1, // default_is_stmt 0xfb, // line_base 0xe, // line_range 0xd, // opcode_base and lengths 0x0, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x1, 0x1, // directory entry format count DW_LNCT_path, DW_FORM_strp, 0x1, // directories count 0x1, 0x0, 0x0, 0x0, // offset into .debug_line_str 0x2, // file_name_entry_format_count DW_LNCT_directory_index, DW_FORM_data1, DW_LNCT_path, DW_FORM_line_strp, 0x1, // filename count 0x0, // directory index 0x1, 0x0, 0x0, 0x0, // offset into .debug_str // end_header DW_LNS_set_file, 0x0, // set address to 0x0 0x0, 0x9, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // Advance Address by 0 and line by 3 0x15, // Advance PC by 1 0x2, 0x1, 0x0, DW_LNE_end_sequence, DW_LNE_end_sequence, // end }; const uint8_t dwarf4_line_program[] = { 0x37, 0x0, 0x0, 0x0, // unit_length (end - begin) // begin 0x04, 0x0, // version 0x1d, 0x0, 0x0, 0x0, // header_length (end_header - begin_header) // begin_header: 0x1, // minimum_instruction_length 0x1, // maximum_operations_per_instruction 0x1, // default_is_stmt 0xfb, // line_base 0xe, // line_range 0xd, // opcode_base and lengths 0x0, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x1, '/', 'a', '\0', // directory entry 1 (zeroth entry implied) '\0', // end of directory table 'b', '/', 'c', '\0', // file entry 1 (zeroth entry implied) 0, // file 1 directory 0, // file 1 modification time 0, // file 1 length '\0', // end of file table // end_header DW_LNS_set_file, 0x0, // set address to 0x0 0x0, 0x9, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // Advance Address by 0 and line by 3 0x15, // Advance PC by 1 0x2, 0x1, 0x0, DW_LNE_end_sequence, DW_LNE_end_sequence, // end }; class MockLineInfoHandler: public LineInfoHandler { public: MOCK_METHOD(void, DefineDir, (const string&, uint32_t dir_num), (override)); 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)); }; const uint8_t string_section[] = {'x', '/', 'a', '\0'}; const uint8_t line_string_section[] = {'x', 'b', '/', 'c', '\0' }; struct LineProgram: public Test { MockLineInfoHandler handler_; }; TEST_F(LineProgram, ReadLinesDwarf5) { ByteReader byte_reader(ENDIANNESS_LITTLE); // LineTables don't specify the offset size like Compilation Units do. byte_reader.SetOffsetSize(4); LineInfo line_reader(dwarf5_line_program, sizeof(dwarf5_line_program), &byte_reader, string_section, sizeof(string_section), line_string_section, sizeof(line_string_section), &handler_); EXPECT_CALL(handler_, DefineDir("/a", 0)).Times(1); EXPECT_CALL(handler_, DefineFile("b/c", 0, 0, 0, 0)).Times(1); EXPECT_CALL(handler_, AddLine(0, 1, 0, 4, 0)).Times(1); EXPECT_EQ(line_reader.Start(), sizeof(dwarf5_line_program)); } TEST_F(LineProgram, ReadLinesDwarf4) { ByteReader byte_reader(ENDIANNESS_LITTLE); // LineTables don't specify the offset size like Compilation Units do. byte_reader.SetOffsetSize(4); // dwarf4 line info headers don't encode the address size. byte_reader.SetAddressSize(8); LineInfo line_reader(dwarf4_line_program, sizeof(dwarf5_line_program), &byte_reader, // dwarf4 line tables can't access the string sections // so pass values likely to make assertions fail if // the code uses them improperly. nullptr, 0, nullptr, 0, &handler_); EXPECT_CALL(handler_, DefineDir("", 0)).Times(1); EXPECT_CALL(handler_, DefineDir("/a", 1)).Times(1); EXPECT_CALL(handler_, DefineFile("", 0, 0, 0, 0)).Times(1); EXPECT_CALL(handler_, DefineFile("b/c", 1, 0, 0, 0)).Times(1); EXPECT_CALL(handler_, AddLine(0, 1, 0, 4, 0)).Times(1); EXPECT_EQ(line_reader.Start(), sizeof(dwarf4_line_program)); } } // anonymous namespace