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