15ffd83dbSDimitry Andric //===-- LineEntry.cpp -----------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "lldb/Symbol/LineEntry.h"
100b57cec5SDimitry Andric #include "lldb/Symbol/CompileUnit.h"
110b57cec5SDimitry Andric #include "lldb/Target/Process.h"
120b57cec5SDimitry Andric #include "lldb/Target/Target.h"
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric using namespace lldb_private;
150b57cec5SDimitry Andric
LineEntry()160b57cec5SDimitry Andric LineEntry::LineEntry()
17*0fca6ea1SDimitry Andric : range(), file_sp(std::make_shared<SupportFile>()),
18*0fca6ea1SDimitry Andric original_file_sp(std::make_shared<SupportFile>()),
19*0fca6ea1SDimitry Andric is_start_of_statement(0), is_start_of_basic_block(0), is_prologue_end(0),
20*0fca6ea1SDimitry Andric is_epilogue_begin(0), is_terminal_entry(0) {}
210b57cec5SDimitry Andric
Clear()220b57cec5SDimitry Andric void LineEntry::Clear() {
230b57cec5SDimitry Andric range.Clear();
24*0fca6ea1SDimitry Andric file_sp = std::make_shared<SupportFile>();
257a6dacacSDimitry Andric original_file_sp = std::make_shared<SupportFile>();
260b57cec5SDimitry Andric line = LLDB_INVALID_LINE_NUMBER;
270b57cec5SDimitry Andric column = 0;
280b57cec5SDimitry Andric is_start_of_statement = 0;
290b57cec5SDimitry Andric is_start_of_basic_block = 0;
300b57cec5SDimitry Andric is_prologue_end = 0;
310b57cec5SDimitry Andric is_epilogue_begin = 0;
320b57cec5SDimitry Andric is_terminal_entry = 0;
330b57cec5SDimitry Andric }
340b57cec5SDimitry Andric
IsValid() const350b57cec5SDimitry Andric bool LineEntry::IsValid() const {
360b57cec5SDimitry Andric return range.GetBaseAddress().IsValid() && line != LLDB_INVALID_LINE_NUMBER;
370b57cec5SDimitry Andric }
380b57cec5SDimitry Andric
DumpStopContext(Stream * s,bool show_fullpaths) const390b57cec5SDimitry Andric bool LineEntry::DumpStopContext(Stream *s, bool show_fullpaths) const {
40*0fca6ea1SDimitry Andric const FileSpec &file = file_sp->GetSpecOnly();
410b57cec5SDimitry Andric if (file) {
420b57cec5SDimitry Andric if (show_fullpaths)
43480093f4SDimitry Andric file.Dump(s->AsRawOstream());
440b57cec5SDimitry Andric else
450b57cec5SDimitry Andric file.GetFilename().Dump(s);
460b57cec5SDimitry Andric
470b57cec5SDimitry Andric if (line)
480b57cec5SDimitry Andric s->PutChar(':');
490b57cec5SDimitry Andric }
500b57cec5SDimitry Andric if (line) {
510b57cec5SDimitry Andric s->Printf("%u", line);
520b57cec5SDimitry Andric if (column) {
530b57cec5SDimitry Andric s->PutChar(':');
540b57cec5SDimitry Andric s->Printf("%u", column);
550b57cec5SDimitry Andric }
560b57cec5SDimitry Andric }
570b57cec5SDimitry Andric return file || line;
580b57cec5SDimitry Andric }
590b57cec5SDimitry Andric
Dump(Stream * s,Target * target,bool show_file,Address::DumpStyle style,Address::DumpStyle fallback_style,bool show_range) const600b57cec5SDimitry Andric bool LineEntry::Dump(Stream *s, Target *target, bool show_file,
610b57cec5SDimitry Andric Address::DumpStyle style,
620b57cec5SDimitry Andric Address::DumpStyle fallback_style, bool show_range) const {
630b57cec5SDimitry Andric if (show_range) {
640b57cec5SDimitry Andric // Show address range
650b57cec5SDimitry Andric if (!range.Dump(s, target, style, fallback_style))
660b57cec5SDimitry Andric return false;
670b57cec5SDimitry Andric } else {
680b57cec5SDimitry Andric // Show address only
690b57cec5SDimitry Andric if (!range.GetBaseAddress().Dump(s, target, style, fallback_style))
700b57cec5SDimitry Andric return false;
710b57cec5SDimitry Andric }
720b57cec5SDimitry Andric if (show_file)
73*0fca6ea1SDimitry Andric *s << ", file = " << GetFile();
740b57cec5SDimitry Andric if (line)
750b57cec5SDimitry Andric s->Printf(", line = %u", line);
760b57cec5SDimitry Andric if (column)
770b57cec5SDimitry Andric s->Printf(", column = %u", column);
780b57cec5SDimitry Andric if (is_start_of_statement)
790b57cec5SDimitry Andric *s << ", is_start_of_statement = TRUE";
800b57cec5SDimitry Andric
810b57cec5SDimitry Andric if (is_start_of_basic_block)
820b57cec5SDimitry Andric *s << ", is_start_of_basic_block = TRUE";
830b57cec5SDimitry Andric
840b57cec5SDimitry Andric if (is_prologue_end)
850b57cec5SDimitry Andric *s << ", is_prologue_end = TRUE";
860b57cec5SDimitry Andric
870b57cec5SDimitry Andric if (is_epilogue_begin)
880b57cec5SDimitry Andric *s << ", is_epilogue_begin = TRUE";
890b57cec5SDimitry Andric
900b57cec5SDimitry Andric if (is_terminal_entry)
910b57cec5SDimitry Andric *s << ", is_terminal_entry = TRUE";
920b57cec5SDimitry Andric return true;
930b57cec5SDimitry Andric }
940b57cec5SDimitry Andric
GetDescription(Stream * s,lldb::DescriptionLevel level,CompileUnit * cu,Target * target,bool show_address_only) const950b57cec5SDimitry Andric bool LineEntry::GetDescription(Stream *s, lldb::DescriptionLevel level,
960b57cec5SDimitry Andric CompileUnit *cu, Target *target,
970b57cec5SDimitry Andric bool show_address_only) const {
980b57cec5SDimitry Andric
990b57cec5SDimitry Andric if (level == lldb::eDescriptionLevelBrief ||
1000b57cec5SDimitry Andric level == lldb::eDescriptionLevelFull) {
1010b57cec5SDimitry Andric if (show_address_only) {
1020b57cec5SDimitry Andric range.GetBaseAddress().Dump(s, target, Address::DumpStyleLoadAddress,
1030b57cec5SDimitry Andric Address::DumpStyleFileAddress);
1040b57cec5SDimitry Andric } else {
1050b57cec5SDimitry Andric range.Dump(s, target, Address::DumpStyleLoadAddress,
1060b57cec5SDimitry Andric Address::DumpStyleFileAddress);
1070b57cec5SDimitry Andric }
1080b57cec5SDimitry Andric
109*0fca6ea1SDimitry Andric *s << ": " << GetFile();
1100b57cec5SDimitry Andric
1110b57cec5SDimitry Andric if (line) {
1120b57cec5SDimitry Andric s->Printf(":%u", line);
1130b57cec5SDimitry Andric if (column)
1140b57cec5SDimitry Andric s->Printf(":%u", column);
1150b57cec5SDimitry Andric }
1160b57cec5SDimitry Andric
1170b57cec5SDimitry Andric if (level == lldb::eDescriptionLevelFull) {
1180b57cec5SDimitry Andric if (is_start_of_statement)
1190b57cec5SDimitry Andric *s << ", is_start_of_statement = TRUE";
1200b57cec5SDimitry Andric
1210b57cec5SDimitry Andric if (is_start_of_basic_block)
1220b57cec5SDimitry Andric *s << ", is_start_of_basic_block = TRUE";
1230b57cec5SDimitry Andric
1240b57cec5SDimitry Andric if (is_prologue_end)
1250b57cec5SDimitry Andric *s << ", is_prologue_end = TRUE";
1260b57cec5SDimitry Andric
1270b57cec5SDimitry Andric if (is_epilogue_begin)
1280b57cec5SDimitry Andric *s << ", is_epilogue_begin = TRUE";
1290b57cec5SDimitry Andric
1300b57cec5SDimitry Andric if (is_terminal_entry)
1310b57cec5SDimitry Andric *s << ", is_terminal_entry = TRUE";
1320b57cec5SDimitry Andric } else {
1330b57cec5SDimitry Andric if (is_terminal_entry)
1340b57cec5SDimitry Andric s->EOL();
1350b57cec5SDimitry Andric }
1360b57cec5SDimitry Andric } else {
1370b57cec5SDimitry Andric return Dump(s, target, true, Address::DumpStyleLoadAddress,
1380b57cec5SDimitry Andric Address::DumpStyleModuleWithFileAddress, true);
1390b57cec5SDimitry Andric }
1400b57cec5SDimitry Andric return true;
1410b57cec5SDimitry Andric }
1420b57cec5SDimitry Andric
operator <(const LineEntry & a,const LineEntry & b)1430b57cec5SDimitry Andric bool lldb_private::operator<(const LineEntry &a, const LineEntry &b) {
1440b57cec5SDimitry Andric return LineEntry::Compare(a, b) < 0;
1450b57cec5SDimitry Andric }
1460b57cec5SDimitry Andric
Compare(const LineEntry & a,const LineEntry & b)1470b57cec5SDimitry Andric int LineEntry::Compare(const LineEntry &a, const LineEntry &b) {
1480b57cec5SDimitry Andric int result = Address::CompareFileAddress(a.range.GetBaseAddress(),
1490b57cec5SDimitry Andric b.range.GetBaseAddress());
1500b57cec5SDimitry Andric if (result != 0)
1510b57cec5SDimitry Andric return result;
1520b57cec5SDimitry Andric
1530b57cec5SDimitry Andric const lldb::addr_t a_byte_size = a.range.GetByteSize();
1540b57cec5SDimitry Andric const lldb::addr_t b_byte_size = b.range.GetByteSize();
1550b57cec5SDimitry Andric
1560b57cec5SDimitry Andric if (a_byte_size < b_byte_size)
1570b57cec5SDimitry Andric return -1;
1580b57cec5SDimitry Andric if (a_byte_size > b_byte_size)
1590b57cec5SDimitry Andric return +1;
1600b57cec5SDimitry Andric
1610b57cec5SDimitry Andric // Check for an end sequence entry mismatch after we have determined that the
1620b57cec5SDimitry Andric // address values are equal. If one of the items is an end sequence, we don't
1630b57cec5SDimitry Andric // care about the line, file, or column info.
1640b57cec5SDimitry Andric if (a.is_terminal_entry > b.is_terminal_entry)
1650b57cec5SDimitry Andric return -1;
1660b57cec5SDimitry Andric if (a.is_terminal_entry < b.is_terminal_entry)
1670b57cec5SDimitry Andric return +1;
1680b57cec5SDimitry Andric
1690b57cec5SDimitry Andric if (a.line < b.line)
1700b57cec5SDimitry Andric return -1;
1710b57cec5SDimitry Andric if (a.line > b.line)
1720b57cec5SDimitry Andric return +1;
1730b57cec5SDimitry Andric
1740b57cec5SDimitry Andric if (a.column < b.column)
1750b57cec5SDimitry Andric return -1;
1760b57cec5SDimitry Andric if (a.column > b.column)
1770b57cec5SDimitry Andric return +1;
1780b57cec5SDimitry Andric
179*0fca6ea1SDimitry Andric return FileSpec::Compare(a.GetFile(), b.GetFile(), true);
1800b57cec5SDimitry Andric }
1810b57cec5SDimitry Andric
GetSameLineContiguousAddressRange(bool include_inlined_functions) const1820b57cec5SDimitry Andric AddressRange LineEntry::GetSameLineContiguousAddressRange(
1830b57cec5SDimitry Andric bool include_inlined_functions) const {
1840b57cec5SDimitry Andric // Add each LineEntry's range to complete_line_range until we find a
1850b57cec5SDimitry Andric // different file / line number.
1860b57cec5SDimitry Andric AddressRange complete_line_range = range;
1870b57cec5SDimitry Andric auto symbol_context_scope = lldb::eSymbolContextLineEntry;
1887a6dacacSDimitry Andric Declaration start_call_site(original_file_sp->GetSpecOnly(), line);
1890b57cec5SDimitry Andric if (include_inlined_functions)
1900b57cec5SDimitry Andric symbol_context_scope |= lldb::eSymbolContextBlock;
1910b57cec5SDimitry Andric
1920b57cec5SDimitry Andric while (true) {
1930b57cec5SDimitry Andric SymbolContext next_line_sc;
1940b57cec5SDimitry Andric Address range_end(complete_line_range.GetBaseAddress());
1950b57cec5SDimitry Andric range_end.Slide(complete_line_range.GetByteSize());
1960b57cec5SDimitry Andric range_end.CalculateSymbolContext(&next_line_sc, symbol_context_scope);
1970b57cec5SDimitry Andric
1980b57cec5SDimitry Andric if (!next_line_sc.line_entry.IsValid() ||
1990b57cec5SDimitry Andric next_line_sc.line_entry.range.GetByteSize() == 0)
2000b57cec5SDimitry Andric break;
2010b57cec5SDimitry Andric
202*0fca6ea1SDimitry Andric if (original_file_sp->Equal(*next_line_sc.line_entry.original_file_sp,
203*0fca6ea1SDimitry Andric SupportFile::eEqualFileSpecAndChecksumIfSet) &&
2040b57cec5SDimitry Andric (next_line_sc.line_entry.line == 0 ||
2050b57cec5SDimitry Andric line == next_line_sc.line_entry.line)) {
2060b57cec5SDimitry Andric // Include any line 0 entries - they indicate that this is compiler-
2070b57cec5SDimitry Andric // generated code that does not correspond to user source code.
2080b57cec5SDimitry Andric // next_line_sc is the same file & line as this LineEntry, so extend
2090b57cec5SDimitry Andric // our AddressRange by its size and continue to see if there are more
2100b57cec5SDimitry Andric // LineEntries that we can combine. However, if there was nothing to
2110b57cec5SDimitry Andric // extend we're done.
2120b57cec5SDimitry Andric if (!complete_line_range.Extend(next_line_sc.line_entry.range))
2130b57cec5SDimitry Andric break;
2140b57cec5SDimitry Andric continue;
2150b57cec5SDimitry Andric }
2160b57cec5SDimitry Andric
2170b57cec5SDimitry Andric if (include_inlined_functions && next_line_sc.block &&
2180b57cec5SDimitry Andric next_line_sc.block->GetContainingInlinedBlock() != nullptr) {
2190b57cec5SDimitry Andric // The next_line_sc might be in a different file if it's an inlined
2200b57cec5SDimitry Andric // function. If this is the case then we still want to expand our line
2210b57cec5SDimitry Andric // range to include them if the inlined function is at the same call site
2220b57cec5SDimitry Andric // as this line entry. The current block could represent a nested inline
2230b57cec5SDimitry Andric // function call so we need to need to check up the block tree to see if
2240b57cec5SDimitry Andric // we find one.
2250b57cec5SDimitry Andric auto inlined_parent_block =
2260b57cec5SDimitry Andric next_line_sc.block->GetContainingInlinedBlockWithCallSite(
2270b57cec5SDimitry Andric start_call_site);
2280b57cec5SDimitry Andric if (!inlined_parent_block)
2290b57cec5SDimitry Andric // We didn't find any parent inlined block with a call site at this line
2300b57cec5SDimitry Andric // entry so this inlined function is probably at another line.
2310b57cec5SDimitry Andric break;
2320b57cec5SDimitry Andric // Extend our AddressRange by the size of the inlined block, but if there
2330b57cec5SDimitry Andric // was nothing to add then we're done.
2340b57cec5SDimitry Andric if (!complete_line_range.Extend(next_line_sc.line_entry.range))
2350b57cec5SDimitry Andric break;
2360b57cec5SDimitry Andric continue;
2370b57cec5SDimitry Andric }
2380b57cec5SDimitry Andric
2390b57cec5SDimitry Andric break;
2400b57cec5SDimitry Andric }
2410b57cec5SDimitry Andric return complete_line_range;
2420b57cec5SDimitry Andric }
2430b57cec5SDimitry Andric
ApplyFileMappings(lldb::TargetSP target_sp)2440b57cec5SDimitry Andric void LineEntry::ApplyFileMappings(lldb::TargetSP target_sp) {
2450b57cec5SDimitry Andric if (target_sp) {
246fe6060f1SDimitry Andric // Apply any file remappings to our file.
2477a6dacacSDimitry Andric if (auto new_file_spec = target_sp->GetSourcePathMap().FindFile(
248*0fca6ea1SDimitry Andric original_file_sp->GetSpecOnly())) {
249*0fca6ea1SDimitry Andric file_sp = std::make_shared<SupportFile>(*new_file_spec,
250*0fca6ea1SDimitry Andric original_file_sp->GetChecksum());
251*0fca6ea1SDimitry Andric }
2520b57cec5SDimitry Andric }
2530b57cec5SDimitry Andric }
254