1 //===-- DWARFUnit.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 "DWARFUnit.h" 10 11 #include "lldb/Core/Module.h" 12 #include "lldb/Symbol/ObjectFile.h" 13 #include "lldb/Utility/LLDBAssert.h" 14 #include "lldb/Utility/StreamString.h" 15 #include "lldb/Utility/Timer.h" 16 #include "llvm/DebugInfo/DWARF/DWARFAddressRange.h" 17 #include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" 18 #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h" 19 #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" 20 #include "llvm/Object/Error.h" 21 22 #include "DWARFCompileUnit.h" 23 #include "DWARFDebugAranges.h" 24 #include "DWARFDebugInfo.h" 25 #include "DWARFTypeUnit.h" 26 #include "LogChannelDWARF.h" 27 #include "SymbolFileDWARFDwo.h" 28 #include <optional> 29 30 using namespace lldb; 31 using namespace lldb_private; 32 using namespace lldb_private::dwarf; 33 using namespace lldb_private::plugin::dwarf; 34 35 extern int g_verbose; 36 37 DWARFUnit::DWARFUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid, 38 const llvm::DWARFUnitHeader &header, 39 const llvm::DWARFAbbreviationDeclarationSet &abbrevs, 40 DIERef::Section section, bool is_dwo) 41 : UserID(uid), m_dwarf(dwarf), m_header(header), m_abbrevs(&abbrevs), 42 m_cancel_scopes(false), m_section(section), m_is_dwo(is_dwo), 43 m_has_parsed_non_skeleton_unit(false), m_dwo_id(header.getDWOId()) {} 44 45 DWARFUnit::~DWARFUnit() = default; 46 47 // Parses first DIE of a compile unit, excluding DWO. 48 void DWARFUnit::ExtractUnitDIENoDwoIfNeeded() { 49 { 50 llvm::sys::ScopedReader lock(m_first_die_mutex); 51 if (m_first_die) 52 return; // Already parsed 53 } 54 llvm::sys::ScopedWriter lock(m_first_die_mutex); 55 if (m_first_die) 56 return; // Already parsed 57 58 ElapsedTime elapsed(m_dwarf.GetDebugInfoParseTimeRef()); 59 60 // Set the offset to that of the first DIE and calculate the start of the 61 // next compilation unit header. 62 lldb::offset_t offset = GetFirstDIEOffset(); 63 64 // We are in our compile unit, parse starting at the offset we were told to 65 // parse 66 const DWARFDataExtractor &data = GetData(); 67 if (offset < GetNextUnitOffset() && 68 m_first_die.Extract(data, *this, &offset)) { 69 AddUnitDIE(m_first_die); 70 return; 71 } 72 } 73 74 // Parses first DIE of a compile unit including DWO. 75 void DWARFUnit::ExtractUnitDIEIfNeeded() { 76 ExtractUnitDIENoDwoIfNeeded(); 77 78 if (m_has_parsed_non_skeleton_unit) 79 return; 80 81 m_has_parsed_non_skeleton_unit = true; 82 m_dwo_error.Clear(); 83 84 if (!m_dwo_id) 85 return; // No DWO file. 86 87 std::shared_ptr<SymbolFileDWARFDwo> dwo_symbol_file = 88 m_dwarf.GetDwoSymbolFileForCompileUnit(*this, m_first_die); 89 if (!dwo_symbol_file) 90 return; 91 92 DWARFUnit *dwo_cu = dwo_symbol_file->GetDWOCompileUnitForHash(*m_dwo_id); 93 94 if (!dwo_cu) { 95 SetDwoError(Status::FromErrorStringWithFormatv( 96 "unable to load .dwo file from \"{0}\" due to ID ({1:x16}) mismatch " 97 "for skeleton DIE at {2:x8}", 98 dwo_symbol_file->GetObjectFile()->GetFileSpec().GetPath(), *m_dwo_id, 99 m_first_die.GetOffset())); 100 return; // Can't fetch the compile unit from the dwo file. 101 } 102 103 // Link the DWO unit to this object, if it hasn't been linked already (this 104 // can happen when we have an index, and the DWO unit is parsed first). 105 if (!dwo_cu->LinkToSkeletonUnit(*this)) { 106 SetDwoError(Status::FromErrorStringWithFormatv( 107 "multiple compile units with Dwo ID {0:x16}", *m_dwo_id)); 108 return; 109 } 110 111 DWARFBaseDIE dwo_cu_die = dwo_cu->GetUnitDIEOnly(); 112 if (!dwo_cu_die.IsValid()) { 113 // Can't fetch the compile unit DIE from the dwo file. 114 SetDwoError(Status::FromErrorStringWithFormatv( 115 "unable to extract compile unit DIE from .dwo file for skeleton " 116 "DIE at {0:x16}", 117 m_first_die.GetOffset())); 118 return; 119 } 120 121 // Here for DWO CU we want to use the address base set in the skeleton unit 122 // (DW_AT_addr_base) if it is available and use the DW_AT_GNU_addr_base 123 // otherwise. We do that because pre-DWARF v5 could use the DW_AT_GNU_* 124 // attributes which were applicable to the DWO units. The corresponding 125 // DW_AT_* attributes standardized in DWARF v5 are also applicable to the 126 // main unit in contrast. 127 if (m_addr_base) 128 dwo_cu->SetAddrBase(*m_addr_base); 129 else if (m_gnu_addr_base) 130 dwo_cu->SetAddrBase(*m_gnu_addr_base); 131 132 if (GetVersion() <= 4 && m_gnu_ranges_base) 133 dwo_cu->SetRangesBase(*m_gnu_ranges_base); 134 else if (dwo_symbol_file->GetDWARFContext() 135 .getOrLoadRngListsData() 136 .GetByteSize() > 0) 137 dwo_cu->SetRangesBase(llvm::DWARFListTableHeader::getHeaderSize(DWARF32)); 138 139 if (GetVersion() >= 5 && 140 dwo_symbol_file->GetDWARFContext().getOrLoadLocListsData().GetByteSize() > 141 0) 142 dwo_cu->SetLoclistsBase(llvm::DWARFListTableHeader::getHeaderSize(DWARF32)); 143 144 dwo_cu->SetBaseAddress(GetBaseAddress()); 145 146 m_dwo = std::shared_ptr<DWARFUnit>(std::move(dwo_symbol_file), dwo_cu); 147 } 148 149 // Parses a compile unit and indexes its DIEs if it hasn't already been done. 150 // It will leave this compile unit extracted forever. 151 void DWARFUnit::ExtractDIEsIfNeeded() { 152 m_cancel_scopes = true; 153 154 { 155 llvm::sys::ScopedReader lock(m_die_array_mutex); 156 if (!m_die_array.empty()) 157 return; // Already parsed 158 } 159 llvm::sys::ScopedWriter lock(m_die_array_mutex); 160 if (!m_die_array.empty()) 161 return; // Already parsed 162 163 ExtractDIEsRWLocked(); 164 } 165 166 // Parses a compile unit and indexes its DIEs if it hasn't already been done. 167 // It will clear this compile unit after returned instance gets out of scope, 168 // no other ScopedExtractDIEs instance is running for this compile unit 169 // and no ExtractDIEsIfNeeded() has been executed during this ScopedExtractDIEs 170 // lifetime. 171 DWARFUnit::ScopedExtractDIEs DWARFUnit::ExtractDIEsScoped() { 172 ScopedExtractDIEs scoped(*this); 173 174 { 175 llvm::sys::ScopedReader lock(m_die_array_mutex); 176 if (!m_die_array.empty()) 177 return scoped; // Already parsed 178 } 179 llvm::sys::ScopedWriter lock(m_die_array_mutex); 180 if (!m_die_array.empty()) 181 return scoped; // Already parsed 182 183 // Otherwise m_die_array would be already populated. 184 lldbassert(!m_cancel_scopes); 185 186 ExtractDIEsRWLocked(); 187 scoped.m_clear_dies = true; 188 return scoped; 189 } 190 191 DWARFUnit::ScopedExtractDIEs::ScopedExtractDIEs(DWARFUnit &cu) : m_cu(&cu) { 192 llvm::sys::ScopedLock lock(m_cu->m_die_array_scoped_mutex); 193 ++m_cu->m_die_array_scoped_count; 194 } 195 196 DWARFUnit::ScopedExtractDIEs::~ScopedExtractDIEs() { 197 if (!m_cu) 198 return; 199 llvm::sys::ScopedLock lock(m_cu->m_die_array_scoped_mutex); 200 --m_cu->m_die_array_scoped_count; 201 if (m_cu->m_die_array_scoped_count == 0 && m_clear_dies && 202 !m_cu->m_cancel_scopes) { 203 llvm::sys::ScopedWriter lock(m_cu->m_die_array_mutex); 204 m_cu->ClearDIEsRWLocked(); 205 } 206 } 207 208 DWARFUnit::ScopedExtractDIEs::ScopedExtractDIEs(ScopedExtractDIEs &&rhs) 209 : m_cu(rhs.m_cu), m_clear_dies(rhs.m_clear_dies) { 210 rhs.m_cu = nullptr; 211 } 212 213 DWARFUnit::ScopedExtractDIEs & 214 DWARFUnit::ScopedExtractDIEs::operator=(DWARFUnit::ScopedExtractDIEs &&rhs) { 215 m_cu = rhs.m_cu; 216 rhs.m_cu = nullptr; 217 m_clear_dies = rhs.m_clear_dies; 218 return *this; 219 } 220 221 // Parses a compile unit and indexes its DIEs, m_die_array_mutex must be 222 // held R/W and m_die_array must be empty. 223 void DWARFUnit::ExtractDIEsRWLocked() { 224 llvm::sys::ScopedWriter first_die_lock(m_first_die_mutex); 225 226 ElapsedTime elapsed(m_dwarf.GetDebugInfoParseTimeRef()); 227 LLDB_SCOPED_TIMERF( 228 "%s", 229 llvm::formatv("{0:x16}: DWARFUnit::ExtractDIEsIfNeeded()", GetOffset()) 230 .str() 231 .c_str()); 232 233 // Set the offset to that of the first DIE and calculate the start of the 234 // next compilation unit header. 235 lldb::offset_t offset = GetFirstDIEOffset(); 236 lldb::offset_t next_cu_offset = GetNextUnitOffset(); 237 238 DWARFDebugInfoEntry die; 239 240 uint32_t depth = 0; 241 // We are in our compile unit, parse starting at the offset we were told to 242 // parse 243 const DWARFDataExtractor &data = GetData(); 244 std::vector<uint32_t> die_index_stack; 245 die_index_stack.reserve(32); 246 die_index_stack.push_back(0); 247 bool prev_die_had_children = false; 248 while (offset < next_cu_offset && die.Extract(data, *this, &offset)) { 249 const bool null_die = die.IsNULL(); 250 if (depth == 0) { 251 assert(m_die_array.empty() && "Compile unit DIE already added"); 252 253 // The average bytes per DIE entry has been seen to be around 14-20 so 254 // lets pre-reserve half of that since we are now stripping the NULL 255 // tags. 256 257 // Only reserve the memory if we are adding children of the main 258 // compile unit DIE. The compile unit DIE is always the first entry, so 259 // if our size is 1, then we are adding the first compile unit child 260 // DIE and should reserve the memory. 261 m_die_array.reserve(GetDebugInfoSize() / 24); 262 m_die_array.push_back(die); 263 264 if (!m_first_die) 265 AddUnitDIE(m_die_array.front()); 266 267 // With -fsplit-dwarf-inlining, clang will emit non-empty skeleton compile 268 // units. We are not able to access these DIE *and* the dwo file 269 // simultaneously. We also don't need to do that as the dwo file will 270 // contain a superset of information. So, we don't even attempt to parse 271 // any remaining DIEs. 272 if (m_dwo) { 273 m_die_array.front().SetHasChildren(false); 274 break; 275 } 276 277 } else { 278 if (null_die) { 279 if (prev_die_had_children) { 280 // This will only happen if a DIE says is has children but all it 281 // contains is a NULL tag. Since we are removing the NULL DIEs from 282 // the list (saves up to 25% in C++ code), we need a way to let the 283 // DIE know that it actually doesn't have children. 284 if (!m_die_array.empty()) 285 m_die_array.back().SetHasChildren(false); 286 } 287 } else { 288 die.SetParentIndex(m_die_array.size() - die_index_stack[depth - 1]); 289 290 if (die_index_stack.back()) 291 m_die_array[die_index_stack.back()].SetSiblingIndex( 292 m_die_array.size() - die_index_stack.back()); 293 294 // Only push the DIE if it isn't a NULL DIE 295 m_die_array.push_back(die); 296 } 297 } 298 299 if (null_die) { 300 // NULL DIE. 301 if (!die_index_stack.empty()) 302 die_index_stack.pop_back(); 303 304 if (depth > 0) 305 --depth; 306 prev_die_had_children = false; 307 } else { 308 die_index_stack.back() = m_die_array.size() - 1; 309 // Normal DIE 310 const bool die_has_children = die.HasChildren(); 311 if (die_has_children) { 312 die_index_stack.push_back(0); 313 ++depth; 314 } 315 prev_die_had_children = die_has_children; 316 } 317 318 if (depth == 0) 319 break; // We are done with this compile unit! 320 } 321 322 if (!m_die_array.empty()) { 323 // The last die cannot have children (if it did, it wouldn't be the last 324 // one). This only makes a difference for malformed dwarf that does not have 325 // a terminating null die. 326 m_die_array.back().SetHasChildren(false); 327 328 if (m_first_die) { 329 // Only needed for the assertion. 330 m_first_die.SetHasChildren(m_die_array.front().HasChildren()); 331 lldbassert(m_first_die == m_die_array.front()); 332 } 333 m_first_die = m_die_array.front(); 334 } 335 336 m_die_array.shrink_to_fit(); 337 338 if (m_dwo) 339 m_dwo->ExtractDIEsIfNeeded(); 340 } 341 342 // This is used when a split dwarf is enabled. 343 // A skeleton compilation unit may contain the DW_AT_str_offsets_base attribute 344 // that points to the first string offset of the CU contribution to the 345 // .debug_str_offsets. At the same time, the corresponding split debug unit also 346 // may use DW_FORM_strx* forms pointing to its own .debug_str_offsets.dwo and 347 // for that case, we should find the offset (skip the section header). 348 void DWARFUnit::SetDwoStrOffsetsBase() { 349 lldb::offset_t baseOffset = 0; 350 351 if (const llvm::DWARFUnitIndex::Entry *entry = m_header.getIndexEntry()) { 352 if (const auto *contribution = 353 entry->getContribution(llvm::DW_SECT_STR_OFFSETS)) 354 baseOffset = contribution->getOffset(); 355 else 356 return; 357 } 358 359 if (GetVersion() >= 5) { 360 const DWARFDataExtractor &strOffsets = 361 GetSymbolFileDWARF().GetDWARFContext().getOrLoadStrOffsetsData(); 362 uint64_t length = strOffsets.GetU32(&baseOffset); 363 if (length == 0xffffffff) 364 length = strOffsets.GetU64(&baseOffset); 365 366 // Check version. 367 if (strOffsets.GetU16(&baseOffset) < 5) 368 return; 369 370 // Skip padding. 371 baseOffset += 2; 372 } 373 374 SetStrOffsetsBase(baseOffset); 375 } 376 377 std::optional<uint64_t> DWARFUnit::GetDWOId() { 378 ExtractUnitDIENoDwoIfNeeded(); 379 return m_dwo_id; 380 } 381 382 // m_die_array_mutex must be already held as read/write. 383 void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) { 384 DWARFAttributes attributes = cu_die.GetAttributes(this); 385 386 // Extract DW_AT_addr_base first, as other attributes may need it. 387 for (size_t i = 0; i < attributes.Size(); ++i) { 388 if (attributes.AttributeAtIndex(i) != DW_AT_addr_base) 389 continue; 390 DWARFFormValue form_value; 391 if (attributes.ExtractFormValueAtIndex(i, form_value)) { 392 SetAddrBase(form_value.Unsigned()); 393 break; 394 } 395 } 396 397 for (size_t i = 0; i < attributes.Size(); ++i) { 398 dw_attr_t attr = attributes.AttributeAtIndex(i); 399 DWARFFormValue form_value; 400 if (!attributes.ExtractFormValueAtIndex(i, form_value)) 401 continue; 402 switch (attr) { 403 default: 404 break; 405 case DW_AT_loclists_base: 406 SetLoclistsBase(form_value.Unsigned()); 407 break; 408 case DW_AT_rnglists_base: 409 SetRangesBase(form_value.Unsigned()); 410 break; 411 case DW_AT_str_offsets_base: 412 SetStrOffsetsBase(form_value.Unsigned()); 413 break; 414 case DW_AT_low_pc: 415 SetBaseAddress(form_value.Address()); 416 break; 417 case DW_AT_entry_pc: 418 // If the value was already set by DW_AT_low_pc, don't update it. 419 if (m_base_addr == LLDB_INVALID_ADDRESS) 420 SetBaseAddress(form_value.Address()); 421 break; 422 case DW_AT_stmt_list: 423 m_line_table_offset = form_value.Unsigned(); 424 break; 425 case DW_AT_GNU_addr_base: 426 m_gnu_addr_base = form_value.Unsigned(); 427 break; 428 case DW_AT_GNU_ranges_base: 429 m_gnu_ranges_base = form_value.Unsigned(); 430 break; 431 case DW_AT_GNU_dwo_id: 432 m_dwo_id = form_value.Unsigned(); 433 break; 434 } 435 } 436 437 if (m_is_dwo) { 438 m_has_parsed_non_skeleton_unit = true; 439 SetDwoStrOffsetsBase(); 440 return; 441 } 442 } 443 444 size_t DWARFUnit::GetDebugInfoSize() const { 445 return GetLengthByteSize() + GetLength() - GetHeaderByteSize(); 446 } 447 448 const llvm::DWARFAbbreviationDeclarationSet * 449 DWARFUnit::GetAbbreviations() const { 450 return m_abbrevs; 451 } 452 453 dw_offset_t DWARFUnit::GetAbbrevOffset() const { 454 return m_abbrevs ? m_abbrevs->getOffset() : DW_INVALID_OFFSET; 455 } 456 457 dw_offset_t DWARFUnit::GetLineTableOffset() { 458 ExtractUnitDIENoDwoIfNeeded(); 459 return m_line_table_offset; 460 } 461 462 void DWARFUnit::SetAddrBase(dw_addr_t addr_base) { m_addr_base = addr_base; } 463 464 // Parse the rangelist table header, including the optional array of offsets 465 // following it (DWARF v5 and later). 466 template <typename ListTableType> 467 static llvm::Expected<ListTableType> 468 ParseListTableHeader(const llvm::DWARFDataExtractor &data, uint64_t offset, 469 DwarfFormat format) { 470 // We are expected to be called with Offset 0 or pointing just past the table 471 // header. Correct Offset in the latter case so that it points to the start 472 // of the header. 473 if (offset == 0) { 474 // This means DW_AT_rnglists_base is missing and therefore DW_FORM_rnglistx 475 // cannot be handled. Returning a default-constructed ListTableType allows 476 // DW_FORM_sec_offset to be supported. 477 return ListTableType(); 478 } 479 480 uint64_t HeaderSize = llvm::DWARFListTableHeader::getHeaderSize(format); 481 if (offset < HeaderSize) 482 return llvm::createStringError(std::errc::invalid_argument, 483 "did not detect a valid" 484 " list table with base = 0x%" PRIx64 "\n", 485 offset); 486 offset -= HeaderSize; 487 ListTableType Table; 488 if (llvm::Error E = Table.extractHeaderAndOffsets(data, &offset)) 489 return std::move(E); 490 return Table; 491 } 492 493 void DWARFUnit::SetLoclistsBase(dw_addr_t loclists_base) { 494 uint64_t offset = 0; 495 if (const llvm::DWARFUnitIndex::Entry *entry = m_header.getIndexEntry()) { 496 const auto *contribution = entry->getContribution(llvm::DW_SECT_LOCLISTS); 497 if (!contribution) { 498 GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( 499 "Failed to find location list contribution for CU with DWO Id " 500 "{0:x16}", 501 *GetDWOId()); 502 return; 503 } 504 offset += contribution->getOffset(); 505 } 506 m_loclists_base = loclists_base; 507 508 uint64_t header_size = llvm::DWARFListTableHeader::getHeaderSize(DWARF32); 509 if (loclists_base < header_size) 510 return; 511 512 m_loclist_table_header.emplace(".debug_loclists", "locations"); 513 offset += loclists_base - header_size; 514 if (llvm::Error E = m_loclist_table_header->extract( 515 m_dwarf.GetDWARFContext().getOrLoadLocListsData().GetAsLLVMDWARF(), 516 &offset)) { 517 GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( 518 "Failed to extract location list table at offset {0:x16} (location " 519 "list base: {1:x16}): {2}", 520 offset, loclists_base, toString(std::move(E)).c_str()); 521 } 522 } 523 524 std::unique_ptr<llvm::DWARFLocationTable> 525 DWARFUnit::GetLocationTable(const DataExtractor &data) const { 526 llvm::DWARFDataExtractor llvm_data( 527 data.GetData(), data.GetByteOrder() == lldb::eByteOrderLittle, 528 data.GetAddressByteSize()); 529 530 if (m_is_dwo || GetVersion() >= 5) 531 return std::make_unique<llvm::DWARFDebugLoclists>(llvm_data, GetVersion()); 532 return std::make_unique<llvm::DWARFDebugLoc>(llvm_data); 533 } 534 535 DWARFDataExtractor DWARFUnit::GetLocationData() const { 536 DWARFContext &Ctx = GetSymbolFileDWARF().GetDWARFContext(); 537 const DWARFDataExtractor &data = 538 GetVersion() >= 5 ? Ctx.getOrLoadLocListsData() : Ctx.getOrLoadLocData(); 539 if (const llvm::DWARFUnitIndex::Entry *entry = m_header.getIndexEntry()) { 540 if (const auto *contribution = entry->getContribution( 541 GetVersion() >= 5 ? llvm::DW_SECT_LOCLISTS : llvm::DW_SECT_EXT_LOC)) 542 return DWARFDataExtractor(data, contribution->getOffset(), 543 contribution->getLength32()); 544 return DWARFDataExtractor(); 545 } 546 return data; 547 } 548 549 DWARFDataExtractor DWARFUnit::GetRnglistData() const { 550 DWARFContext &Ctx = GetSymbolFileDWARF().GetDWARFContext(); 551 const DWARFDataExtractor &data = Ctx.getOrLoadRngListsData(); 552 if (const llvm::DWARFUnitIndex::Entry *entry = m_header.getIndexEntry()) { 553 if (const auto *contribution = 554 entry->getContribution(llvm::DW_SECT_RNGLISTS)) 555 return DWARFDataExtractor(data, contribution->getOffset(), 556 contribution->getLength32()); 557 GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( 558 "Failed to find range list contribution for CU with signature {0:x16}", 559 entry->getSignature()); 560 561 return DWARFDataExtractor(); 562 } 563 return data; 564 } 565 566 void DWARFUnit::SetRangesBase(dw_addr_t ranges_base) { 567 lldbassert(!m_rnglist_table_done); 568 569 m_ranges_base = ranges_base; 570 } 571 572 const std::optional<llvm::DWARFDebugRnglistTable> & 573 DWARFUnit::GetRnglistTable() { 574 if (GetVersion() >= 5 && !m_rnglist_table_done) { 575 m_rnglist_table_done = true; 576 if (auto table_or_error = 577 ParseListTableHeader<llvm::DWARFDebugRnglistTable>( 578 GetRnglistData().GetAsLLVMDWARF(), m_ranges_base, DWARF32)) 579 m_rnglist_table = std::move(table_or_error.get()); 580 else 581 GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( 582 "Failed to extract range list table at offset {0:x16}: {1}", 583 m_ranges_base, toString(table_or_error.takeError()).c_str()); 584 } 585 return m_rnglist_table; 586 } 587 588 // This function is called only for DW_FORM_rnglistx. 589 llvm::Expected<uint64_t> DWARFUnit::GetRnglistOffset(uint32_t Index) { 590 if (!GetRnglistTable()) 591 return llvm::createStringError(std::errc::invalid_argument, 592 "missing or invalid range list table"); 593 if (!m_ranges_base) 594 return llvm::createStringError( 595 std::errc::invalid_argument, 596 llvm::formatv("DW_FORM_rnglistx cannot be used without " 597 "DW_AT_rnglists_base for CU at {0:x16}", 598 GetOffset()) 599 .str() 600 .c_str()); 601 if (std::optional<uint64_t> off = GetRnglistTable()->getOffsetEntry( 602 GetRnglistData().GetAsLLVM(), Index)) 603 return *off + m_ranges_base; 604 return llvm::createStringError( 605 std::errc::invalid_argument, 606 "invalid range list table index %u; OffsetEntryCount is %u, " 607 "DW_AT_rnglists_base is %" PRIu64, 608 Index, GetRnglistTable()->getOffsetEntryCount(), m_ranges_base); 609 } 610 611 void DWARFUnit::SetStrOffsetsBase(dw_offset_t str_offsets_base) { 612 m_str_offsets_base = str_offsets_base; 613 } 614 615 dw_addr_t DWARFUnit::ReadAddressFromDebugAddrSection(uint32_t index) const { 616 uint32_t index_size = GetAddressByteSize(); 617 dw_offset_t addr_base = GetAddrBase(); 618 dw_addr_t offset = addr_base + static_cast<dw_addr_t>(index) * index_size; 619 const DWARFDataExtractor &data = 620 m_dwarf.GetDWARFContext().getOrLoadAddrData(); 621 if (data.ValidOffsetForDataOfSize(offset, index_size)) 622 return data.GetMaxU64_unchecked(&offset, index_size); 623 return LLDB_INVALID_ADDRESS; 624 } 625 626 // It may be called only with m_die_array_mutex held R/W. 627 void DWARFUnit::ClearDIEsRWLocked() { 628 m_die_array.clear(); 629 m_die_array.shrink_to_fit(); 630 631 if (m_dwo && !m_dwo->m_cancel_scopes) 632 m_dwo->ClearDIEsRWLocked(); 633 } 634 635 lldb::ByteOrder DWARFUnit::GetByteOrder() const { 636 return m_dwarf.GetObjectFile()->GetByteOrder(); 637 } 638 639 void DWARFUnit::SetBaseAddress(dw_addr_t base_addr) { m_base_addr = base_addr; } 640 641 // Compare function DWARFDebugAranges::Range structures 642 static bool CompareDIEOffset(const DWARFDebugInfoEntry &die, 643 const dw_offset_t die_offset) { 644 return die.GetOffset() < die_offset; 645 } 646 647 // GetDIE() 648 // 649 // Get the DIE (Debug Information Entry) with the specified offset by first 650 // checking if the DIE is contained within this compile unit and grabbing the 651 // DIE from this compile unit. Otherwise we grab the DIE from the DWARF file. 652 DWARFDIE 653 DWARFUnit::GetDIE(dw_offset_t die_offset) { 654 if (die_offset == DW_INVALID_OFFSET) 655 return DWARFDIE(); // Not found 656 657 if (!ContainsDIEOffset(die_offset)) { 658 GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( 659 "GetDIE for DIE {0:x16} is outside of its CU {1:x16}", die_offset, 660 GetOffset()); 661 return DWARFDIE(); // Not found 662 } 663 664 ExtractDIEsIfNeeded(); 665 DWARFDebugInfoEntry::const_iterator end = m_die_array.cend(); 666 DWARFDebugInfoEntry::const_iterator pos = 667 lower_bound(m_die_array.cbegin(), end, die_offset, CompareDIEOffset); 668 669 if (pos != end && die_offset == (*pos).GetOffset()) 670 return DWARFDIE(this, &(*pos)); 671 return DWARFDIE(); // Not found 672 } 673 674 llvm::StringRef DWARFUnit::PeekDIEName(dw_offset_t die_offset) { 675 DWARFDebugInfoEntry die; 676 if (!die.Extract(GetData(), *this, &die_offset)) 677 return llvm::StringRef(); 678 679 // Does die contain a DW_AT_Name? 680 if (const char *name = 681 die.GetAttributeValueAsString(this, DW_AT_name, nullptr)) 682 return name; 683 684 // Does its DW_AT_specification or DW_AT_abstract_origin contain an AT_Name? 685 for (auto attr : {DW_AT_specification, DW_AT_abstract_origin}) { 686 DWARFFormValue form_value; 687 if (!die.GetAttributeValue(this, attr, form_value)) 688 continue; 689 auto [unit, offset] = form_value.ReferencedUnitAndOffset(); 690 if (unit) 691 if (auto name = unit->PeekDIEName(offset); !name.empty()) 692 return name; 693 } 694 695 return llvm::StringRef(); 696 } 697 698 llvm::Expected<std::pair<uint64_t, bool>> 699 DWARFUnit::GetDIEBitSizeAndSign(uint64_t relative_die_offset) const { 700 // Retrieve the type DIE that the value is being converted to. This 701 // offset is compile unit relative so we need to fix it up. 702 const uint64_t abs_die_offset = relative_die_offset + GetOffset(); 703 // FIXME: the constness has annoying ripple effects. 704 DWARFDIE die = const_cast<DWARFUnit *>(this)->GetDIE(abs_die_offset); 705 if (!die) 706 return llvm::createStringError("cannot resolve DW_OP_convert type DIE"); 707 uint64_t encoding = 708 die.GetAttributeValueAsUnsigned(DW_AT_encoding, DW_ATE_hi_user); 709 uint64_t bit_size = die.GetAttributeValueAsUnsigned(DW_AT_byte_size, 0) * 8; 710 if (!bit_size) 711 bit_size = die.GetAttributeValueAsUnsigned(DW_AT_bit_size, 0); 712 if (!bit_size) 713 return llvm::createStringError("unsupported type size"); 714 bool sign; 715 switch (encoding) { 716 case DW_ATE_signed: 717 case DW_ATE_signed_char: 718 sign = true; 719 break; 720 case DW_ATE_unsigned: 721 case DW_ATE_unsigned_char: 722 sign = false; 723 break; 724 default: 725 return llvm::createStringError("unsupported encoding"); 726 } 727 return std::pair{bit_size, sign}; 728 } 729 730 lldb::offset_t 731 DWARFUnit::GetVendorDWARFOpcodeSize(const DataExtractor &data, 732 const lldb::offset_t data_offset, 733 const uint8_t op) const { 734 return GetSymbolFileDWARF().GetVendorDWARFOpcodeSize(data, data_offset, op); 735 } 736 737 bool DWARFUnit::ParseVendorDWARFOpcode(uint8_t op, const DataExtractor &opcodes, 738 lldb::offset_t &offset, 739 std::vector<Value> &stack) const { 740 return GetSymbolFileDWARF().ParseVendorDWARFOpcode(op, opcodes, offset, 741 stack); 742 } 743 744 bool DWARFUnit::ParseDWARFLocationList( 745 const DataExtractor &data, DWARFExpressionList &location_list) const { 746 location_list.Clear(); 747 std::unique_ptr<llvm::DWARFLocationTable> loctable_up = 748 GetLocationTable(data); 749 Log *log = GetLog(DWARFLog::DebugInfo); 750 auto lookup_addr = 751 [&](uint32_t index) -> std::optional<llvm::object::SectionedAddress> { 752 addr_t address = ReadAddressFromDebugAddrSection(index); 753 if (address == LLDB_INVALID_ADDRESS) 754 return std::nullopt; 755 return llvm::object::SectionedAddress{address}; 756 }; 757 auto process_list = [&](llvm::Expected<llvm::DWARFLocationExpression> loc) { 758 if (!loc) { 759 LLDB_LOG_ERROR(log, loc.takeError(), "{0}"); 760 return true; 761 } 762 auto buffer_sp = 763 std::make_shared<DataBufferHeap>(loc->Expr.data(), loc->Expr.size()); 764 DWARFExpression expr = DWARFExpression(DataExtractor( 765 buffer_sp, data.GetByteOrder(), data.GetAddressByteSize())); 766 location_list.AddExpression(loc->Range->LowPC, loc->Range->HighPC, expr); 767 return true; 768 }; 769 llvm::Error error = loctable_up->visitAbsoluteLocationList( 770 0, llvm::object::SectionedAddress{GetBaseAddress()}, lookup_addr, 771 process_list); 772 location_list.Sort(); 773 if (error) { 774 LLDB_LOG_ERROR(log, std::move(error), "{0}"); 775 return false; 776 } 777 return true; 778 } 779 780 DWARFUnit &DWARFUnit::GetNonSkeletonUnit() { 781 ExtractUnitDIEIfNeeded(); 782 if (m_dwo) 783 return *m_dwo; 784 return *this; 785 } 786 787 uint8_t DWARFUnit::GetAddressByteSize(const DWARFUnit *cu) { 788 if (cu) 789 return cu->GetAddressByteSize(); 790 return DWARFUnit::GetDefaultAddressSize(); 791 } 792 793 uint8_t DWARFUnit::GetDefaultAddressSize() { return 4; } 794 795 DWARFCompileUnit *DWARFUnit::GetSkeletonUnit() { 796 if (m_skeleton_unit.load() == nullptr && IsDWOUnit()) { 797 SymbolFileDWARFDwo *dwo = 798 llvm::dyn_cast_or_null<SymbolFileDWARFDwo>(&GetSymbolFileDWARF()); 799 // Do a reverse lookup if the skeleton compile unit wasn't set. 800 DWARFUnit *candidate_skeleton_unit = 801 dwo ? dwo->GetBaseSymbolFile().GetSkeletonUnit(this) : nullptr; 802 if (candidate_skeleton_unit) 803 (void)LinkToSkeletonUnit(*candidate_skeleton_unit); 804 // Linking may fail due to a race, so be sure to return the actual value. 805 } 806 return llvm::dyn_cast_or_null<DWARFCompileUnit>(m_skeleton_unit.load()); 807 } 808 809 bool DWARFUnit::LinkToSkeletonUnit(DWARFUnit &skeleton_unit) { 810 DWARFUnit *expected_unit = nullptr; 811 if (m_skeleton_unit.compare_exchange_strong(expected_unit, &skeleton_unit)) 812 return true; 813 if (expected_unit == &skeleton_unit) { 814 // Exchange failed because it already contained the right value. 815 return true; 816 } 817 return false; // Already linked to a different unit. 818 } 819 820 bool DWARFUnit::Supports_unnamed_objc_bitfields() { 821 if (GetProducer() == eProducerClang) 822 return GetProducerVersion() >= llvm::VersionTuple(425, 0, 13); 823 // Assume all other compilers didn't have incorrect ObjC bitfield info. 824 return true; 825 } 826 827 void DWARFUnit::ParseProducerInfo() { 828 m_producer = eProducerOther; 829 const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly(); 830 if (!die) 831 return; 832 833 llvm::StringRef producer( 834 die->GetAttributeValueAsString(this, DW_AT_producer, nullptr)); 835 if (producer.empty()) 836 return; 837 838 static const RegularExpression g_swiftlang_version_regex( 839 llvm::StringRef(R"(swiftlang-([0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?))")); 840 static const RegularExpression g_clang_version_regex( 841 llvm::StringRef(R"(clang-([0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?))")); 842 843 llvm::SmallVector<llvm::StringRef, 3> matches; 844 if (g_swiftlang_version_regex.Execute(producer, &matches)) { 845 m_producer_version.tryParse(matches[1]); 846 m_producer = eProducerSwift; 847 } else if (producer.contains("clang")) { 848 if (g_clang_version_regex.Execute(producer, &matches)) 849 m_producer_version.tryParse(matches[1]); 850 m_producer = eProducerClang; 851 } else if (producer.contains("GNU")) { 852 m_producer = eProducerGCC; 853 } 854 } 855 856 DWARFProducer DWARFUnit::GetProducer() { 857 if (m_producer == eProducerInvalid) 858 ParseProducerInfo(); 859 return m_producer; 860 } 861 862 llvm::VersionTuple DWARFUnit::GetProducerVersion() { 863 if (m_producer_version.empty()) 864 ParseProducerInfo(); 865 return m_producer_version; 866 } 867 868 uint64_t DWARFUnit::GetDWARFLanguageType() { 869 if (m_language_type) 870 return *m_language_type; 871 872 const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly(); 873 if (!die) 874 m_language_type = 0; 875 else 876 m_language_type = die->GetAttributeValueAsUnsigned(this, DW_AT_language, 0); 877 return *m_language_type; 878 } 879 880 bool DWARFUnit::GetIsOptimized() { 881 if (m_is_optimized == eLazyBoolCalculate) { 882 const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly(); 883 if (die) { 884 m_is_optimized = eLazyBoolNo; 885 if (die->GetAttributeValueAsUnsigned(this, DW_AT_APPLE_optimized, 0) == 886 1) { 887 m_is_optimized = eLazyBoolYes; 888 } 889 } 890 } 891 return m_is_optimized == eLazyBoolYes; 892 } 893 894 FileSpec::Style DWARFUnit::GetPathStyle() { 895 if (!m_comp_dir) 896 ComputeCompDirAndGuessPathStyle(); 897 return m_comp_dir->GetPathStyle(); 898 } 899 900 const FileSpec &DWARFUnit::GetCompilationDirectory() { 901 if (!m_comp_dir) 902 ComputeCompDirAndGuessPathStyle(); 903 return *m_comp_dir; 904 } 905 906 const FileSpec &DWARFUnit::GetAbsolutePath() { 907 if (!m_file_spec) 908 ComputeAbsolutePath(); 909 return *m_file_spec; 910 } 911 912 FileSpec DWARFUnit::GetFile(size_t file_idx) { 913 return m_dwarf.GetFile(*this, file_idx); 914 } 915 916 // DWARF2/3 suggests the form hostname:pathname for compilation directory. 917 // Remove the host part if present. 918 static llvm::StringRef 919 removeHostnameFromPathname(llvm::StringRef path_from_dwarf) { 920 if (!path_from_dwarf.contains(':')) 921 return path_from_dwarf; 922 llvm::StringRef host, path; 923 std::tie(host, path) = path_from_dwarf.split(':'); 924 925 if (host.contains('/')) 926 return path_from_dwarf; 927 928 // check whether we have a windows path, and so the first character is a 929 // drive-letter not a hostname. 930 if (host.size() == 1 && llvm::isAlpha(host[0]) && 931 (path.starts_with("\\") || path.starts_with("/"))) 932 return path_from_dwarf; 933 934 return path; 935 } 936 937 void DWARFUnit::ComputeCompDirAndGuessPathStyle() { 938 m_comp_dir = FileSpec(); 939 const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly(); 940 if (!die) 941 return; 942 943 llvm::StringRef comp_dir = removeHostnameFromPathname( 944 die->GetAttributeValueAsString(this, DW_AT_comp_dir, nullptr)); 945 if (!comp_dir.empty()) { 946 FileSpec::Style comp_dir_style = 947 FileSpec::GuessPathStyle(comp_dir).value_or(FileSpec::Style::native); 948 m_comp_dir = FileSpec(comp_dir, comp_dir_style); 949 } else { 950 // Try to detect the style based on the DW_AT_name attribute, but just store 951 // the detected style in the m_comp_dir field. 952 const char *name = 953 die->GetAttributeValueAsString(this, DW_AT_name, nullptr); 954 m_comp_dir = FileSpec( 955 "", FileSpec::GuessPathStyle(name).value_or(FileSpec::Style::native)); 956 } 957 } 958 959 void DWARFUnit::ComputeAbsolutePath() { 960 m_file_spec = FileSpec(); 961 const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly(); 962 if (!die) 963 return; 964 965 m_file_spec = 966 FileSpec(die->GetAttributeValueAsString(this, DW_AT_name, nullptr), 967 GetPathStyle()); 968 969 if (m_file_spec->IsRelative()) 970 m_file_spec->MakeAbsolute(GetCompilationDirectory()); 971 } 972 973 SymbolFileDWARFDwo *DWARFUnit::GetDwoSymbolFile(bool load_all_debug_info) { 974 if (load_all_debug_info) 975 ExtractUnitDIEIfNeeded(); 976 if (m_dwo) 977 return &llvm::cast<SymbolFileDWARFDwo>(m_dwo->GetSymbolFileDWARF()); 978 return nullptr; 979 } 980 981 const DWARFDebugAranges &DWARFUnit::GetFunctionAranges() { 982 if (m_func_aranges_up == nullptr) { 983 m_func_aranges_up = std::make_unique<DWARFDebugAranges>(); 984 const DWARFDebugInfoEntry *die = DIEPtr(); 985 if (die) 986 die->BuildFunctionAddressRangeTable(this, m_func_aranges_up.get()); 987 988 if (m_dwo) { 989 const DWARFDebugInfoEntry *dwo_die = m_dwo->DIEPtr(); 990 if (dwo_die) 991 dwo_die->BuildFunctionAddressRangeTable(m_dwo.get(), 992 m_func_aranges_up.get()); 993 } 994 995 const bool minimize = false; 996 m_func_aranges_up->Sort(minimize); 997 } 998 return *m_func_aranges_up; 999 } 1000 1001 llvm::Expected<DWARFUnitSP> 1002 DWARFUnit::extract(SymbolFileDWARF &dwarf, user_id_t uid, 1003 const DWARFDataExtractor &debug_info, 1004 DIERef::Section section, lldb::offset_t *offset_ptr) { 1005 assert(debug_info.ValidOffset(*offset_ptr)); 1006 1007 DWARFContext &context = dwarf.GetDWARFContext(); 1008 1009 // FIXME: Either properly map between DIERef::Section and 1010 // llvm::DWARFSectionKind or switch to llvm's definition entirely. 1011 llvm::DWARFSectionKind section_kind_llvm = 1012 section == DIERef::Section::DebugInfo 1013 ? llvm::DWARFSectionKind::DW_SECT_INFO 1014 : llvm::DWARFSectionKind::DW_SECT_EXT_TYPES; 1015 1016 llvm::DWARFDataExtractor debug_info_llvm = debug_info.GetAsLLVMDWARF(); 1017 llvm::DWARFUnitHeader header; 1018 if (llvm::Error extract_err = header.extract( 1019 context.GetAsLLVM(), debug_info_llvm, offset_ptr, section_kind_llvm)) 1020 return std::move(extract_err); 1021 1022 if (context.isDwo()) { 1023 const llvm::DWARFUnitIndex::Entry *entry = nullptr; 1024 const llvm::DWARFUnitIndex &index = header.isTypeUnit() 1025 ? context.GetAsLLVM().getTUIndex() 1026 : context.GetAsLLVM().getCUIndex(); 1027 if (index) { 1028 if (header.isTypeUnit()) 1029 entry = index.getFromHash(header.getTypeHash()); 1030 else if (auto dwo_id = header.getDWOId()) 1031 entry = index.getFromHash(*dwo_id); 1032 } 1033 if (!entry) 1034 entry = index.getFromOffset(header.getOffset()); 1035 if (entry) 1036 if (llvm::Error err = header.applyIndexEntry(entry)) 1037 return std::move(err); 1038 } 1039 1040 const llvm::DWARFDebugAbbrev *abbr = dwarf.DebugAbbrev(); 1041 if (!abbr) 1042 return llvm::make_error<llvm::object::GenericBinaryError>( 1043 "No debug_abbrev data"); 1044 1045 bool abbr_offset_OK = 1046 dwarf.GetDWARFContext().getOrLoadAbbrevData().ValidOffset( 1047 header.getAbbrOffset()); 1048 if (!abbr_offset_OK) 1049 return llvm::make_error<llvm::object::GenericBinaryError>( 1050 "Abbreviation offset for unit is not valid"); 1051 1052 llvm::Expected<const llvm::DWARFAbbreviationDeclarationSet *> abbrevs_or_err = 1053 abbr->getAbbreviationDeclarationSet(header.getAbbrOffset()); 1054 if (!abbrevs_or_err) 1055 return abbrevs_or_err.takeError(); 1056 1057 const llvm::DWARFAbbreviationDeclarationSet *abbrevs = *abbrevs_or_err; 1058 if (!abbrevs) 1059 return llvm::make_error<llvm::object::GenericBinaryError>( 1060 "No abbrev exists at the specified offset."); 1061 1062 bool is_dwo = dwarf.GetDWARFContext().isDwo(); 1063 if (header.isTypeUnit()) 1064 return DWARFUnitSP( 1065 new DWARFTypeUnit(dwarf, uid, header, *abbrevs, section, is_dwo)); 1066 return DWARFUnitSP( 1067 new DWARFCompileUnit(dwarf, uid, header, *abbrevs, section, is_dwo)); 1068 } 1069 1070 const lldb_private::DWARFDataExtractor &DWARFUnit::GetData() const { 1071 return m_section == DIERef::Section::DebugTypes 1072 ? m_dwarf.GetDWARFContext().getOrLoadDebugTypesData() 1073 : m_dwarf.GetDWARFContext().getOrLoadDebugInfoData(); 1074 } 1075 1076 uint32_t DWARFUnit::GetHeaderByteSize() const { return m_header.getSize(); } 1077 1078 std::optional<uint64_t> 1079 DWARFUnit::GetStringOffsetSectionItem(uint32_t index) const { 1080 lldb::offset_t offset = 1081 GetStrOffsetsBase() + index * m_header.getDwarfOffsetByteSize(); 1082 return m_dwarf.GetDWARFContext().getOrLoadStrOffsetsData().GetMaxU64( 1083 &offset, m_header.getDwarfOffsetByteSize()); 1084 } 1085 1086 llvm::Expected<llvm::DWARFAddressRangesVector> 1087 DWARFUnit::FindRnglistFromOffset(dw_offset_t offset) { 1088 if (GetVersion() <= 4) { 1089 llvm::DWARFDataExtractor data = 1090 m_dwarf.GetDWARFContext().getOrLoadRangesData().GetAsLLVMDWARF(); 1091 data.setAddressSize(m_header.getAddressByteSize()); 1092 1093 llvm::DWARFDebugRangeList list; 1094 if (llvm::Error e = list.extract(data, &offset)) 1095 return e; 1096 return list.getAbsoluteRanges( 1097 llvm::object::SectionedAddress{GetBaseAddress()}); 1098 } 1099 1100 // DWARF >= v5 1101 if (!GetRnglistTable()) 1102 return llvm::createStringError(std::errc::invalid_argument, 1103 "missing or invalid range list table"); 1104 1105 llvm::DWARFDataExtractor data = GetRnglistData().GetAsLLVMDWARF(); 1106 1107 // As DW_AT_rnglists_base may be missing we need to call setAddressSize. 1108 data.setAddressSize(m_header.getAddressByteSize()); 1109 auto range_list_or_error = GetRnglistTable()->findList(data, offset); 1110 if (!range_list_or_error) 1111 return range_list_or_error.takeError(); 1112 1113 return range_list_or_error->getAbsoluteRanges( 1114 llvm::object::SectionedAddress{GetBaseAddress()}, GetAddressByteSize(), 1115 [&](uint32_t index) { 1116 uint32_t index_size = GetAddressByteSize(); 1117 dw_offset_t addr_base = GetAddrBase(); 1118 lldb::offset_t offset = 1119 addr_base + static_cast<lldb::offset_t>(index) * index_size; 1120 return llvm::object::SectionedAddress{ 1121 m_dwarf.GetDWARFContext().getOrLoadAddrData().GetMaxU64( 1122 &offset, index_size)}; 1123 }); 1124 } 1125 1126 llvm::Expected<llvm::DWARFAddressRangesVector> 1127 DWARFUnit::FindRnglistFromIndex(uint32_t index) { 1128 llvm::Expected<uint64_t> maybe_offset = GetRnglistOffset(index); 1129 if (!maybe_offset) 1130 return maybe_offset.takeError(); 1131 return FindRnglistFromOffset(*maybe_offset); 1132 } 1133 1134 bool DWARFUnit::HasAny(llvm::ArrayRef<dw_tag_t> tags) { 1135 ExtractUnitDIEIfNeeded(); 1136 if (m_dwo) 1137 return m_dwo->HasAny(tags); 1138 1139 for (const auto &die : m_die_array) { 1140 for (const auto tag : tags) { 1141 if (tag == die.Tag()) 1142 return true; 1143 } 1144 } 1145 return false; 1146 } 1147