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 §ion_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