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