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&: s->AsRawOstream()); |
41 | else |
42 | file.GetFilename().Dump(s); |
43 | |
44 | if (line) |
45 | s->PutChar(ch: ':'); |
46 | } |
47 | if (line) { |
48 | s->Printf(format: "%u" , line); |
49 | if (column) { |
50 | s->PutChar(ch: ':'); |
51 | s->Printf(format: "%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, exe_scope: target, style, fallback_style)) |
67 | return false; |
68 | } |
69 | if (show_file) |
70 | *s << ", file = " << file; |
71 | if (line) |
72 | s->Printf(format: ", line = %u" , line); |
73 | if (column) |
74 | s->Printf(format: ", 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, exe_scope: target, style: Address::DumpStyleLoadAddress, |
100 | fallback_style: Address::DumpStyleFileAddress); |
101 | } else { |
102 | range.Dump(s, target, style: Address::DumpStyleLoadAddress, |
103 | fallback_style: Address::DumpStyleFileAddress); |
104 | } |
105 | |
106 | *s << ": " << file; |
107 | |
108 | if (line) { |
109 | s->Printf(format: ":%u" , line); |
110 | if (column) |
111 | s->Printf(format: ":%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, show_file: true, style: Address::DumpStyleLoadAddress, |
135 | fallback_style: Address::DumpStyleModuleWithFileAddress, show_range: true); |
136 | } |
137 | return true; |
138 | } |
139 | |
140 | bool lldb_private::operator<(const LineEntry &a, const LineEntry &b) { |
141 | return LineEntry::Compare(lhs: a, rhs: b) < 0; |
142 | } |
143 | |
144 | int LineEntry::Compare(const LineEntry &a, const LineEntry &b) { |
145 | int result = Address::CompareFileAddress(lhs: a.range.GetBaseAddress(), |
146 | rhs: 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(lhs: a.file, rhs: b.file, full: 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(offset: complete_line_range.GetByteSize()); |
193 | range_end.CalculateSymbolContext(sc: &next_line_sc, resolve_scope: 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(rhs_range: 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 | find_call_site: 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(rhs_range: 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 | orig_spec: original_file_sp->GetSpecOnly())) |
245 | file = *new_file_spec; |
246 | } |
247 | } |
248 | |