xref: /llvm-project/lldb/unittests/Symbol/TestLineEntry.cpp (revision a669a237c45a515bea0d258cbbecdbbb3170d57a)
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 
SetUp()49 void LineEntryTest::SetUp() {
50   auto ExpectedFile = TestFile::fromYamlFile("inlined-functions.yaml");
51   ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
52   m_file.emplace(std::move(*ExpectedFile));
53   m_module_sp = std::make_shared<Module>(m_file->moduleSpec());
54 }
55 
56   // TODO: Handle SourceLocationSpec column information
GetLineEntriesForLine(uint32_t line,std::optional<uint16_t> column=std::nullopt)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, lldb::eSymbolContextCompUnit,
64       sc_comp_units);
65   if (sc_comp_units.GetSize() == 0)
66     return llvm::createStringError(llvm::inconvertibleErrorCode(),
67                                    "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       location_spec, eSymbolContextLineEntry, sc_line_entries);
75   if (sc_line_entries.GetSize() == 0)
76     return llvm::createStringError(llvm::inconvertibleErrorCode(),
77                                    "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.
TEST_F(LineEntryTest,GetAllExactLineMatchesWithoutColumn)83 TEST_F(LineEntryTest, GetAllExactLineMatchesWithoutColumn) {
84   auto sc_line_entries = GetLineEntriesForLine(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.
TEST_F(LineEntryTest,GetAllExactLineColumnMatches)90 TEST_F(LineEntryTest, GetAllExactLineColumnMatches) {
91   auto sc_line_entries = GetLineEntriesForLine(12, 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 
TEST_F(LineEntryTest,GetSameLineContiguousAddressRangeNoInlines)98 TEST_F(LineEntryTest, GetSameLineContiguousAddressRangeNoInlines) {
99   auto sc_line_entries = GetLineEntriesForLine(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 
TEST_F(LineEntryTest,GetSameLineContiguousAddressRangeOneInline)108 TEST_F(LineEntryTest, GetSameLineContiguousAddressRangeOneInline) {
109   auto sc_line_entries = GetLineEntriesForLine(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 
TEST_F(LineEntryTest,GetSameLineContiguousAddressRangeNestedInline)118 TEST_F(LineEntryTest, GetSameLineContiguousAddressRangeNestedInline) {
119   auto sc_line_entries = GetLineEntriesForLine(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