1 //===-- LineEntry.cpp -------------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "lldb/Symbol/LineEntry.h" 10 #include "lldb/Symbol/CompileUnit.h" 11 #include "lldb/Target/Process.h" 12 #include "lldb/Target/Target.h" 13 14 using namespace lldb_private; 15 16 LineEntry::LineEntry() 17 : range(), file(), line(LLDB_INVALID_LINE_NUMBER), column(0), 18 is_start_of_statement(0), is_start_of_basic_block(0), is_prologue_end(0), 19 is_epilogue_begin(0), is_terminal_entry(0) {} 20 21 LineEntry::LineEntry(const lldb::SectionSP §ion_sp, 22 lldb::addr_t section_offset, lldb::addr_t byte_size, 23 const FileSpec &_file, uint32_t _line, uint16_t _column, 24 bool _is_start_of_statement, bool _is_start_of_basic_block, 25 bool _is_prologue_end, bool _is_epilogue_begin, 26 bool _is_terminal_entry) 27 : range(section_sp, section_offset, byte_size), file(_file), 28 original_file(_file), line(_line), column(_column), 29 is_start_of_statement(_is_start_of_statement), 30 is_start_of_basic_block(_is_start_of_basic_block), 31 is_prologue_end(_is_prologue_end), is_epilogue_begin(_is_epilogue_begin), 32 is_terminal_entry(_is_terminal_entry) {} 33 34 void LineEntry::Clear() { 35 range.Clear(); 36 file.Clear(); 37 original_file.Clear(); 38 line = LLDB_INVALID_LINE_NUMBER; 39 column = 0; 40 is_start_of_statement = 0; 41 is_start_of_basic_block = 0; 42 is_prologue_end = 0; 43 is_epilogue_begin = 0; 44 is_terminal_entry = 0; 45 } 46 47 bool LineEntry::IsValid() const { 48 return range.GetBaseAddress().IsValid() && line != LLDB_INVALID_LINE_NUMBER; 49 } 50 51 bool LineEntry::DumpStopContext(Stream *s, bool show_fullpaths) const { 52 if (file) { 53 if (show_fullpaths) 54 file.Dump(s); 55 else 56 file.GetFilename().Dump(s); 57 58 if (line) 59 s->PutChar(':'); 60 } 61 if (line) { 62 s->Printf("%u", line); 63 if (column) { 64 s->PutChar(':'); 65 s->Printf("%u", column); 66 } 67 } 68 return file || line; 69 } 70 71 bool LineEntry::Dump(Stream *s, Target *target, bool show_file, 72 Address::DumpStyle style, 73 Address::DumpStyle fallback_style, bool show_range) const { 74 if (show_range) { 75 // Show address range 76 if (!range.Dump(s, target, style, fallback_style)) 77 return false; 78 } else { 79 // Show address only 80 if (!range.GetBaseAddress().Dump(s, target, style, fallback_style)) 81 return false; 82 } 83 if (show_file) 84 *s << ", file = " << file; 85 if (line) 86 s->Printf(", line = %u", line); 87 if (column) 88 s->Printf(", column = %u", column); 89 if (is_start_of_statement) 90 *s << ", is_start_of_statement = TRUE"; 91 92 if (is_start_of_basic_block) 93 *s << ", is_start_of_basic_block = TRUE"; 94 95 if (is_prologue_end) 96 *s << ", is_prologue_end = TRUE"; 97 98 if (is_epilogue_begin) 99 *s << ", is_epilogue_begin = TRUE"; 100 101 if (is_terminal_entry) 102 *s << ", is_terminal_entry = TRUE"; 103 return true; 104 } 105 106 bool LineEntry::GetDescription(Stream *s, lldb::DescriptionLevel level, 107 CompileUnit *cu, Target *target, 108 bool show_address_only) const { 109 110 if (level == lldb::eDescriptionLevelBrief || 111 level == lldb::eDescriptionLevelFull) { 112 if (show_address_only) { 113 range.GetBaseAddress().Dump(s, target, Address::DumpStyleLoadAddress, 114 Address::DumpStyleFileAddress); 115 } else { 116 range.Dump(s, target, Address::DumpStyleLoadAddress, 117 Address::DumpStyleFileAddress); 118 } 119 120 *s << ": " << file; 121 122 if (line) { 123 s->Printf(":%u", line); 124 if (column) 125 s->Printf(":%u", column); 126 } 127 128 if (level == lldb::eDescriptionLevelFull) { 129 if (is_start_of_statement) 130 *s << ", is_start_of_statement = TRUE"; 131 132 if (is_start_of_basic_block) 133 *s << ", is_start_of_basic_block = TRUE"; 134 135 if (is_prologue_end) 136 *s << ", is_prologue_end = TRUE"; 137 138 if (is_epilogue_begin) 139 *s << ", is_epilogue_begin = TRUE"; 140 141 if (is_terminal_entry) 142 *s << ", is_terminal_entry = TRUE"; 143 } else { 144 if (is_terminal_entry) 145 s->EOL(); 146 } 147 } else { 148 return Dump(s, target, true, Address::DumpStyleLoadAddress, 149 Address::DumpStyleModuleWithFileAddress, true); 150 } 151 return true; 152 } 153 154 bool lldb_private::operator<(const LineEntry &a, const LineEntry &b) { 155 return LineEntry::Compare(a, b) < 0; 156 } 157 158 int LineEntry::Compare(const LineEntry &a, const LineEntry &b) { 159 int result = Address::CompareFileAddress(a.range.GetBaseAddress(), 160 b.range.GetBaseAddress()); 161 if (result != 0) 162 return result; 163 164 const lldb::addr_t a_byte_size = a.range.GetByteSize(); 165 const lldb::addr_t b_byte_size = b.range.GetByteSize(); 166 167 if (a_byte_size < b_byte_size) 168 return -1; 169 if (a_byte_size > b_byte_size) 170 return +1; 171 172 // Check for an end sequence entry mismatch after we have determined that the 173 // address values are equal. If one of the items is an end sequence, we don't 174 // care about the line, file, or column info. 175 if (a.is_terminal_entry > b.is_terminal_entry) 176 return -1; 177 if (a.is_terminal_entry < b.is_terminal_entry) 178 return +1; 179 180 if (a.line < b.line) 181 return -1; 182 if (a.line > b.line) 183 return +1; 184 185 if (a.column < b.column) 186 return -1; 187 if (a.column > b.column) 188 return +1; 189 190 return FileSpec::Compare(a.file, b.file, true); 191 } 192 193 AddressRange LineEntry::GetSameLineContiguousAddressRange( 194 bool include_inlined_functions) const { 195 // Add each LineEntry's range to complete_line_range until we find a 196 // different file / line number. 197 AddressRange complete_line_range = range; 198 auto symbol_context_scope = lldb::eSymbolContextLineEntry; 199 Declaration start_call_site(original_file, line); 200 if (include_inlined_functions) 201 symbol_context_scope |= lldb::eSymbolContextBlock; 202 203 while (true) { 204 SymbolContext next_line_sc; 205 Address range_end(complete_line_range.GetBaseAddress()); 206 range_end.Slide(complete_line_range.GetByteSize()); 207 range_end.CalculateSymbolContext(&next_line_sc, symbol_context_scope); 208 209 if (!next_line_sc.line_entry.IsValid() || 210 next_line_sc.line_entry.range.GetByteSize() == 0) 211 break; 212 213 if (original_file == next_line_sc.line_entry.original_file && 214 (next_line_sc.line_entry.line == 0 || 215 line == next_line_sc.line_entry.line)) { 216 // Include any line 0 entries - they indicate that this is compiler- 217 // generated code that does not correspond to user source code. 218 // next_line_sc is the same file & line as this LineEntry, so extend 219 // our AddressRange by its size and continue to see if there are more 220 // LineEntries that we can combine. However, if there was nothing to 221 // extend we're done. 222 if (!complete_line_range.Extend(next_line_sc.line_entry.range)) 223 break; 224 continue; 225 } 226 227 if (include_inlined_functions && next_line_sc.block && 228 next_line_sc.block->GetContainingInlinedBlock() != nullptr) { 229 // The next_line_sc might be in a different file if it's an inlined 230 // function. If this is the case then we still want to expand our line 231 // range to include them if the inlined function is at the same call site 232 // as this line entry. The current block could represent a nested inline 233 // function call so we need to need to check up the block tree to see if 234 // we find one. 235 auto inlined_parent_block = 236 next_line_sc.block->GetContainingInlinedBlockWithCallSite( 237 start_call_site); 238 if (!inlined_parent_block) 239 // We didn't find any parent inlined block with a call site at this line 240 // entry so this inlined function is probably at another line. 241 break; 242 // Extend our AddressRange by the size of the inlined block, but if there 243 // was nothing to add then we're done. 244 if (!complete_line_range.Extend(next_line_sc.line_entry.range)) 245 break; 246 continue; 247 } 248 249 break; 250 } 251 return complete_line_range; 252 } 253 254 void LineEntry::ApplyFileMappings(lldb::TargetSP target_sp) { 255 if (target_sp) { 256 // Apply any file remappings to our file 257 FileSpec new_file_spec; 258 if (target_sp->GetSourcePathMap().FindFile(original_file, new_file_spec)) 259 file = new_file_spec; 260 } 261 } 262