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