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
30using namespace lldb;
31using namespace lldb_private;
32using namespace lldb_private::plugin::dwarf;
33
34class LineEntryTest : public testing::Test {
35 SubsystemRAII<FileSystem, HostInfo, ObjectFileMachO, SymbolFileDWARF,
36 TypeSystemClang>
37 subsystem;
38
39public:
40 void SetUp() override;
41
42protected:
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
49void 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
57llvm::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.
83TEST_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.
90TEST_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
98TEST_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
108TEST_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
118TEST_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
130inline __attribute__((always_inline)) int sum2(int a, int b) {
131 int result = a + b;
132 return result;
133}
134
135int sum3(int a, int b, int c) {
136 int result = a + b + c;
137 return result;
138}
139
140inline __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
146int 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.
1580x20: src.cpp:17
1590x21: src.cpp:17
1600x26: src.cpp:17
1610x27: src.cpp:17
1620x29: src.cpp:17
1630x2e: src.cpp:17
1640x2f: src.cpp:17
1650x31: src.cpp:17
1660x36: src.cpp:18
1670x37: src.cpp:18
1680x39: src.cpp:18
1690x3e: src.cpp:18
1700x3f: src.cpp:18
1710x41: src.cpp:18
1720x46: src.cpp:18
1730x47: src.cpp:18
1740x49: src.cpp:18
1750x4e: src.cpp:18
1760x4f: src.cpp:18
1770x51: src.cpp:18
1780x56: src.cpp:18
1790x57: src.cpp:18
1800x59: src.cpp:18
1810x5e: src.cpp:18 -> sum2@src.cpp:2
1820x5f: src.cpp:18 -> sum2@src.cpp:2
1830x61: src.cpp:18 -> sum2@src.cpp:2
1840x66: src.cpp:18 -> sum2@src.cpp:2
1850x67: src.cpp:18 -> sum2@src.cpp:2
1860x69: src.cpp:18 -> sum2@src.cpp:2
1870x6e: src.cpp:18 -> sum2@src.cpp:2
1880x6f: src.cpp:18 -> sum2@src.cpp:2
1890x71: src.cpp:18 -> sum2@src.cpp:2
1900x76: src.cpp:18 -> sum2@src.cpp:2
1910x77: src.cpp:18 -> sum2@src.cpp:2
1920x79: src.cpp:18 -> sum2@src.cpp:2
1930x7e: src.cpp:18 -> sum2@src.cpp:2
1940x7f: src.cpp:19 -> sum4@src.cpp:12
1950x81: src.cpp:19 -> sum4@src.cpp:12
1960x86: src.cpp:19 -> sum4@src.cpp:12
1970x87: src.cpp:19 -> sum4@src.cpp:12
1980x89: src.cpp:19 -> sum4@src.cpp:12
1990x8e: src.cpp:19 -> sum4@src.cpp:12 -> sum2@src.cpp:2
2000x8f: src.cpp:19 -> sum4@src.cpp:12 -> sum2@src.cpp:2
2010x91: src.cpp:19 -> sum4@src.cpp:12 -> sum2@src.cpp:2
2020x96: src.cpp:19 -> sum4@src.cpp:12 -> sum2@src.cpp:3
2030x97: src.cpp:19 -> sum4@src.cpp:12
2040x99: src.cpp:19 -> sum4@src.cpp:12
2050x9e: src.cpp:19 -> sum4@src.cpp:12
2060x9f: src.cpp:19 -> sum4@src.cpp:12
2070xa1: src.cpp:19 -> sum4@src.cpp:12
2080xa6: src.cpp:19 -> sum4@src.cpp:12 -> sum2@src.cpp:2
2090xa7: src.cpp:19 -> sum4@src.cpp:12 -> sum2@src.cpp:2
2100xa9: src.cpp:19 -> sum4@src.cpp:12 -> sum2@src.cpp:2
2110xae: src.cpp:19 -> sum4@src.cpp:12
2120xaf: src.cpp:19 -> sum4@src.cpp:12
2130xb1: src.cpp:19 -> sum4@src.cpp:12
2140xb6: src.cpp:19 -> sum4@src.cpp:13
2150xb7: src.cpp:19 -> sum4@src.cpp:13
2160xb9: src.cpp:19 -> sum4@src.cpp:14
2170xbe: src.cpp:19
2180xbf: src.cpp:19
2190xc1: src.cpp:19
2200xc6: src.cpp:19
2210xc7: src.cpp:19
2220xc9: src.cpp:19
2230xce: src.cpp:20 -> sum2@src.cpp:2
2240xcf: src.cpp:20 -> sum2@src.cpp:2
2250xd1: src.cpp:20 -> sum2@src.cpp:2
2260xd6: src.cpp:21
2270xd7: src.cpp:21
2280xd9: src.cpp:21
2290xde: src.cpp:21
230*/
231

source code of lldb/unittests/Symbol/TestLineEntry.cpp