1 | //===-- TestLineEntry.cpp -------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "gtest/gtest.h" |
10 | #include <iostream> |
11 | #include <optional> |
12 | |
13 | #include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h" |
14 | #include "Plugins/SymbolFile/DWARF/DWARFASTParserClang.h" |
15 | #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h" |
16 | #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" |
17 | #include "TestingSupport/SubsystemRAII.h" |
18 | #include "TestingSupport/TestUtilities.h" |
19 | |
20 | #include "lldb/Core/Module.h" |
21 | #include "lldb/Host/FileSystem.h" |
22 | #include "lldb/Host/HostInfo.h" |
23 | #include "lldb/Symbol/CompileUnit.h" |
24 | #include "lldb/Symbol/SymbolContext.h" |
25 | |
26 | #include "llvm/Support/FileUtilities.h" |
27 | #include "llvm/Support/Program.h" |
28 | #include "llvm/Testing/Support/Error.h" |
29 | |
30 | using namespace lldb; |
31 | using namespace lldb_private; |
32 | using namespace lldb_private::plugin::dwarf; |
33 | |
34 | class LineEntryTest : public testing::Test { |
35 | SubsystemRAII<FileSystem, HostInfo, ObjectFileMachO, SymbolFileDWARF, |
36 | TypeSystemClang> |
37 | subsystem; |
38 | |
39 | public: |
40 | void SetUp() override; |
41 | |
42 | protected: |
43 | llvm::Expected<SymbolContextList> |
44 | GetLineEntriesForLine(uint32_t line, std::optional<uint16_t> column); |
45 | std::optional<TestFile> m_file; |
46 | ModuleSP m_module_sp; |
47 | }; |
48 | |
49 | void LineEntryTest::SetUp() { |
50 | auto ExpectedFile = TestFile::fromYamlFile(Name: "inlined-functions.yaml" ); |
51 | ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded()); |
52 | m_file.emplace(args: std::move(*ExpectedFile)); |
53 | m_module_sp = std::make_shared<Module>(args: m_file->moduleSpec()); |
54 | } |
55 | |
56 | // TODO: Handle SourceLocationSpec column information |
57 | llvm::Expected<SymbolContextList> LineEntryTest::GetLineEntriesForLine( |
58 | uint32_t line, std::optional<uint16_t> column = std::nullopt) { |
59 | SymbolContextList sc_comp_units; |
60 | SymbolContextList sc_line_entries; |
61 | FileSpec file_spec("inlined-functions.cpp" ); |
62 | m_module_sp->ResolveSymbolContextsForFileSpec( |
63 | file_spec, line, /*check_inlines=*/true, resolve_scope: lldb::eSymbolContextCompUnit, |
64 | sc_list&: sc_comp_units); |
65 | if (sc_comp_units.GetSize() == 0) |
66 | return llvm::createStringError(EC: llvm::inconvertibleErrorCode(), |
67 | Msg: "No comp unit found on the test object." ); |
68 | |
69 | SourceLocationSpec location_spec(file_spec, line, column, |
70 | /*check_inlines=*/true, |
71 | /*exact_match=*/true); |
72 | |
73 | sc_comp_units[0].comp_unit->ResolveSymbolContext( |
74 | src_location_spec: location_spec, resolve_scope: eSymbolContextLineEntry, sc_list&: sc_line_entries); |
75 | if (sc_line_entries.GetSize() == 0) |
76 | return llvm::createStringError(EC: llvm::inconvertibleErrorCode(), |
77 | Msg: "No line entry found on the test object." ); |
78 | return sc_line_entries; |
79 | } |
80 | |
81 | // This tests if we can get all line entries that match the passed line, if |
82 | // no column is specified. |
83 | TEST_F(LineEntryTest, GetAllExactLineMatchesWithoutColumn) { |
84 | auto sc_line_entries = GetLineEntriesForLine(line: 12); |
85 | ASSERT_THAT_EXPECTED(sc_line_entries, llvm::Succeeded()); |
86 | ASSERT_EQ(sc_line_entries->NumLineEntriesWithLine(12), 6u); |
87 | } |
88 | |
89 | // This tests if we can get exact line and column matches. |
90 | TEST_F(LineEntryTest, GetAllExactLineColumnMatches) { |
91 | auto sc_line_entries = GetLineEntriesForLine(line: 12, column: 39); |
92 | ASSERT_THAT_EXPECTED(sc_line_entries, llvm::Succeeded()); |
93 | ASSERT_EQ(sc_line_entries->NumLineEntriesWithLine(12), 1u); |
94 | auto line_entry = sc_line_entries.get()[0].line_entry; |
95 | ASSERT_EQ(line_entry.column, 39); |
96 | } |
97 | |
98 | TEST_F(LineEntryTest, GetSameLineContiguousAddressRangeNoInlines) { |
99 | auto sc_line_entries = GetLineEntriesForLine(line: 18); |
100 | ASSERT_THAT_EXPECTED(sc_line_entries, llvm::Succeeded()); |
101 | auto line_entry = sc_line_entries.get()[0].line_entry; |
102 | bool include_inlined_functions = false; |
103 | auto range = |
104 | line_entry.GetSameLineContiguousAddressRange(include_inlined_functions); |
105 | ASSERT_EQ(range.GetByteSize(), (uint64_t)0x24); |
106 | } |
107 | |
108 | TEST_F(LineEntryTest, GetSameLineContiguousAddressRangeOneInline) { |
109 | auto sc_line_entries = GetLineEntriesForLine(line: 18); |
110 | ASSERT_THAT_EXPECTED(sc_line_entries, llvm::Succeeded()); |
111 | auto line_entry = sc_line_entries.get()[0].line_entry; |
112 | bool include_inlined_functions = true; |
113 | auto range = |
114 | line_entry.GetSameLineContiguousAddressRange(include_inlined_functions); |
115 | ASSERT_EQ(range.GetByteSize(), (uint64_t)0x49); |
116 | } |
117 | |
118 | TEST_F(LineEntryTest, GetSameLineContiguousAddressRangeNestedInline) { |
119 | auto sc_line_entries = GetLineEntriesForLine(line: 12); |
120 | ASSERT_THAT_EXPECTED(sc_line_entries, llvm::Succeeded()); |
121 | auto line_entry = sc_line_entries.get()[0].line_entry; |
122 | bool include_inlined_functions = true; |
123 | auto range = |
124 | line_entry.GetSameLineContiguousAddressRange(include_inlined_functions); |
125 | ASSERT_EQ(range.GetByteSize(), (uint64_t)0x33); |
126 | } |
127 | |
128 | /* |
129 | # inlined-functions.cpp |
130 | inline __attribute__((always_inline)) int sum2(int a, int b) { |
131 | int result = a + b; |
132 | return result; |
133 | } |
134 | |
135 | int sum3(int a, int b, int c) { |
136 | int result = a + b + c; |
137 | return result; |
138 | } |
139 | |
140 | inline __attribute__((always_inline)) int sum4(int a, int b, int c, int d) { |
141 | int result = sum2(a, b) + sum2(c, d); |
142 | result += 0; |
143 | return result; |
144 | } |
145 | |
146 | int main(int argc, char** argv) { |
147 | sum3(3, 4, 5) + sum2(1, 2); |
148 | int sum = sum4(1, 2, 3, 4); |
149 | sum2(5, 6); |
150 | return 0; |
151 | } |
152 | |
153 | // g++ -c inlined-functions.cpp -o inlined-functions.o -g -Wno-unused-value |
154 | // obj2yaml inlined-functions.o > inlined-functions.yaml |
155 | |
156 | # Dump of source line per address: |
157 | # inlined-functions.cpp is src.cpp for space considerations. |
158 | 0x20: src.cpp:17 |
159 | 0x21: src.cpp:17 |
160 | 0x26: src.cpp:17 |
161 | 0x27: src.cpp:17 |
162 | 0x29: src.cpp:17 |
163 | 0x2e: src.cpp:17 |
164 | 0x2f: src.cpp:17 |
165 | 0x31: src.cpp:17 |
166 | 0x36: src.cpp:18 |
167 | 0x37: src.cpp:18 |
168 | 0x39: src.cpp:18 |
169 | 0x3e: src.cpp:18 |
170 | 0x3f: src.cpp:18 |
171 | 0x41: src.cpp:18 |
172 | 0x46: src.cpp:18 |
173 | 0x47: src.cpp:18 |
174 | 0x49: src.cpp:18 |
175 | 0x4e: src.cpp:18 |
176 | 0x4f: src.cpp:18 |
177 | 0x51: src.cpp:18 |
178 | 0x56: src.cpp:18 |
179 | 0x57: src.cpp:18 |
180 | 0x59: src.cpp:18 |
181 | 0x5e: src.cpp:18 -> sum2@src.cpp:2 |
182 | 0x5f: src.cpp:18 -> sum2@src.cpp:2 |
183 | 0x61: src.cpp:18 -> sum2@src.cpp:2 |
184 | 0x66: src.cpp:18 -> sum2@src.cpp:2 |
185 | 0x67: src.cpp:18 -> sum2@src.cpp:2 |
186 | 0x69: src.cpp:18 -> sum2@src.cpp:2 |
187 | 0x6e: src.cpp:18 -> sum2@src.cpp:2 |
188 | 0x6f: src.cpp:18 -> sum2@src.cpp:2 |
189 | 0x71: src.cpp:18 -> sum2@src.cpp:2 |
190 | 0x76: src.cpp:18 -> sum2@src.cpp:2 |
191 | 0x77: src.cpp:18 -> sum2@src.cpp:2 |
192 | 0x79: src.cpp:18 -> sum2@src.cpp:2 |
193 | 0x7e: src.cpp:18 -> sum2@src.cpp:2 |
194 | 0x7f: src.cpp:19 -> sum4@src.cpp:12 |
195 | 0x81: src.cpp:19 -> sum4@src.cpp:12 |
196 | 0x86: src.cpp:19 -> sum4@src.cpp:12 |
197 | 0x87: src.cpp:19 -> sum4@src.cpp:12 |
198 | 0x89: src.cpp:19 -> sum4@src.cpp:12 |
199 | 0x8e: src.cpp:19 -> sum4@src.cpp:12 -> sum2@src.cpp:2 |
200 | 0x8f: src.cpp:19 -> sum4@src.cpp:12 -> sum2@src.cpp:2 |
201 | 0x91: src.cpp:19 -> sum4@src.cpp:12 -> sum2@src.cpp:2 |
202 | 0x96: src.cpp:19 -> sum4@src.cpp:12 -> sum2@src.cpp:3 |
203 | 0x97: src.cpp:19 -> sum4@src.cpp:12 |
204 | 0x99: src.cpp:19 -> sum4@src.cpp:12 |
205 | 0x9e: src.cpp:19 -> sum4@src.cpp:12 |
206 | 0x9f: src.cpp:19 -> sum4@src.cpp:12 |
207 | 0xa1: src.cpp:19 -> sum4@src.cpp:12 |
208 | 0xa6: src.cpp:19 -> sum4@src.cpp:12 -> sum2@src.cpp:2 |
209 | 0xa7: src.cpp:19 -> sum4@src.cpp:12 -> sum2@src.cpp:2 |
210 | 0xa9: src.cpp:19 -> sum4@src.cpp:12 -> sum2@src.cpp:2 |
211 | 0xae: src.cpp:19 -> sum4@src.cpp:12 |
212 | 0xaf: src.cpp:19 -> sum4@src.cpp:12 |
213 | 0xb1: src.cpp:19 -> sum4@src.cpp:12 |
214 | 0xb6: src.cpp:19 -> sum4@src.cpp:13 |
215 | 0xb7: src.cpp:19 -> sum4@src.cpp:13 |
216 | 0xb9: src.cpp:19 -> sum4@src.cpp:14 |
217 | 0xbe: src.cpp:19 |
218 | 0xbf: src.cpp:19 |
219 | 0xc1: src.cpp:19 |
220 | 0xc6: src.cpp:19 |
221 | 0xc7: src.cpp:19 |
222 | 0xc9: src.cpp:19 |
223 | 0xce: src.cpp:20 -> sum2@src.cpp:2 |
224 | 0xcf: src.cpp:20 -> sum2@src.cpp:2 |
225 | 0xd1: src.cpp:20 -> sum2@src.cpp:2 |
226 | 0xd6: src.cpp:21 |
227 | 0xd7: src.cpp:21 |
228 | 0xd9: src.cpp:21 |
229 | 0xde: src.cpp:21 |
230 | */ |
231 | |