//===-- LineEntry.cpp -------------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "lldb/Symbol/LineEntry.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" using namespace lldb_private; LineEntry::LineEntry() : range(), file(), line(LLDB_INVALID_LINE_NUMBER), column(0), is_start_of_statement(0), is_start_of_basic_block(0), is_prologue_end(0), is_epilogue_begin(0), is_terminal_entry(0) {} LineEntry::LineEntry(const lldb::SectionSP §ion_sp, lldb::addr_t section_offset, lldb::addr_t byte_size, const FileSpec &_file, uint32_t _line, uint16_t _column, bool _is_start_of_statement, bool _is_start_of_basic_block, bool _is_prologue_end, bool _is_epilogue_begin, bool _is_terminal_entry) : range(section_sp, section_offset, byte_size), file(_file), original_file(_file), line(_line), column(_column), is_start_of_statement(_is_start_of_statement), is_start_of_basic_block(_is_start_of_basic_block), is_prologue_end(_is_prologue_end), is_epilogue_begin(_is_epilogue_begin), is_terminal_entry(_is_terminal_entry) {} void LineEntry::Clear() { range.Clear(); file.Clear(); original_file.Clear(); line = LLDB_INVALID_LINE_NUMBER; column = 0; is_start_of_statement = 0; is_start_of_basic_block = 0; is_prologue_end = 0; is_epilogue_begin = 0; is_terminal_entry = 0; } bool LineEntry::IsValid() const { return range.GetBaseAddress().IsValid() && line != LLDB_INVALID_LINE_NUMBER; } bool LineEntry::DumpStopContext(Stream *s, bool show_fullpaths) const { if (file) { if (show_fullpaths) file.Dump(s->AsRawOstream()); else file.GetFilename().Dump(s); if (line) s->PutChar(':'); } if (line) { s->Printf("%u", line); if (column) { s->PutChar(':'); s->Printf("%u", column); } } return file || line; } bool LineEntry::Dump(Stream *s, Target *target, bool show_file, Address::DumpStyle style, Address::DumpStyle fallback_style, bool show_range) const { if (show_range) { // Show address range if (!range.Dump(s, target, style, fallback_style)) return false; } else { // Show address only if (!range.GetBaseAddress().Dump(s, target, style, fallback_style)) return false; } if (show_file) *s << ", file = " << file; if (line) s->Printf(", line = %u", line); if (column) s->Printf(", column = %u", column); if (is_start_of_statement) *s << ", is_start_of_statement = TRUE"; if (is_start_of_basic_block) *s << ", is_start_of_basic_block = TRUE"; if (is_prologue_end) *s << ", is_prologue_end = TRUE"; if (is_epilogue_begin) *s << ", is_epilogue_begin = TRUE"; if (is_terminal_entry) *s << ", is_terminal_entry = TRUE"; return true; } bool LineEntry::GetDescription(Stream *s, lldb::DescriptionLevel level, CompileUnit *cu, Target *target, bool show_address_only) const { if (level == lldb::eDescriptionLevelBrief || level == lldb::eDescriptionLevelFull) { if (show_address_only) { range.GetBaseAddress().Dump(s, target, Address::DumpStyleLoadAddress, Address::DumpStyleFileAddress); } else { range.Dump(s, target, Address::DumpStyleLoadAddress, Address::DumpStyleFileAddress); } *s << ": " << file; if (line) { s->Printf(":%u", line); if (column) s->Printf(":%u", column); } if (level == lldb::eDescriptionLevelFull) { if (is_start_of_statement) *s << ", is_start_of_statement = TRUE"; if (is_start_of_basic_block) *s << ", is_start_of_basic_block = TRUE"; if (is_prologue_end) *s << ", is_prologue_end = TRUE"; if (is_epilogue_begin) *s << ", is_epilogue_begin = TRUE"; if (is_terminal_entry) *s << ", is_terminal_entry = TRUE"; } else { if (is_terminal_entry) s->EOL(); } } else { return Dump(s, target, true, Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress, true); } return true; } bool lldb_private::operator<(const LineEntry &a, const LineEntry &b) { return LineEntry::Compare(a, b) < 0; } int LineEntry::Compare(const LineEntry &a, const LineEntry &b) { int result = Address::CompareFileAddress(a.range.GetBaseAddress(), b.range.GetBaseAddress()); if (result != 0) return result; const lldb::addr_t a_byte_size = a.range.GetByteSize(); const lldb::addr_t b_byte_size = b.range.GetByteSize(); if (a_byte_size < b_byte_size) return -1; if (a_byte_size > b_byte_size) return +1; // Check for an end sequence entry mismatch after we have determined that the // address values are equal. If one of the items is an end sequence, we don't // care about the line, file, or column info. if (a.is_terminal_entry > b.is_terminal_entry) return -1; if (a.is_terminal_entry < b.is_terminal_entry) return +1; if (a.line < b.line) return -1; if (a.line > b.line) return +1; if (a.column < b.column) return -1; if (a.column > b.column) return +1; return FileSpec::Compare(a.file, b.file, true); } AddressRange LineEntry::GetSameLineContiguousAddressRange( bool include_inlined_functions) const { // Add each LineEntry's range to complete_line_range until we find a // different file / line number. AddressRange complete_line_range = range; auto symbol_context_scope = lldb::eSymbolContextLineEntry; Declaration start_call_site(original_file, line); if (include_inlined_functions) symbol_context_scope |= lldb::eSymbolContextBlock; while (true) { SymbolContext next_line_sc; Address range_end(complete_line_range.GetBaseAddress()); range_end.Slide(complete_line_range.GetByteSize()); range_end.CalculateSymbolContext(&next_line_sc, symbol_context_scope); if (!next_line_sc.line_entry.IsValid() || next_line_sc.line_entry.range.GetByteSize() == 0) break; if (original_file == next_line_sc.line_entry.original_file && (next_line_sc.line_entry.line == 0 || line == next_line_sc.line_entry.line)) { // Include any line 0 entries - they indicate that this is compiler- // generated code that does not correspond to user source code. // next_line_sc is the same file & line as this LineEntry, so extend // our AddressRange by its size and continue to see if there are more // LineEntries that we can combine. However, if there was nothing to // extend we're done. if (!complete_line_range.Extend(next_line_sc.line_entry.range)) break; continue; } if (include_inlined_functions && next_line_sc.block && next_line_sc.block->GetContainingInlinedBlock() != nullptr) { // The next_line_sc might be in a different file if it's an inlined // function. If this is the case then we still want to expand our line // range to include them if the inlined function is at the same call site // as this line entry. The current block could represent a nested inline // function call so we need to need to check up the block tree to see if // we find one. auto inlined_parent_block = next_line_sc.block->GetContainingInlinedBlockWithCallSite( start_call_site); if (!inlined_parent_block) // We didn't find any parent inlined block with a call site at this line // entry so this inlined function is probably at another line. break; // Extend our AddressRange by the size of the inlined block, but if there // was nothing to add then we're done. if (!complete_line_range.Extend(next_line_sc.line_entry.range)) break; continue; } break; } return complete_line_range; } void LineEntry::ApplyFileMappings(lldb::TargetSP target_sp) { if (target_sp) { // Apply any file remappings to our file FileSpec new_file_spec; if (target_sp->GetSourcePathMap().FindFile(original_file, new_file_spec)) file = new_file_spec; } }