xref: /freebsd/contrib/llvm-project/lldb/source/Symbol/LineEntry.cpp (revision 7fdf597e96a02165cfe22ff357b857d5fa15ed8a)
1 //===-- LineEntry.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 "lldb/Symbol/LineEntry.h"
10 #include "lldb/Symbol/CompileUnit.h"
11 #include "lldb/Target/Process.h"
12 #include "lldb/Target/Target.h"
13 
14 using namespace lldb_private;
15 
16 LineEntry::LineEntry()
17     : range(), file_sp(std::make_shared<SupportFile>()),
18       original_file_sp(std::make_shared<SupportFile>()),
19       is_start_of_statement(0), is_start_of_basic_block(0), is_prologue_end(0),
20       is_epilogue_begin(0), is_terminal_entry(0) {}
21 
22 void LineEntry::Clear() {
23   range.Clear();
24   file_sp = std::make_shared<SupportFile>();
25   original_file_sp = std::make_shared<SupportFile>();
26   line = LLDB_INVALID_LINE_NUMBER;
27   column = 0;
28   is_start_of_statement = 0;
29   is_start_of_basic_block = 0;
30   is_prologue_end = 0;
31   is_epilogue_begin = 0;
32   is_terminal_entry = 0;
33 }
34 
35 bool LineEntry::IsValid() const {
36   return range.GetBaseAddress().IsValid() && line != LLDB_INVALID_LINE_NUMBER;
37 }
38 
39 bool LineEntry::DumpStopContext(Stream *s, bool show_fullpaths) const {
40   const FileSpec &file = file_sp->GetSpecOnly();
41   if (file) {
42     if (show_fullpaths)
43       file.Dump(s->AsRawOstream());
44     else
45       file.GetFilename().Dump(s);
46 
47     if (line)
48       s->PutChar(':');
49   }
50   if (line) {
51     s->Printf("%u", line);
52     if (column) {
53       s->PutChar(':');
54       s->Printf("%u", column);
55     }
56   }
57   return file || line;
58 }
59 
60 bool LineEntry::Dump(Stream *s, Target *target, bool show_file,
61                      Address::DumpStyle style,
62                      Address::DumpStyle fallback_style, bool show_range) const {
63   if (show_range) {
64     // Show address range
65     if (!range.Dump(s, target, style, fallback_style))
66       return false;
67   } else {
68     // Show address only
69     if (!range.GetBaseAddress().Dump(s, target, style, fallback_style))
70       return false;
71   }
72   if (show_file)
73     *s << ", file = " << GetFile();
74   if (line)
75     s->Printf(", line = %u", line);
76   if (column)
77     s->Printf(", column = %u", column);
78   if (is_start_of_statement)
79     *s << ", is_start_of_statement = TRUE";
80 
81   if (is_start_of_basic_block)
82     *s << ", is_start_of_basic_block = TRUE";
83 
84   if (is_prologue_end)
85     *s << ", is_prologue_end = TRUE";
86 
87   if (is_epilogue_begin)
88     *s << ", is_epilogue_begin = TRUE";
89 
90   if (is_terminal_entry)
91     *s << ", is_terminal_entry = TRUE";
92   return true;
93 }
94 
95 bool LineEntry::GetDescription(Stream *s, lldb::DescriptionLevel level,
96                                CompileUnit *cu, Target *target,
97                                bool show_address_only) const {
98 
99   if (level == lldb::eDescriptionLevelBrief ||
100       level == lldb::eDescriptionLevelFull) {
101     if (show_address_only) {
102       range.GetBaseAddress().Dump(s, target, Address::DumpStyleLoadAddress,
103                                   Address::DumpStyleFileAddress);
104     } else {
105       range.Dump(s, target, Address::DumpStyleLoadAddress,
106                  Address::DumpStyleFileAddress);
107     }
108 
109     *s << ": " << GetFile();
110 
111     if (line) {
112       s->Printf(":%u", line);
113       if (column)
114         s->Printf(":%u", column);
115     }
116 
117     if (level == lldb::eDescriptionLevelFull) {
118       if (is_start_of_statement)
119         *s << ", is_start_of_statement = TRUE";
120 
121       if (is_start_of_basic_block)
122         *s << ", is_start_of_basic_block = TRUE";
123 
124       if (is_prologue_end)
125         *s << ", is_prologue_end = TRUE";
126 
127       if (is_epilogue_begin)
128         *s << ", is_epilogue_begin = TRUE";
129 
130       if (is_terminal_entry)
131         *s << ", is_terminal_entry = TRUE";
132     } else {
133       if (is_terminal_entry)
134         s->EOL();
135     }
136   } else {
137     return Dump(s, target, true, Address::DumpStyleLoadAddress,
138                 Address::DumpStyleModuleWithFileAddress, true);
139   }
140   return true;
141 }
142 
143 bool lldb_private::operator<(const LineEntry &a, const LineEntry &b) {
144   return LineEntry::Compare(a, b) < 0;
145 }
146 
147 int LineEntry::Compare(const LineEntry &a, const LineEntry &b) {
148   int result = Address::CompareFileAddress(a.range.GetBaseAddress(),
149                                            b.range.GetBaseAddress());
150   if (result != 0)
151     return result;
152 
153   const lldb::addr_t a_byte_size = a.range.GetByteSize();
154   const lldb::addr_t b_byte_size = b.range.GetByteSize();
155 
156   if (a_byte_size < b_byte_size)
157     return -1;
158   if (a_byte_size > b_byte_size)
159     return +1;
160 
161   // Check for an end sequence entry mismatch after we have determined that the
162   // address values are equal. If one of the items is an end sequence, we don't
163   // care about the line, file, or column info.
164   if (a.is_terminal_entry > b.is_terminal_entry)
165     return -1;
166   if (a.is_terminal_entry < b.is_terminal_entry)
167     return +1;
168 
169   if (a.line < b.line)
170     return -1;
171   if (a.line > b.line)
172     return +1;
173 
174   if (a.column < b.column)
175     return -1;
176   if (a.column > b.column)
177     return +1;
178 
179   return FileSpec::Compare(a.GetFile(), b.GetFile(), true);
180 }
181 
182 AddressRange LineEntry::GetSameLineContiguousAddressRange(
183     bool include_inlined_functions) const {
184   // Add each LineEntry's range to complete_line_range until we find a
185   // different file / line number.
186   AddressRange complete_line_range = range;
187   auto symbol_context_scope = lldb::eSymbolContextLineEntry;
188   Declaration start_call_site(original_file_sp->GetSpecOnly(), line);
189   if (include_inlined_functions)
190     symbol_context_scope |= lldb::eSymbolContextBlock;
191 
192   while (true) {
193     SymbolContext next_line_sc;
194     Address range_end(complete_line_range.GetBaseAddress());
195     range_end.Slide(complete_line_range.GetByteSize());
196     range_end.CalculateSymbolContext(&next_line_sc, symbol_context_scope);
197 
198     if (!next_line_sc.line_entry.IsValid() ||
199         next_line_sc.line_entry.range.GetByteSize() == 0)
200       break;
201 
202     if (original_file_sp->Equal(*next_line_sc.line_entry.original_file_sp,
203                                 SupportFile::eEqualFileSpecAndChecksumIfSet) &&
204         (next_line_sc.line_entry.line == 0 ||
205          line == next_line_sc.line_entry.line)) {
206       // Include any line 0 entries - they indicate that this is compiler-
207       // generated code that does not correspond to user source code.
208       // next_line_sc is the same file & line as this LineEntry, so extend
209       // our AddressRange by its size and continue to see if there are more
210       // LineEntries that we can combine. However, if there was nothing to
211       // extend we're done.
212       if (!complete_line_range.Extend(next_line_sc.line_entry.range))
213         break;
214       continue;
215     }
216 
217     if (include_inlined_functions && next_line_sc.block &&
218         next_line_sc.block->GetContainingInlinedBlock() != nullptr) {
219       // The next_line_sc might be in a different file if it's an inlined
220       // function. If this is the case then we still want to expand our line
221       // range to include them if the inlined function is at the same call site
222       // as this line entry. The current block could represent a nested inline
223       // function call so we need to need to check up the block tree to see if
224       // we find one.
225       auto inlined_parent_block =
226           next_line_sc.block->GetContainingInlinedBlockWithCallSite(
227               start_call_site);
228       if (!inlined_parent_block)
229         // We didn't find any parent inlined block with a call site at this line
230         // entry so this inlined function is probably at another line.
231         break;
232       // Extend our AddressRange by the size of the inlined block, but if there
233       // was nothing to add then we're done.
234       if (!complete_line_range.Extend(next_line_sc.line_entry.range))
235         break;
236       continue;
237     }
238 
239     break;
240   }
241   return complete_line_range;
242 }
243 
244 void LineEntry::ApplyFileMappings(lldb::TargetSP target_sp) {
245   if (target_sp) {
246     // Apply any file remappings to our file.
247     if (auto new_file_spec = target_sp->GetSourcePathMap().FindFile(
248             original_file_sp->GetSpecOnly())) {
249       file_sp = std::make_shared<SupportFile>(*new_file_spec,
250                                               original_file_sp->GetChecksum());
251     }
252   }
253 }
254