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