1 //===-- HashedNameToDIE.cpp -------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "HashedNameToDIE.h" 11 12 void 13 DWARFMappedHash::ExtractDIEArray (const DIEInfoArray &die_info_array, DIEArray &die_offsets) 14 { 15 const size_t count = die_info_array.size(); 16 for (size_t i=0; i<count; ++i) 17 die_offsets.emplace_back(die_info_array[i].cu_offset, die_info_array[i].offset); 18 } 19 20 void 21 DWARFMappedHash::ExtractDIEArray (const DIEInfoArray &die_info_array, 22 const dw_tag_t tag, 23 DIEArray &die_offsets) 24 { 25 if (tag == 0) 26 { 27 ExtractDIEArray (die_info_array, die_offsets); 28 } 29 else 30 { 31 const size_t count = die_info_array.size(); 32 for (size_t i=0; i<count; ++i) 33 { 34 const dw_tag_t die_tag = die_info_array[i].tag; 35 bool tag_matches = die_tag == 0 || tag == die_tag; 36 if (!tag_matches) 37 { 38 if (die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type) 39 tag_matches = tag == DW_TAG_structure_type || tag == DW_TAG_class_type; 40 } 41 if (tag_matches) 42 die_offsets.emplace_back(die_info_array[i].cu_offset, die_info_array[i].offset); 43 } 44 } 45 } 46 47 void 48 DWARFMappedHash::ExtractDIEArray (const DIEInfoArray &die_info_array, 49 const dw_tag_t tag, 50 const uint32_t qualified_name_hash, 51 DIEArray &die_offsets) 52 { 53 if (tag == 0) 54 { 55 ExtractDIEArray (die_info_array, die_offsets); 56 } 57 else 58 { 59 const size_t count = die_info_array.size(); 60 for (size_t i=0; i<count; ++i) 61 { 62 if (qualified_name_hash != die_info_array[i].qualified_name_hash) 63 continue; 64 const dw_tag_t die_tag = die_info_array[i].tag; 65 bool tag_matches = die_tag == 0 || tag == die_tag; 66 if (!tag_matches) 67 { 68 if (die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type) 69 tag_matches = tag == DW_TAG_structure_type || tag == DW_TAG_class_type; 70 } 71 if (tag_matches) 72 die_offsets.emplace_back(die_info_array[i].cu_offset, die_info_array[i].offset); 73 } 74 } 75 } 76 77 void 78 DWARFMappedHash::ExtractClassOrStructDIEArray (const DIEInfoArray &die_info_array, 79 bool return_implementation_only_if_available, 80 DIEArray &die_offsets) 81 { 82 const size_t count = die_info_array.size(); 83 for (size_t i=0; i<count; ++i) 84 { 85 const dw_tag_t die_tag = die_info_array[i].tag; 86 if (die_tag == 0 || die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type) 87 { 88 if (die_info_array[i].type_flags & eTypeFlagClassIsImplementation) 89 { 90 if (return_implementation_only_if_available) 91 { 92 // We found the one true definition for this class, so 93 // only return that 94 die_offsets.clear(); 95 die_offsets.emplace_back(die_info_array[i].cu_offset, die_info_array[i].offset); 96 return; 97 } 98 else 99 { 100 // Put the one true definition as the first entry so it 101 // matches first 102 die_offsets.emplace(die_offsets.begin(), die_info_array[i].cu_offset, die_info_array[i].offset); 103 } 104 } 105 else 106 { 107 die_offsets.emplace_back(die_info_array[i].cu_offset, die_info_array[i].offset); 108 } 109 } 110 } 111 } 112 113 void 114 DWARFMappedHash::ExtractTypesFromDIEArray (const DIEInfoArray &die_info_array, 115 uint32_t type_flag_mask, 116 uint32_t type_flag_value, 117 DIEArray &die_offsets) 118 { 119 const size_t count = die_info_array.size(); 120 for (size_t i=0; i<count; ++i) 121 { 122 if ((die_info_array[i].type_flags & type_flag_mask) == type_flag_value) 123 die_offsets.emplace_back(die_info_array[i].cu_offset, die_info_array[i].offset); 124 } 125 } 126 127 const char * 128 DWARFMappedHash::GetAtomTypeName (uint16_t atom) 129 { 130 switch (atom) 131 { 132 case eAtomTypeNULL: return "NULL"; 133 case eAtomTypeDIEOffset: return "die-offset"; 134 case eAtomTypeCUOffset: return "cu-offset"; 135 case eAtomTypeTag: return "die-tag"; 136 case eAtomTypeNameFlags: return "name-flags"; 137 case eAtomTypeTypeFlags: return "type-flags"; 138 case eAtomTypeQualNameHash: return "qualified-name-hash"; 139 } 140 return "<invalid>"; 141 } 142 143 DWARFMappedHash::DIEInfo::DIEInfo () : 144 cu_offset (DW_INVALID_OFFSET), 145 offset (DW_INVALID_OFFSET), 146 tag (0), 147 type_flags (0), 148 qualified_name_hash (0) 149 { 150 } 151 152 DWARFMappedHash::DIEInfo::DIEInfo (dw_offset_t c, 153 dw_offset_t o, 154 dw_tag_t t, 155 uint32_t f, 156 uint32_t h) : 157 cu_offset (c), 158 offset (o), 159 tag (t), 160 type_flags (f), 161 qualified_name_hash (h) 162 { 163 } 164 165 DWARFMappedHash::Prologue::Prologue (dw_offset_t _die_base_offset) : 166 die_base_offset (_die_base_offset), 167 atoms(), 168 atom_mask (0), 169 min_hash_data_byte_size(0), 170 hash_data_has_fixed_byte_size(true) 171 { 172 // Define an array of DIE offsets by first defining an array, 173 // and then define the atom type for the array, in this case 174 // we have an array of DIE offsets 175 AppendAtom (eAtomTypeDIEOffset, DW_FORM_data4); 176 } 177 178 void 179 DWARFMappedHash::Prologue::ClearAtoms () 180 { 181 hash_data_has_fixed_byte_size = true; 182 min_hash_data_byte_size = 0; 183 atom_mask = 0; 184 atoms.clear(); 185 } 186 187 bool 188 DWARFMappedHash::Prologue::ContainsAtom (AtomType atom_type) const 189 { 190 return (atom_mask & (1u << atom_type)) != 0; 191 } 192 193 void 194 DWARFMappedHash::Prologue::Clear () 195 { 196 die_base_offset = 0; 197 ClearAtoms (); 198 } 199 200 void 201 DWARFMappedHash::Prologue::AppendAtom (AtomType type, dw_form_t form) 202 { 203 atoms.push_back ({type, form}); 204 atom_mask |= 1u << type; 205 switch (form) 206 { 207 case DW_FORM_indirect: 208 case DW_FORM_exprloc: 209 case DW_FORM_flag_present: 210 case DW_FORM_ref_sig8: 211 assert (!"Unhandled atom form"); 212 break; 213 214 case DW_FORM_string: 215 case DW_FORM_block: 216 case DW_FORM_block1: 217 case DW_FORM_sdata: 218 case DW_FORM_udata: 219 case DW_FORM_ref_udata: 220 case DW_FORM_GNU_addr_index: 221 case DW_FORM_GNU_str_index: 222 hash_data_has_fixed_byte_size = false; 223 LLVM_FALLTHROUGH; 224 case DW_FORM_flag: 225 case DW_FORM_data1: 226 case DW_FORM_ref1: 227 case DW_FORM_sec_offset: 228 min_hash_data_byte_size += 1; 229 break; 230 231 case DW_FORM_block2: 232 hash_data_has_fixed_byte_size = false; 233 LLVM_FALLTHROUGH; 234 case DW_FORM_data2: 235 case DW_FORM_ref2: 236 min_hash_data_byte_size += 2; 237 break; 238 239 case DW_FORM_block4: 240 hash_data_has_fixed_byte_size = false; 241 LLVM_FALLTHROUGH; 242 case DW_FORM_data4: 243 case DW_FORM_ref4: 244 case DW_FORM_addr: 245 case DW_FORM_ref_addr: 246 case DW_FORM_strp: 247 min_hash_data_byte_size += 4; 248 break; 249 250 case DW_FORM_data8: 251 case DW_FORM_ref8: 252 min_hash_data_byte_size += 8; 253 break; 254 255 } 256 } 257 258 lldb::offset_t 259 DWARFMappedHash::Prologue::Read (const lldb_private::DataExtractor &data, 260 lldb::offset_t offset) 261 { 262 ClearAtoms (); 263 264 die_base_offset = data.GetU32 (&offset); 265 266 const uint32_t atom_count = data.GetU32 (&offset); 267 if (atom_count == 0x00060003u) 268 { 269 // Old format, deal with contents of old pre-release format 270 while (data.GetU32(&offset)) 271 /* do nothing */; 272 273 // Hardcode to the only known value for now. 274 AppendAtom (eAtomTypeDIEOffset, DW_FORM_data4); 275 } 276 else 277 { 278 for (uint32_t i=0; i<atom_count; ++i) 279 { 280 AtomType type = (AtomType)data.GetU16 (&offset); 281 dw_form_t form = (dw_form_t)data.GetU16 (&offset); 282 AppendAtom (type, form); 283 } 284 } 285 return offset; 286 } 287 288 size_t 289 DWARFMappedHash::Prologue::GetByteSize () const 290 { 291 // Add an extra count to the atoms size for the zero termination Atom that gets 292 // written to disk 293 return sizeof(die_base_offset) + sizeof(uint32_t) + atoms.size() * sizeof(Atom); 294 } 295 296 size_t 297 DWARFMappedHash::Prologue::GetMinimumHashDataByteSize () const 298 { 299 return min_hash_data_byte_size; 300 } 301 302 bool 303 DWARFMappedHash::Prologue::HashDataHasFixedByteSize() const 304 { 305 return hash_data_has_fixed_byte_size; 306 } 307 308 size_t 309 DWARFMappedHash::Header::GetByteSize (const HeaderData &header_data) 310 { 311 return header_data.GetByteSize(); 312 } 313 314 lldb::offset_t 315 DWARFMappedHash::Header::Read (lldb_private::DataExtractor &data, lldb::offset_t offset) 316 { 317 offset = MappedHash::Header<Prologue>::Read (data, offset); 318 if (offset != UINT32_MAX) 319 { 320 offset = header_data.Read (data, offset); 321 } 322 return offset; 323 } 324 325 bool 326 DWARFMappedHash::Header::Read (const lldb_private::DWARFDataExtractor &data, 327 lldb::offset_t *offset_ptr, 328 DIEInfo &hash_data) const 329 { 330 const size_t num_atoms = header_data.atoms.size(); 331 if (num_atoms == 0) 332 return false; 333 334 for (size_t i=0; i<num_atoms; ++i) 335 { 336 DWARFFormValue form_value (NULL, header_data.atoms[i].form); 337 338 if (!form_value.ExtractValue(data, offset_ptr)) 339 return false; 340 341 switch (header_data.atoms[i].type) 342 { 343 case eAtomTypeDIEOffset: // DIE offset, check form for encoding 344 hash_data.offset = (dw_offset_t)form_value.Reference (header_data.die_base_offset); 345 break; 346 347 case eAtomTypeTag: // DW_TAG value for the DIE 348 hash_data.tag = (dw_tag_t)form_value.Unsigned (); 349 break; 350 351 case eAtomTypeTypeFlags: // Flags from enum TypeFlags 352 hash_data.type_flags = (uint32_t)form_value.Unsigned (); 353 break; 354 355 case eAtomTypeQualNameHash: // Flags from enum TypeFlags 356 hash_data.qualified_name_hash = form_value.Unsigned (); 357 break; 358 359 default: 360 // We can always skip atoms we don't know about 361 break; 362 } 363 } 364 return true; 365 } 366 367 void 368 DWARFMappedHash::Header::Dump (lldb_private::Stream& strm, const DIEInfo &hash_data) const 369 { 370 const size_t num_atoms = header_data.atoms.size(); 371 for (size_t i=0; i<num_atoms; ++i) 372 { 373 if (i > 0) 374 strm.PutCString (", "); 375 376 DWARFFormValue form_value (NULL, header_data.atoms[i].form); 377 switch (header_data.atoms[i].type) 378 { 379 case eAtomTypeDIEOffset: // DIE offset, check form for encoding 380 strm.Printf ("{0x%8.8x}", hash_data.offset); 381 break; 382 383 case eAtomTypeTag: // DW_TAG value for the DIE 384 { 385 const char *tag_cstr = lldb_private::DW_TAG_value_to_name (hash_data.tag); 386 if (tag_cstr) 387 strm.PutCString (tag_cstr); 388 else 389 strm.Printf ("DW_TAG_(0x%4.4x)", hash_data.tag); 390 } 391 break; 392 393 case eAtomTypeTypeFlags: // Flags from enum TypeFlags 394 strm.Printf ("0x%2.2x", hash_data.type_flags); 395 if (hash_data.type_flags) 396 { 397 strm.PutCString (" ("); 398 if (hash_data.type_flags & eTypeFlagClassIsImplementation) 399 strm.PutCString (" implementation"); 400 strm.PutCString (" )"); 401 } 402 break; 403 404 case eAtomTypeQualNameHash: // Flags from enum TypeFlags 405 strm.Printf ("0x%8.8x", hash_data.qualified_name_hash); 406 break; 407 408 default: 409 strm.Printf ("AtomType(0x%x)", header_data.atoms[i].type); 410 break; 411 } 412 } 413 } 414 415 DWARFMappedHash::MemoryTable::MemoryTable (lldb_private::DWARFDataExtractor &table_data, 416 const lldb_private::DWARFDataExtractor &string_table, 417 const char *name) : 418 MappedHash::MemoryTable<uint32_t, Header, DIEInfoArray> (table_data), 419 m_data (table_data), 420 m_string_table (string_table), 421 m_name (name) 422 { 423 } 424 425 const char * 426 DWARFMappedHash::MemoryTable::GetStringForKeyType (KeyType key) const 427 { 428 // The key in the DWARF table is the .debug_str offset for the string 429 return m_string_table.PeekCStr (key); 430 } 431 432 bool 433 DWARFMappedHash::MemoryTable::ReadHashData (uint32_t hash_data_offset, HashData &hash_data) const 434 { 435 lldb::offset_t offset = hash_data_offset; 436 offset += 4; // Skip string table offset that contains offset of hash name in .debug_str 437 const uint32_t count = m_data.GetU32 (&offset); 438 if (count > 0) 439 { 440 hash_data.resize(count); 441 for (uint32_t i=0; i<count; ++i) 442 { 443 if (!m_header.Read(m_data, &offset, hash_data[i])) 444 return false; 445 } 446 } 447 else 448 hash_data.clear(); 449 return true; 450 } 451 452 DWARFMappedHash::MemoryTable::Result 453 DWARFMappedHash::MemoryTable::GetHashDataForName (const char *name, 454 lldb::offset_t* hash_data_offset_ptr, 455 Pair &pair) const 456 { 457 pair.key = m_data.GetU32 (hash_data_offset_ptr); 458 pair.value.clear(); 459 460 // If the key is zero, this terminates our chain of HashData objects 461 // for this hash value. 462 if (pair.key == 0) 463 return eResultEndOfHashData; 464 465 // There definitely should be a string for this string offset, if 466 // there isn't, there is something wrong, return and error 467 const char *strp_cstr = m_string_table.PeekCStr (pair.key); 468 if (strp_cstr == NULL) 469 { 470 *hash_data_offset_ptr = UINT32_MAX; 471 return eResultError; 472 } 473 474 const uint32_t count = m_data.GetU32 (hash_data_offset_ptr); 475 const size_t min_total_hash_data_size = count * m_header.header_data.GetMinimumHashDataByteSize(); 476 if (count > 0 && m_data.ValidOffsetForDataOfSize (*hash_data_offset_ptr, min_total_hash_data_size)) 477 { 478 // We have at least one HashData entry, and we have enough 479 // data to parse at least "count" HashData entries. 480 481 // First make sure the entire C string matches... 482 const bool match = strcmp (name, strp_cstr) == 0; 483 484 if (!match && m_header.header_data.HashDataHasFixedByteSize()) 485 { 486 // If the string doesn't match and we have fixed size data, 487 // we can just add the total byte size of all HashData objects 488 // to the hash data offset and be done... 489 *hash_data_offset_ptr += min_total_hash_data_size; 490 } 491 else 492 { 493 // If the string does match, or we don't have fixed size data 494 // then we need to read the hash data as a stream. If the 495 // string matches we also append all HashData objects to the 496 // value array. 497 for (uint32_t i=0; i<count; ++i) 498 { 499 DIEInfo die_info; 500 if (m_header.Read(m_data, hash_data_offset_ptr, die_info)) 501 { 502 // Only happened if the HashData of the string matched... 503 if (match) 504 pair.value.push_back (die_info); 505 } 506 else 507 { 508 // Something went wrong while reading the data 509 *hash_data_offset_ptr = UINT32_MAX; 510 return eResultError; 511 } 512 } 513 } 514 // Return the correct response depending on if the string matched 515 // or not... 516 if (match) 517 return eResultKeyMatch; // The key (cstring) matches and we have lookup results! 518 else 519 return eResultKeyMismatch; // The key doesn't match, this function will get called 520 // again for the next key/value or the key terminator 521 // which in our case is a zero .debug_str offset. 522 } 523 else 524 { 525 *hash_data_offset_ptr = UINT32_MAX; 526 return eResultError; 527 } 528 } 529 530 DWARFMappedHash::MemoryTable::Result 531 DWARFMappedHash::MemoryTable::AppendHashDataForRegularExpression ( 532 const lldb_private::RegularExpression& regex, 533 lldb::offset_t* hash_data_offset_ptr, 534 Pair &pair) const 535 { 536 pair.key = m_data.GetU32 (hash_data_offset_ptr); 537 // If the key is zero, this terminates our chain of HashData objects 538 // for this hash value. 539 if (pair.key == 0) 540 return eResultEndOfHashData; 541 542 // There definitely should be a string for this string offset, if 543 // there isn't, there is something wrong, return and error 544 const char *strp_cstr = m_string_table.PeekCStr (pair.key); 545 if (strp_cstr == NULL) 546 return eResultError; 547 548 const uint32_t count = m_data.GetU32 (hash_data_offset_ptr); 549 const size_t min_total_hash_data_size = count * m_header.header_data.GetMinimumHashDataByteSize(); 550 if (count > 0 && m_data.ValidOffsetForDataOfSize (*hash_data_offset_ptr, min_total_hash_data_size)) 551 { 552 const bool match = regex.Execute(strp_cstr); 553 554 if (!match && m_header.header_data.HashDataHasFixedByteSize()) 555 { 556 // If the regex doesn't match and we have fixed size data, 557 // we can just add the total byte size of all HashData objects 558 // to the hash data offset and be done... 559 *hash_data_offset_ptr += min_total_hash_data_size; 560 } 561 else 562 { 563 // If the string does match, or we don't have fixed size data 564 // then we need to read the hash data as a stream. If the 565 // string matches we also append all HashData objects to the 566 // value array. 567 for (uint32_t i=0; i<count; ++i) 568 { 569 DIEInfo die_info; 570 if (m_header.Read(m_data, hash_data_offset_ptr, die_info)) 571 { 572 // Only happened if the HashData of the string matched... 573 if (match) 574 pair.value.push_back (die_info); 575 } 576 else 577 { 578 // Something went wrong while reading the data 579 *hash_data_offset_ptr = UINT32_MAX; 580 return eResultError; 581 } 582 } 583 } 584 // Return the correct response depending on if the string matched 585 // or not... 586 if (match) 587 return eResultKeyMatch; // The key (cstring) matches and we have lookup results! 588 else 589 return eResultKeyMismatch; // The key doesn't match, this function will get called 590 // again for the next key/value or the key terminator 591 // which in our case is a zero .debug_str offset. 592 } 593 else 594 { 595 *hash_data_offset_ptr = UINT32_MAX; 596 return eResultError; 597 } 598 } 599 600 size_t 601 DWARFMappedHash::MemoryTable::AppendAllDIEsThatMatchingRegex ( 602 const lldb_private::RegularExpression& regex, 603 DIEInfoArray &die_info_array) const 604 { 605 const uint32_t hash_count = m_header.hashes_count; 606 Pair pair; 607 for (uint32_t offset_idx=0; offset_idx<hash_count; ++offset_idx) 608 { 609 lldb::offset_t hash_data_offset = GetHashDataOffset (offset_idx); 610 while (hash_data_offset != UINT32_MAX) 611 { 612 const lldb::offset_t prev_hash_data_offset = hash_data_offset; 613 Result hash_result = AppendHashDataForRegularExpression (regex, &hash_data_offset, pair); 614 if (prev_hash_data_offset == hash_data_offset) 615 break; 616 617 // Check the result of getting our hash data 618 switch (hash_result) 619 { 620 case eResultKeyMatch: 621 case eResultKeyMismatch: 622 // Whether we matches or not, it doesn't matter, we 623 // keep looking. 624 break; 625 626 case eResultEndOfHashData: 627 case eResultError: 628 hash_data_offset = UINT32_MAX; 629 break; 630 } 631 } 632 } 633 die_info_array.swap (pair.value); 634 return die_info_array.size(); 635 } 636 637 size_t 638 DWARFMappedHash::MemoryTable::AppendAllDIEsInRange (const uint32_t die_offset_start, 639 const uint32_t die_offset_end, 640 DIEInfoArray &die_info_array) const 641 { 642 const uint32_t hash_count = m_header.hashes_count; 643 for (uint32_t offset_idx=0; offset_idx<hash_count; ++offset_idx) 644 { 645 bool done = false; 646 lldb::offset_t hash_data_offset = GetHashDataOffset (offset_idx); 647 while (!done && hash_data_offset != UINT32_MAX) 648 { 649 KeyType key = m_data.GetU32 (&hash_data_offset); 650 // If the key is zero, this terminates our chain of HashData objects 651 // for this hash value. 652 if (key == 0) 653 break; 654 655 const uint32_t count = m_data.GetU32 (&hash_data_offset); 656 for (uint32_t i=0; i<count; ++i) 657 { 658 DIEInfo die_info; 659 if (m_header.Read(m_data, &hash_data_offset, die_info)) 660 { 661 if (die_info.offset == 0) 662 done = true; 663 if (die_offset_start <= die_info.offset && die_info.offset < die_offset_end) 664 die_info_array.push_back(die_info); 665 } 666 } 667 } 668 } 669 return die_info_array.size(); 670 } 671 672 size_t 673 DWARFMappedHash::MemoryTable::FindByName (const char *name, DIEArray &die_offsets) 674 { 675 if (!name || !name[0]) 676 return 0; 677 678 DIEInfoArray die_info_array; 679 if (FindByName(name, die_info_array)) 680 DWARFMappedHash::ExtractDIEArray (die_info_array, die_offsets); 681 return die_info_array.size(); 682 } 683 684 size_t 685 DWARFMappedHash::MemoryTable::FindByNameAndTag (const char *name, 686 const dw_tag_t tag, 687 DIEArray &die_offsets) 688 { 689 DIEInfoArray die_info_array; 690 if (FindByName(name, die_info_array)) 691 DWARFMappedHash::ExtractDIEArray (die_info_array, tag, die_offsets); 692 return die_info_array.size(); 693 } 694 695 size_t 696 DWARFMappedHash::MemoryTable::FindByNameAndTagAndQualifiedNameHash (const char *name, 697 const dw_tag_t tag, 698 const uint32_t qualified_name_hash, 699 DIEArray &die_offsets) 700 { 701 DIEInfoArray die_info_array; 702 if (FindByName(name, die_info_array)) 703 DWARFMappedHash::ExtractDIEArray (die_info_array, tag, qualified_name_hash, die_offsets); 704 return die_info_array.size(); 705 } 706 707 size_t 708 DWARFMappedHash::MemoryTable::FindCompleteObjCClassByName (const char *name, 709 DIEArray &die_offsets, 710 bool must_be_implementation) 711 { 712 DIEInfoArray die_info_array; 713 if (FindByName(name, die_info_array)) 714 { 715 if (must_be_implementation && GetHeader().header_data.ContainsAtom (eAtomTypeTypeFlags)) 716 { 717 // If we have two atoms, then we have the DIE offset and 718 // the type flags so we can find the objective C class 719 // efficiently. 720 DWARFMappedHash::ExtractTypesFromDIEArray (die_info_array, 721 UINT32_MAX, 722 eTypeFlagClassIsImplementation, 723 die_offsets); 724 } 725 else 726 { 727 // We don't only want the one true definition, so try and see 728 // what we can find, and only return class or struct DIEs. 729 // If we do have the full implementation, then return it alone, 730 // else return all possible matches. 731 const bool return_implementation_only_if_available = true; 732 DWARFMappedHash::ExtractClassOrStructDIEArray (die_info_array, 733 return_implementation_only_if_available, 734 die_offsets); 735 } 736 } 737 return die_offsets.size(); 738 } 739 740 size_t 741 DWARFMappedHash::MemoryTable::FindByName (const char *name, DIEInfoArray &die_info_array) 742 { 743 if (!name || !name[0]) 744 return 0; 745 746 Pair kv_pair; 747 size_t old_size = die_info_array.size(); 748 if (Find (name, kv_pair)) 749 { 750 die_info_array.swap(kv_pair.value); 751 return die_info_array.size() - old_size; 752 } 753 return 0; 754 } 755