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: Sterling Augustine <[email protected]>
30
31 // dwarf2reader_lineinfo_unittest.cc: Unit tests for google_breakpad::LineInfo
32
33 #ifdef HAVE_CONFIG_H
34 #include <config.h> // Must come first
35 #endif
36
37 #include <stdint.h>
38 #include <stdlib.h>
39
40 #include <string>
41 #include <vector>
42
43 #include "breakpad_googletest_includes.h"
44 #include "common/dwarf/bytereader.h"
45 #include "common/dwarf/dwarf2reader.h"
46 #include "google_breakpad/common/breakpad_types.h"
47
48 using std::vector;
49 using testing::InSequence;
50 using testing::Return;
51 using testing::Sequence;
52 using testing::Test;
53 using testing::_;
54
55 using namespace google_breakpad;
56
57 namespace {
58
59 const uint8_t dwarf5_line_program[] = {
60 0x40, 0x0, 0x0, 0x0, // unit_length (end - begin)
61 // begin
62 0x05, 0x0, // version
63 0x8, // address_size
64 0x0, // segment_selector_size
65 0x26, 0x0, 0x0, 0x0, // header_length (end_header_end - begin_header)
66 // begin_header:
67 0x1, // minimum_instruction_length
68 0x1, // maximum_operations_per_instruction
69 0x1, // default_is_stmt
70 0xfb, // line_base
71 0xe, // line_range
72 0xd, // opcode_base and lengths
73 0x0, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x1,
74 0x1, // directory entry format count
75 DW_LNCT_path, DW_FORM_strp,
76 0x1, // directories count
77 0x1, 0x0, 0x0, 0x0, // offset into .debug_line_str
78 0x2, // file_name_entry_format_count
79 DW_LNCT_directory_index, DW_FORM_data1,
80 DW_LNCT_path, DW_FORM_line_strp,
81 0x1, // filename count
82 0x0, // directory index
83 0x1, 0x0, 0x0, 0x0, // offset into .debug_str
84 // end_header
85 DW_LNS_set_file, 0x0,
86 // set address to 0x0
87 0x0, 0x9, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
88 // Advance Address by 0 and line by 3
89 0x15,
90 // Advance PC by 1
91 0x2, 0x1,
92 0x0,
93 DW_LNE_end_sequence,
94 DW_LNE_end_sequence,
95 // end
96 };
97
98 const uint8_t dwarf4_line_program[] = {
99 0x37, 0x0, 0x0, 0x0, // unit_length (end - begin)
100 // begin
101 0x04, 0x0, // version
102 0x1d, 0x0, 0x0, 0x0, // header_length (end_header - begin_header)
103 // begin_header:
104 0x1, // minimum_instruction_length
105 0x1, // maximum_operations_per_instruction
106 0x1, // default_is_stmt
107 0xfb, // line_base
108 0xe, // line_range
109 0xd, // opcode_base and lengths
110 0x0, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x1,
111 '/', 'a', '\0', // directory entry 1 (zeroth entry implied)
112 '\0', // end of directory table
113 'b', '/', 'c', '\0', // file entry 1 (zeroth entry implied)
114 0, // file 1 directory
115 0, // file 1 modification time
116 0, // file 1 length
117 '\0', // end of file table
118 // end_header
119 DW_LNS_set_file, 0x0,
120 // set address to 0x0
121 0x0, 0x9, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
122 // Advance Address by 0 and line by 3
123 0x15,
124 // Advance PC by 1
125 0x2, 0x1,
126 0x0,
127 DW_LNE_end_sequence,
128 DW_LNE_end_sequence,
129 // end
130 };
131
132 class MockLineInfoHandler: public LineInfoHandler {
133 public:
134 MOCK_METHOD(void, DefineDir, (const string&, uint32_t dir_num), (override));
135 MOCK_METHOD(void, DefineFile, (const string& name, int32_t file_num,
136 uint32_t dir_num, uint64_t mod_time,
137 uint64_t length), (override));
138 MOCK_METHOD(void, AddLine, (uint64_t address, uint64_t length,
139 uint32_t file_num, uint32_t line_num,
140 uint32_t column_num), (override));
141 };
142
143 const uint8_t string_section[] = {'x', '/', 'a', '\0'};
144 const uint8_t line_string_section[] = {'x', 'b', '/', 'c', '\0' };
145
146 struct LineProgram: public Test {
147 MockLineInfoHandler handler_;
148 };
149
TEST_F(LineProgram,ReadLinesDwarf5)150 TEST_F(LineProgram, ReadLinesDwarf5) {
151 ByteReader byte_reader(ENDIANNESS_LITTLE);
152 // LineTables don't specify the offset size like Compilation Units do.
153 byte_reader.SetOffsetSize(4);
154 LineInfo line_reader(dwarf5_line_program,
155 sizeof(dwarf5_line_program),
156 &byte_reader,
157 string_section,
158 sizeof(string_section),
159 line_string_section,
160 sizeof(line_string_section),
161 &handler_);
162 EXPECT_CALL(handler_, DefineDir("/a", 0)).Times(1);
163 EXPECT_CALL(handler_, DefineFile("b/c", 0, 0, 0, 0)).Times(1);
164 EXPECT_CALL(handler_, AddLine(0, 1, 0, 4, 0)).Times(1);
165 EXPECT_EQ(line_reader.Start(), sizeof(dwarf5_line_program));
166 }
167
TEST_F(LineProgram,ReadLinesDwarf4)168 TEST_F(LineProgram, ReadLinesDwarf4) {
169 ByteReader byte_reader(ENDIANNESS_LITTLE);
170 // LineTables don't specify the offset size like Compilation Units do.
171 byte_reader.SetOffsetSize(4);
172 // dwarf4 line info headers don't encode the address size.
173 byte_reader.SetAddressSize(8);
174 LineInfo line_reader(dwarf4_line_program,
175 sizeof(dwarf4_line_program),
176 &byte_reader,
177 // dwarf4 line tables can't access the string sections
178 // so pass values likely to make assertions fail if
179 // the code uses them improperly.
180 nullptr, 0, nullptr, 0,
181 &handler_);
182 EXPECT_CALL(handler_, DefineDir("", 0)).Times(1);
183 EXPECT_CALL(handler_, DefineDir("/a", 1)).Times(1);
184 EXPECT_CALL(handler_, DefineFile("", 0, 0, 0, 0)).Times(1);
185 EXPECT_CALL(handler_, DefineFile("b/c", 1, 0, 0, 0)).Times(1);
186 EXPECT_CALL(handler_, AddLine(0, 1, 0, 4, 0)).Times(1);
187 EXPECT_EQ(line_reader.Start(), sizeof(dwarf4_line_program));
188 }
189
190 } // anonymous namespace
191