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