xref: /freebsd/contrib/llvm-project/lldb/source/Symbol/LineEntry.cpp (revision 480093f4440d54b30b3025afeac24b48f2ba7a2e)
10b57cec5SDimitry Andric //===-- LineEntry.cpp -------------------------------------------*- C++ -*-===//
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 
160b57cec5SDimitry Andric LineEntry::LineEntry()
170b57cec5SDimitry Andric     : range(), file(), line(LLDB_INVALID_LINE_NUMBER), column(0),
180b57cec5SDimitry Andric       is_start_of_statement(0), is_start_of_basic_block(0), is_prologue_end(0),
190b57cec5SDimitry Andric       is_epilogue_begin(0), is_terminal_entry(0) {}
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric LineEntry::LineEntry(const lldb::SectionSP &section_sp,
220b57cec5SDimitry Andric                      lldb::addr_t section_offset, lldb::addr_t byte_size,
230b57cec5SDimitry Andric                      const FileSpec &_file, uint32_t _line, uint16_t _column,
240b57cec5SDimitry Andric                      bool _is_start_of_statement, bool _is_start_of_basic_block,
250b57cec5SDimitry Andric                      bool _is_prologue_end, bool _is_epilogue_begin,
260b57cec5SDimitry Andric                      bool _is_terminal_entry)
270b57cec5SDimitry Andric     : range(section_sp, section_offset, byte_size), file(_file),
280b57cec5SDimitry Andric       original_file(_file), line(_line), column(_column),
290b57cec5SDimitry Andric       is_start_of_statement(_is_start_of_statement),
300b57cec5SDimitry Andric       is_start_of_basic_block(_is_start_of_basic_block),
310b57cec5SDimitry Andric       is_prologue_end(_is_prologue_end), is_epilogue_begin(_is_epilogue_begin),
320b57cec5SDimitry Andric       is_terminal_entry(_is_terminal_entry) {}
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric void LineEntry::Clear() {
350b57cec5SDimitry Andric   range.Clear();
360b57cec5SDimitry Andric   file.Clear();
370b57cec5SDimitry Andric   original_file.Clear();
380b57cec5SDimitry Andric   line = LLDB_INVALID_LINE_NUMBER;
390b57cec5SDimitry Andric   column = 0;
400b57cec5SDimitry Andric   is_start_of_statement = 0;
410b57cec5SDimitry Andric   is_start_of_basic_block = 0;
420b57cec5SDimitry Andric   is_prologue_end = 0;
430b57cec5SDimitry Andric   is_epilogue_begin = 0;
440b57cec5SDimitry Andric   is_terminal_entry = 0;
450b57cec5SDimitry Andric }
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric bool LineEntry::IsValid() const {
480b57cec5SDimitry Andric   return range.GetBaseAddress().IsValid() && line != LLDB_INVALID_LINE_NUMBER;
490b57cec5SDimitry Andric }
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric bool LineEntry::DumpStopContext(Stream *s, bool show_fullpaths) const {
520b57cec5SDimitry Andric   if (file) {
530b57cec5SDimitry Andric     if (show_fullpaths)
54*480093f4SDimitry Andric       file.Dump(s->AsRawOstream());
550b57cec5SDimitry Andric     else
560b57cec5SDimitry Andric       file.GetFilename().Dump(s);
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric     if (line)
590b57cec5SDimitry Andric       s->PutChar(':');
600b57cec5SDimitry Andric   }
610b57cec5SDimitry Andric   if (line) {
620b57cec5SDimitry Andric     s->Printf("%u", line);
630b57cec5SDimitry Andric     if (column) {
640b57cec5SDimitry Andric       s->PutChar(':');
650b57cec5SDimitry Andric       s->Printf("%u", column);
660b57cec5SDimitry Andric     }
670b57cec5SDimitry Andric   }
680b57cec5SDimitry Andric   return file || line;
690b57cec5SDimitry Andric }
700b57cec5SDimitry Andric 
710b57cec5SDimitry Andric bool LineEntry::Dump(Stream *s, Target *target, bool show_file,
720b57cec5SDimitry Andric                      Address::DumpStyle style,
730b57cec5SDimitry Andric                      Address::DumpStyle fallback_style, bool show_range) const {
740b57cec5SDimitry Andric   if (show_range) {
750b57cec5SDimitry Andric     // Show address range
760b57cec5SDimitry Andric     if (!range.Dump(s, target, style, fallback_style))
770b57cec5SDimitry Andric       return false;
780b57cec5SDimitry Andric   } else {
790b57cec5SDimitry Andric     // Show address only
800b57cec5SDimitry Andric     if (!range.GetBaseAddress().Dump(s, target, style, fallback_style))
810b57cec5SDimitry Andric       return false;
820b57cec5SDimitry Andric   }
830b57cec5SDimitry Andric   if (show_file)
840b57cec5SDimitry Andric     *s << ", file = " << file;
850b57cec5SDimitry Andric   if (line)
860b57cec5SDimitry Andric     s->Printf(", line = %u", line);
870b57cec5SDimitry Andric   if (column)
880b57cec5SDimitry Andric     s->Printf(", column = %u", column);
890b57cec5SDimitry Andric   if (is_start_of_statement)
900b57cec5SDimitry Andric     *s << ", is_start_of_statement = TRUE";
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric   if (is_start_of_basic_block)
930b57cec5SDimitry Andric     *s << ", is_start_of_basic_block = TRUE";
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric   if (is_prologue_end)
960b57cec5SDimitry Andric     *s << ", is_prologue_end = TRUE";
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric   if (is_epilogue_begin)
990b57cec5SDimitry Andric     *s << ", is_epilogue_begin = TRUE";
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric   if (is_terminal_entry)
1020b57cec5SDimitry Andric     *s << ", is_terminal_entry = TRUE";
1030b57cec5SDimitry Andric   return true;
1040b57cec5SDimitry Andric }
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric bool LineEntry::GetDescription(Stream *s, lldb::DescriptionLevel level,
1070b57cec5SDimitry Andric                                CompileUnit *cu, Target *target,
1080b57cec5SDimitry Andric                                bool show_address_only) const {
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric   if (level == lldb::eDescriptionLevelBrief ||
1110b57cec5SDimitry Andric       level == lldb::eDescriptionLevelFull) {
1120b57cec5SDimitry Andric     if (show_address_only) {
1130b57cec5SDimitry Andric       range.GetBaseAddress().Dump(s, target, Address::DumpStyleLoadAddress,
1140b57cec5SDimitry Andric                                   Address::DumpStyleFileAddress);
1150b57cec5SDimitry Andric     } else {
1160b57cec5SDimitry Andric       range.Dump(s, target, Address::DumpStyleLoadAddress,
1170b57cec5SDimitry Andric                  Address::DumpStyleFileAddress);
1180b57cec5SDimitry Andric     }
1190b57cec5SDimitry Andric 
1200b57cec5SDimitry Andric     *s << ": " << file;
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric     if (line) {
1230b57cec5SDimitry Andric       s->Printf(":%u", line);
1240b57cec5SDimitry Andric       if (column)
1250b57cec5SDimitry Andric         s->Printf(":%u", column);
1260b57cec5SDimitry Andric     }
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric     if (level == lldb::eDescriptionLevelFull) {
1290b57cec5SDimitry Andric       if (is_start_of_statement)
1300b57cec5SDimitry Andric         *s << ", is_start_of_statement = TRUE";
1310b57cec5SDimitry Andric 
1320b57cec5SDimitry Andric       if (is_start_of_basic_block)
1330b57cec5SDimitry Andric         *s << ", is_start_of_basic_block = TRUE";
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric       if (is_prologue_end)
1360b57cec5SDimitry Andric         *s << ", is_prologue_end = TRUE";
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric       if (is_epilogue_begin)
1390b57cec5SDimitry Andric         *s << ", is_epilogue_begin = TRUE";
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric       if (is_terminal_entry)
1420b57cec5SDimitry Andric         *s << ", is_terminal_entry = TRUE";
1430b57cec5SDimitry Andric     } else {
1440b57cec5SDimitry Andric       if (is_terminal_entry)
1450b57cec5SDimitry Andric         s->EOL();
1460b57cec5SDimitry Andric     }
1470b57cec5SDimitry Andric   } else {
1480b57cec5SDimitry Andric     return Dump(s, target, true, Address::DumpStyleLoadAddress,
1490b57cec5SDimitry Andric                 Address::DumpStyleModuleWithFileAddress, true);
1500b57cec5SDimitry Andric   }
1510b57cec5SDimitry Andric   return true;
1520b57cec5SDimitry Andric }
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric bool lldb_private::operator<(const LineEntry &a, const LineEntry &b) {
1550b57cec5SDimitry Andric   return LineEntry::Compare(a, b) < 0;
1560b57cec5SDimitry Andric }
1570b57cec5SDimitry Andric 
1580b57cec5SDimitry Andric int LineEntry::Compare(const LineEntry &a, const LineEntry &b) {
1590b57cec5SDimitry Andric   int result = Address::CompareFileAddress(a.range.GetBaseAddress(),
1600b57cec5SDimitry Andric                                            b.range.GetBaseAddress());
1610b57cec5SDimitry Andric   if (result != 0)
1620b57cec5SDimitry Andric     return result;
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric   const lldb::addr_t a_byte_size = a.range.GetByteSize();
1650b57cec5SDimitry Andric   const lldb::addr_t b_byte_size = b.range.GetByteSize();
1660b57cec5SDimitry Andric 
1670b57cec5SDimitry Andric   if (a_byte_size < b_byte_size)
1680b57cec5SDimitry Andric     return -1;
1690b57cec5SDimitry Andric   if (a_byte_size > b_byte_size)
1700b57cec5SDimitry Andric     return +1;
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric   // Check for an end sequence entry mismatch after we have determined that the
1730b57cec5SDimitry Andric   // address values are equal. If one of the items is an end sequence, we don't
1740b57cec5SDimitry Andric   // care about the line, file, or column info.
1750b57cec5SDimitry Andric   if (a.is_terminal_entry > b.is_terminal_entry)
1760b57cec5SDimitry Andric     return -1;
1770b57cec5SDimitry Andric   if (a.is_terminal_entry < b.is_terminal_entry)
1780b57cec5SDimitry Andric     return +1;
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric   if (a.line < b.line)
1810b57cec5SDimitry Andric     return -1;
1820b57cec5SDimitry Andric   if (a.line > b.line)
1830b57cec5SDimitry Andric     return +1;
1840b57cec5SDimitry Andric 
1850b57cec5SDimitry Andric   if (a.column < b.column)
1860b57cec5SDimitry Andric     return -1;
1870b57cec5SDimitry Andric   if (a.column > b.column)
1880b57cec5SDimitry Andric     return +1;
1890b57cec5SDimitry Andric 
1900b57cec5SDimitry Andric   return FileSpec::Compare(a.file, b.file, true);
1910b57cec5SDimitry Andric }
1920b57cec5SDimitry Andric 
1930b57cec5SDimitry Andric AddressRange LineEntry::GetSameLineContiguousAddressRange(
1940b57cec5SDimitry Andric     bool include_inlined_functions) const {
1950b57cec5SDimitry Andric   // Add each LineEntry's range to complete_line_range until we find a
1960b57cec5SDimitry Andric   // different file / line number.
1970b57cec5SDimitry Andric   AddressRange complete_line_range = range;
1980b57cec5SDimitry Andric   auto symbol_context_scope = lldb::eSymbolContextLineEntry;
1990b57cec5SDimitry Andric   Declaration start_call_site(original_file, line);
2000b57cec5SDimitry Andric   if (include_inlined_functions)
2010b57cec5SDimitry Andric     symbol_context_scope |= lldb::eSymbolContextBlock;
2020b57cec5SDimitry Andric 
2030b57cec5SDimitry Andric   while (true) {
2040b57cec5SDimitry Andric     SymbolContext next_line_sc;
2050b57cec5SDimitry Andric     Address range_end(complete_line_range.GetBaseAddress());
2060b57cec5SDimitry Andric     range_end.Slide(complete_line_range.GetByteSize());
2070b57cec5SDimitry Andric     range_end.CalculateSymbolContext(&next_line_sc, symbol_context_scope);
2080b57cec5SDimitry Andric 
2090b57cec5SDimitry Andric     if (!next_line_sc.line_entry.IsValid() ||
2100b57cec5SDimitry Andric         next_line_sc.line_entry.range.GetByteSize() == 0)
2110b57cec5SDimitry Andric       break;
2120b57cec5SDimitry Andric 
2130b57cec5SDimitry Andric     if (original_file == next_line_sc.line_entry.original_file &&
2140b57cec5SDimitry Andric         (next_line_sc.line_entry.line == 0 ||
2150b57cec5SDimitry Andric          line == next_line_sc.line_entry.line)) {
2160b57cec5SDimitry Andric       // Include any line 0 entries - they indicate that this is compiler-
2170b57cec5SDimitry Andric       // generated code that does not correspond to user source code.
2180b57cec5SDimitry Andric       // next_line_sc is the same file & line as this LineEntry, so extend
2190b57cec5SDimitry Andric       // our AddressRange by its size and continue to see if there are more
2200b57cec5SDimitry Andric       // LineEntries that we can combine. However, if there was nothing to
2210b57cec5SDimitry Andric       // extend we're done.
2220b57cec5SDimitry Andric       if (!complete_line_range.Extend(next_line_sc.line_entry.range))
2230b57cec5SDimitry Andric         break;
2240b57cec5SDimitry Andric       continue;
2250b57cec5SDimitry Andric     }
2260b57cec5SDimitry Andric 
2270b57cec5SDimitry Andric     if (include_inlined_functions && next_line_sc.block &&
2280b57cec5SDimitry Andric         next_line_sc.block->GetContainingInlinedBlock() != nullptr) {
2290b57cec5SDimitry Andric       // The next_line_sc might be in a different file if it's an inlined
2300b57cec5SDimitry Andric       // function. If this is the case then we still want to expand our line
2310b57cec5SDimitry Andric       // range to include them if the inlined function is at the same call site
2320b57cec5SDimitry Andric       // as this line entry. The current block could represent a nested inline
2330b57cec5SDimitry Andric       // function call so we need to need to check up the block tree to see if
2340b57cec5SDimitry Andric       // we find one.
2350b57cec5SDimitry Andric       auto inlined_parent_block =
2360b57cec5SDimitry Andric           next_line_sc.block->GetContainingInlinedBlockWithCallSite(
2370b57cec5SDimitry Andric               start_call_site);
2380b57cec5SDimitry Andric       if (!inlined_parent_block)
2390b57cec5SDimitry Andric         // We didn't find any parent inlined block with a call site at this line
2400b57cec5SDimitry Andric         // entry so this inlined function is probably at another line.
2410b57cec5SDimitry Andric         break;
2420b57cec5SDimitry Andric       // Extend our AddressRange by the size of the inlined block, but if there
2430b57cec5SDimitry Andric       // was nothing to add then we're done.
2440b57cec5SDimitry Andric       if (!complete_line_range.Extend(next_line_sc.line_entry.range))
2450b57cec5SDimitry Andric         break;
2460b57cec5SDimitry Andric       continue;
2470b57cec5SDimitry Andric     }
2480b57cec5SDimitry Andric 
2490b57cec5SDimitry Andric     break;
2500b57cec5SDimitry Andric   }
2510b57cec5SDimitry Andric   return complete_line_range;
2520b57cec5SDimitry Andric }
2530b57cec5SDimitry Andric 
2540b57cec5SDimitry Andric void LineEntry::ApplyFileMappings(lldb::TargetSP target_sp) {
2550b57cec5SDimitry Andric   if (target_sp) {
2560b57cec5SDimitry Andric     // Apply any file remappings to our file
2570b57cec5SDimitry Andric     FileSpec new_file_spec;
2580b57cec5SDimitry Andric     if (target_sp->GetSourcePathMap().FindFile(original_file, new_file_spec))
2590b57cec5SDimitry Andric       file = new_file_spec;
2600b57cec5SDimitry Andric   }
2610b57cec5SDimitry Andric }
262