1 //===-- TestLineEntry.cpp -------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "gtest/gtest.h"
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"
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"
26 #include "llvm/Support/FileUtilities.h"
27 #include "llvm/Support/Program.h"
28 #include "llvm/Testing/Support/Error.h"
31 using namespace lldb_private
;
32 using namespace lldb_private::plugin::dwarf
;
34 class LineEntryTest
: public testing::Test
{
35 SubsystemRAII
<FileSystem
, HostInfo
, ObjectFileMachO
, SymbolFileDWARF
,
40 void SetUp() override
;
43 llvm::Expected
<SymbolContextList
>
44 GetLineEntriesForLine(uint32_t line
, std::optional
<uint16_t> column
);
45 std::optional
<TestFile
> m_file
;
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());
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, lldb::eSymbolContextCompUnit
,
65 if (sc_comp_units
.GetSize() == 0)
66 return llvm::createStringError(llvm::inconvertibleErrorCode(),
67 "No comp unit found on the test object.");
69 SourceLocationSpec
location_spec(file_spec
, line
, column
,
70 /*check_inlines=*/true,
71 /*exact_match=*/true);
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
;
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(12);
85 ASSERT_THAT_EXPECTED(sc_line_entries
, llvm::Succeeded());
86 ASSERT_EQ(sc_line_entries
->NumLineEntriesWithLine(12), 6u);
89 // This tests if we can get exact line and column matches.
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);
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;
104 line_entry
.GetSameLineContiguousAddressRange(include_inlined_functions
);
105 ASSERT_EQ(range
.GetByteSize(), (uint64_t)0x24);
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;
114 line_entry
.GetSameLineContiguousAddressRange(include_inlined_functions
);
115 ASSERT_EQ(range
.GetByteSize(), (uint64_t)0x49);
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;
124 line_entry
.GetSameLineContiguousAddressRange(include_inlined_functions
);
125 ASSERT_EQ(range
.GetByteSize(), (uint64_t)0x33);
129 # inlined-functions.cpp
130 inline __attribute__((always_inline)) int sum2(int a, int b) {
135 int sum3(int a, int b, int c) {
136 int result = a + b + c;
140 inline __attribute__((always_inline)) int sum4(int a, int b, int c, int d) {
141 int result = sum2(a, b) + sum2(c, d);
146 int main(int argc, char** argv) {
147 sum3(3, 4, 5) + sum2(1, 2);
148 int sum = sum4(1, 2, 3, 4);
153 // g++ -c inlined-functions.cpp -o inlined-functions.o -g -Wno-unused-value
154 // obj2yaml inlined-functions.o > inlined-functions.yaml
156 # Dump of source line per address:
157 # inlined-functions.cpp is src.cpp for space considerations.
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
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