xref: /src/contrib/llvm-project/lldb/source/Symbol/LineEntry.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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