1dda28197Spatrick //===-- LineEntry.cpp -----------------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "lldb/Symbol/LineEntry.h"
10061da546Spatrick #include "lldb/Symbol/CompileUnit.h"
11061da546Spatrick #include "lldb/Target/Process.h"
12061da546Spatrick #include "lldb/Target/Target.h"
13061da546Spatrick
14061da546Spatrick using namespace lldb_private;
15061da546Spatrick
LineEntry()16061da546Spatrick LineEntry::LineEntry()
17*be691f3bSpatrick : range(), file(), is_start_of_statement(0), is_start_of_basic_block(0),
18*be691f3bSpatrick is_prologue_end(0), is_epilogue_begin(0), is_terminal_entry(0) {}
19061da546Spatrick
LineEntry(const lldb::SectionSP & section_sp,lldb::addr_t section_offset,lldb::addr_t byte_size,const FileSpec & _file,uint32_t _line,uint16_t _column,bool _is_start_of_statement,bool _is_start_of_basic_block,bool _is_prologue_end,bool _is_epilogue_begin,bool _is_terminal_entry)20061da546Spatrick LineEntry::LineEntry(const lldb::SectionSP §ion_sp,
21061da546Spatrick lldb::addr_t section_offset, lldb::addr_t byte_size,
22061da546Spatrick const FileSpec &_file, uint32_t _line, uint16_t _column,
23061da546Spatrick bool _is_start_of_statement, bool _is_start_of_basic_block,
24061da546Spatrick bool _is_prologue_end, bool _is_epilogue_begin,
25061da546Spatrick bool _is_terminal_entry)
26061da546Spatrick : range(section_sp, section_offset, byte_size), file(_file),
27061da546Spatrick original_file(_file), line(_line), column(_column),
28061da546Spatrick is_start_of_statement(_is_start_of_statement),
29061da546Spatrick is_start_of_basic_block(_is_start_of_basic_block),
30061da546Spatrick is_prologue_end(_is_prologue_end), is_epilogue_begin(_is_epilogue_begin),
31061da546Spatrick is_terminal_entry(_is_terminal_entry) {}
32061da546Spatrick
Clear()33061da546Spatrick void LineEntry::Clear() {
34061da546Spatrick range.Clear();
35061da546Spatrick file.Clear();
36061da546Spatrick original_file.Clear();
37061da546Spatrick line = LLDB_INVALID_LINE_NUMBER;
38061da546Spatrick column = 0;
39061da546Spatrick is_start_of_statement = 0;
40061da546Spatrick is_start_of_basic_block = 0;
41061da546Spatrick is_prologue_end = 0;
42061da546Spatrick is_epilogue_begin = 0;
43061da546Spatrick is_terminal_entry = 0;
44061da546Spatrick }
45061da546Spatrick
IsValid() const46061da546Spatrick bool LineEntry::IsValid() const {
47061da546Spatrick return range.GetBaseAddress().IsValid() && line != LLDB_INVALID_LINE_NUMBER;
48061da546Spatrick }
49061da546Spatrick
DumpStopContext(Stream * s,bool show_fullpaths) const50061da546Spatrick bool LineEntry::DumpStopContext(Stream *s, bool show_fullpaths) const {
51061da546Spatrick if (file) {
52061da546Spatrick if (show_fullpaths)
53061da546Spatrick file.Dump(s->AsRawOstream());
54061da546Spatrick else
55061da546Spatrick file.GetFilename().Dump(s);
56061da546Spatrick
57061da546Spatrick if (line)
58061da546Spatrick s->PutChar(':');
59061da546Spatrick }
60061da546Spatrick if (line) {
61061da546Spatrick s->Printf("%u", line);
62061da546Spatrick if (column) {
63061da546Spatrick s->PutChar(':');
64061da546Spatrick s->Printf("%u", column);
65061da546Spatrick }
66061da546Spatrick }
67061da546Spatrick return file || line;
68061da546Spatrick }
69061da546Spatrick
Dump(Stream * s,Target * target,bool show_file,Address::DumpStyle style,Address::DumpStyle fallback_style,bool show_range) const70061da546Spatrick bool LineEntry::Dump(Stream *s, Target *target, bool show_file,
71061da546Spatrick Address::DumpStyle style,
72061da546Spatrick Address::DumpStyle fallback_style, bool show_range) const {
73061da546Spatrick if (show_range) {
74061da546Spatrick // Show address range
75061da546Spatrick if (!range.Dump(s, target, style, fallback_style))
76061da546Spatrick return false;
77061da546Spatrick } else {
78061da546Spatrick // Show address only
79061da546Spatrick if (!range.GetBaseAddress().Dump(s, target, style, fallback_style))
80061da546Spatrick return false;
81061da546Spatrick }
82061da546Spatrick if (show_file)
83061da546Spatrick *s << ", file = " << file;
84061da546Spatrick if (line)
85061da546Spatrick s->Printf(", line = %u", line);
86061da546Spatrick if (column)
87061da546Spatrick s->Printf(", column = %u", column);
88061da546Spatrick if (is_start_of_statement)
89061da546Spatrick *s << ", is_start_of_statement = TRUE";
90061da546Spatrick
91061da546Spatrick if (is_start_of_basic_block)
92061da546Spatrick *s << ", is_start_of_basic_block = TRUE";
93061da546Spatrick
94061da546Spatrick if (is_prologue_end)
95061da546Spatrick *s << ", is_prologue_end = TRUE";
96061da546Spatrick
97061da546Spatrick if (is_epilogue_begin)
98061da546Spatrick *s << ", is_epilogue_begin = TRUE";
99061da546Spatrick
100061da546Spatrick if (is_terminal_entry)
101061da546Spatrick *s << ", is_terminal_entry = TRUE";
102061da546Spatrick return true;
103061da546Spatrick }
104061da546Spatrick
GetDescription(Stream * s,lldb::DescriptionLevel level,CompileUnit * cu,Target * target,bool show_address_only) const105061da546Spatrick bool LineEntry::GetDescription(Stream *s, lldb::DescriptionLevel level,
106061da546Spatrick CompileUnit *cu, Target *target,
107061da546Spatrick bool show_address_only) const {
108061da546Spatrick
109061da546Spatrick if (level == lldb::eDescriptionLevelBrief ||
110061da546Spatrick level == lldb::eDescriptionLevelFull) {
111061da546Spatrick if (show_address_only) {
112061da546Spatrick range.GetBaseAddress().Dump(s, target, Address::DumpStyleLoadAddress,
113061da546Spatrick Address::DumpStyleFileAddress);
114061da546Spatrick } else {
115061da546Spatrick range.Dump(s, target, Address::DumpStyleLoadAddress,
116061da546Spatrick Address::DumpStyleFileAddress);
117061da546Spatrick }
118061da546Spatrick
119061da546Spatrick *s << ": " << file;
120061da546Spatrick
121061da546Spatrick if (line) {
122061da546Spatrick s->Printf(":%u", line);
123061da546Spatrick if (column)
124061da546Spatrick s->Printf(":%u", column);
125061da546Spatrick }
126061da546Spatrick
127061da546Spatrick if (level == lldb::eDescriptionLevelFull) {
128061da546Spatrick if (is_start_of_statement)
129061da546Spatrick *s << ", is_start_of_statement = TRUE";
130061da546Spatrick
131061da546Spatrick if (is_start_of_basic_block)
132061da546Spatrick *s << ", is_start_of_basic_block = TRUE";
133061da546Spatrick
134061da546Spatrick if (is_prologue_end)
135061da546Spatrick *s << ", is_prologue_end = TRUE";
136061da546Spatrick
137061da546Spatrick if (is_epilogue_begin)
138061da546Spatrick *s << ", is_epilogue_begin = TRUE";
139061da546Spatrick
140061da546Spatrick if (is_terminal_entry)
141061da546Spatrick *s << ", is_terminal_entry = TRUE";
142061da546Spatrick } else {
143061da546Spatrick if (is_terminal_entry)
144061da546Spatrick s->EOL();
145061da546Spatrick }
146061da546Spatrick } else {
147061da546Spatrick return Dump(s, target, true, Address::DumpStyleLoadAddress,
148061da546Spatrick Address::DumpStyleModuleWithFileAddress, true);
149061da546Spatrick }
150061da546Spatrick return true;
151061da546Spatrick }
152061da546Spatrick
operator <(const LineEntry & a,const LineEntry & b)153061da546Spatrick bool lldb_private::operator<(const LineEntry &a, const LineEntry &b) {
154061da546Spatrick return LineEntry::Compare(a, b) < 0;
155061da546Spatrick }
156061da546Spatrick
Compare(const LineEntry & a,const LineEntry & b)157061da546Spatrick int LineEntry::Compare(const LineEntry &a, const LineEntry &b) {
158061da546Spatrick int result = Address::CompareFileAddress(a.range.GetBaseAddress(),
159061da546Spatrick b.range.GetBaseAddress());
160061da546Spatrick if (result != 0)
161061da546Spatrick return result;
162061da546Spatrick
163061da546Spatrick const lldb::addr_t a_byte_size = a.range.GetByteSize();
164061da546Spatrick const lldb::addr_t b_byte_size = b.range.GetByteSize();
165061da546Spatrick
166061da546Spatrick if (a_byte_size < b_byte_size)
167061da546Spatrick return -1;
168061da546Spatrick if (a_byte_size > b_byte_size)
169061da546Spatrick return +1;
170061da546Spatrick
171061da546Spatrick // Check for an end sequence entry mismatch after we have determined that the
172061da546Spatrick // address values are equal. If one of the items is an end sequence, we don't
173061da546Spatrick // care about the line, file, or column info.
174061da546Spatrick if (a.is_terminal_entry > b.is_terminal_entry)
175061da546Spatrick return -1;
176061da546Spatrick if (a.is_terminal_entry < b.is_terminal_entry)
177061da546Spatrick return +1;
178061da546Spatrick
179061da546Spatrick if (a.line < b.line)
180061da546Spatrick return -1;
181061da546Spatrick if (a.line > b.line)
182061da546Spatrick return +1;
183061da546Spatrick
184061da546Spatrick if (a.column < b.column)
185061da546Spatrick return -1;
186061da546Spatrick if (a.column > b.column)
187061da546Spatrick return +1;
188061da546Spatrick
189061da546Spatrick return FileSpec::Compare(a.file, b.file, true);
190061da546Spatrick }
191061da546Spatrick
GetSameLineContiguousAddressRange(bool include_inlined_functions) const192061da546Spatrick AddressRange LineEntry::GetSameLineContiguousAddressRange(
193061da546Spatrick bool include_inlined_functions) const {
194061da546Spatrick // Add each LineEntry's range to complete_line_range until we find a
195061da546Spatrick // different file / line number.
196061da546Spatrick AddressRange complete_line_range = range;
197061da546Spatrick auto symbol_context_scope = lldb::eSymbolContextLineEntry;
198061da546Spatrick Declaration start_call_site(original_file, line);
199061da546Spatrick if (include_inlined_functions)
200061da546Spatrick symbol_context_scope |= lldb::eSymbolContextBlock;
201061da546Spatrick
202061da546Spatrick while (true) {
203061da546Spatrick SymbolContext next_line_sc;
204061da546Spatrick Address range_end(complete_line_range.GetBaseAddress());
205061da546Spatrick range_end.Slide(complete_line_range.GetByteSize());
206061da546Spatrick range_end.CalculateSymbolContext(&next_line_sc, symbol_context_scope);
207061da546Spatrick
208061da546Spatrick if (!next_line_sc.line_entry.IsValid() ||
209061da546Spatrick next_line_sc.line_entry.range.GetByteSize() == 0)
210061da546Spatrick break;
211061da546Spatrick
212061da546Spatrick if (original_file == next_line_sc.line_entry.original_file &&
213061da546Spatrick (next_line_sc.line_entry.line == 0 ||
214061da546Spatrick line == next_line_sc.line_entry.line)) {
215061da546Spatrick // Include any line 0 entries - they indicate that this is compiler-
216061da546Spatrick // generated code that does not correspond to user source code.
217061da546Spatrick // next_line_sc is the same file & line as this LineEntry, so extend
218061da546Spatrick // our AddressRange by its size and continue to see if there are more
219061da546Spatrick // LineEntries that we can combine. However, if there was nothing to
220061da546Spatrick // extend we're done.
221061da546Spatrick if (!complete_line_range.Extend(next_line_sc.line_entry.range))
222061da546Spatrick break;
223061da546Spatrick continue;
224061da546Spatrick }
225061da546Spatrick
226061da546Spatrick if (include_inlined_functions && next_line_sc.block &&
227061da546Spatrick next_line_sc.block->GetContainingInlinedBlock() != nullptr) {
228061da546Spatrick // The next_line_sc might be in a different file if it's an inlined
229061da546Spatrick // function. If this is the case then we still want to expand our line
230061da546Spatrick // range to include them if the inlined function is at the same call site
231061da546Spatrick // as this line entry. The current block could represent a nested inline
232061da546Spatrick // function call so we need to need to check up the block tree to see if
233061da546Spatrick // we find one.
234061da546Spatrick auto inlined_parent_block =
235061da546Spatrick next_line_sc.block->GetContainingInlinedBlockWithCallSite(
236061da546Spatrick start_call_site);
237061da546Spatrick if (!inlined_parent_block)
238061da546Spatrick // We didn't find any parent inlined block with a call site at this line
239061da546Spatrick // entry so this inlined function is probably at another line.
240061da546Spatrick break;
241061da546Spatrick // Extend our AddressRange by the size of the inlined block, but if there
242061da546Spatrick // was nothing to add then we're done.
243061da546Spatrick if (!complete_line_range.Extend(next_line_sc.line_entry.range))
244061da546Spatrick break;
245061da546Spatrick continue;
246061da546Spatrick }
247061da546Spatrick
248061da546Spatrick break;
249061da546Spatrick }
250061da546Spatrick return complete_line_range;
251061da546Spatrick }
252061da546Spatrick
ApplyFileMappings(lldb::TargetSP target_sp)253061da546Spatrick void LineEntry::ApplyFileMappings(lldb::TargetSP target_sp) {
254061da546Spatrick if (target_sp) {
255*be691f3bSpatrick // Apply any file remappings to our file.
256*be691f3bSpatrick if (auto new_file_spec =
257*be691f3bSpatrick target_sp->GetSourcePathMap().FindFile(original_file))
258*be691f3bSpatrick file = *new_file_spec;
259061da546Spatrick }
260061da546Spatrick }
261