1cfca06d7SDimitry Andric //===-- LineEntry.cpp -----------------------------------------------------===//
2f034231aSEd Maste //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f034231aSEd Maste //
7f034231aSEd Maste //===----------------------------------------------------------------------===//
8f034231aSEd Maste
9f034231aSEd Maste #include "lldb/Symbol/LineEntry.h"
10f034231aSEd Maste #include "lldb/Symbol/CompileUnit.h"
11f034231aSEd Maste #include "lldb/Target/Process.h"
12f034231aSEd Maste #include "lldb/Target/Target.h"
13f034231aSEd Maste
14f034231aSEd Maste using namespace lldb_private;
15f034231aSEd Maste
LineEntry()1614f1b3e8SDimitry Andric LineEntry::LineEntry()
17ac9a064cSDimitry Andric : range(), file_sp(std::make_shared<SupportFile>()),
18ac9a064cSDimitry Andric original_file_sp(std::make_shared<SupportFile>()),
19ac9a064cSDimitry Andric is_start_of_statement(0), is_start_of_basic_block(0), is_prologue_end(0),
20ac9a064cSDimitry Andric is_epilogue_begin(0), is_terminal_entry(0) {}
21f034231aSEd Maste
Clear()2214f1b3e8SDimitry Andric void LineEntry::Clear() {
23f034231aSEd Maste range.Clear();
24ac9a064cSDimitry Andric file_sp = std::make_shared<SupportFile>();
254df029ccSDimitry Andric original_file_sp = std::make_shared<SupportFile>();
26f21a844fSEd Maste line = LLDB_INVALID_LINE_NUMBER;
27f034231aSEd Maste column = 0;
28f034231aSEd Maste is_start_of_statement = 0;
29f034231aSEd Maste is_start_of_basic_block = 0;
30f034231aSEd Maste is_prologue_end = 0;
31f034231aSEd Maste is_epilogue_begin = 0;
32f034231aSEd Maste is_terminal_entry = 0;
33f034231aSEd Maste }
34f034231aSEd Maste
IsValid() const3514f1b3e8SDimitry Andric bool LineEntry::IsValid() const {
36f21a844fSEd Maste return range.GetBaseAddress().IsValid() && line != LLDB_INVALID_LINE_NUMBER;
37f034231aSEd Maste }
38f034231aSEd Maste
DumpStopContext(Stream * s,bool show_fullpaths) const3914f1b3e8SDimitry Andric bool LineEntry::DumpStopContext(Stream *s, bool show_fullpaths) const {
40ac9a064cSDimitry Andric const FileSpec &file = file_sp->GetSpecOnly();
4114f1b3e8SDimitry Andric if (file) {
42f034231aSEd Maste if (show_fullpaths)
43706b4fc4SDimitry Andric file.Dump(s->AsRawOstream());
44f034231aSEd Maste else
45f034231aSEd Maste file.GetFilename().Dump(s);
46f034231aSEd Maste
47f034231aSEd Maste if (line)
48f034231aSEd Maste s->PutChar(':');
49f034231aSEd Maste }
5094994d37SDimitry Andric if (line) {
51f034231aSEd Maste s->Printf("%u", line);
5294994d37SDimitry Andric if (column) {
5394994d37SDimitry Andric s->PutChar(':');
5494994d37SDimitry Andric s->Printf("%u", column);
5594994d37SDimitry Andric }
5694994d37SDimitry Andric }
5794994d37SDimitry Andric return file || line;
58f034231aSEd Maste }
59f034231aSEd Maste
Dump(Stream * s,Target * target,bool show_file,Address::DumpStyle style,Address::DumpStyle fallback_style,bool show_range) const6014f1b3e8SDimitry Andric bool LineEntry::Dump(Stream *s, Target *target, bool show_file,
61f034231aSEd Maste Address::DumpStyle style,
6214f1b3e8SDimitry Andric Address::DumpStyle fallback_style, bool show_range) const {
6314f1b3e8SDimitry Andric if (show_range) {
64f034231aSEd Maste // Show address range
65f034231aSEd Maste if (!range.Dump(s, target, style, fallback_style))
66f034231aSEd Maste return false;
6714f1b3e8SDimitry Andric } else {
68f034231aSEd Maste // Show address only
6914f1b3e8SDimitry Andric if (!range.GetBaseAddress().Dump(s, target, style, fallback_style))
70f034231aSEd Maste return false;
71f034231aSEd Maste }
72f034231aSEd Maste if (show_file)
73ac9a064cSDimitry Andric *s << ", file = " << GetFile();
74f034231aSEd Maste if (line)
75f034231aSEd Maste s->Printf(", line = %u", line);
76f034231aSEd Maste if (column)
77f034231aSEd Maste s->Printf(", column = %u", column);
78f034231aSEd Maste if (is_start_of_statement)
79f034231aSEd Maste *s << ", is_start_of_statement = TRUE";
80f034231aSEd Maste
81f034231aSEd Maste if (is_start_of_basic_block)
82f034231aSEd Maste *s << ", is_start_of_basic_block = TRUE";
83f034231aSEd Maste
84f034231aSEd Maste if (is_prologue_end)
85f034231aSEd Maste *s << ", is_prologue_end = TRUE";
86f034231aSEd Maste
87f034231aSEd Maste if (is_epilogue_begin)
88f034231aSEd Maste *s << ", is_epilogue_begin = TRUE";
89f034231aSEd Maste
90f034231aSEd Maste if (is_terminal_entry)
91f034231aSEd Maste *s << ", is_terminal_entry = TRUE";
92f034231aSEd Maste return true;
93f034231aSEd Maste }
94f034231aSEd Maste
GetDescription(Stream * s,lldb::DescriptionLevel level,CompileUnit * cu,Target * target,bool show_address_only) const9514f1b3e8SDimitry Andric bool LineEntry::GetDescription(Stream *s, lldb::DescriptionLevel level,
9614f1b3e8SDimitry Andric CompileUnit *cu, Target *target,
9714f1b3e8SDimitry Andric bool show_address_only) const {
98f034231aSEd Maste
9914f1b3e8SDimitry Andric if (level == lldb::eDescriptionLevelBrief ||
10014f1b3e8SDimitry Andric level == lldb::eDescriptionLevelFull) {
10114f1b3e8SDimitry Andric if (show_address_only) {
10214f1b3e8SDimitry Andric range.GetBaseAddress().Dump(s, target, Address::DumpStyleLoadAddress,
10314f1b3e8SDimitry Andric Address::DumpStyleFileAddress);
10414f1b3e8SDimitry Andric } else {
10514f1b3e8SDimitry Andric range.Dump(s, target, Address::DumpStyleLoadAddress,
10614f1b3e8SDimitry Andric Address::DumpStyleFileAddress);
107f034231aSEd Maste }
108f034231aSEd Maste
109ac9a064cSDimitry Andric *s << ": " << GetFile();
110f034231aSEd Maste
11114f1b3e8SDimitry Andric if (line) {
112f034231aSEd Maste s->Printf(":%u", line);
113f034231aSEd Maste if (column)
114f034231aSEd Maste s->Printf(":%u", column);
115f034231aSEd Maste }
116f034231aSEd Maste
11714f1b3e8SDimitry Andric if (level == lldb::eDescriptionLevelFull) {
118f034231aSEd Maste if (is_start_of_statement)
119f034231aSEd Maste *s << ", is_start_of_statement = TRUE";
120f034231aSEd Maste
121f034231aSEd Maste if (is_start_of_basic_block)
122f034231aSEd Maste *s << ", is_start_of_basic_block = TRUE";
123f034231aSEd Maste
124f034231aSEd Maste if (is_prologue_end)
125f034231aSEd Maste *s << ", is_prologue_end = TRUE";
126f034231aSEd Maste
127f034231aSEd Maste if (is_epilogue_begin)
128f034231aSEd Maste *s << ", is_epilogue_begin = TRUE";
129f034231aSEd Maste
130f034231aSEd Maste if (is_terminal_entry)
131f034231aSEd Maste *s << ", is_terminal_entry = TRUE";
13214f1b3e8SDimitry Andric } else {
133f034231aSEd Maste if (is_terminal_entry)
134f034231aSEd Maste s->EOL();
135f034231aSEd Maste }
13614f1b3e8SDimitry Andric } else {
13714f1b3e8SDimitry Andric return Dump(s, target, true, Address::DumpStyleLoadAddress,
13814f1b3e8SDimitry Andric Address::DumpStyleModuleWithFileAddress, true);
139f034231aSEd Maste }
140f034231aSEd Maste return true;
141f034231aSEd Maste }
142f034231aSEd Maste
operator <(const LineEntry & a,const LineEntry & b)14314f1b3e8SDimitry Andric bool lldb_private::operator<(const LineEntry &a, const LineEntry &b) {
144f034231aSEd Maste return LineEntry::Compare(a, b) < 0;
145f034231aSEd Maste }
146f034231aSEd Maste
Compare(const LineEntry & a,const LineEntry & b)14714f1b3e8SDimitry Andric int LineEntry::Compare(const LineEntry &a, const LineEntry &b) {
14814f1b3e8SDimitry Andric int result = Address::CompareFileAddress(a.range.GetBaseAddress(),
14914f1b3e8SDimitry Andric b.range.GetBaseAddress());
150f034231aSEd Maste if (result != 0)
151f034231aSEd Maste return result;
152f034231aSEd Maste
153f034231aSEd Maste const lldb::addr_t a_byte_size = a.range.GetByteSize();
154f034231aSEd Maste const lldb::addr_t b_byte_size = b.range.GetByteSize();
155f034231aSEd Maste
156f034231aSEd Maste if (a_byte_size < b_byte_size)
157f034231aSEd Maste return -1;
158f034231aSEd Maste if (a_byte_size > b_byte_size)
159f034231aSEd Maste return +1;
160f034231aSEd Maste
161f73363f1SDimitry Andric // Check for an end sequence entry mismatch after we have determined that the
162f73363f1SDimitry Andric // address values are equal. If one of the items is an end sequence, we don't
163f73363f1SDimitry Andric // care about the line, file, or column info.
164f034231aSEd Maste if (a.is_terminal_entry > b.is_terminal_entry)
165f034231aSEd Maste return -1;
166f034231aSEd Maste if (a.is_terminal_entry < b.is_terminal_entry)
167f034231aSEd Maste return +1;
168f034231aSEd Maste
169f034231aSEd Maste if (a.line < b.line)
170f034231aSEd Maste return -1;
171f034231aSEd Maste if (a.line > b.line)
172f034231aSEd Maste return +1;
173f034231aSEd Maste
174f034231aSEd Maste if (a.column < b.column)
175f034231aSEd Maste return -1;
176f034231aSEd Maste if (a.column > b.column)
177f034231aSEd Maste return +1;
178f034231aSEd Maste
179ac9a064cSDimitry Andric return FileSpec::Compare(a.GetFile(), b.GetFile(), true);
180f034231aSEd Maste }
181f034231aSEd Maste
GetSameLineContiguousAddressRange(bool include_inlined_functions) const1825f29bb8aSDimitry Andric AddressRange LineEntry::GetSameLineContiguousAddressRange(
1835f29bb8aSDimitry Andric bool include_inlined_functions) const {
184f73363f1SDimitry Andric // Add each LineEntry's range to complete_line_range until we find a
185f73363f1SDimitry Andric // different file / line number.
186e81d9d49SDimitry Andric AddressRange complete_line_range = range;
1875f29bb8aSDimitry Andric auto symbol_context_scope = lldb::eSymbolContextLineEntry;
1884df029ccSDimitry Andric Declaration start_call_site(original_file_sp->GetSpecOnly(), line);
1895f29bb8aSDimitry Andric if (include_inlined_functions)
1905f29bb8aSDimitry Andric symbol_context_scope |= lldb::eSymbolContextBlock;
191e81d9d49SDimitry Andric
19214f1b3e8SDimitry Andric while (true) {
193e81d9d49SDimitry Andric SymbolContext next_line_sc;
194e81d9d49SDimitry Andric Address range_end(complete_line_range.GetBaseAddress());
195e81d9d49SDimitry Andric range_end.Slide(complete_line_range.GetByteSize());
1965f29bb8aSDimitry Andric range_end.CalculateSymbolContext(&next_line_sc, symbol_context_scope);
197e81d9d49SDimitry Andric
1985f29bb8aSDimitry Andric if (!next_line_sc.line_entry.IsValid() ||
1995f29bb8aSDimitry Andric next_line_sc.line_entry.range.GetByteSize() == 0)
2005f29bb8aSDimitry Andric break;
2015f29bb8aSDimitry Andric
202ac9a064cSDimitry Andric if (original_file_sp->Equal(*next_line_sc.line_entry.original_file_sp,
203ac9a064cSDimitry Andric SupportFile::eEqualFileSpecAndChecksumIfSet) &&
2045f29bb8aSDimitry Andric (next_line_sc.line_entry.line == 0 ||
2055f29bb8aSDimitry Andric line == next_line_sc.line_entry.line)) {
206f73363f1SDimitry Andric // Include any line 0 entries - they indicate that this is compiler-
207f73363f1SDimitry Andric // generated code that does not correspond to user source code.
2085f29bb8aSDimitry Andric // next_line_sc is the same file & line as this LineEntry, so extend
2095f29bb8aSDimitry Andric // our AddressRange by its size and continue to see if there are more
2105f29bb8aSDimitry Andric // LineEntries that we can combine. However, if there was nothing to
2115f29bb8aSDimitry Andric // extend we're done.
2125f29bb8aSDimitry Andric if (!complete_line_range.Extend(next_line_sc.line_entry.range))
2135f29bb8aSDimitry Andric break;
214e81d9d49SDimitry Andric continue;
215e81d9d49SDimitry Andric }
216e81d9d49SDimitry Andric
2175f29bb8aSDimitry Andric if (include_inlined_functions && next_line_sc.block &&
2185f29bb8aSDimitry Andric next_line_sc.block->GetContainingInlinedBlock() != nullptr) {
2195f29bb8aSDimitry Andric // The next_line_sc might be in a different file if it's an inlined
2205f29bb8aSDimitry Andric // function. If this is the case then we still want to expand our line
2215f29bb8aSDimitry Andric // range to include them if the inlined function is at the same call site
2225f29bb8aSDimitry Andric // as this line entry. The current block could represent a nested inline
2235f29bb8aSDimitry Andric // function call so we need to need to check up the block tree to see if
2245f29bb8aSDimitry Andric // we find one.
2255f29bb8aSDimitry Andric auto inlined_parent_block =
2265f29bb8aSDimitry Andric next_line_sc.block->GetContainingInlinedBlockWithCallSite(
2275f29bb8aSDimitry Andric start_call_site);
2285f29bb8aSDimitry Andric if (!inlined_parent_block)
2295f29bb8aSDimitry Andric // We didn't find any parent inlined block with a call site at this line
2305f29bb8aSDimitry Andric // entry so this inlined function is probably at another line.
2315f29bb8aSDimitry Andric break;
2325f29bb8aSDimitry Andric // Extend our AddressRange by the size of the inlined block, but if there
2335f29bb8aSDimitry Andric // was nothing to add then we're done.
2345f29bb8aSDimitry Andric if (!complete_line_range.Extend(next_line_sc.line_entry.range))
2355f29bb8aSDimitry Andric break;
236e81d9d49SDimitry Andric continue;
237e81d9d49SDimitry Andric }
2385f29bb8aSDimitry Andric
239e81d9d49SDimitry Andric break;
240e81d9d49SDimitry Andric }
241e81d9d49SDimitry Andric return complete_line_range;
242e81d9d49SDimitry Andric }
243f3fbd1c0SDimitry Andric
ApplyFileMappings(lldb::TargetSP target_sp)24414f1b3e8SDimitry Andric void LineEntry::ApplyFileMappings(lldb::TargetSP target_sp) {
24514f1b3e8SDimitry Andric if (target_sp) {
246344a3780SDimitry Andric // Apply any file remappings to our file.
2474df029ccSDimitry Andric if (auto new_file_spec = target_sp->GetSourcePathMap().FindFile(
248ac9a064cSDimitry Andric original_file_sp->GetSpecOnly())) {
249ac9a064cSDimitry Andric file_sp = std::make_shared<SupportFile>(*new_file_spec,
250ac9a064cSDimitry Andric original_file_sp->GetChecksum());
251ac9a064cSDimitry Andric }
252f3fbd1c0SDimitry Andric }
253f3fbd1c0SDimitry Andric }
254