|  | //===-- SymbolFileDWARF.cpp ------------------------------------*- C++ -*-===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "SymbolFileDWARF.h" | 
|  |  | 
|  | // Other libraries and framework includes | 
|  | #include "clang/AST/ASTConsumer.h" | 
|  | #include "clang/AST/ASTContext.h" | 
|  | #include "clang/AST/Decl.h" | 
|  | #include "clang/AST/DeclGroup.h" | 
|  | #include "clang/AST/DeclObjC.h" | 
|  | #include "clang/AST/DeclTemplate.h" | 
|  | #include "clang/Basic/Builtins.h" | 
|  | #include "clang/Basic/IdentifierTable.h" | 
|  | #include "clang/Basic/LangOptions.h" | 
|  | #include "clang/Basic/SourceManager.h" | 
|  | #include "clang/Basic/TargetInfo.h" | 
|  | #include "clang/Basic/Specifiers.h" | 
|  | #include "clang/Sema/DeclSpec.h" | 
|  |  | 
|  | #include "llvm/Support/Casting.h" | 
|  |  | 
|  | #include "lldb/Core/Module.h" | 
|  | #include "lldb/Core/PluginManager.h" | 
|  | #include "lldb/Core/RegularExpression.h" | 
|  | #include "lldb/Core/Scalar.h" | 
|  | #include "lldb/Core/Section.h" | 
|  | #include "lldb/Core/StreamFile.h" | 
|  | #include "lldb/Core/StreamString.h" | 
|  | #include "lldb/Core/Timer.h" | 
|  | #include "lldb/Core/Value.h" | 
|  |  | 
|  | #include "lldb/Host/Host.h" | 
|  |  | 
|  | #include "lldb/Symbol/Block.h" | 
|  | #include "lldb/Symbol/ClangExternalASTSourceCallbacks.h" | 
|  | #include "lldb/Symbol/CompileUnit.h" | 
|  | #include "lldb/Symbol/LineTable.h" | 
|  | #include "lldb/Symbol/ObjectFile.h" | 
|  | #include "lldb/Symbol/SymbolVendor.h" | 
|  | #include "lldb/Symbol/VariableList.h" | 
|  |  | 
|  | #include "lldb/Target/ObjCLanguageRuntime.h" | 
|  | #include "lldb/Target/CPPLanguageRuntime.h" | 
|  |  | 
|  | #include "DWARFCompileUnit.h" | 
|  | #include "DWARFDebugAbbrev.h" | 
|  | #include "DWARFDebugAranges.h" | 
|  | #include "DWARFDebugInfo.h" | 
|  | #include "DWARFDebugInfoEntry.h" | 
|  | #include "DWARFDebugLine.h" | 
|  | #include "DWARFDebugPubnames.h" | 
|  | #include "DWARFDebugRanges.h" | 
|  | #include "DWARFDeclContext.h" | 
|  | #include "DWARFDIECollection.h" | 
|  | #include "DWARFFormValue.h" | 
|  | #include "DWARFLocationList.h" | 
|  | #include "LogChannelDWARF.h" | 
|  | #include "SymbolFileDWARFDebugMap.h" | 
|  |  | 
|  | #include <map> | 
|  |  | 
|  | //#define ENABLE_DEBUG_PRINTF // COMMENT OUT THIS LINE PRIOR TO CHECKIN | 
|  |  | 
|  | #ifdef ENABLE_DEBUG_PRINTF | 
|  | #include <stdio.h> | 
|  | #define DEBUG_PRINTF(fmt, ...) printf(fmt, __VA_ARGS__) | 
|  | #else | 
|  | #define DEBUG_PRINTF(fmt, ...) | 
|  | #endif | 
|  |  | 
|  | #define DIE_IS_BEING_PARSED ((lldb_private::Type*)1) | 
|  |  | 
|  | using namespace lldb; | 
|  | using namespace lldb_private; | 
|  |  | 
|  | //static inline bool | 
|  | //child_requires_parent_class_union_or_struct_to_be_completed (dw_tag_t tag) | 
|  | //{ | 
|  | //    switch (tag) | 
|  | //    { | 
|  | //    default: | 
|  | //        break; | 
|  | //    case DW_TAG_subprogram: | 
|  | //    case DW_TAG_inlined_subroutine: | 
|  | //    case DW_TAG_class_type: | 
|  | //    case DW_TAG_structure_type: | 
|  | //    case DW_TAG_union_type: | 
|  | //        return true; | 
|  | //    } | 
|  | //    return false; | 
|  | //} | 
|  | // | 
|  | static AccessType | 
|  | DW_ACCESS_to_AccessType (uint32_t dwarf_accessibility) | 
|  | { | 
|  | switch (dwarf_accessibility) | 
|  | { | 
|  | case DW_ACCESS_public:      return eAccessPublic; | 
|  | case DW_ACCESS_private:     return eAccessPrivate; | 
|  | case DW_ACCESS_protected:   return eAccessProtected; | 
|  | default:                    break; | 
|  | } | 
|  | return eAccessNone; | 
|  | } | 
|  |  | 
|  | #if defined(LLDB_CONFIGURATION_DEBUG) || defined(LLDB_CONFIGURATION_RELEASE) | 
|  |  | 
|  | class DIEStack | 
|  | { | 
|  | public: | 
|  |  | 
|  | void Push (DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die) | 
|  | { | 
|  | m_dies.push_back (DIEInfo(cu, die)); | 
|  | } | 
|  |  | 
|  |  | 
|  | void LogDIEs (Log *log, SymbolFileDWARF *dwarf) | 
|  | { | 
|  | StreamString log_strm; | 
|  | const size_t n = m_dies.size(); | 
|  | log_strm.Printf("DIEStack[%" PRIu64 "]:\n", (uint64_t)n); | 
|  | for (size_t i=0; i<n; i++) | 
|  | { | 
|  | DWARFCompileUnit *cu = m_dies[i].cu; | 
|  | const DWARFDebugInfoEntry *die = m_dies[i].die; | 
|  | std::string qualified_name; | 
|  | die->GetQualifiedName(dwarf, cu, qualified_name); | 
|  | log_strm.Printf ("[%" PRIu64 "] 0x%8.8x: %s name='%s'\n", | 
|  | (uint64_t)i, | 
|  | die->GetOffset(), | 
|  | DW_TAG_value_to_name(die->Tag()), | 
|  | qualified_name.c_str()); | 
|  | } | 
|  | log->PutCString(log_strm.GetData()); | 
|  | } | 
|  | void Pop () | 
|  | { | 
|  | m_dies.pop_back(); | 
|  | } | 
|  |  | 
|  | class ScopedPopper | 
|  | { | 
|  | public: | 
|  | ScopedPopper (DIEStack &die_stack) : | 
|  | m_die_stack (die_stack), | 
|  | m_valid (false) | 
|  | { | 
|  | } | 
|  |  | 
|  | void | 
|  | Push (DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die) | 
|  | { | 
|  | m_valid = true; | 
|  | m_die_stack.Push (cu, die); | 
|  | } | 
|  |  | 
|  | ~ScopedPopper () | 
|  | { | 
|  | if (m_valid) | 
|  | m_die_stack.Pop(); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | protected: | 
|  | DIEStack &m_die_stack; | 
|  | bool m_valid; | 
|  | }; | 
|  |  | 
|  | protected: | 
|  | struct DIEInfo { | 
|  | DIEInfo (DWARFCompileUnit *c, const DWARFDebugInfoEntry *d) : | 
|  | cu(c), | 
|  | die(d) | 
|  | { | 
|  | } | 
|  | DWARFCompileUnit *cu; | 
|  | const DWARFDebugInfoEntry *die; | 
|  | }; | 
|  | typedef std::vector<DIEInfo> Stack; | 
|  | Stack m_dies; | 
|  | }; | 
|  | #endif | 
|  |  | 
|  | void | 
|  | SymbolFileDWARF::Initialize() | 
|  | { | 
|  | LogChannelDWARF::Initialize(); | 
|  | PluginManager::RegisterPlugin (GetPluginNameStatic(), | 
|  | GetPluginDescriptionStatic(), | 
|  | CreateInstance); | 
|  | } | 
|  |  | 
|  | void | 
|  | SymbolFileDWARF::Terminate() | 
|  | { | 
|  | PluginManager::UnregisterPlugin (CreateInstance); | 
|  | LogChannelDWARF::Initialize(); | 
|  | } | 
|  |  | 
|  |  | 
|  | lldb_private::ConstString | 
|  | SymbolFileDWARF::GetPluginNameStatic() | 
|  | { | 
|  | static ConstString g_name("dwarf"); | 
|  | return g_name; | 
|  | } | 
|  |  | 
|  | const char * | 
|  | SymbolFileDWARF::GetPluginDescriptionStatic() | 
|  | { | 
|  | return "DWARF and DWARF3 debug symbol file reader."; | 
|  | } | 
|  |  | 
|  |  | 
|  | SymbolFile* | 
|  | SymbolFileDWARF::CreateInstance (ObjectFile* obj_file) | 
|  | { | 
|  | return new SymbolFileDWARF(obj_file); | 
|  | } | 
|  |  | 
|  | TypeList * | 
|  | SymbolFileDWARF::GetTypeList () | 
|  | { | 
|  | if (GetDebugMapSymfile ()) | 
|  | return m_debug_map_symfile->GetTypeList(); | 
|  | return m_obj_file->GetModule()->GetTypeList(); | 
|  |  | 
|  | } | 
|  | void | 
|  | SymbolFileDWARF::GetTypes (DWARFCompileUnit* cu, | 
|  | const DWARFDebugInfoEntry *die, | 
|  | dw_offset_t min_die_offset, | 
|  | dw_offset_t max_die_offset, | 
|  | uint32_t type_mask, | 
|  | TypeSet &type_set) | 
|  | { | 
|  | if (cu) | 
|  | { | 
|  | if (die) | 
|  | { | 
|  | const dw_offset_t die_offset = die->GetOffset(); | 
|  |  | 
|  | if (die_offset >= max_die_offset) | 
|  | return; | 
|  |  | 
|  | if (die_offset >= min_die_offset) | 
|  | { | 
|  | const dw_tag_t tag = die->Tag(); | 
|  |  | 
|  | bool add_type = false; | 
|  |  | 
|  | switch (tag) | 
|  | { | 
|  | case DW_TAG_array_type:         add_type = (type_mask & eTypeClassArray         ) != 0; break; | 
|  | case DW_TAG_unspecified_type: | 
|  | case DW_TAG_base_type:          add_type = (type_mask & eTypeClassBuiltin       ) != 0; break; | 
|  | case DW_TAG_class_type:         add_type = (type_mask & eTypeClassClass         ) != 0; break; | 
|  | case DW_TAG_structure_type:     add_type = (type_mask & eTypeClassStruct        ) != 0; break; | 
|  | case DW_TAG_union_type:         add_type = (type_mask & eTypeClassUnion         ) != 0; break; | 
|  | case DW_TAG_enumeration_type:   add_type = (type_mask & eTypeClassEnumeration   ) != 0; break; | 
|  | case DW_TAG_subroutine_type: | 
|  | case DW_TAG_subprogram: | 
|  | case DW_TAG_inlined_subroutine: add_type = (type_mask & eTypeClassFunction      ) != 0; break; | 
|  | case DW_TAG_pointer_type:       add_type = (type_mask & eTypeClassPointer       ) != 0; break; | 
|  | case DW_TAG_rvalue_reference_type: | 
|  | case DW_TAG_reference_type:     add_type = (type_mask & eTypeClassReference     ) != 0; break; | 
|  | case DW_TAG_typedef:            add_type = (type_mask & eTypeClassTypedef       ) != 0; break; | 
|  | case DW_TAG_ptr_to_member_type: add_type = (type_mask & eTypeClassMemberPointer ) != 0; break; | 
|  | } | 
|  |  | 
|  | if (add_type) | 
|  | { | 
|  | const bool assert_not_being_parsed = true; | 
|  | Type *type = ResolveTypeUID (cu, die, assert_not_being_parsed); | 
|  | if (type) | 
|  | { | 
|  | if (type_set.find(type) == type_set.end()) | 
|  | type_set.insert(type); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | for (const DWARFDebugInfoEntry *child_die = die->GetFirstChild(); | 
|  | child_die != NULL; | 
|  | child_die = child_die->GetSibling()) | 
|  | { | 
|  | GetTypes (cu, child_die, min_die_offset, max_die_offset, type_mask, type_set); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | size_t | 
|  | SymbolFileDWARF::GetTypes (SymbolContextScope *sc_scope, | 
|  | uint32_t type_mask, | 
|  | TypeList &type_list) | 
|  |  | 
|  | { | 
|  | TypeSet type_set; | 
|  |  | 
|  | CompileUnit *comp_unit = NULL; | 
|  | DWARFCompileUnit* dwarf_cu = NULL; | 
|  | if (sc_scope) | 
|  | comp_unit = sc_scope->CalculateSymbolContextCompileUnit(); | 
|  |  | 
|  | if (comp_unit) | 
|  | { | 
|  | dwarf_cu = GetDWARFCompileUnit(comp_unit); | 
|  | if (dwarf_cu == 0) | 
|  | return 0; | 
|  | GetTypes (dwarf_cu, | 
|  | dwarf_cu->DIE(), | 
|  | dwarf_cu->GetOffset(), | 
|  | dwarf_cu->GetNextCompileUnitOffset(), | 
|  | type_mask, | 
|  | type_set); | 
|  | } | 
|  | else | 
|  | { | 
|  | DWARFDebugInfo* info = DebugInfo(); | 
|  | if (info) | 
|  | { | 
|  | const size_t num_cus = info->GetNumCompileUnits(); | 
|  | for (size_t cu_idx=0; cu_idx<num_cus; ++cu_idx) | 
|  | { | 
|  | dwarf_cu = info->GetCompileUnitAtIndex(cu_idx); | 
|  | if (dwarf_cu) | 
|  | { | 
|  | GetTypes (dwarf_cu, | 
|  | dwarf_cu->DIE(), | 
|  | 0, | 
|  | UINT32_MAX, | 
|  | type_mask, | 
|  | type_set); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | //    if (m_using_apple_tables) | 
|  | //    { | 
|  | //        DWARFMappedHash::MemoryTable *apple_types = m_apple_types_ap.get(); | 
|  | //        if (apple_types) | 
|  | //        { | 
|  | //            apple_types->ForEach([this, &type_set, apple_types, type_mask](const DWARFMappedHash::DIEInfoArray &die_info_array) -> bool { | 
|  | // | 
|  | //                for (auto die_info: die_info_array) | 
|  | //                { | 
|  | //                    bool add_type = TagMatchesTypeMask (type_mask, 0); | 
|  | //                    if (!add_type) | 
|  | //                    { | 
|  | //                        dw_tag_t tag = die_info.tag; | 
|  | //                        if (tag == 0) | 
|  | //                        { | 
|  | //                            const DWARFDebugInfoEntry *die = DebugInfo()->GetDIEPtr(die_info.offset, NULL); | 
|  | //                            tag = die->Tag(); | 
|  | //                        } | 
|  | //                        add_type = TagMatchesTypeMask (type_mask, tag); | 
|  | //                    } | 
|  | //                    if (add_type) | 
|  | //                    { | 
|  | //                        Type *type = ResolveTypeUID(die_info.offset); | 
|  | // | 
|  | //                        if (type_set.find(type) == type_set.end()) | 
|  | //                            type_set.insert(type); | 
|  | //                    } | 
|  | //                } | 
|  | //                return true; // Keep iterating | 
|  | //            }); | 
|  | //        } | 
|  | //    } | 
|  | //    else | 
|  | //    { | 
|  | //        if (!m_indexed) | 
|  | //            Index (); | 
|  | // | 
|  | //        m_type_index.ForEach([this, &type_set, type_mask](const char *name, uint32_t die_offset) -> bool { | 
|  | // | 
|  | //            bool add_type = TagMatchesTypeMask (type_mask, 0); | 
|  | // | 
|  | //            if (!add_type) | 
|  | //            { | 
|  | //                const DWARFDebugInfoEntry *die = DebugInfo()->GetDIEPtr(die_offset, NULL); | 
|  | //                if (die) | 
|  | //                { | 
|  | //                    const dw_tag_t tag = die->Tag(); | 
|  | //                    add_type = TagMatchesTypeMask (type_mask, tag); | 
|  | //                } | 
|  | //            } | 
|  | // | 
|  | //            if (add_type) | 
|  | //            { | 
|  | //                Type *type = ResolveTypeUID(die_offset); | 
|  | // | 
|  | //                if (type_set.find(type) == type_set.end()) | 
|  | //                    type_set.insert(type); | 
|  | //            } | 
|  | //            return true; // Keep iterating | 
|  | //        }); | 
|  | //    } | 
|  |  | 
|  | std::set<ClangASTType> clang_type_set; | 
|  | size_t num_types_added = 0; | 
|  | for (Type *type : type_set) | 
|  | { | 
|  | ClangASTType clang_type = type->GetClangForwardType(); | 
|  | if (clang_type_set.find(clang_type) == clang_type_set.end()) | 
|  | { | 
|  | clang_type_set.insert(clang_type); | 
|  | type_list.Insert (type->shared_from_this()); | 
|  | ++num_types_added; | 
|  | } | 
|  | } | 
|  | return num_types_added; | 
|  | } | 
|  |  | 
|  |  | 
|  | //---------------------------------------------------------------------- | 
|  | // Gets the first parent that is a lexical block, function or inlined | 
|  | // subroutine, or compile unit. | 
|  | //---------------------------------------------------------------------- | 
|  | static const DWARFDebugInfoEntry * | 
|  | GetParentSymbolContextDIE(const DWARFDebugInfoEntry *child_die) | 
|  | { | 
|  | const DWARFDebugInfoEntry *die; | 
|  | for (die = child_die->GetParent(); die != NULL; die = die->GetParent()) | 
|  | { | 
|  | dw_tag_t tag = die->Tag(); | 
|  |  | 
|  | switch (tag) | 
|  | { | 
|  | case DW_TAG_compile_unit: | 
|  | case DW_TAG_subprogram: | 
|  | case DW_TAG_inlined_subroutine: | 
|  | case DW_TAG_lexical_block: | 
|  | return die; | 
|  | } | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  |  | 
|  | SymbolFileDWARF::SymbolFileDWARF(ObjectFile* objfile) : | 
|  | SymbolFile (objfile), | 
|  | UserID (0),  // Used by SymbolFileDWARFDebugMap to when this class parses .o files to contain the .o file index/ID | 
|  | m_debug_map_module_wp (), | 
|  | m_debug_map_symfile (NULL), | 
|  | m_clang_tu_decl (NULL), | 
|  | m_flags(), | 
|  | m_data_debug_abbrev (), | 
|  | m_data_debug_aranges (), | 
|  | m_data_debug_frame (), | 
|  | m_data_debug_info (), | 
|  | m_data_debug_line (), | 
|  | m_data_debug_loc (), | 
|  | m_data_debug_ranges (), | 
|  | m_data_debug_str (), | 
|  | m_data_apple_names (), | 
|  | m_data_apple_types (), | 
|  | m_data_apple_namespaces (), | 
|  | m_abbr(), | 
|  | m_info(), | 
|  | m_line(), | 
|  | m_apple_names_ap (), | 
|  | m_apple_types_ap (), | 
|  | m_apple_namespaces_ap (), | 
|  | m_apple_objc_ap (), | 
|  | m_function_basename_index(), | 
|  | m_function_fullname_index(), | 
|  | m_function_method_index(), | 
|  | m_function_selector_index(), | 
|  | m_objc_class_selectors_index(), | 
|  | m_global_index(), | 
|  | m_type_index(), | 
|  | m_namespace_index(), | 
|  | m_indexed (false), | 
|  | m_is_external_ast_source (false), | 
|  | m_using_apple_tables (false), | 
|  | m_supports_DW_AT_APPLE_objc_complete_type (eLazyBoolCalculate), | 
|  | m_ranges(), | 
|  | m_unique_ast_type_map () | 
|  | { | 
|  | } | 
|  |  | 
|  | SymbolFileDWARF::~SymbolFileDWARF() | 
|  | { | 
|  | if (m_is_external_ast_source) | 
|  | { | 
|  | ModuleSP module_sp (m_obj_file->GetModule()); | 
|  | if (module_sp) | 
|  | module_sp->GetClangASTContext().RemoveExternalSource (); | 
|  | } | 
|  | } | 
|  |  | 
|  | static const ConstString & | 
|  | GetDWARFMachOSegmentName () | 
|  | { | 
|  | static ConstString g_dwarf_section_name ("__DWARF"); | 
|  | return g_dwarf_section_name; | 
|  | } | 
|  |  | 
|  | UniqueDWARFASTTypeMap & | 
|  | SymbolFileDWARF::GetUniqueDWARFASTTypeMap () | 
|  | { | 
|  | if (GetDebugMapSymfile ()) | 
|  | return m_debug_map_symfile->GetUniqueDWARFASTTypeMap (); | 
|  | return m_unique_ast_type_map; | 
|  | } | 
|  |  | 
|  | ClangASTContext & | 
|  | SymbolFileDWARF::GetClangASTContext () | 
|  | { | 
|  | if (GetDebugMapSymfile ()) | 
|  | return m_debug_map_symfile->GetClangASTContext (); | 
|  |  | 
|  | ClangASTContext &ast = m_obj_file->GetModule()->GetClangASTContext(); | 
|  | if (!m_is_external_ast_source) | 
|  | { | 
|  | m_is_external_ast_source = true; | 
|  | llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> ast_source_ap ( | 
|  | new ClangExternalASTSourceCallbacks (SymbolFileDWARF::CompleteTagDecl, | 
|  | SymbolFileDWARF::CompleteObjCInterfaceDecl, | 
|  | SymbolFileDWARF::FindExternalVisibleDeclsByName, | 
|  | SymbolFileDWARF::LayoutRecordType, | 
|  | this)); | 
|  | ast.SetExternalSource (ast_source_ap); | 
|  | } | 
|  | return ast; | 
|  | } | 
|  |  | 
|  | void | 
|  | SymbolFileDWARF::InitializeObject() | 
|  | { | 
|  | // Install our external AST source callbacks so we can complete Clang types. | 
|  | ModuleSP module_sp (m_obj_file->GetModule()); | 
|  | if (module_sp) | 
|  | { | 
|  | const SectionList *section_list = module_sp->GetSectionList(); | 
|  |  | 
|  | const Section* section = section_list->FindSectionByName(GetDWARFMachOSegmentName ()).get(); | 
|  |  | 
|  | // Memory map the DWARF mach-o segment so we have everything mmap'ed | 
|  | // to keep our heap memory usage down. | 
|  | if (section) | 
|  | m_obj_file->MemoryMapSectionData(section, m_dwarf_data); | 
|  | } | 
|  | get_apple_names_data(); | 
|  | if (m_data_apple_names.GetByteSize() > 0) | 
|  | { | 
|  | m_apple_names_ap.reset (new DWARFMappedHash::MemoryTable (m_data_apple_names, get_debug_str_data(), ".apple_names")); | 
|  | if (m_apple_names_ap->IsValid()) | 
|  | m_using_apple_tables = true; | 
|  | else | 
|  | m_apple_names_ap.reset(); | 
|  | } | 
|  | get_apple_types_data(); | 
|  | if (m_data_apple_types.GetByteSize() > 0) | 
|  | { | 
|  | m_apple_types_ap.reset (new DWARFMappedHash::MemoryTable (m_data_apple_types, get_debug_str_data(), ".apple_types")); | 
|  | if (m_apple_types_ap->IsValid()) | 
|  | m_using_apple_tables = true; | 
|  | else | 
|  | m_apple_types_ap.reset(); | 
|  | } | 
|  |  | 
|  | get_apple_namespaces_data(); | 
|  | if (m_data_apple_namespaces.GetByteSize() > 0) | 
|  | { | 
|  | m_apple_namespaces_ap.reset (new DWARFMappedHash::MemoryTable (m_data_apple_namespaces, get_debug_str_data(), ".apple_namespaces")); | 
|  | if (m_apple_namespaces_ap->IsValid()) | 
|  | m_using_apple_tables = true; | 
|  | else | 
|  | m_apple_namespaces_ap.reset(); | 
|  | } | 
|  |  | 
|  | get_apple_objc_data(); | 
|  | if (m_data_apple_objc.GetByteSize() > 0) | 
|  | { | 
|  | m_apple_objc_ap.reset (new DWARFMappedHash::MemoryTable (m_data_apple_objc, get_debug_str_data(), ".apple_objc")); | 
|  | if (m_apple_objc_ap->IsValid()) | 
|  | m_using_apple_tables = true; | 
|  | else | 
|  | m_apple_objc_ap.reset(); | 
|  | } | 
|  | } | 
|  |  | 
|  | bool | 
|  | SymbolFileDWARF::SupportedVersion(uint16_t version) | 
|  | { | 
|  | return version == 2 || version == 3 || version == 4; | 
|  | } | 
|  |  | 
|  | uint32_t | 
|  | SymbolFileDWARF::CalculateAbilities () | 
|  | { | 
|  | uint32_t abilities = 0; | 
|  | if (m_obj_file != NULL) | 
|  | { | 
|  | const Section* section = NULL; | 
|  | const SectionList *section_list = m_obj_file->GetSectionList(); | 
|  | if (section_list == NULL) | 
|  | return 0; | 
|  |  | 
|  | uint64_t debug_abbrev_file_size = 0; | 
|  | uint64_t debug_info_file_size = 0; | 
|  | uint64_t debug_line_file_size = 0; | 
|  |  | 
|  | section = section_list->FindSectionByName(GetDWARFMachOSegmentName ()).get(); | 
|  |  | 
|  | if (section) | 
|  | section_list = §ion->GetChildren (); | 
|  |  | 
|  | section = section_list->FindSectionByType (eSectionTypeDWARFDebugInfo, true).get(); | 
|  | if (section != NULL) | 
|  | { | 
|  | debug_info_file_size = section->GetFileSize(); | 
|  |  | 
|  | section = section_list->FindSectionByType (eSectionTypeDWARFDebugAbbrev, true).get(); | 
|  | if (section) | 
|  | debug_abbrev_file_size = section->GetFileSize(); | 
|  | else | 
|  | m_flags.Set (flagsGotDebugAbbrevData); | 
|  |  | 
|  | section = section_list->FindSectionByType (eSectionTypeDWARFDebugAranges, true).get(); | 
|  | if (!section) | 
|  | m_flags.Set (flagsGotDebugArangesData); | 
|  |  | 
|  | section = section_list->FindSectionByType (eSectionTypeDWARFDebugFrame, true).get(); | 
|  | if (!section) | 
|  | m_flags.Set (flagsGotDebugFrameData); | 
|  |  | 
|  | section = section_list->FindSectionByType (eSectionTypeDWARFDebugLine, true).get(); | 
|  | if (section) | 
|  | debug_line_file_size = section->GetFileSize(); | 
|  | else | 
|  | m_flags.Set (flagsGotDebugLineData); | 
|  |  | 
|  | section = section_list->FindSectionByType (eSectionTypeDWARFDebugLoc, true).get(); | 
|  | if (!section) | 
|  | m_flags.Set (flagsGotDebugLocData); | 
|  |  | 
|  | section = section_list->FindSectionByType (eSectionTypeDWARFDebugMacInfo, true).get(); | 
|  | if (!section) | 
|  | m_flags.Set (flagsGotDebugMacInfoData); | 
|  |  | 
|  | section = section_list->FindSectionByType (eSectionTypeDWARFDebugPubNames, true).get(); | 
|  | if (!section) | 
|  | m_flags.Set (flagsGotDebugPubNamesData); | 
|  |  | 
|  | section = section_list->FindSectionByType (eSectionTypeDWARFDebugPubTypes, true).get(); | 
|  | if (!section) | 
|  | m_flags.Set (flagsGotDebugPubTypesData); | 
|  |  | 
|  | section = section_list->FindSectionByType (eSectionTypeDWARFDebugRanges, true).get(); | 
|  | if (!section) | 
|  | m_flags.Set (flagsGotDebugRangesData); | 
|  |  | 
|  | section = section_list->FindSectionByType (eSectionTypeDWARFDebugStr, true).get(); | 
|  | if (!section) | 
|  | m_flags.Set (flagsGotDebugStrData); | 
|  | } | 
|  | else | 
|  | { | 
|  | const char *symfile_dir_cstr = m_obj_file->GetFileSpec().GetDirectory().GetCString(); | 
|  | if (symfile_dir_cstr) | 
|  | { | 
|  | if (strcasestr(symfile_dir_cstr, ".dsym")) | 
|  | { | 
|  | if (m_obj_file->GetType() == ObjectFile::eTypeDebugInfo) | 
|  | { | 
|  | // We have a dSYM file that didn't have a any debug info. | 
|  | // If the string table has a size of 1, then it was made from | 
|  | // an executable with no debug info, or from an executable that | 
|  | // was stripped. | 
|  | section = section_list->FindSectionByType (eSectionTypeDWARFDebugStr, true).get(); | 
|  | if (section && section->GetFileSize() == 1) | 
|  | { | 
|  | m_obj_file->GetModule()->ReportWarning ("empty dSYM file detected, dSYM was created with an executable with no debug info."); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (debug_abbrev_file_size > 0 && debug_info_file_size > 0) | 
|  | abilities |= CompileUnits | Functions | Blocks | GlobalVariables | LocalVariables | VariableTypes; | 
|  |  | 
|  | if (debug_line_file_size > 0) | 
|  | abilities |= LineTables; | 
|  | } | 
|  | return abilities; | 
|  | } | 
|  |  | 
|  | const DWARFDataExtractor& | 
|  | SymbolFileDWARF::GetCachedSectionData (uint32_t got_flag, SectionType sect_type, DWARFDataExtractor &data) | 
|  | { | 
|  | if (m_flags.IsClear (got_flag)) | 
|  | { | 
|  | ModuleSP module_sp (m_obj_file->GetModule()); | 
|  | m_flags.Set (got_flag); | 
|  | const SectionList *section_list = module_sp->GetSectionList(); | 
|  | if (section_list) | 
|  | { | 
|  | SectionSP section_sp (section_list->FindSectionByType(sect_type, true)); | 
|  | if (section_sp) | 
|  | { | 
|  | // See if we memory mapped the DWARF segment? | 
|  | if (m_dwarf_data.GetByteSize()) | 
|  | { | 
|  | data.SetData(m_dwarf_data, section_sp->GetOffset (), section_sp->GetFileSize()); | 
|  | } | 
|  | else | 
|  | { | 
|  | if (m_obj_file->ReadSectionData (section_sp.get(), data) == 0) | 
|  | data.Clear(); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | return data; | 
|  | } | 
|  |  | 
|  | const DWARFDataExtractor& | 
|  | SymbolFileDWARF::get_debug_abbrev_data() | 
|  | { | 
|  | return GetCachedSectionData (flagsGotDebugAbbrevData, eSectionTypeDWARFDebugAbbrev, m_data_debug_abbrev); | 
|  | } | 
|  |  | 
|  | const DWARFDataExtractor& | 
|  | SymbolFileDWARF::get_debug_aranges_data() | 
|  | { | 
|  | return GetCachedSectionData (flagsGotDebugArangesData, eSectionTypeDWARFDebugAranges, m_data_debug_aranges); | 
|  | } | 
|  |  | 
|  | const DWARFDataExtractor& | 
|  | SymbolFileDWARF::get_debug_frame_data() | 
|  | { | 
|  | return GetCachedSectionData (flagsGotDebugFrameData, eSectionTypeDWARFDebugFrame, m_data_debug_frame); | 
|  | } | 
|  |  | 
|  | const DWARFDataExtractor& | 
|  | SymbolFileDWARF::get_debug_info_data() | 
|  | { | 
|  | return GetCachedSectionData (flagsGotDebugInfoData, eSectionTypeDWARFDebugInfo, m_data_debug_info); | 
|  | } | 
|  |  | 
|  | const DWARFDataExtractor& | 
|  | SymbolFileDWARF::get_debug_line_data() | 
|  | { | 
|  | return GetCachedSectionData (flagsGotDebugLineData, eSectionTypeDWARFDebugLine, m_data_debug_line); | 
|  | } | 
|  |  | 
|  | const DWARFDataExtractor& | 
|  | SymbolFileDWARF::get_debug_loc_data() | 
|  | { | 
|  | return GetCachedSectionData (flagsGotDebugLocData, eSectionTypeDWARFDebugLoc, m_data_debug_loc); | 
|  | } | 
|  |  | 
|  | const DWARFDataExtractor& | 
|  | SymbolFileDWARF::get_debug_ranges_data() | 
|  | { | 
|  | return GetCachedSectionData (flagsGotDebugRangesData, eSectionTypeDWARFDebugRanges, m_data_debug_ranges); | 
|  | } | 
|  |  | 
|  | const DWARFDataExtractor& | 
|  | SymbolFileDWARF::get_debug_str_data() | 
|  | { | 
|  | return GetCachedSectionData (flagsGotDebugStrData, eSectionTypeDWARFDebugStr, m_data_debug_str); | 
|  | } | 
|  |  | 
|  | const DWARFDataExtractor& | 
|  | SymbolFileDWARF::get_apple_names_data() | 
|  | { | 
|  | return GetCachedSectionData (flagsGotAppleNamesData, eSectionTypeDWARFAppleNames, m_data_apple_names); | 
|  | } | 
|  |  | 
|  | const DWARFDataExtractor& | 
|  | SymbolFileDWARF::get_apple_types_data() | 
|  | { | 
|  | return GetCachedSectionData (flagsGotAppleTypesData, eSectionTypeDWARFAppleTypes, m_data_apple_types); | 
|  | } | 
|  |  | 
|  | const DWARFDataExtractor& | 
|  | SymbolFileDWARF::get_apple_namespaces_data() | 
|  | { | 
|  | return GetCachedSectionData (flagsGotAppleNamespacesData, eSectionTypeDWARFAppleNamespaces, m_data_apple_namespaces); | 
|  | } | 
|  |  | 
|  | const DWARFDataExtractor& | 
|  | SymbolFileDWARF::get_apple_objc_data() | 
|  | { | 
|  | return GetCachedSectionData (flagsGotAppleObjCData, eSectionTypeDWARFAppleObjC, m_data_apple_objc); | 
|  | } | 
|  |  | 
|  |  | 
|  | DWARFDebugAbbrev* | 
|  | SymbolFileDWARF::DebugAbbrev() | 
|  | { | 
|  | if (m_abbr.get() == NULL) | 
|  | { | 
|  | const DWARFDataExtractor &debug_abbrev_data = get_debug_abbrev_data(); | 
|  | if (debug_abbrev_data.GetByteSize() > 0) | 
|  | { | 
|  | m_abbr.reset(new DWARFDebugAbbrev()); | 
|  | if (m_abbr.get()) | 
|  | m_abbr->Parse(debug_abbrev_data); | 
|  | } | 
|  | } | 
|  | return m_abbr.get(); | 
|  | } | 
|  |  | 
|  | const DWARFDebugAbbrev* | 
|  | SymbolFileDWARF::DebugAbbrev() const | 
|  | { | 
|  | return m_abbr.get(); | 
|  | } | 
|  |  | 
|  |  | 
|  | DWARFDebugInfo* | 
|  | SymbolFileDWARF::DebugInfo() | 
|  | { | 
|  | if (m_info.get() == NULL) | 
|  | { | 
|  | Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p", | 
|  | __PRETTY_FUNCTION__, static_cast<void*>(this)); | 
|  | if (get_debug_info_data().GetByteSize() > 0) | 
|  | { | 
|  | m_info.reset(new DWARFDebugInfo()); | 
|  | if (m_info.get()) | 
|  | { | 
|  | m_info->SetDwarfData(this); | 
|  | } | 
|  | } | 
|  | } | 
|  | return m_info.get(); | 
|  | } | 
|  |  | 
|  | const DWARFDebugInfo* | 
|  | SymbolFileDWARF::DebugInfo() const | 
|  | { | 
|  | return m_info.get(); | 
|  | } | 
|  |  | 
|  | DWARFCompileUnit* | 
|  | SymbolFileDWARF::GetDWARFCompileUnit(lldb_private::CompileUnit *comp_unit) | 
|  | { | 
|  | DWARFDebugInfo* info = DebugInfo(); | 
|  | if (info) | 
|  | { | 
|  | if (GetDebugMapSymfile ()) | 
|  | { | 
|  | // The debug map symbol file made the compile units for this DWARF | 
|  | // file which is .o file with DWARF in it, and we should have | 
|  | // only 1 compile unit which is at offset zero in the DWARF. | 
|  | // TODO: modify to support LTO .o files where each .o file might | 
|  | // have multiple DW_TAG_compile_unit tags. | 
|  | return info->GetCompileUnit(0).get(); | 
|  | } | 
|  | else | 
|  | { | 
|  | // Just a normal DWARF file whose user ID for the compile unit is | 
|  | // the DWARF offset itself | 
|  | return info->GetCompileUnit((dw_offset_t)comp_unit->GetID()).get(); | 
|  | } | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  |  | 
|  | DWARFDebugRanges* | 
|  | SymbolFileDWARF::DebugRanges() | 
|  | { | 
|  | if (m_ranges.get() == NULL) | 
|  | { | 
|  | Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p", | 
|  | __PRETTY_FUNCTION__, static_cast<void*>(this)); | 
|  | if (get_debug_ranges_data().GetByteSize() > 0) | 
|  | { | 
|  | m_ranges.reset(new DWARFDebugRanges()); | 
|  | if (m_ranges.get()) | 
|  | m_ranges->Extract(this); | 
|  | } | 
|  | } | 
|  | return m_ranges.get(); | 
|  | } | 
|  |  | 
|  | const DWARFDebugRanges* | 
|  | SymbolFileDWARF::DebugRanges() const | 
|  | { | 
|  | return m_ranges.get(); | 
|  | } | 
|  |  | 
|  | lldb::CompUnitSP | 
|  | SymbolFileDWARF::ParseCompileUnit (DWARFCompileUnit* dwarf_cu, uint32_t cu_idx) | 
|  | { | 
|  | CompUnitSP cu_sp; | 
|  | if (dwarf_cu) | 
|  | { | 
|  | CompileUnit *comp_unit = (CompileUnit*)dwarf_cu->GetUserData(); | 
|  | if (comp_unit) | 
|  | { | 
|  | // We already parsed this compile unit, had out a shared pointer to it | 
|  | cu_sp = comp_unit->shared_from_this(); | 
|  | } | 
|  | else | 
|  | { | 
|  | if (GetDebugMapSymfile ()) | 
|  | { | 
|  | // Let the debug map create the compile unit | 
|  | cu_sp = m_debug_map_symfile->GetCompileUnit(this); | 
|  | dwarf_cu->SetUserData(cu_sp.get()); | 
|  | } | 
|  | else | 
|  | { | 
|  | ModuleSP module_sp (m_obj_file->GetModule()); | 
|  | if (module_sp) | 
|  | { | 
|  | const DWARFDebugInfoEntry * cu_die = dwarf_cu->GetCompileUnitDIEOnly (); | 
|  | if (cu_die) | 
|  | { | 
|  | const char * cu_die_name = cu_die->GetName(this, dwarf_cu); | 
|  | const char * cu_comp_dir = cu_die->GetAttributeValueAsString(this, dwarf_cu, DW_AT_comp_dir, NULL); | 
|  | LanguageType cu_language = (LanguageType)cu_die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_language, 0); | 
|  | if (cu_die_name) | 
|  | { | 
|  | std::string ramapped_file; | 
|  | FileSpec cu_file_spec; | 
|  |  | 
|  | if (cu_die_name[0] == '/' || cu_comp_dir == NULL || cu_comp_dir[0] == '\0') | 
|  | { | 
|  | // If we have a full path to the compile unit, we don't need to resolve | 
|  | // the file.  This can be expensive e.g. when the source files are NFS mounted. | 
|  | if (module_sp->RemapSourceFile(cu_die_name, ramapped_file)) | 
|  | cu_file_spec.SetFile (ramapped_file.c_str(), false); | 
|  | else | 
|  | cu_file_spec.SetFile (cu_die_name, false); | 
|  | } | 
|  | else | 
|  | { | 
|  | std::string fullpath(cu_comp_dir); | 
|  | if (*fullpath.rbegin() != '/') | 
|  | fullpath += '/'; | 
|  | fullpath += cu_die_name; | 
|  | if (module_sp->RemapSourceFile (fullpath.c_str(), ramapped_file)) | 
|  | cu_file_spec.SetFile (ramapped_file.c_str(), false); | 
|  | else | 
|  | cu_file_spec.SetFile (fullpath.c_str(), false); | 
|  | } | 
|  |  | 
|  | cu_sp.reset(new CompileUnit (module_sp, | 
|  | dwarf_cu, | 
|  | cu_file_spec, | 
|  | MakeUserID(dwarf_cu->GetOffset()), | 
|  | cu_language)); | 
|  | if (cu_sp) | 
|  | { | 
|  | dwarf_cu->SetUserData(cu_sp.get()); | 
|  |  | 
|  | // Figure out the compile unit index if we weren't given one | 
|  | if (cu_idx == UINT32_MAX) | 
|  | DebugInfo()->GetCompileUnit(dwarf_cu->GetOffset(), &cu_idx); | 
|  |  | 
|  | m_obj_file->GetModule()->GetSymbolVendor()->SetCompileUnitAtIndex(cu_idx, cu_sp); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | return cu_sp; | 
|  | } | 
|  |  | 
|  | uint32_t | 
|  | SymbolFileDWARF::GetNumCompileUnits() | 
|  | { | 
|  | DWARFDebugInfo* info = DebugInfo(); | 
|  | if (info) | 
|  | return info->GetNumCompileUnits(); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | CompUnitSP | 
|  | SymbolFileDWARF::ParseCompileUnitAtIndex(uint32_t cu_idx) | 
|  | { | 
|  | CompUnitSP cu_sp; | 
|  | DWARFDebugInfo* info = DebugInfo(); | 
|  | if (info) | 
|  | { | 
|  | DWARFCompileUnit* dwarf_cu = info->GetCompileUnitAtIndex(cu_idx); | 
|  | if (dwarf_cu) | 
|  | cu_sp = ParseCompileUnit(dwarf_cu, cu_idx); | 
|  | } | 
|  | return cu_sp; | 
|  | } | 
|  |  | 
|  | static void | 
|  | AddRangesToBlock (Block& block, | 
|  | DWARFDebugRanges::RangeList& ranges, | 
|  | addr_t block_base_addr) | 
|  | { | 
|  | const size_t num_ranges = ranges.GetSize(); | 
|  | for (size_t i = 0; i<num_ranges; ++i) | 
|  | { | 
|  | const DWARFDebugRanges::Range &range = ranges.GetEntryRef (i); | 
|  | const addr_t range_base = range.GetRangeBase(); | 
|  | assert (range_base >= block_base_addr); | 
|  | block.AddRange(Block::Range (range_base - block_base_addr, range.GetByteSize()));; | 
|  | } | 
|  | block.FinalizeRanges (); | 
|  | } | 
|  |  | 
|  |  | 
|  | Function * | 
|  | SymbolFileDWARF::ParseCompileUnitFunction (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die) | 
|  | { | 
|  | DWARFDebugRanges::RangeList func_ranges; | 
|  | const char *name = NULL; | 
|  | const char *mangled = NULL; | 
|  | int decl_file = 0; | 
|  | int decl_line = 0; | 
|  | int decl_column = 0; | 
|  | int call_file = 0; | 
|  | int call_line = 0; | 
|  | int call_column = 0; | 
|  | DWARFExpression frame_base; | 
|  |  | 
|  | assert (die->Tag() == DW_TAG_subprogram); | 
|  |  | 
|  | if (die->Tag() != DW_TAG_subprogram) | 
|  | return NULL; | 
|  |  | 
|  | if (die->GetDIENamesAndRanges (this, | 
|  | dwarf_cu, | 
|  | name, | 
|  | mangled, | 
|  | func_ranges, | 
|  | decl_file, | 
|  | decl_line, | 
|  | decl_column, | 
|  | call_file, | 
|  | call_line, | 
|  | call_column, | 
|  | &frame_base)) | 
|  | { | 
|  | // Union of all ranges in the function DIE (if the function is discontiguous) | 
|  | AddressRange func_range; | 
|  | lldb::addr_t lowest_func_addr = func_ranges.GetMinRangeBase (0); | 
|  | lldb::addr_t highest_func_addr = func_ranges.GetMaxRangeEnd (0); | 
|  | if (lowest_func_addr != LLDB_INVALID_ADDRESS && lowest_func_addr <= highest_func_addr) | 
|  | { | 
|  | ModuleSP module_sp (m_obj_file->GetModule()); | 
|  | func_range.GetBaseAddress().ResolveAddressUsingFileSections (lowest_func_addr, module_sp->GetSectionList()); | 
|  | if (func_range.GetBaseAddress().IsValid()) | 
|  | func_range.SetByteSize(highest_func_addr - lowest_func_addr); | 
|  | } | 
|  |  | 
|  | if (func_range.GetBaseAddress().IsValid()) | 
|  | { | 
|  | Mangled func_name; | 
|  | if (mangled) | 
|  | func_name.SetValue(ConstString(mangled), true); | 
|  | else if (name) | 
|  | func_name.SetValue(ConstString(name), false); | 
|  |  | 
|  | FunctionSP func_sp; | 
|  | std::unique_ptr<Declaration> decl_ap; | 
|  | if (decl_file != 0 || decl_line != 0 || decl_column != 0) | 
|  | decl_ap.reset(new Declaration (sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(decl_file), | 
|  | decl_line, | 
|  | decl_column)); | 
|  |  | 
|  | // Supply the type _only_ if it has already been parsed | 
|  | Type *func_type = m_die_to_type.lookup (die); | 
|  |  | 
|  | assert(func_type == NULL || func_type != DIE_IS_BEING_PARSED); | 
|  |  | 
|  | if (FixupAddress (func_range.GetBaseAddress())) | 
|  | { | 
|  | const user_id_t func_user_id = MakeUserID(die->GetOffset()); | 
|  | func_sp.reset(new Function (sc.comp_unit, | 
|  | MakeUserID(func_user_id),       // UserID is the DIE offset | 
|  | MakeUserID(func_user_id), | 
|  | func_name, | 
|  | func_type, | 
|  | func_range));           // first address range | 
|  |  | 
|  | if (func_sp.get() != NULL) | 
|  | { | 
|  | if (frame_base.IsValid()) | 
|  | func_sp->GetFrameBaseExpression() = frame_base; | 
|  | sc.comp_unit->AddFunction(func_sp); | 
|  | return func_sp.get(); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | bool | 
|  | SymbolFileDWARF::FixupAddress (Address &addr) | 
|  | { | 
|  | SymbolFileDWARFDebugMap * debug_map_symfile = GetDebugMapSymfile (); | 
|  | if (debug_map_symfile) | 
|  | { | 
|  | return debug_map_symfile->LinkOSOAddress(addr); | 
|  | } | 
|  | // This is a normal DWARF file, no address fixups need to happen | 
|  | return true; | 
|  | } | 
|  | lldb::LanguageType | 
|  | SymbolFileDWARF::ParseCompileUnitLanguage (const SymbolContext& sc) | 
|  | { | 
|  | assert (sc.comp_unit); | 
|  | DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); | 
|  | if (dwarf_cu) | 
|  | { | 
|  | const DWARFDebugInfoEntry *die = dwarf_cu->GetCompileUnitDIEOnly(); | 
|  | if (die) | 
|  | { | 
|  | const uint32_t language = die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_language, 0); | 
|  | if (language) | 
|  | return (lldb::LanguageType)language; | 
|  | } | 
|  | } | 
|  | return eLanguageTypeUnknown; | 
|  | } | 
|  |  | 
|  | size_t | 
|  | SymbolFileDWARF::ParseCompileUnitFunctions(const SymbolContext &sc) | 
|  | { | 
|  | assert (sc.comp_unit); | 
|  | size_t functions_added = 0; | 
|  | DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); | 
|  | if (dwarf_cu) | 
|  | { | 
|  | DWARFDIECollection function_dies; | 
|  | const size_t num_functions = dwarf_cu->AppendDIEsWithTag (DW_TAG_subprogram, function_dies); | 
|  | size_t func_idx; | 
|  | for (func_idx = 0; func_idx < num_functions; ++func_idx) | 
|  | { | 
|  | const DWARFDebugInfoEntry *die = function_dies.GetDIEPtrAtIndex(func_idx); | 
|  | if (sc.comp_unit->FindFunctionByUID (MakeUserID(die->GetOffset())).get() == NULL) | 
|  | { | 
|  | if (ParseCompileUnitFunction(sc, dwarf_cu, die)) | 
|  | ++functions_added; | 
|  | } | 
|  | } | 
|  | //FixupTypes(); | 
|  | } | 
|  | return functions_added; | 
|  | } | 
|  |  | 
|  | bool | 
|  | SymbolFileDWARF::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpecList& support_files) | 
|  | { | 
|  | assert (sc.comp_unit); | 
|  | DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); | 
|  | if (dwarf_cu) | 
|  | { | 
|  | const DWARFDebugInfoEntry * cu_die = dwarf_cu->GetCompileUnitDIEOnly(); | 
|  |  | 
|  | if (cu_die) | 
|  | { | 
|  | const char * cu_comp_dir = cu_die->GetAttributeValueAsString(this, dwarf_cu, DW_AT_comp_dir, NULL); | 
|  | dw_offset_t stmt_list = cu_die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_stmt_list, DW_INVALID_OFFSET); | 
|  |  | 
|  | // All file indexes in DWARF are one based and a file of index zero is | 
|  | // supposed to be the compile unit itself. | 
|  | support_files.Append (*sc.comp_unit); | 
|  |  | 
|  | return DWARFDebugLine::ParseSupportFiles(sc.comp_unit->GetModule(), get_debug_line_data(), cu_comp_dir, stmt_list, support_files); | 
|  | } | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | struct ParseDWARFLineTableCallbackInfo | 
|  | { | 
|  | LineTable* line_table; | 
|  | std::unique_ptr<LineSequence> sequence_ap; | 
|  | }; | 
|  |  | 
|  | //---------------------------------------------------------------------- | 
|  | // ParseStatementTableCallback | 
|  | //---------------------------------------------------------------------- | 
|  | static void | 
|  | ParseDWARFLineTableCallback(dw_offset_t offset, const DWARFDebugLine::State& state, void* userData) | 
|  | { | 
|  | if (state.row == DWARFDebugLine::State::StartParsingLineTable) | 
|  | { | 
|  | // Just started parsing the line table | 
|  | } | 
|  | else if (state.row == DWARFDebugLine::State::DoneParsingLineTable) | 
|  | { | 
|  | // Done parsing line table, nothing to do for the cleanup | 
|  | } | 
|  | else | 
|  | { | 
|  | ParseDWARFLineTableCallbackInfo* info = (ParseDWARFLineTableCallbackInfo*)userData; | 
|  | LineTable* line_table = info->line_table; | 
|  |  | 
|  | // If this is our first time here, we need to create a | 
|  | // sequence container. | 
|  | if (!info->sequence_ap.get()) | 
|  | { | 
|  | info->sequence_ap.reset(line_table->CreateLineSequenceContainer()); | 
|  | assert(info->sequence_ap.get()); | 
|  | } | 
|  | line_table->AppendLineEntryToSequence (info->sequence_ap.get(), | 
|  | state.address, | 
|  | state.line, | 
|  | state.column, | 
|  | state.file, | 
|  | state.is_stmt, | 
|  | state.basic_block, | 
|  | state.prologue_end, | 
|  | state.epilogue_begin, | 
|  | state.end_sequence); | 
|  | if (state.end_sequence) | 
|  | { | 
|  | // First, put the current sequence into the line table. | 
|  | line_table->InsertSequence(info->sequence_ap.get()); | 
|  | // Then, empty it to prepare for the next sequence. | 
|  | info->sequence_ap->Clear(); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | bool | 
|  | SymbolFileDWARF::ParseCompileUnitLineTable (const SymbolContext &sc) | 
|  | { | 
|  | assert (sc.comp_unit); | 
|  | if (sc.comp_unit->GetLineTable() != NULL) | 
|  | return true; | 
|  |  | 
|  | DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); | 
|  | if (dwarf_cu) | 
|  | { | 
|  | const DWARFDebugInfoEntry *dwarf_cu_die = dwarf_cu->GetCompileUnitDIEOnly(); | 
|  | if (dwarf_cu_die) | 
|  | { | 
|  | const dw_offset_t cu_line_offset = dwarf_cu_die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_stmt_list, DW_INVALID_OFFSET); | 
|  | if (cu_line_offset != DW_INVALID_OFFSET) | 
|  | { | 
|  | std::unique_ptr<LineTable> line_table_ap(new LineTable(sc.comp_unit)); | 
|  | if (line_table_ap.get()) | 
|  | { | 
|  | ParseDWARFLineTableCallbackInfo info; | 
|  | info.line_table = line_table_ap.get(); | 
|  | lldb::offset_t offset = cu_line_offset; | 
|  | DWARFDebugLine::ParseStatementTable(get_debug_line_data(), &offset, ParseDWARFLineTableCallback, &info); | 
|  | if (m_debug_map_symfile) | 
|  | { | 
|  | // We have an object file that has a line table with addresses | 
|  | // that are not linked. We need to link the line table and convert | 
|  | // the addresses that are relative to the .o file into addresses | 
|  | // for the main executable. | 
|  | sc.comp_unit->SetLineTable (m_debug_map_symfile->LinkOSOLineTable (this, line_table_ap.get())); | 
|  | } | 
|  | else | 
|  | { | 
|  | sc.comp_unit->SetLineTable(line_table_ap.release()); | 
|  | return true; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | size_t | 
|  | SymbolFileDWARF::ParseFunctionBlocks | 
|  | ( | 
|  | const SymbolContext& sc, | 
|  | Block *parent_block, | 
|  | DWARFCompileUnit* dwarf_cu, | 
|  | const DWARFDebugInfoEntry *die, | 
|  | addr_t subprogram_low_pc, | 
|  | uint32_t depth | 
|  | ) | 
|  | { | 
|  | size_t blocks_added = 0; | 
|  | while (die != NULL) | 
|  | { | 
|  | dw_tag_t tag = die->Tag(); | 
|  |  | 
|  | switch (tag) | 
|  | { | 
|  | case DW_TAG_inlined_subroutine: | 
|  | case DW_TAG_subprogram: | 
|  | case DW_TAG_lexical_block: | 
|  | { | 
|  | Block *block = NULL; | 
|  | if (tag == DW_TAG_subprogram) | 
|  | { | 
|  | // Skip any DW_TAG_subprogram DIEs that are inside | 
|  | // of a normal or inlined functions. These will be | 
|  | // parsed on their own as separate entities. | 
|  |  | 
|  | if (depth > 0) | 
|  | break; | 
|  |  | 
|  | block = parent_block; | 
|  | } | 
|  | else | 
|  | { | 
|  | BlockSP block_sp(new Block (MakeUserID(die->GetOffset()))); | 
|  | parent_block->AddChild(block_sp); | 
|  | block = block_sp.get(); | 
|  | } | 
|  | DWARFDebugRanges::RangeList ranges; | 
|  | const char *name = NULL; | 
|  | const char *mangled_name = NULL; | 
|  |  | 
|  | int decl_file = 0; | 
|  | int decl_line = 0; | 
|  | int decl_column = 0; | 
|  | int call_file = 0; | 
|  | int call_line = 0; | 
|  | int call_column = 0; | 
|  | if (die->GetDIENamesAndRanges (this, | 
|  | dwarf_cu, | 
|  | name, | 
|  | mangled_name, | 
|  | ranges, | 
|  | decl_file, decl_line, decl_column, | 
|  | call_file, call_line, call_column)) | 
|  | { | 
|  | if (tag == DW_TAG_subprogram) | 
|  | { | 
|  | assert (subprogram_low_pc == LLDB_INVALID_ADDRESS); | 
|  | subprogram_low_pc = ranges.GetMinRangeBase(0); | 
|  | } | 
|  | else if (tag == DW_TAG_inlined_subroutine) | 
|  | { | 
|  | // We get called here for inlined subroutines in two ways. | 
|  | // The first time is when we are making the Function object | 
|  | // for this inlined concrete instance.  Since we're creating a top level block at | 
|  | // here, the subprogram_low_pc will be LLDB_INVALID_ADDRESS.  So we need to | 
|  | // adjust the containing address. | 
|  | // The second time is when we are parsing the blocks inside the function that contains | 
|  | // the inlined concrete instance.  Since these will be blocks inside the containing "real" | 
|  | // function the offset will be for that function. | 
|  | if (subprogram_low_pc == LLDB_INVALID_ADDRESS) | 
|  | { | 
|  | subprogram_low_pc = ranges.GetMinRangeBase(0); | 
|  | } | 
|  | } | 
|  |  | 
|  | AddRangesToBlock (*block, ranges, subprogram_low_pc); | 
|  |  | 
|  | if (tag != DW_TAG_subprogram && (name != NULL || mangled_name != NULL)) | 
|  | { | 
|  | std::unique_ptr<Declaration> decl_ap; | 
|  | if (decl_file != 0 || decl_line != 0 || decl_column != 0) | 
|  | decl_ap.reset(new Declaration(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(decl_file), | 
|  | decl_line, decl_column)); | 
|  |  | 
|  | std::unique_ptr<Declaration> call_ap; | 
|  | if (call_file != 0 || call_line != 0 || call_column != 0) | 
|  | call_ap.reset(new Declaration(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(call_file), | 
|  | call_line, call_column)); | 
|  |  | 
|  | block->SetInlinedFunctionInfo (name, mangled_name, decl_ap.get(), call_ap.get()); | 
|  | } | 
|  |  | 
|  | ++blocks_added; | 
|  |  | 
|  | if (die->HasChildren()) | 
|  | { | 
|  | blocks_added += ParseFunctionBlocks (sc, | 
|  | block, | 
|  | dwarf_cu, | 
|  | die->GetFirstChild(), | 
|  | subprogram_low_pc, | 
|  | depth + 1); | 
|  | } | 
|  | } | 
|  | } | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  |  | 
|  | // Only parse siblings of the block if we are not at depth zero. A depth | 
|  | // of zero indicates we are currently parsing the top level | 
|  | // DW_TAG_subprogram DIE | 
|  |  | 
|  | if (depth == 0) | 
|  | die = NULL; | 
|  | else | 
|  | die = die->GetSibling(); | 
|  | } | 
|  | return blocks_added; | 
|  | } | 
|  |  | 
|  | bool | 
|  | SymbolFileDWARF::ParseTemplateDIE (DWARFCompileUnit* dwarf_cu, | 
|  | const DWARFDebugInfoEntry *die, | 
|  | ClangASTContext::TemplateParameterInfos &template_param_infos) | 
|  | { | 
|  | const dw_tag_t tag = die->Tag(); | 
|  |  | 
|  | switch (tag) | 
|  | { | 
|  | case DW_TAG_template_type_parameter: | 
|  | case DW_TAG_template_value_parameter: | 
|  | { | 
|  | const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize()); | 
|  |  | 
|  | DWARFDebugInfoEntry::Attributes attributes; | 
|  | const size_t num_attributes = die->GetAttributes (this, | 
|  | dwarf_cu, | 
|  | fixed_form_sizes, | 
|  | attributes); | 
|  | const char *name = NULL; | 
|  | Type *lldb_type = NULL; | 
|  | ClangASTType clang_type; | 
|  | uint64_t uval64 = 0; | 
|  | bool uval64_valid = false; | 
|  | if (num_attributes > 0) | 
|  | { | 
|  | DWARFFormValue form_value; | 
|  | for (size_t i=0; i<num_attributes; ++i) | 
|  | { | 
|  | const dw_attr_t attr = attributes.AttributeAtIndex(i); | 
|  |  | 
|  | switch (attr) | 
|  | { | 
|  | case DW_AT_name: | 
|  | if (attributes.ExtractFormValueAtIndex(this, i, form_value)) | 
|  | name = form_value.AsCString(&get_debug_str_data()); | 
|  | break; | 
|  |  | 
|  | case DW_AT_type: | 
|  | if (attributes.ExtractFormValueAtIndex(this, i, form_value)) | 
|  | { | 
|  | const dw_offset_t type_die_offset = form_value.Reference(dwarf_cu); | 
|  | lldb_type = ResolveTypeUID(type_die_offset); | 
|  | if (lldb_type) | 
|  | clang_type = lldb_type->GetClangForwardType(); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case DW_AT_const_value: | 
|  | if (attributes.ExtractFormValueAtIndex(this, i, form_value)) | 
|  | { | 
|  | uval64_valid = true; | 
|  | uval64 = form_value.Unsigned(); | 
|  | } | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | clang::ASTContext *ast = GetClangASTContext().getASTContext(); | 
|  | if (!clang_type) | 
|  | clang_type = GetClangASTContext().GetBasicType(eBasicTypeVoid); | 
|  |  | 
|  | if (clang_type) | 
|  | { | 
|  | bool is_signed = false; | 
|  | if (name && name[0]) | 
|  | template_param_infos.names.push_back(name); | 
|  | else | 
|  | template_param_infos.names.push_back(NULL); | 
|  |  | 
|  | if (tag == DW_TAG_template_value_parameter && | 
|  | lldb_type != NULL && | 
|  | clang_type.IsIntegerType (is_signed) && | 
|  | uval64_valid) | 
|  | { | 
|  | llvm::APInt apint (lldb_type->GetByteSize() * 8, uval64, is_signed); | 
|  | template_param_infos.args.push_back (clang::TemplateArgument (*ast, | 
|  | llvm::APSInt(apint), | 
|  | clang_type.GetQualType())); | 
|  | } | 
|  | else | 
|  | { | 
|  | template_param_infos.args.push_back (clang::TemplateArgument (clang_type.GetQualType())); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | } | 
|  | } | 
|  | return true; | 
|  |  | 
|  | default: | 
|  | break; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool | 
|  | SymbolFileDWARF::ParseTemplateParameterInfos (DWARFCompileUnit* dwarf_cu, | 
|  | const DWARFDebugInfoEntry *parent_die, | 
|  | ClangASTContext::TemplateParameterInfos &template_param_infos) | 
|  | { | 
|  |  | 
|  | if (parent_die == NULL) | 
|  | return false; | 
|  |  | 
|  | Args template_parameter_names; | 
|  | for (const DWARFDebugInfoEntry *die = parent_die->GetFirstChild(); | 
|  | die != NULL; | 
|  | die = die->GetSibling()) | 
|  | { | 
|  | const dw_tag_t tag = die->Tag(); | 
|  |  | 
|  | switch (tag) | 
|  | { | 
|  | case DW_TAG_template_type_parameter: | 
|  | case DW_TAG_template_value_parameter: | 
|  | ParseTemplateDIE (dwarf_cu, die, template_param_infos); | 
|  | break; | 
|  |  | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  | if (template_param_infos.args.empty()) | 
|  | return false; | 
|  | return template_param_infos.args.size() == template_param_infos.names.size(); | 
|  | } | 
|  |  | 
|  | clang::ClassTemplateDecl * | 
|  | SymbolFileDWARF::ParseClassTemplateDecl (clang::DeclContext *decl_ctx, | 
|  | lldb::AccessType access_type, | 
|  | const char *parent_name, | 
|  | int tag_decl_kind, | 
|  | const ClangASTContext::TemplateParameterInfos &template_param_infos) | 
|  | { | 
|  | if (template_param_infos.IsValid()) | 
|  | { | 
|  | std::string template_basename(parent_name); | 
|  | template_basename.erase (template_basename.find('<')); | 
|  | ClangASTContext &ast = GetClangASTContext(); | 
|  |  | 
|  | return ast.CreateClassTemplateDecl (decl_ctx, | 
|  | access_type, | 
|  | template_basename.c_str(), | 
|  | tag_decl_kind, | 
|  | template_param_infos); | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | class SymbolFileDWARF::DelayedAddObjCClassProperty | 
|  | { | 
|  | public: | 
|  | DelayedAddObjCClassProperty | 
|  | ( | 
|  | const ClangASTType     &class_opaque_type, | 
|  | const char             *property_name, | 
|  | const ClangASTType     &property_opaque_type,  // The property type is only required if you don't have an ivar decl | 
|  | clang::ObjCIvarDecl    *ivar_decl, | 
|  | const char             *property_setter_name, | 
|  | const char             *property_getter_name, | 
|  | uint32_t                property_attributes, | 
|  | const ClangASTMetadata *metadata | 
|  | ) : | 
|  | m_class_opaque_type     (class_opaque_type), | 
|  | m_property_name         (property_name), | 
|  | m_property_opaque_type  (property_opaque_type), | 
|  | m_ivar_decl             (ivar_decl), | 
|  | m_property_setter_name  (property_setter_name), | 
|  | m_property_getter_name  (property_getter_name), | 
|  | m_property_attributes   (property_attributes) | 
|  | { | 
|  | if (metadata != NULL) | 
|  | { | 
|  | m_metadata_ap.reset(new ClangASTMetadata()); | 
|  | *m_metadata_ap = *metadata; | 
|  | } | 
|  | } | 
|  |  | 
|  | DelayedAddObjCClassProperty (const DelayedAddObjCClassProperty &rhs) | 
|  | { | 
|  | *this = rhs; | 
|  | } | 
|  |  | 
|  | DelayedAddObjCClassProperty& operator= (const DelayedAddObjCClassProperty &rhs) | 
|  | { | 
|  | m_class_opaque_type    = rhs.m_class_opaque_type; | 
|  | m_property_name        = rhs.m_property_name; | 
|  | m_property_opaque_type = rhs.m_property_opaque_type; | 
|  | m_ivar_decl            = rhs.m_ivar_decl; | 
|  | m_property_setter_name = rhs.m_property_setter_name; | 
|  | m_property_getter_name = rhs.m_property_getter_name; | 
|  | m_property_attributes  = rhs.m_property_attributes; | 
|  |  | 
|  | if (rhs.m_metadata_ap.get()) | 
|  | { | 
|  | m_metadata_ap.reset (new ClangASTMetadata()); | 
|  | *m_metadata_ap = *rhs.m_metadata_ap; | 
|  | } | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | bool | 
|  | Finalize() | 
|  | { | 
|  | return m_class_opaque_type.AddObjCClassProperty (m_property_name, | 
|  | m_property_opaque_type, | 
|  | m_ivar_decl, | 
|  | m_property_setter_name, | 
|  | m_property_getter_name, | 
|  | m_property_attributes, | 
|  | m_metadata_ap.get()); | 
|  | } | 
|  | private: | 
|  | ClangASTType            m_class_opaque_type; | 
|  | const char             *m_property_name; | 
|  | ClangASTType            m_property_opaque_type; | 
|  | clang::ObjCIvarDecl    *m_ivar_decl; | 
|  | const char             *m_property_setter_name; | 
|  | const char             *m_property_getter_name; | 
|  | uint32_t                m_property_attributes; | 
|  | std::unique_ptr<ClangASTMetadata> m_metadata_ap; | 
|  | }; | 
|  |  | 
|  | struct BitfieldInfo | 
|  | { | 
|  | uint64_t bit_size; | 
|  | uint64_t bit_offset; | 
|  |  | 
|  | BitfieldInfo () : | 
|  | bit_size (LLDB_INVALID_ADDRESS), | 
|  | bit_offset (LLDB_INVALID_ADDRESS) | 
|  | { | 
|  | } | 
|  |  | 
|  | void | 
|  | Clear() | 
|  | { | 
|  | bit_size = LLDB_INVALID_ADDRESS; | 
|  | bit_offset = LLDB_INVALID_ADDRESS; | 
|  | } | 
|  |  | 
|  | bool IsValid () | 
|  | { | 
|  | return (bit_size != LLDB_INVALID_ADDRESS) && | 
|  | (bit_offset != LLDB_INVALID_ADDRESS); | 
|  | } | 
|  | }; | 
|  |  | 
|  |  | 
|  | bool | 
|  | SymbolFileDWARF::ClassOrStructIsVirtual (DWARFCompileUnit* dwarf_cu, | 
|  | const DWARFDebugInfoEntry *parent_die) | 
|  | { | 
|  | if (parent_die) | 
|  | { | 
|  | for (const DWARFDebugInfoEntry *die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling()) | 
|  | { | 
|  | dw_tag_t tag = die->Tag(); | 
|  | bool check_virtuality = false; | 
|  | switch (tag) | 
|  | { | 
|  | case DW_TAG_inheritance: | 
|  | case DW_TAG_subprogram: | 
|  | check_virtuality = true; | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | if (check_virtuality) | 
|  | { | 
|  | if (die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_virtuality, 0) != 0) | 
|  | return true; | 
|  | } | 
|  | } | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | size_t | 
|  | SymbolFileDWARF::ParseChildMembers | 
|  | ( | 
|  | const SymbolContext& sc, | 
|  | DWARFCompileUnit* dwarf_cu, | 
|  | const DWARFDebugInfoEntry *parent_die, | 
|  | ClangASTType &class_clang_type, | 
|  | const LanguageType class_language, | 
|  | std::vector<clang::CXXBaseSpecifier *>& base_classes, | 
|  | std::vector<int>& member_accessibilities, | 
|  | DWARFDIECollection& member_function_dies, | 
|  | DelayedPropertyList& delayed_properties, | 
|  | AccessType& default_accessibility, | 
|  | bool &is_a_class, | 
|  | LayoutInfo &layout_info | 
|  | ) | 
|  | { | 
|  | if (parent_die == NULL) | 
|  | return 0; | 
|  |  | 
|  | size_t count = 0; | 
|  | const DWARFDebugInfoEntry *die; | 
|  | const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize()); | 
|  | uint32_t member_idx = 0; | 
|  | BitfieldInfo last_field_info; | 
|  | ModuleSP module = GetObjectFile()->GetModule(); | 
|  |  | 
|  | for (die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling()) | 
|  | { | 
|  | dw_tag_t tag = die->Tag(); | 
|  |  | 
|  | switch (tag) | 
|  | { | 
|  | case DW_TAG_member: | 
|  | case DW_TAG_APPLE_property: | 
|  | { | 
|  | DWARFDebugInfoEntry::Attributes attributes; | 
|  | const size_t num_attributes = die->GetAttributes (this, | 
|  | dwarf_cu, | 
|  | fixed_form_sizes, | 
|  | attributes); | 
|  | if (num_attributes > 0) | 
|  | { | 
|  | Declaration decl; | 
|  | //DWARFExpression location; | 
|  | const char *name = NULL; | 
|  | const char *prop_name = NULL; | 
|  | const char *prop_getter_name = NULL; | 
|  | const char *prop_setter_name = NULL; | 
|  | uint32_t prop_attributes = 0; | 
|  |  | 
|  |  | 
|  | bool is_artificial = false; | 
|  | lldb::user_id_t encoding_uid = LLDB_INVALID_UID; | 
|  | AccessType accessibility = eAccessNone; | 
|  | uint32_t member_byte_offset = UINT32_MAX; | 
|  | size_t byte_size = 0; | 
|  | size_t bit_offset = 0; | 
|  | size_t bit_size = 0; | 
|  | bool is_external = false; // On DW_TAG_members, this means the member is static | 
|  | uint32_t i; | 
|  | for (i=0; i<num_attributes && !is_artificial; ++i) | 
|  | { | 
|  | const dw_attr_t attr = attributes.AttributeAtIndex(i); | 
|  | DWARFFormValue form_value; | 
|  | if (attributes.ExtractFormValueAtIndex(this, i, form_value)) | 
|  | { | 
|  | switch (attr) | 
|  | { | 
|  | case DW_AT_decl_file:   decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break; | 
|  | case DW_AT_decl_line:   decl.SetLine(form_value.Unsigned()); break; | 
|  | case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break; | 
|  | case DW_AT_name:        name = form_value.AsCString(&get_debug_str_data()); break; | 
|  | case DW_AT_type:        encoding_uid = form_value.Reference(dwarf_cu); break; | 
|  | case DW_AT_bit_offset:  bit_offset = form_value.Unsigned(); break; | 
|  | case DW_AT_bit_size:    bit_size = form_value.Unsigned(); break; | 
|  | case DW_AT_byte_size:   byte_size = form_value.Unsigned(); break; | 
|  | case DW_AT_data_member_location: | 
|  | if (form_value.BlockData()) | 
|  | { | 
|  | Value initialValue(0); | 
|  | Value memberOffset(0); | 
|  | const DWARFDataExtractor& debug_info_data = get_debug_info_data(); | 
|  | uint32_t block_length = form_value.Unsigned(); | 
|  | uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart(); | 
|  | if (DWARFExpression::Evaluate(NULL, // ExecutionContext * | 
|  | NULL, // ClangExpressionVariableList * | 
|  | NULL, // ClangExpressionDeclMap * | 
|  | NULL, // RegisterContext * | 
|  | module, | 
|  | debug_info_data, | 
|  | block_offset, | 
|  | block_length, | 
|  | eRegisterKindDWARF, | 
|  | &initialValue, | 
|  | memberOffset, | 
|  | NULL)) | 
|  | { | 
|  | member_byte_offset = memberOffset.ResolveValue(NULL).UInt(); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | // With DWARF 3 and later, if the value is an integer constant, | 
|  | // this form value is the offset in bytes from the beginning | 
|  | // of the containing entity. | 
|  | member_byte_offset = form_value.Unsigned(); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case DW_AT_accessibility: accessibility = DW_ACCESS_to_AccessType (form_value.Unsigned()); break; | 
|  | case DW_AT_artificial: is_artificial = form_value.Boolean(); break; | 
|  | case DW_AT_APPLE_property_name:      prop_name = form_value.AsCString(&get_debug_str_data()); break; | 
|  | case DW_AT_APPLE_property_getter:    prop_getter_name = form_value.AsCString(&get_debug_str_data()); break; | 
|  | case DW_AT_APPLE_property_setter:    prop_setter_name = form_value.AsCString(&get_debug_str_data()); break; | 
|  | case DW_AT_APPLE_property_attribute: prop_attributes = form_value.Unsigned(); break; | 
|  | case DW_AT_external:                 is_external = form_value.Boolean(); break; | 
|  |  | 
|  | default: | 
|  | case DW_AT_declaration: | 
|  | case DW_AT_description: | 
|  | case DW_AT_mutable: | 
|  | case DW_AT_visibility: | 
|  | case DW_AT_sibling: | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (prop_name) | 
|  | { | 
|  | ConstString fixed_getter; | 
|  | ConstString fixed_setter; | 
|  |  | 
|  | // Check if the property getter/setter were provided as full | 
|  | // names.  We want basenames, so we extract them. | 
|  |  | 
|  | if (prop_getter_name && prop_getter_name[0] == '-') | 
|  | { | 
|  | ObjCLanguageRuntime::MethodName prop_getter_method(prop_getter_name, true); | 
|  | prop_getter_name = prop_getter_method.GetSelector().GetCString(); | 
|  | } | 
|  |  | 
|  | if (prop_setter_name && prop_setter_name[0] == '-') | 
|  | { | 
|  | ObjCLanguageRuntime::MethodName prop_setter_method(prop_setter_name, true); | 
|  | prop_setter_name = prop_setter_method.GetSelector().GetCString(); | 
|  | } | 
|  |  | 
|  | // If the names haven't been provided, they need to be | 
|  | // filled in. | 
|  |  | 
|  | if (!prop_getter_name) | 
|  | { | 
|  | prop_getter_name = prop_name; | 
|  | } | 
|  | if (!prop_setter_name && prop_name[0] && !(prop_attributes & DW_APPLE_PROPERTY_readonly)) | 
|  | { | 
|  | StreamString ss; | 
|  |  | 
|  | ss.Printf("set%c%s:", | 
|  | toupper(prop_name[0]), | 
|  | &prop_name[1]); | 
|  |  | 
|  | fixed_setter.SetCString(ss.GetData()); | 
|  | prop_setter_name = fixed_setter.GetCString(); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Clang has a DWARF generation bug where sometimes it | 
|  | // represents fields that are references with bad byte size | 
|  | // and bit size/offset information such as: | 
|  | // | 
|  | //  DW_AT_byte_size( 0x00 ) | 
|  | //  DW_AT_bit_size( 0x40 ) | 
|  | //  DW_AT_bit_offset( 0xffffffffffffffc0 ) | 
|  | // | 
|  | // So check the bit offset to make sure it is sane, and if | 
|  | // the values are not sane, remove them. If we don't do this | 
|  | // then we will end up with a crash if we try to use this | 
|  | // type in an expression when clang becomes unhappy with its | 
|  | // recycled debug info. | 
|  |  | 
|  | if (bit_offset > 128) | 
|  | { | 
|  | bit_size = 0; | 
|  | bit_offset = 0; | 
|  | } | 
|  |  | 
|  | // FIXME: Make Clang ignore Objective-C accessibility for expressions | 
|  | if (class_language == eLanguageTypeObjC || | 
|  | class_language == eLanguageTypeObjC_plus_plus) | 
|  | accessibility = eAccessNone; | 
|  |  | 
|  | if (member_idx == 0 && !is_artificial && name && (strstr (name, "_vptr$") == name)) | 
|  | { | 
|  | // Not all compilers will mark the vtable pointer | 
|  | // member as artificial (llvm-gcc). We can't have | 
|  | // the virtual members in our classes otherwise it | 
|  | // throws off all child offsets since we end up | 
|  | // having and extra pointer sized member in our | 
|  | // class layouts. | 
|  | is_artificial = true; | 
|  | } | 
|  |  | 
|  | // Handle static members | 
|  | if (is_external && member_byte_offset == UINT32_MAX) | 
|  | { | 
|  | Type *var_type = ResolveTypeUID(encoding_uid); | 
|  |  | 
|  | if (var_type) | 
|  | { | 
|  | if (accessibility == eAccessNone) | 
|  | accessibility = eAccessPublic; | 
|  | class_clang_type.AddVariableToRecordType (name, | 
|  | var_type->GetClangLayoutType(), | 
|  | accessibility); | 
|  | } | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (is_artificial == false) | 
|  | { | 
|  | Type *member_type = ResolveTypeUID(encoding_uid); | 
|  |  | 
|  | clang::FieldDecl *field_decl = NULL; | 
|  | if (tag == DW_TAG_member) | 
|  | { | 
|  | if (member_type) | 
|  | { | 
|  | if (accessibility == eAccessNone) | 
|  | accessibility = default_accessibility; | 
|  | member_accessibilities.push_back(accessibility); | 
|  |  | 
|  | uint64_t field_bit_offset = (member_byte_offset == UINT32_MAX ? 0 : (member_byte_offset * 8)); | 
|  | if (bit_size > 0) | 
|  | { | 
|  |  | 
|  | BitfieldInfo this_field_info; | 
|  | this_field_info.bit_offset = field_bit_offset; | 
|  | this_field_info.bit_size = bit_size; | 
|  |  | 
|  | ///////////////////////////////////////////////////////////// | 
|  | // How to locate a field given the DWARF debug information | 
|  | // | 
|  | // AT_byte_size indicates the size of the word in which the | 
|  | // bit offset must be interpreted. | 
|  | // | 
|  | // AT_data_member_location indicates the byte offset of the | 
|  | // word from the base address of the structure. | 
|  | // | 
|  | // AT_bit_offset indicates how many bits into the word | 
|  | // (according to the host endianness) the low-order bit of | 
|  | // the field starts.  AT_bit_offset can be negative. | 
|  | // | 
|  | // AT_bit_size indicates the size of the field in bits. | 
|  | ///////////////////////////////////////////////////////////// | 
|  |  | 
|  | if (byte_size == 0) | 
|  | byte_size = member_type->GetByteSize(); | 
|  |  | 
|  | if (GetObjectFile()->GetByteOrder() == eByteOrderLittle) | 
|  | { | 
|  | this_field_info.bit_offset += byte_size * 8; | 
|  | this_field_info.bit_offset -= (bit_offset + bit_size); | 
|  | } | 
|  | else | 
|  | { | 
|  | this_field_info.bit_offset += bit_offset; | 
|  | } | 
|  |  | 
|  | // Update the field bit offset we will report for layout | 
|  | field_bit_offset = this_field_info.bit_offset; | 
|  |  | 
|  | // If the member to be emitted did not start on a character boundary and there is | 
|  | // empty space between the last field and this one, then we need to emit an | 
|  | // anonymous member filling up the space up to its start.  There are three cases | 
|  | // here: | 
|  | // | 
|  | // 1 If the previous member ended on a character boundary, then we can emit an | 
|  | //   anonymous member starting at the most recent character boundary. | 
|  | // | 
|  | // 2 If the previous member did not end on a character boundary and the distance | 
|  | //   from the end of the previous member to the current member is less than a | 
|  | //   word width, then we can emit an anonymous member starting right after the | 
|  | //   previous member and right before this member. | 
|  | // | 
|  | // 3 If the previous member did not end on a character boundary and the distance | 
|  | //   from the end of the previous member to the current member is greater than | 
|  | //   or equal a word width, then we act as in Case 1. | 
|  |  | 
|  | const uint64_t character_width = 8; | 
|  | const uint64_t word_width = 32; | 
|  |  | 
|  | // Objective-C has invalid DW_AT_bit_offset values in older versions | 
|  | // of clang, so we have to be careful and only insert unnamed bitfields | 
|  | // if we have a new enough clang. | 
|  | bool detect_unnamed_bitfields = true; | 
|  |  | 
|  | if (class_language == eLanguageTypeObjC || class_language == eLanguageTypeObjC_plus_plus) | 
|  | detect_unnamed_bitfields = dwarf_cu->Supports_unnamed_objc_bitfields (); | 
|  |  | 
|  | if (detect_unnamed_bitfields) | 
|  | { | 
|  | BitfieldInfo anon_field_info; | 
|  |  | 
|  | if ((this_field_info.bit_offset % character_width) != 0) // not char aligned | 
|  | { | 
|  | uint64_t last_field_end = 0; | 
|  |  | 
|  | if (last_field_info.IsValid()) | 
|  | last_field_end = last_field_info.bit_offset + last_field_info.bit_size; | 
|  |  | 
|  | if (this_field_info.bit_offset != last_field_end) | 
|  | { | 
|  | if (((last_field_end % character_width) == 0) ||                    // case 1 | 
|  | (this_field_info.bit_offset - last_field_end >= word_width))    // case 3 | 
|  | { | 
|  | anon_field_info.bit_size = this_field_info.bit_offset % character_width; | 
|  | anon_field_info.bit_offset = this_field_info.bit_offset - anon_field_info.bit_size; | 
|  | } | 
|  | else                                                                // case 2 | 
|  | { | 
|  | anon_field_info.bit_size = this_field_info.bit_offset - last_field_end; | 
|  | anon_field_info.bit_offset = last_field_end; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (anon_field_info.IsValid()) | 
|  | { | 
|  | clang::FieldDecl *unnamed_bitfield_decl = class_clang_type.AddFieldToRecordType (NULL, | 
|  | GetClangASTContext().GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, word_width), | 
|  | accessibility, | 
|  | anon_field_info.bit_size); | 
|  |  | 
|  | layout_info.field_offsets.insert(std::make_pair(unnamed_bitfield_decl, anon_field_info.bit_offset)); | 
|  | } | 
|  | } | 
|  | last_field_info = this_field_info; | 
|  | } | 
|  | else | 
|  | { | 
|  | last_field_info.Clear(); | 
|  | } | 
|  |  | 
|  | ClangASTType member_clang_type = member_type->GetClangLayoutType(); | 
|  |  | 
|  | { | 
|  | // Older versions of clang emit array[0] and array[1] in the same way (<rdar://problem/12566646>). | 
|  | // If the current field is at the end of the structure, then there is definitely no room for extra | 
|  | // elements and we override the type to array[0]. | 
|  |  | 
|  | ClangASTType member_array_element_type; | 
|  | uint64_t member_array_size; | 
|  | bool member_array_is_incomplete; | 
|  |  | 
|  | if (member_clang_type.IsArrayType(&member_array_element_type, | 
|  | &member_array_size, | 
|  | &member_array_is_incomplete) && | 
|  | !member_array_is_incomplete) | 
|  | { | 
|  | uint64_t parent_byte_size = parent_die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_byte_size, UINT64_MAX); | 
|  |  | 
|  | if (member_byte_offset >= parent_byte_size) | 
|  | { | 
|  | if (member_array_size != 1) | 
|  | { | 
|  | GetObjectFile()->GetModule()->ReportError ("0x%8.8" PRIx64 ": DW_TAG_member '%s' refers to type 0x%8.8" PRIx64 " which extends beyond the bounds of 0x%8.8" PRIx64, | 
|  | MakeUserID(die->GetOffset()), | 
|  | name, | 
|  | encoding_uid, | 
|  | MakeUserID(parent_die->GetOffset())); | 
|  | } | 
|  |  | 
|  | member_clang_type = GetClangASTContext().CreateArrayType(member_array_element_type, 0, false); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | field_decl = class_clang_type.AddFieldToRecordType (name, | 
|  | member_clang_type, | 
|  | accessibility, | 
|  | bit_size); | 
|  |  | 
|  | GetClangASTContext().SetMetadataAsUserID (field_decl, MakeUserID(die->GetOffset())); | 
|  |  | 
|  | layout_info.field_offsets.insert(std::make_pair(field_decl, field_bit_offset)); | 
|  |  | 
|  | } | 
|  | else | 
|  | { | 
|  | if (name) | 
|  | GetObjectFile()->GetModule()->ReportError ("0x%8.8" PRIx64 ": DW_TAG_member '%s' refers to type 0x%8.8" PRIx64 " which was unable to be parsed", | 
|  | MakeUserID(die->GetOffset()), | 
|  | name, | 
|  | encoding_uid); | 
|  | else | 
|  | GetObjectFile()->GetModule()->ReportError ("0x%8.8" PRIx64 ": DW_TAG_member refers to type 0x%8.8" PRIx64 " which was unable to be parsed", | 
|  | MakeUserID(die->GetOffset()), | 
|  | encoding_uid); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (prop_name != NULL) | 
|  | { | 
|  | clang::ObjCIvarDecl *ivar_decl = NULL; | 
|  |  | 
|  | if (field_decl) | 
|  | { | 
|  | ivar_decl = clang::dyn_cast<clang::ObjCIvarDecl>(field_decl); | 
|  | assert (ivar_decl != NULL); | 
|  | } | 
|  |  | 
|  | ClangASTMetadata metadata; | 
|  | metadata.SetUserID (MakeUserID(die->GetOffset())); | 
|  | delayed_properties.push_back(DelayedAddObjCClassProperty(class_clang_type, | 
|  | prop_name, | 
|  | member_type->GetClangLayoutType(), | 
|  | ivar_decl, | 
|  | prop_setter_name, | 
|  | prop_getter_name, | 
|  | prop_attributes, | 
|  | &metadata)); | 
|  |  | 
|  | if (ivar_decl) | 
|  | GetClangASTContext().SetMetadataAsUserID (ivar_decl, MakeUserID(die->GetOffset())); | 
|  | } | 
|  | } | 
|  | } | 
|  | ++member_idx; | 
|  | } | 
|  | break; | 
|  |  | 
|  | case DW_TAG_subprogram: | 
|  | // Let the type parsing code handle this one for us. | 
|  | member_function_dies.Append (die); | 
|  | break; | 
|  |  | 
|  | case DW_TAG_inheritance: | 
|  | { | 
|  | is_a_class = true; | 
|  | if (default_accessibility == eAccessNone) | 
|  | default_accessibility = eAccessPrivate; | 
|  | // TODO: implement DW_TAG_inheritance type parsing | 
|  | DWARFDebugInfoEntry::Attributes attributes; | 
|  | const size_t num_attributes = die->GetAttributes (this, | 
|  | dwarf_cu, | 
|  | fixed_form_sizes, | 
|  | attributes); | 
|  | if (num_attributes > 0) | 
|  | { | 
|  | Declaration decl; | 
|  | DWARFExpression location; | 
|  | lldb::user_id_t encoding_uid = LLDB_INVALID_UID; | 
|  | AccessType accessibility = default_accessibility; | 
|  | bool is_virtual = false; | 
|  | bool is_base_of_class = true; | 
|  | off_t member_byte_offset = 0; | 
|  | uint32_t i; | 
|  | for (i=0; i<num_attributes; ++i) | 
|  | { | 
|  | const dw_attr_t attr = attributes.AttributeAtIndex(i); | 
|  | DWARFFormValue form_value; | 
|  | if (attributes.ExtractFormValueAtIndex(this, i, form_value)) | 
|  | { | 
|  | switch (attr) | 
|  | { | 
|  | case DW_AT_decl_file:   decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break; | 
|  | case DW_AT_decl_line:   decl.SetLine(form_value.Unsigned()); break; | 
|  | case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break; | 
|  | case DW_AT_type:        encoding_uid = form_value.Reference(dwarf_cu); break; | 
|  | case DW_AT_data_member_location: | 
|  | if (form_value.BlockData()) | 
|  | { | 
|  | Value initialValue(0); | 
|  | Value memberOffset(0); | 
|  | const DWARFDataExtractor& debug_info_data = get_debug_info_data(); | 
|  | uint32_t block_length = form_value.Unsigned(); | 
|  | uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart(); | 
|  | if (DWARFExpression::Evaluate (NULL, | 
|  | NULL, | 
|  | NULL, | 
|  | NULL, | 
|  | module, | 
|  | debug_info_data, | 
|  | block_offset, | 
|  | block_length, | 
|  | eRegisterKindDWARF, | 
|  | &initialValue, | 
|  | memberOffset, | 
|  | NULL)) | 
|  | { | 
|  | member_byte_offset = memberOffset.ResolveValue(NULL).UInt(); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | // With DWARF 3 and later, if the value is an integer constant, | 
|  | // this form value is the offset in bytes from the beginning | 
|  | // of the containing entity. | 
|  | member_byte_offset = form_value.Unsigned(); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case DW_AT_accessibility: | 
|  | accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned()); | 
|  | break; | 
|  |  | 
|  | case DW_AT_virtuality: | 
|  | is_virtual = form_value.Boolean(); | 
|  | break; | 
|  |  | 
|  | case DW_AT_sibling: | 
|  | break; | 
|  |  | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | Type *base_class_type = ResolveTypeUID(encoding_uid); | 
|  | assert(base_class_type); | 
|  |  | 
|  | ClangASTType base_class_clang_type = base_class_type->GetClangFullType(); | 
|  | assert (base_class_clang_type); | 
|  | if (class_language == eLanguageTypeObjC) | 
|  | { | 
|  | class_clang_type.SetObjCSuperClass(base_class_clang_type); | 
|  | } | 
|  | else | 
|  | { | 
|  | base_classes.push_back (base_class_clang_type.CreateBaseClassSpecifier (accessibility, | 
|  | is_virtual, | 
|  | is_base_of_class)); | 
|  |  | 
|  | if (is_virtual) | 
|  | { | 
|  | // Do not specify any offset for virtual inheritance. The DWARF produced by clang doesn't | 
|  | // give us a constant offset, but gives us a DWARF expressions that requires an actual object | 
|  | // in memory. the DW_AT_data_member_location for a virtual base class looks like: | 
|  | //      DW_AT_data_member_location( DW_OP_dup, DW_OP_deref, DW_OP_constu(0x00000018), DW_OP_minus, DW_OP_deref, DW_OP_plus ) | 
|  | // Given this, there is really no valid response we can give to clang for virtual base | 
|  | // class offsets, and this should eventually be removed from LayoutRecordType() in the external | 
|  | // AST source in clang. | 
|  | } | 
|  | else | 
|  | { | 
|  | layout_info.base_offsets.insert(std::make_pair(base_class_clang_type.GetAsCXXRecordDecl(), | 
|  | clang::CharUnits::fromQuantity(member_byte_offset))); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | break; | 
|  |  | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | return count; | 
|  | } | 
|  |  | 
|  |  | 
|  | clang::DeclContext* | 
|  | SymbolFileDWARF::GetClangDeclContextContainingTypeUID (lldb::user_id_t type_uid) | 
|  | { | 
|  | DWARFDebugInfo* debug_info = DebugInfo(); | 
|  | if (debug_info && UserIDMatches(type_uid)) | 
|  | { | 
|  | DWARFCompileUnitSP cu_sp; | 
|  | const DWARFDebugInfoEntry* die = debug_info->GetDIEPtr(type_uid, &cu_sp); | 
|  | if (die) | 
|  | return GetClangDeclContextContainingDIE (cu_sp.get(), die, NULL); | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | clang::DeclContext* | 
|  | SymbolFileDWARF::GetClangDeclContextForTypeUID (const lldb_private::SymbolContext &sc, lldb::user_id_t type_uid) | 
|  | { | 
|  | if (UserIDMatches(type_uid)) | 
|  | return GetClangDeclContextForDIEOffset (sc, type_uid); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | Type* | 
|  | SymbolFileDWARF::ResolveTypeUID (lldb::user_id_t type_uid) | 
|  | { | 
|  | if (UserIDMatches(type_uid)) | 
|  | { | 
|  | DWARFDebugInfo* debug_info = DebugInfo(); | 
|  | if (debug_info) | 
|  | { | 
|  | DWARFCompileUnitSP cu_sp; | 
|  | const DWARFDebugInfoEntry* type_die = debug_info->GetDIEPtr(type_uid, &cu_sp); | 
|  | const bool assert_not_being_parsed = true; | 
|  | return ResolveTypeUID (cu_sp.get(), type_die, assert_not_being_parsed); | 
|  | } | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | Type* | 
|  | SymbolFileDWARF::ResolveTypeUID (DWARFCompileUnit* cu, const DWARFDebugInfoEntry* die, bool assert_not_being_parsed) | 
|  | { | 
|  | if (die != NULL) | 
|  | { | 
|  | Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO)); | 
|  | if (log) | 
|  | GetObjectFile()->GetModule()->LogMessage (log, | 
|  | "SymbolFileDWARF::ResolveTypeUID (die = 0x%8.8x) %s '%s'", | 
|  | die->GetOffset(), | 
|  | DW_TAG_value_to_name(die->Tag()), | 
|  | die->GetName(this, cu)); | 
|  |  | 
|  | // We might be coming in in the middle of a type tree (a class | 
|  | // withing a class, an enum within a class), so parse any needed | 
|  | // parent DIEs before we get to this one... | 
|  | const DWARFDebugInfoEntry *decl_ctx_die = GetDeclContextDIEContainingDIE (cu, die); | 
|  | switch (decl_ctx_die->Tag()) | 
|  | { | 
|  | case DW_TAG_structure_type: | 
|  | case DW_TAG_union_type: | 
|  | case DW_TAG_class_type: | 
|  | { | 
|  | // Get the type, which could be a forward declaration | 
|  | if (log) | 
|  | GetObjectFile()->GetModule()->LogMessage (log, | 
|  | "SymbolFileDWARF::ResolveTypeUID (die = 0x%8.8x) %s '%s' resolve parent forward type for 0x%8.8x", | 
|  | die->GetOffset(), | 
|  | DW_TAG_value_to_name(die->Tag()), | 
|  | die->GetName(this, cu), | 
|  | decl_ctx_die->GetOffset()); | 
|  | // | 
|  | //                Type *parent_type = ResolveTypeUID (cu, decl_ctx_die, assert_not_being_parsed); | 
|  | //                if (child_requires_parent_class_union_or_struct_to_be_completed(die->Tag())) | 
|  | //                { | 
|  | //                    if (log) | 
|  | //                        GetObjectFile()->GetModule()->LogMessage (log, | 
|  | //                                                                  "SymbolFileDWARF::ResolveTypeUID (die = 0x%8.8x) %s '%s' resolve parent full type for 0x%8.8x since die is a function", | 
|  | //                                                                  die->GetOffset(), | 
|  | //                                                                  DW_TAG_value_to_name(die->Tag()), | 
|  | //                                                                  die->GetName(this, cu), | 
|  | //                                                                  decl_ctx_die->GetOffset()); | 
|  | //                    // Ask the type to complete itself if it already hasn't since if we | 
|  | //                    // want a function (method or static) from a class, the class must | 
|  | //                    // create itself and add it's own methods and class functions. | 
|  | //                    if (parent_type) | 
|  | //                        parent_type->GetClangFullType(); | 
|  | //                } | 
|  | } | 
|  | break; | 
|  |  | 
|  | default: | 
|  | break; | 
|  | } | 
|  | return ResolveType (cu, die); | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | // This function is used when SymbolFileDWARFDebugMap owns a bunch of | 
|  | // SymbolFileDWARF objects to detect if this DWARF file is the one that | 
|  | // can resolve a clang_type. | 
|  | bool | 
|  | SymbolFileDWARF::HasForwardDeclForClangType (const ClangASTType &clang_type) | 
|  | { | 
|  | ClangASTType clang_type_no_qualifiers = clang_type.RemoveFastQualifiers(); | 
|  | const DWARFDebugInfoEntry* die = m_forward_decl_clang_type_to_die.lookup (clang_type_no_qualifiers.GetOpaqueQualType()); | 
|  | return die != NULL; | 
|  | } | 
|  |  | 
|  |  | 
|  | bool | 
|  | SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type) | 
|  | { | 
|  | // We have a struct/union/class/enum that needs to be fully resolved. | 
|  | ClangASTType clang_type_no_qualifiers = clang_type.RemoveFastQualifiers(); | 
|  | const DWARFDebugInfoEntry* die = m_forward_decl_clang_type_to_die.lookup (clang_type_no_qualifiers.GetOpaqueQualType()); | 
|  | if (die == NULL) | 
|  | { | 
|  | // We have already resolved this type... | 
|  | return true; | 
|  | } | 
|  | // Once we start resolving this type, remove it from the forward declaration | 
|  | // map in case anyone child members or other types require this type to get resolved. | 
|  | // The type will get resolved when all of the calls to SymbolFileDWARF::ResolveClangOpaqueTypeDefinition | 
|  | // are done. | 
|  | m_forward_decl_clang_type_to_die.erase (clang_type_no_qualifiers.GetOpaqueQualType()); | 
|  |  | 
|  | // Disable external storage for this type so we don't get anymore | 
|  | // clang::ExternalASTSource queries for this type. | 
|  | clang_type.SetHasExternalStorage (false); | 
|  |  | 
|  | DWARFDebugInfo* debug_info = DebugInfo(); | 
|  |  | 
|  | DWARFCompileUnit *dwarf_cu = debug_info->GetCompileUnitContainingDIE (die->GetOffset()).get(); | 
|  | Type *type = m_die_to_type.lookup (die); | 
|  |  | 
|  | const dw_tag_t tag = die->Tag(); | 
|  |  | 
|  | Log *log (LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO|DWARF_LOG_TYPE_COMPLETION)); | 
|  | if (log) | 
|  | GetObjectFile()->GetModule()->LogMessageVerboseBacktrace (log, | 
|  | "0x%8.8" PRIx64 ": %s '%s' resolving forward declaration...", | 
|  | MakeUserID(die->GetOffset()), | 
|  | DW_TAG_value_to_name(tag), | 
|  | type->GetName().AsCString()); | 
|  | assert (clang_type); | 
|  | DWARFDebugInfoEntry::Attributes attributes; | 
|  |  | 
|  | switch (tag) | 
|  | { | 
|  | case DW_TAG_structure_type: | 
|  | case DW_TAG_union_type: | 
|  | case DW_TAG_class_type: | 
|  | { | 
|  | LayoutInfo layout_info; | 
|  |  | 
|  | { | 
|  | if (die->HasChildren()) | 
|  | { | 
|  | LanguageType class_language = eLanguageTypeUnknown; | 
|  | if (clang_type.IsObjCObjectOrInterfaceType()) | 
|  | { | 
|  | class_language = eLanguageTypeObjC; | 
|  | // For objective C we don't start the definition when | 
|  | // the class is created. | 
|  | clang_type.StartTagDeclarationDefinition (); | 
|  | } | 
|  |  | 
|  | int tag_decl_kind = -1; | 
|  | AccessType default_accessibility = eAccessNone; | 
|  | if (tag == DW_TAG_structure_type) | 
|  | { | 
|  | tag_decl_kind = clang::TTK_Struct; | 
|  | default_accessibility = eAccessPublic; | 
|  | } | 
|  | else if (tag == DW_TAG_union_type) | 
|  | { | 
|  | tag_decl_kind = clang::TTK_Union; | 
|  | default_accessibility = eAccessPublic; | 
|  | } | 
|  | else if (tag == DW_TAG_class_type) | 
|  | { | 
|  | tag_decl_kind = clang::TTK_Class; | 
|  | default_accessibility = eAccessPrivate; | 
|  | } | 
|  |  | 
|  | SymbolContext sc(GetCompUnitForDWARFCompUnit(dwarf_cu)); | 
|  | std::vector<clang::CXXBaseSpecifier *> base_classes; | 
|  | std::vector<int> member_accessibilities; | 
|  | bool is_a_class = false; | 
|  | // Parse members and base classes first | 
|  | DWARFDIECollection member_function_dies; | 
|  |  | 
|  | DelayedPropertyList delayed_properties; | 
|  | ParseChildMembers (sc, | 
|  | dwarf_cu, | 
|  | die, | 
|  | clang_type, | 
|  | class_language, | 
|  | base_classes, | 
|  | member_accessibilities, | 
|  | member_function_dies, | 
|  | delayed_properties, | 
|  | default_accessibility, | 
|  | is_a_class, | 
|  | layout_info); | 
|  |  | 
|  | // Now parse any methods if there were any... | 
|  | size_t num_functions = member_function_dies.Size(); | 
|  | if (num_functions > 0) | 
|  | { | 
|  | for (size_t i=0; i<num_functions; ++i) | 
|  | { | 
|  | ResolveType(dwarf_cu, member_function_dies.GetDIEPtrAtIndex(i)); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (class_language == eLanguageTypeObjC) | 
|  | { | 
|  | ConstString class_name (clang_type.GetTypeName()); | 
|  | if (class_name) | 
|  | { | 
|  | DIEArray method_die_offsets; | 
|  | if (m_using_apple_tables) | 
|  | { | 
|  | if (m_apple_objc_ap.get()) | 
|  | m_apple_objc_ap->FindByName(class_name.GetCString(), method_die_offsets); | 
|  | } | 
|  | else | 
|  | { | 
|  | if (!m_indexed) | 
|  | Index (); | 
|  |  | 
|  | m_objc_class_selectors_index.Find (class_name, method_die_offsets); | 
|  | } | 
|  |  | 
|  | if (!method_die_offsets.empty()) | 
|  | { | 
|  | DWARFDebugInfo* debug_info = DebugInfo(); | 
|  |  | 
|  | DWARFCompileUnit* method_cu = NULL; | 
|  | const size_t num_matches = method_die_offsets.size(); | 
|  | for (size_t i=0; i<num_matches; ++i) | 
|  | { | 
|  | const dw_offset_t die_offset = method_die_offsets[i]; | 
|  | DWARFDebugInfoEntry *method_die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &method_cu); | 
|  |  | 
|  | if (method_die) | 
|  | ResolveType (method_cu, method_die); | 
|  | else | 
|  | { | 
|  | if (m_using_apple_tables) | 
|  | { | 
|  | GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_objc accelerator table had bad die 0x%8.8x for '%s')\n", | 
|  | die_offset, class_name.GetCString()); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | for (DelayedPropertyList::iterator pi = delayed_properties.begin(), pe = delayed_properties.end(); | 
|  | pi != pe; | 
|  | ++pi) | 
|  | pi->Finalize(); | 
|  | } | 
|  | } | 
|  |  | 
|  | // If we have a DW_TAG_structure_type instead of a DW_TAG_class_type we | 
|  | // need to tell the clang type it is actually a class. | 
|  | if (class_language != eLanguageTypeObjC) | 
|  | { | 
|  | if (is_a_class && tag_decl_kind != clang::TTK_Class) | 
|  | clang_type.SetTagTypeKind (clang::TTK_Class); | 
|  | } | 
|  |  | 
|  | // Since DW_TAG_structure_type gets used for both classes | 
|  | // and structures, we may need to set any DW_TAG_member | 
|  | // fields to have a "private" access if none was specified. | 
|  | // When we parsed the child members we tracked that actual | 
|  | // accessibility value for each DW_TAG_member in the | 
|  | // "member_accessibilities" array. If the value for the | 
|  | // member is zero, then it was set to the "default_accessibility" | 
|  | // which for structs was "public". Below we correct this | 
|  | // by setting any fields to "private" that weren't correctly | 
|  | // set. | 
|  | if (is_a_class && !member_accessibilities.empty()) | 
|  | { | 
|  | // This is a class and all members that didn't have | 
|  | // their access specified are private. | 
|  | clang_type.SetDefaultAccessForRecordFields (eAccessPrivate, | 
|  | &member_accessibilities.front(), | 
|  | member_accessibilities.size()); | 
|  | } | 
|  |  | 
|  | if (!base_classes.empty()) | 
|  | { | 
|  | // Make sure all base classes refer to complete types and not | 
|  | // forward declarations. If we don't do this, clang will crash | 
|  | // with an assertion in the call to clang_type.SetBaseClassesForClassType() | 
|  | bool base_class_error = false; | 
|  | for (auto &base_class : base_classes) | 
|  | { | 
|  | clang::TypeSourceInfo *type_source_info = base_class->getTypeSourceInfo(); | 
|  | if (type_source_info) | 
|  | { | 
|  | ClangASTType base_class_type (GetClangASTContext().getASTContext(), type_source_info->getType()); | 
|  | if (base_class_type.GetCompleteType() == false) | 
|  | { | 
|  | if (!base_class_error) | 
|  | { | 
|  | GetObjectFile()->GetModule()->ReportError ("DWARF DIE at 0x%8.8x for class '%s' has a base class '%s' that is a forward declaration, not a complete definition.\nPlease file a bug against the compiler and include the preprocessed output for %s", | 
|  | die->GetOffset(), | 
|  | die->GetName(this, dwarf_cu), | 
|  | base_class_type.GetTypeName().GetCString(), | 
|  | sc.comp_unit ? sc.comp_unit->GetPath().c_str() : "the source file"); | 
|  | } | 
|  | // We have no choice other than to pretend that the base class | 
|  | // is complete. If we don't do this, clang will crash when we | 
|  | // call setBases() inside of "clang_type.SetBaseClassesForClassType()" | 
|  | // below. Since we provide layout assistance, all ivars in this | 
|  | // class and other classes will be fine, this is the best we can do | 
|  | // short of crashing. | 
|  | base_class_type.StartTagDeclarationDefinition (); | 
|  | base_class_type.CompleteTagDeclarationDefinition (); | 
|  | } | 
|  | } | 
|  | } | 
|  | clang_type.SetBaseClassesForClassType (&base_classes.front(), | 
|  | base_classes.size()); | 
|  |  | 
|  | // Clang will copy each CXXBaseSpecifier in "base_classes" | 
|  | // so we have to free them all. | 
|  | ClangASTType::DeleteBaseClassSpecifiers (&base_classes.front(), | 
|  | base_classes.size()); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | clang_type.BuildIndirectFields (); | 
|  | clang_type.CompleteTagDeclarationDefinition (); | 
|  |  | 
|  | if (!layout_info.field_offsets.empty() || | 
|  | !layout_info.base_offsets.empty()  || | 
|  | !layout_info.vbase_offsets.empty() ) | 
|  | { | 
|  | if (type) | 
|  | layout_info.bit_size = type->GetByteSize() * 8; | 
|  | if (layout_info.bit_size == 0) | 
|  | layout_info.bit_size = die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_byte_size, 0) * 8; | 
|  |  | 
|  | clang::CXXRecordDecl *record_decl = clang_type.GetAsCXXRecordDecl(); | 
|  | if (record_decl) | 
|  | { | 
|  | if (log) | 
|  | { | 
|  | GetObjectFile()->GetModule()->LogMessage (log, | 
|  | "SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (clang_type = %p) caching layout info for record_decl = %p, bit_size = %" PRIu64 ", alignment = %" PRIu64 ", field_offsets[%u], base_offsets[%u], vbase_offsets[%u])", | 
|  | static_cast<void*>(clang_type.GetOpaqueQualType()), | 
|  | static_cast<void*>(record_decl), | 
|  | layout_info.bit_size, | 
|  | layout_info.alignment, | 
|  | static_cast<uint32_t>(layout_info.field_offsets.size()), | 
|  | static_cast<uint32_t>(layout_info.base_offsets.size()), | 
|  | static_cast<uint32_t>(layout_info.vbase_offsets.size())); | 
|  |  | 
|  | uint32_t idx; | 
|  | { | 
|  | llvm::DenseMap <const clang::FieldDecl *, uint64_t>::const_iterator pos, end = layout_info.field_offsets.end(); | 
|  | for (idx = 0, pos = layout_info.field_offsets.begin(); pos != end; ++pos, ++idx) | 
|  | { | 
|  | GetObjectFile()->GetModule()->LogMessage (log, | 
|  | "SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (clang_type = %p) field[%u] = { bit_offset=%u, name='%s' }", | 
|  | static_cast<void*>(clang_type.GetOpaqueQualType()), | 
|  | idx, | 
|  | static_cast<uint32_t>(pos->second), | 
|  | pos->first->getNameAsString().c_str()); | 
|  | } | 
|  | } | 
|  |  | 
|  | { | 
|  | llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits>::const_iterator base_pos, base_end = layout_info.base_offsets.end(); | 
|  | for (idx = 0, base_pos = layout_info.base_offsets.begin(); base_pos != base_end; ++base_pos, ++idx) | 
|  | { | 
|  | GetObjectFile()->GetModule()->LogMessage (log, | 
|  | "SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (clang_type = %p) base[%u] = { byte_offset=%u, name='%s' }", | 
|  | clang_type.GetOpaqueQualType(), | 
|  | idx, | 
|  | (uint32_t)base_pos->second.getQuantity(), | 
|  | base_pos->first->getNameAsString().c_str()); | 
|  | } | 
|  | } | 
|  | { | 
|  | llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits>::const_iterator vbase_pos, vbase_end = layout_info.vbase_offsets.end(); | 
|  | for (idx = 0, vbase_pos = layout_info.vbase_offsets.begin(); vbase_pos != vbase_end; ++vbase_pos, ++idx) | 
|  | { | 
|  | GetObjectFile()->GetModule()->LogMessage (log, | 
|  | "SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (clang_type = %p) vbase[%u] = { byte_offset=%u, name='%s' }", | 
|  | static_cast<void*>(clang_type.GetOpaqueQualType()), | 
|  | idx, | 
|  | static_cast<uint32_t>(vbase_pos->second.getQuantity()), | 
|  | vbase_pos->first->getNameAsString().c_str()); | 
|  | } | 
|  | } | 
|  | } | 
|  | m_record_decl_to_layout_map.insert(std::make_pair(record_decl, layout_info)); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return (bool)clang_type; | 
|  |  | 
|  | case DW_TAG_enumeration_type: | 
|  | clang_type.StartTagDeclarationDefinition (); | 
|  | if (die->HasChildren()) | 
|  | { | 
|  | SymbolContext sc(GetCompUnitForDWARFCompUnit(dwarf_cu)); | 
|  | bool is_signed = false; | 
|  | clang_type.IsIntegerType(is_signed); | 
|  | ParseChildEnumerators(sc, clang_type, is_signed, type->GetByteSize(), dwarf_cu, die); | 
|  | } | 
|  | clang_type.CompleteTagDeclarationDefinition (); | 
|  | return (bool)clang_type; | 
|  |  | 
|  | default: | 
|  | assert(false && "not a forward clang type decl!"); | 
|  | break; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | Type* | 
|  | SymbolFileDWARF::ResolveType (DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry* type_die, bool assert_not_being_parsed) | 
|  | { | 
|  | if (type_die != NULL) | 
|  | { | 
|  | Type *type = m_die_to_type.lookup (type_die); | 
|  |  | 
|  | if (type == NULL) | 
|  | type = GetTypeForDIE (dwarf_cu, type_die).get(); | 
|  |  | 
|  | if (assert_not_being_parsed) | 
|  | { | 
|  | if (type != DIE_IS_BEING_PARSED) | 
|  | return type; | 
|  |  | 
|  | GetObjectFile()->GetModule()->ReportError ("Parsing a die that is being parsed die: 0x%8.8x: %s %s", | 
|  | type_die->GetOffset(), | 
|  | DW_TAG_value_to_name(type_die->Tag()), | 
|  | type_die->GetName(this, dwarf_cu)); | 
|  |  | 
|  | } | 
|  | else | 
|  | return type; | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | CompileUnit* | 
|  | SymbolFileDWARF::GetCompUnitForDWARFCompUnit (DWARFCompileUnit* dwarf_cu, uint32_t cu_idx) | 
|  | { | 
|  | // Check if the symbol vendor already knows about this compile unit? | 
|  | if (dwarf_cu->GetUserData() == NULL) | 
|  | { | 
|  | // The symbol vendor doesn't know about this compile unit, we | 
|  | // need to parse and add it to the symbol vendor object. | 
|  | return ParseCompileUnit(dwarf_cu, cu_idx).get(); | 
|  | } | 
|  | return (CompileUnit*)dwarf_cu->GetUserData(); | 
|  | } | 
|  |  | 
|  | bool | 
|  | SymbolFileDWARF::GetFunction (DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry* func_die, SymbolContext& sc) | 
|  | { | 
|  | sc.Clear(false); | 
|  | // Check if the symbol vendor already knows about this compile unit? | 
|  | sc.comp_unit = GetCompUnitForDWARFCompUnit(dwarf_cu, UINT32_MAX); | 
|  |  | 
|  | sc.function = sc.comp_unit->FindFunctionByUID (MakeUserID(func_die->GetOffset())).get(); | 
|  | if (sc.function == NULL) | 
|  | sc.function = ParseCompileUnitFunction(sc, dwarf_cu, func_die); | 
|  |  | 
|  | if (sc.function) | 
|  | { | 
|  | sc.module_sp = sc.function->CalculateSymbolContextModule(); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | uint32_t | 
|  | SymbolFileDWARF::ResolveSymbolContext (const Address& so_addr, uint32_t resolve_scope, SymbolContext& sc) | 
|  | { | 
|  | Timer scoped_timer(__PRETTY_FUNCTION__, | 
|  | "SymbolFileDWARF::ResolveSymbolContext (so_addr = { section = %p, offset = 0x%" PRIx64 " }, resolve_scope = 0x%8.8x)", | 
|  | static_cast<void*>(so_addr.GetSection().get()), | 
|  | so_addr.GetOffset(), resolve_scope); | 
|  | uint32_t resolved = 0; | 
|  | if (resolve_scope & (   eSymbolContextCompUnit | | 
|  | eSymbolContextFunction | | 
|  | eSymbolContextBlock | | 
|  | eSymbolContextLineEntry)) | 
|  | { | 
|  | lldb::addr_t file_vm_addr = so_addr.GetFileAddress(); | 
|  |  | 
|  | DWARFDebugInfo* debug_info = DebugInfo(); | 
|  | if (debug_info) | 
|  | { | 
|  | const dw_offset_t cu_offset = debug_info->GetCompileUnitAranges().FindAddress(file_vm_addr); | 
|  | if (cu_offset != DW_INVALID_OFFSET) | 
|  | { | 
|  | uint32_t cu_idx = DW_INVALID_INDEX; | 
|  | DWARFCompileUnit* dwarf_cu = debug_info->GetCompileUnit(cu_offset, &cu_idx).get(); | 
|  | if (dwarf_cu) | 
|  | { | 
|  | sc.comp_unit = GetCompUnitForDWARFCompUnit(dwarf_cu, cu_idx); | 
|  | if (sc.comp_unit) | 
|  | { | 
|  | resolved |= eSymbolContextCompUnit; | 
|  |  | 
|  | bool force_check_line_table = false; | 
|  | if (resolve_scope & (eSymbolContextFunction | eSymbolContextBlock)) | 
|  | { | 
|  | DWARFDebugInfoEntry *function_die = NULL; | 
|  | DWARFDebugInfoEntry *block_die = NULL; | 
|  | if (resolve_scope & eSymbolContextBlock) | 
|  | { | 
|  | dwarf_cu->LookupAddress(file_vm_addr, &function_die, &block_die); | 
|  | } | 
|  | else | 
|  | { | 
|  | dwarf_cu->LookupAddress(file_vm_addr, &function_die, NULL); | 
|  | } | 
|  |  | 
|  | if (function_die != NULL) | 
|  | { | 
|  | sc.function = sc.comp_unit->FindFunctionByUID (MakeUserID(function_die->GetOffset())).get(); | 
|  | if (sc.function == NULL) | 
|  | sc.function = ParseCompileUnitFunction(sc, dwarf_cu, function_die); | 
|  | } | 
|  | else | 
|  | { | 
|  | // We might have had a compile unit that had discontiguous | 
|  | // address ranges where the gaps are symbols that don't have | 
|  | // any debug info. Discontiguous compile unit address ranges | 
|  | // should only happen when there aren't other functions from | 
|  | // other compile units in these gaps. This helps keep the size | 
|  | // of the aranges down. | 
|  | force_check_line_table = true; | 
|  | } | 
|  |  | 
|  | if (sc.function != NULL) | 
|  | { | 
|  | resolved |= eSymbolContextFunction; | 
|  |  | 
|  | if (resolve_scope & eSymbolContextBlock) | 
|  | { | 
|  | Block& block = sc.function->GetBlock (true); | 
|  |  | 
|  | if (block_die != NULL) | 
|  | sc.block = block.FindBlockByID (MakeUserID(block_die->GetOffset())); | 
|  | else | 
|  | sc.block = block.FindBlockByID (MakeUserID(function_die->GetOffset())); | 
|  | if (sc.block) | 
|  | resolved |= eSymbolContextBlock; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if ((resolve_scope & eSymbolContextLineEntry) || force_check_line_table) | 
|  | { | 
|  | LineTable *line_table = sc.comp_unit->GetLineTable(); | 
|  | if (line_table != NULL) | 
|  | { | 
|  | // And address that makes it into this function should be in terms | 
|  | // of this debug file if there is no debug map, or it will be an | 
|  | // address in the .o file which needs to be fixed up to be in terms | 
|  | // of the debug map executable. Either way, calling FixupAddress() | 
|  | // will work for us. | 
|  | Address exe_so_addr (so_addr); | 
|  | if (FixupAddress(exe_so_addr)) | 
|  | { | 
|  | if (line_table->FindLineEntryByAddress (exe_so_addr, sc.line_entry)) | 
|  | { | 
|  | resolved |= eSymbolContextLineEntry; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (force_check_line_table && !(resolved & eSymbolContextLineEntry)) | 
|  | { | 
|  | // We might have had a compile unit that had discontiguous | 
|  | // address ranges where the gaps are symbols that don't have | 
|  | // any debug info. Discontiguous compile unit address ranges | 
|  | // should only happen when there aren't other functions from | 
|  | // other compile units in these gaps. This helps keep the size | 
|  | // of the aranges down. | 
|  | sc.comp_unit = NULL; | 
|  | resolved &= ~eSymbolContextCompUnit; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | GetObjectFile()->GetModule()->ReportWarning ("0x%8.8x: compile unit %u failed to create a valid lldb_private::CompileUnit class.", | 
|  | cu_offset, | 
|  | cu_idx); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | return resolved; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | uint32_t | 
|  | SymbolFileDWARF::ResolveSymbolContext(const FileSpec& file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, SymbolContextList& sc_list) | 
|  | { | 
|  | const uint32_t prev_size = sc_list.GetSize(); | 
|  | if (resolve_scope & eSymbolContextCompUnit) | 
|  | { | 
|  | DWARFDebugInfo* debug_info = DebugInfo(); | 
|  | if (debug_info) | 
|  | { | 
|  | uint32_t cu_idx; | 
|  | DWARFCompileUnit* dwarf_cu = NULL; | 
|  |  | 
|  | for (cu_idx = 0; (dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx)) != NULL; ++cu_idx) | 
|  | { | 
|  | CompileUnit *dc_cu = GetCompUnitForDWARFCompUnit(dwarf_cu, cu_idx); | 
|  | const bool full_match = (bool)file_spec.GetDirectory(); | 
|  | bool file_spec_matches_cu_file_spec = dc_cu != NULL && FileSpec::Equal(file_spec, *dc_cu, full_match); | 
|  | if (check_inlines || file_spec_matches_cu_file_spec) | 
|  | { | 
|  | SymbolContext sc (m_obj_file->GetModule()); | 
|  | sc.comp_unit = GetCompUnitForDWARFCompUnit(dwarf_cu, cu_idx); | 
|  | if (sc.comp_unit) | 
|  | { | 
|  | uint32_t file_idx = UINT32_MAX; | 
|  |  | 
|  | // If we are looking for inline functions only and we don't | 
|  | // find it in the support files, we are done. | 
|  | if (check_inlines) | 
|  | { | 
|  | file_idx = sc.comp_unit->GetSupportFiles().FindFileIndex (1, file_spec, true); | 
|  | if (file_idx == UINT32_MAX) | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (line != 0) | 
|  | { | 
|  | LineTable *line_table = sc.comp_unit->GetLineTable(); | 
|  |  | 
|  | if (line_table != NULL && line != 0) | 
|  | { | 
|  | // We will have already looked up the file index if | 
|  | // we are searching for inline entries. | 
|  | if (!check_inlines) | 
|  | file_idx = sc.comp_unit->GetSupportFiles().FindFileIndex (1, file_spec, true); | 
|  |  | 
|  | if (file_idx != UINT32_MAX) | 
|  | { | 
|  | uint32_t found_line; | 
|  | uint32_t line_idx = line_table->FindLineEntryIndexByFileIndex (0, file_idx, line, false, &sc.line_entry); | 
|  | found_line = sc.line_entry.line; | 
|  |  | 
|  | while (line_idx != UINT32_MAX) | 
|  | { | 
|  | sc.function = NULL; | 
|  | sc.block = NULL; | 
|  | if (resolve_scope & (eSymbolContextFunction | eSymbolContextBlock)) | 
|  | { | 
|  | const lldb::addr_t file_vm_addr = sc.line_entry.range.GetBaseAddress().GetFileAddress(); | 
|  | if (file_vm_addr != LLDB_INVALID_ADDRESS) | 
|  | { | 
|  | DWARFDebugInfoEntry *function_die = NULL; | 
|  | DWARFDebugInfoEntry *block_die = NULL; | 
|  | dwarf_cu->LookupAddress(file_vm_addr, &function_die, resolve_scope & eSymbolContextBlock ? &block_die : NULL); | 
|  |  | 
|  | if (function_die != NULL) | 
|  | { | 
|  | sc.function = sc.comp_unit->FindFunctionByUID (MakeUserID(function_die->GetOffset())).get(); | 
|  | if (sc.function == NULL) | 
|  | sc.function = ParseCompileUnitFunction(sc, dwarf_cu, function_die); | 
|  | } | 
|  |  | 
|  | if (sc.function != NULL) | 
|  | { | 
|  | Block& block = sc.function->GetBlock (true); | 
|  |  | 
|  | if (block_die != NULL) | 
|  | sc.block = block.FindBlockByID (MakeUserID(block_die->GetOffset())); | 
|  | else | 
|  | sc.block = block.FindBlockByID (MakeUserID(function_die->GetOffset())); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | sc_list.Append(sc); | 
|  | line_idx = line_table->FindLineEntryIndexByFileIndex (line_idx + 1, file_idx, found_line, true, &sc.line_entry); | 
|  | } | 
|  | } | 
|  | } | 
|  | else if (file_spec_matches_cu_file_spec && !check_inlines) | 
|  | { | 
|  | // only append the context if we aren't looking for inline call sites | 
|  | // by file and line and if the file spec matches that of the compile unit | 
|  | sc_list.Append(sc); | 
|  | } | 
|  | } | 
|  | else if (file_spec_matches_cu_file_spec && !check_inlines) | 
|  | { | 
|  | // only append the context if we aren't looking for inline call sites | 
|  | // by file and line and if the file spec matches that of the compile unit | 
|  | sc_list.Append(sc); | 
|  | } | 
|  |  | 
|  | if (!check_inlines) | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | return sc_list.GetSize() - prev_size; | 
|  | } | 
|  |  | 
|  | void | 
|  | SymbolFileDWARF::Index () | 
|  | { | 
|  | if (m_indexed) | 
|  | return; | 
|  | m_indexed = true; | 
|  | Timer scoped_timer (__PRETTY_FUNCTION__, | 
|  | "SymbolFileDWARF::Index (%s)", | 
|  | GetObjectFile()->GetFileSpec().GetFilename().AsCString()); | 
|  |  | 
|  | DWARFDebugInfo* debug_info = DebugInfo(); | 
|  | if (debug_info) | 
|  | { | 
|  | uint32_t cu_idx = 0; | 
|  | const uint32_t num_compile_units = GetNumCompileUnits(); | 
|  | for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) | 
|  | { | 
|  | DWARFCompileUnit* dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx); | 
|  |  | 
|  | bool clear_dies = dwarf_cu->ExtractDIEsIfNeeded (false) > 1; | 
|  |  | 
|  | dwarf_cu->Index (cu_idx, | 
|  | m_function_basename_index, | 
|  | m_function_fullname_index, | 
|  | m_function_method_index, | 
|  | m_function_selector_index, | 
|  | m_objc_class_selectors_index, | 
|  | m_global_index, | 
|  | m_type_index, | 
|  | m_namespace_index); | 
|  |  | 
|  | // Keep memory down by clearing DIEs if this generate function | 
|  | // caused them to be parsed | 
|  | if (clear_dies) | 
|  | dwarf_cu->ClearDIEs (true); | 
|  | } | 
|  |  | 
|  | m_function_basename_index.Finalize(); | 
|  | m_function_fullname_index.Finalize(); | 
|  | m_function_method_index.Finalize(); | 
|  | m_function_selector_index.Finalize(); | 
|  | m_objc_class_selectors_index.Finalize(); | 
|  | m_global_index.Finalize(); | 
|  | m_type_index.Finalize(); | 
|  | m_namespace_index.Finalize(); | 
|  |  | 
|  | #if defined (ENABLE_DEBUG_PRINTF) | 
|  | StreamFile s(stdout, false); | 
|  | s.Printf ("DWARF index for '%s':", | 
|  | GetObjectFile()->GetFileSpec().GetPath().c_str()); | 
|  | s.Printf("\nFunction basenames:\n");    m_function_basename_index.Dump (&s); | 
|  | s.Printf("\nFunction fullnames:\n");    m_function_fullname_index.Dump (&s); | 
|  | s.Printf("\nFunction methods:\n");      m_function_method_index.Dump (&s); | 
|  | s.Printf("\nFunction selectors:\n");    m_function_selector_index.Dump (&s); | 
|  | s.Printf("\nObjective C class selectors:\n");    m_objc_class_selectors_index.Dump (&s); | 
|  | s.Printf("\nGlobals and statics:\n");   m_global_index.Dump (&s); | 
|  | s.Printf("\nTypes:\n");                 m_type_index.Dump (&s); | 
|  | s.Printf("\nNamepaces:\n");             m_namespace_index.Dump (&s); | 
|  | #endif | 
|  | } | 
|  | } | 
|  |  | 
|  | bool | 
|  | SymbolFileDWARF::NamespaceDeclMatchesThisSymbolFile (const ClangNamespaceDecl *namespace_decl) | 
|  | { | 
|  | if (namespace_decl == NULL) | 
|  | { | 
|  | // Invalid namespace decl which means we aren't matching only things | 
|  | // in this symbol file, so return true to indicate it matches this | 
|  | // symbol file. | 
|  | return true; | 
|  | } | 
|  |  | 
|  | clang::ASTContext *namespace_ast = namespace_decl->GetASTContext(); | 
|  |  | 
|  | if (namespace_ast == NULL) | 
|  | return true;    // No AST in the "namespace_decl", return true since it | 
|  | // could then match any symbol file, including this one | 
|  |  | 
|  | if (namespace_ast == GetClangASTContext().getASTContext()) | 
|  | return true;    // The ASTs match, return true | 
|  |  | 
|  | // The namespace AST was valid, and it does not match... | 
|  | Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); | 
|  |  | 
|  | if (log) | 
|  | GetObjectFile()->GetModule()->LogMessage(log, "Valid namespace does not match symbol file"); | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool | 
|  | SymbolFileDWARF::DIEIsInNamespace (const ClangNamespaceDecl *namespace_decl, | 
|  | DWARFCompileUnit* cu, | 
|  | const DWARFDebugInfoEntry* die) | 
|  | { | 
|  | // No namespace specified, so the answer is | 
|  | if (namespace_decl == NULL) | 
|  | return true; | 
|  |  | 
|  | Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); | 
|  |  | 
|  | const DWARFDebugInfoEntry *decl_ctx_die = NULL; | 
|  | clang::DeclContext *die_clang_decl_ctx = GetClangDeclContextContainingDIE (cu, die, &decl_ctx_die); | 
|  | if (decl_ctx_die) | 
|  | { | 
|  | clang::NamespaceDecl *clang_namespace_decl = namespace_decl->GetNamespaceDecl(); | 
|  |  | 
|  | if (clang_namespace_decl) | 
|  | { | 
|  | if (decl_ctx_die->Tag() != DW_TAG_namespace) | 
|  | { | 
|  | if (log) | 
|  | GetObjectFile()->GetModule()->LogMessage(log, "Found a match, but its parent is not a namespace"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (clang_namespace_decl == die_clang_decl_ctx) | 
|  | return true; | 
|  | else | 
|  | return false; | 
|  | } | 
|  | else | 
|  | { | 
|  | // We have a namespace_decl that was not NULL but it contained | 
|  | // a NULL "clang::NamespaceDecl", so this means the global namespace | 
|  | // So as long the contained decl context DIE isn't a namespace | 
|  | // we should be ok. | 
|  | if (decl_ctx_die->Tag() != DW_TAG_namespace) | 
|  | return true; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (log) | 
|  | GetObjectFile()->GetModule()->LogMessage(log, "Found a match, but its parent doesn't exist"); | 
|  |  | 
|  | return false; | 
|  | } | 
|  | uint32_t | 
|  | SymbolFileDWARF::FindGlobalVariables (const ConstString &name, const lldb_private::ClangNamespaceDecl *namespace_decl, bool append, uint32_t max_matches, VariableList& variables) | 
|  | { | 
|  | Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); | 
|  |  | 
|  | if (log) | 
|  | GetObjectFile()->GetModule()->LogMessage (log, | 
|  | "SymbolFileDWARF::FindGlobalVariables (name=\"%s\", namespace_decl=%p, append=%u, max_matches=%u, variables)", | 
|  | name.GetCString(), | 
|  | static_cast<const void*>(namespace_decl), | 
|  | append, max_matches); | 
|  |  | 
|  | if (!NamespaceDeclMatchesThisSymbolFile(namespace_decl)) | 
|  | return 0; | 
|  |  | 
|  | DWARFDebugInfo* info = DebugInfo(); | 
|  | if (info == NULL) | 
|  | return 0; | 
|  |  | 
|  | // If we aren't appending the results to this list, then clear the list | 
|  | if (!append) | 
|  | variables.Clear(); | 
|  |  | 
|  | // Remember how many variables are in the list before we search in case | 
|  | // we are appending the results to a variable list. | 
|  | const uint32_t original_size = variables.GetSize(); | 
|  |  | 
|  | DIEArray die_offsets; | 
|  |  | 
|  | if (m_using_apple_tables) | 
|  | { | 
|  | if (m_apple_names_ap.get()) | 
|  | { | 
|  | const char *name_cstr = name.GetCString(); | 
|  | const char *base_name_start; | 
|  | const char *base_name_end = NULL; | 
|  |  | 
|  | if (!CPPLanguageRuntime::StripNamespacesFromVariableName(name_cstr, base_name_start, base_name_end)) | 
|  | base_name_start = name_cstr; | 
|  |  | 
|  | m_apple_names_ap->FindByName (base_name_start, die_offsets); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | // Index the DWARF if we haven't already | 
|  | if (!m_indexed) | 
|  | Index (); | 
|  |  | 
|  | m_global_index.Find (name, die_offsets); | 
|  | } | 
|  |  | 
|  | const size_t num_die_matches = die_offsets.size(); | 
|  | if (num_die_matches) | 
|  | { | 
|  | SymbolContext sc; | 
|  | sc.module_sp = m_obj_file->GetModule(); | 
|  | assert (sc.module_sp); | 
|  |  | 
|  | DWARFDebugInfo* debug_info = DebugInfo(); | 
|  | DWARFCompileUnit* dwarf_cu = NULL; | 
|  | const DWARFDebugInfoEntry* die = NULL; | 
|  | bool done = false; | 
|  | for (size_t i=0; i<num_die_matches && !done; ++i) | 
|  | { | 
|  | const dw_offset_t die_offset = die_offsets[i]; | 
|  | die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu); | 
|  |  | 
|  | if (die) | 
|  | { | 
|  | switch (die->Tag()) | 
|  | { | 
|  | default: | 
|  | case DW_TAG_subprogram: | 
|  | case DW_TAG_inlined_subroutine: | 
|  | case DW_TAG_try_block: | 
|  | case DW_TAG_catch_block: | 
|  | break; | 
|  |  | 
|  | case DW_TAG_variable: | 
|  | { | 
|  | sc.comp_unit = GetCompUnitForDWARFCompUnit(dwarf_cu, UINT32_MAX); | 
|  |  | 
|  | if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die)) | 
|  | continue; | 
|  |  | 
|  | ParseVariables(sc, dwarf_cu, LLDB_INVALID_ADDRESS, die, false, false, &variables); | 
|  |  | 
|  | if (variables.GetSize() - original_size >= max_matches) | 
|  | done = true; | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | if (m_using_apple_tables) | 
|  | { | 
|  | GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_names accelerator table had bad die 0x%8.8x for '%s')\n", | 
|  | die_offset, name.GetCString()); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Return the number of variable that were appended to the list | 
|  | const uint32_t num_matches = variables.GetSize() - original_size; | 
|  | if (log && num_matches > 0) | 
|  | { | 
|  | GetObjectFile()->GetModule()->LogMessage (log, | 
|  | "SymbolFileDWARF::FindGlobalVariables (name=\"%s\", namespace_decl=%p, append=%u, max_matches=%u, variables) => %u", | 
|  | name.GetCString(), | 
|  | static_cast<const void*>(namespace_decl), | 
|  | append, max_matches, | 
|  | num_matches); | 
|  | } | 
|  | return num_matches; | 
|  | } | 
|  |  | 
|  | uint32_t | 
|  | SymbolFileDWARF::FindGlobalVariables(const RegularExpression& regex, bool append, uint32_t max_matches, VariableList& variables) | 
|  | { | 
|  | Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); | 
|  |  | 
|  | if (log) | 
|  | { | 
|  | GetObjectFile()->GetModule()->LogMessage (log, | 
|  | "SymbolFileDWARF::FindGlobalVariables (regex=\"%s\", append=%u, max_matches=%u, variables)", | 
|  | regex.GetText(), append, | 
|  | max_matches); | 
|  | } | 
|  |  | 
|  | DWARFDebugInfo* info = DebugInfo(); | 
|  | if (info == NULL) | 
|  | return 0; | 
|  |  | 
|  | // If we aren't appending the results to this list, then clear the list | 
|  | if (!append) | 
|  | variables.Clear(); | 
|  |  | 
|  | // Remember how many variables are in the list before we search in case | 
|  | // we are appending the results to a variable list. | 
|  | const uint32_t original_size = variables.GetSize(); | 
|  |  | 
|  | DIEArray die_offsets; | 
|  |  | 
|  | if (m_using_apple_tables) | 
|  | { | 
|  | if (m_apple_names_ap.get()) | 
|  | { | 
|  | DWARFMappedHash::DIEInfoArray hash_data_array; | 
|  | if (m_apple_names_ap->AppendAllDIEsThatMatchingRegex (regex, hash_data_array)) | 
|  | DWARFMappedHash::ExtractDIEArray (hash_data_array, die_offsets); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | // Index the DWARF if we haven't already | 
|  | if (!m_indexed) | 
|  | Index (); | 
|  |  | 
|  | m_global_index.Find (regex, die_offsets); | 
|  | } | 
|  |  | 
|  | SymbolContext sc; | 
|  | sc.module_sp = m_obj_file->GetModule(); | 
|  | assert (sc.module_sp); | 
|  |  | 
|  | DWARFCompileUnit* dwarf_cu = NULL; | 
|  | const DWARFDebugInfoEntry* die = NULL; | 
|  | const size_t num_matches = die_offsets.size(); | 
|  | if (num_matches) | 
|  | { | 
|  | DWARFDebugInfo* debug_info = DebugInfo(); | 
|  | for (size_t i=0; i<num_matches; ++i) | 
|  | { | 
|  | const dw_offset_t die_offset = die_offsets[i]; | 
|  | die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu); | 
|  |  | 
|  | if (die) | 
|  | { | 
|  | sc.comp_unit = GetCompUnitForDWARFCompUnit(dwarf_cu, UINT32_MAX); | 
|  |  | 
|  | ParseVariables(sc, dwarf_cu, LLDB_INVALID_ADDRESS, die, false, false, &variables); | 
|  |  | 
|  | if (variables.GetSize() - original_size >= max_matches) | 
|  | break; | 
|  | } | 
|  | else | 
|  | { | 
|  | if (m_using_apple_tables) | 
|  | { | 
|  | GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_names accelerator table had bad die 0x%8.8x for regex '%s')\n", | 
|  | die_offset, regex.GetText()); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Return the number of variable that were appended to the list | 
|  | return variables.GetSize() - original_size; | 
|  | } | 
|  |  | 
|  |  | 
|  | bool | 
|  | SymbolFileDWARF::ResolveFunction (dw_offset_t die_offset, | 
|  | DWARFCompileUnit *&dwarf_cu, | 
|  | SymbolContextList& sc_list) | 
|  | { | 
|  | const DWARFDebugInfoEntry *die = DebugInfo()->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu); | 
|  | return ResolveFunction (dwarf_cu, die, sc_list); | 
|  | } | 
|  |  | 
|  |  | 
|  | bool | 
|  | SymbolFileDWARF::ResolveFunction (DWARFCompileUnit *cu, | 
|  | const DWARFDebugInfoEntry *die, | 
|  | SymbolContextList& sc_list) | 
|  | { | 
|  | SymbolContext sc; | 
|  |  | 
|  | if (die == NULL) | 
|  | return false; | 
|  |  | 
|  | // If we were passed a die that is not a function, just return false... | 
|  | if (die->Tag() != DW_TAG_subprogram && die->Tag() != DW_TAG_inlined_subroutine) | 
|  | return false; | 
|  |  | 
|  | const DWARFDebugInfoEntry* inlined_die = NULL; | 
|  | if (die->Tag() == DW_TAG_inlined_subroutine) | 
|  | { | 
|  | inlined_die = die; | 
|  |  | 
|  | while ((die = die->GetParent()) != NULL) | 
|  | { | 
|  | if (die->Tag() == DW_TAG_subprogram) | 
|  | break; | 
|  | } | 
|  | } | 
|  | assert (die->Tag() == DW_TAG_subprogram); | 
|  | if (GetFunction (cu, die, sc)) | 
|  | { | 
|  | Address addr; | 
|  | // Parse all blocks if needed | 
|  | if (inlined_die) | 
|  | { | 
|  | sc.block = sc.function->GetBlock (true).FindBlockByID (MakeUserID(inlined_die->GetOffset())); | 
|  | assert (sc.block != NULL); | 
|  | if (sc.block->GetStartAddress (addr) == false) | 
|  | addr.Clear(); | 
|  | } | 
|  | else | 
|  | { | 
|  | sc.block = NULL; | 
|  | addr = sc.function->GetAddressRange().GetBaseAddress(); | 
|  | } | 
|  |  | 
|  | if (addr.IsValid()) | 
|  | { | 
|  | sc_list.Append(sc); | 
|  | return true; | 
|  | } | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | void | 
|  | SymbolFileDWARF::FindFunctions (const ConstString &name, | 
|  | const NameToDIE &name_to_die, | 
|  | SymbolContextList& sc_list) | 
|  | { | 
|  | DIEArray die_offsets; | 
|  | if (name_to_die.Find (name, die_offsets)) | 
|  | { | 
|  | ParseFunctions (die_offsets, sc_list); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | void | 
|  | SymbolFileDWARF::FindFunctions (const RegularExpression ®ex, | 
|  | const NameToDIE &name_to_die, | 
|  | SymbolContextList& sc_list) | 
|  | { | 
|  | DIEArray die_offsets; | 
|  | if (name_to_die.Find (regex, die_offsets)) | 
|  | { | 
|  | ParseFunctions (die_offsets, sc_list); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | void | 
|  | SymbolFileDWARF::FindFunctions (const RegularExpression ®ex, | 
|  | const DWARFMappedHash::MemoryTable &memory_table, | 
|  | SymbolContextList& sc_list) | 
|  | { | 
|  | DIEArray die_offsets; | 
|  | DWARFMappedHash::DIEInfoArray hash_data_array; | 
|  | if (memory_table.AppendAllDIEsThatMatchingRegex (regex, hash_data_array)) | 
|  | { | 
|  | DWARFMappedHash::ExtractDIEArray (hash_data_array, die_offsets); | 
|  | ParseFunctions (die_offsets, sc_list); | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | SymbolFileDWARF::ParseFunctions (const DIEArray &die_offsets, | 
|  | SymbolContextList& sc_list) | 
|  | { | 
|  | const size_t num_matches = die_offsets.size(); | 
|  | if (num_matches) | 
|  | { | 
|  | SymbolContext sc; | 
|  |  | 
|  | DWARFCompileUnit* dwarf_cu = NULL; | 
|  | for (size_t i=0; i<num_matches; ++i) | 
|  | { | 
|  | const dw_offset_t die_offset = die_offsets[i]; | 
|  | ResolveFunction (die_offset, dwarf_cu, sc_list); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | bool | 
|  | SymbolFileDWARF::FunctionDieMatchesPartialName (const DWARFDebugInfoEntry* die, | 
|  | const DWARFCompileUnit *dwarf_cu, | 
|  | uint32_t name_type_mask, | 
|  | const char *partial_name, | 
|  | const char *base_name_start, | 
|  | const char *base_name_end) | 
|  | { | 
|  | // If we are looking only for methods, throw away all the ones that are or aren't in C++ classes: | 
|  | if (name_type_mask == eFunctionNameTypeMethod || name_type_mask == eFunctionNameTypeBase) | 
|  | { | 
|  | clang::DeclContext *containing_decl_ctx = GetClangDeclContextContainingDIEOffset(die->GetOffset()); | 
|  | if (!containing_decl_ctx) | 
|  | return false; | 
|  |  | 
|  | bool is_cxx_method = DeclKindIsCXXClass(containing_decl_ctx->getDeclKind()); | 
|  |  | 
|  | if (name_type_mask == eFunctionNameTypeMethod) | 
|  | { | 
|  | if (is_cxx_method == false) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (name_type_mask == eFunctionNameTypeBase) | 
|  | { | 
|  | if (is_cxx_method == true) | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Now we need to check whether the name we got back for this type matches the extra specifications | 
|  | // that were in the name we're looking up: | 
|  | if (base_name_start != partial_name || *base_name_end != '\0') | 
|  | { | 
|  | // First see if the stuff to the left matches the full name.  To do that let's see if | 
|  | // we can pull out the mips linkage name attribute: | 
|  |  | 
|  | Mangled best_name; | 
|  | DWARFDebugInfoEntry::Attributes attributes; | 
|  | DWARFFormValue form_value; | 
|  | die->GetAttributes(this, dwarf_cu, NULL, attributes); | 
|  | uint32_t idx = attributes.FindAttributeIndex(DW_AT_MIPS_linkage_name); | 
|  | if (idx == UINT32_MAX) | 
|  | idx = attributes.FindAttributeIndex(DW_AT_linkage_name); | 
|  | if (idx != UINT32_MAX) | 
|  | { | 
|  | if (attributes.ExtractFormValueAtIndex(this, idx, form_value)) | 
|  | { | 
|  | const char *mangled_name = form_value.AsCString(&get_debug_str_data()); | 
|  | if (mangled_name) | 
|  | best_name.SetValue (ConstString(mangled_name), true); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!best_name) | 
|  | { | 
|  | idx = attributes.FindAttributeIndex(DW_AT_name); | 
|  | if (idx != UINT32_MAX && attributes.ExtractFormValueAtIndex(this, idx, form_value)) | 
|  | { | 
|  | const char *name = form_value.AsCString(&get_debug_str_data()); | 
|  | best_name.SetValue (ConstString(name), false); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (best_name.GetDemangledName()) | 
|  | { | 
|  | const char *demangled = best_name.GetDemangledName().GetCString(); | 
|  | if (demangled) | 
|  | { | 
|  | std::string name_no_parens(partial_name, base_name_end - partial_name); | 
|  | const char *partial_in_demangled = strstr (demangled, name_no_parens.c_str()); | 
|  | if (partial_in_demangled == NULL) | 
|  | return false; | 
|  | else | 
|  | { | 
|  | // Sort out the case where our name is something like "Process::Destroy" and the match is | 
|  | // "SBProcess::Destroy" - that shouldn't be a match.  We should really always match on | 
|  | // namespace boundaries... | 
|  |  | 
|  | if (partial_name[0] == ':'  && partial_name[1] == ':') | 
|  | { | 
|  | // The partial name was already on a namespace boundary so all matches are good. | 
|  | return true; | 
|  | } | 
|  | else if (partial_in_demangled == demangled) | 
|  | { | 
|  | // They both start the same, so this is an good match. | 
|  | return true; | 
|  | } | 
|  | else | 
|  | { | 
|  | if (partial_in_demangled - demangled == 1) | 
|  | { | 
|  | // Only one character difference, can't be a namespace boundary... | 
|  | return false; | 
|  | } | 
|  | else if (*(partial_in_demangled - 1) == ':' && *(partial_in_demangled - 2) == ':') | 
|  | { | 
|  | // We are on a namespace boundary, so this is also good. | 
|  | return true; | 
|  | } | 
|  | else | 
|  | return false; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | uint32_t | 
|  | SymbolFileDWARF::FindFunctions (const ConstString &name, | 
|  | const lldb_private::ClangNamespaceDecl *namespace_decl, | 
|  | uint32_t name_type_mask, | 
|  | bool include_inlines, | 
|  | bool append, | 
|  | SymbolContextList& sc_list) | 
|  | { | 
|  | Timer scoped_timer (__PRETTY_FUNCTION__, | 
|  | "SymbolFileDWARF::FindFunctions (name = '%s')", | 
|  | name.AsCString()); | 
|  |  | 
|  | // eFunctionNameTypeAuto should be pre-resolved by a call to Module::PrepareForFunctionNameLookup() | 
|  | assert ((name_type_mask & eFunctionNameTypeAuto) == 0); | 
|  |  | 
|  | Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); | 
|  |  | 
|  | if (log) | 
|  | { | 
|  | GetObjectFile()->GetModule()->LogMessage (log, | 
|  | "SymbolFileDWARF::FindFunctions (name=\"%s\", name_type_mask=0x%x, append=%u, sc_list)", | 
|  | name.GetCString(), | 
|  | name_type_mask, | 
|  | append); | 
|  | } | 
|  |  | 
|  | // If we aren't appending the results to this list, then clear the list | 
|  | if (!append) | 
|  | sc_list.Clear(); | 
|  |  | 
|  | if (!NamespaceDeclMatchesThisSymbolFile(namespace_decl)) | 
|  | return 0; | 
|  |  | 
|  | // If name is empty then we won't find anything. | 
|  | if (name.IsEmpty()) | 
|  | return 0; | 
|  |  | 
|  | // Remember how many sc_list are in the list before we search in case | 
|  | // we are appending the results to a variable list. | 
|  |  | 
|  | const char *name_cstr = name.GetCString(); | 
|  |  | 
|  | const uint32_t original_size = sc_list.GetSize(); | 
|  |  | 
|  | DWARFDebugInfo* info = DebugInfo(); | 
|  | if (info == NULL) | 
|  | return 0; | 
|  |  | 
|  | DWARFCompileUnit *dwarf_cu = NULL; | 
|  | std::set<const DWARFDebugInfoEntry *> resolved_dies; | 
|  | if (m_using_apple_tables) | 
|  | { | 
|  | if (m_apple_names_ap.get()) | 
|  | { | 
|  |  | 
|  | DIEArray die_offsets; | 
|  |  | 
|  | uint32_t num_matches = 0; | 
|  |  | 
|  | if (name_type_mask & eFunctionNameTypeFull) | 
|  | { | 
|  | // If they asked for the full name, match what they typed.  At some point we may | 
|  | // want to canonicalize this (strip double spaces, etc.  For now, we just add all the | 
|  | // dies that we find by exact match. | 
|  | num_matches = m_apple_names_ap->FindByName (name_cstr, die_offsets); | 
|  | for (uint32_t i = 0; i < num_matches; i++) | 
|  | { | 
|  | const dw_offset_t die_offset = die_offsets[i]; | 
|  | const DWARFDebugInfoEntry *die = info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu); | 
|  | if (die) | 
|  | { | 
|  | if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die)) | 
|  | continue; | 
|  |  | 
|  | if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine) | 
|  | continue; | 
|  |  | 
|  | if (resolved_dies.find(die) == resolved_dies.end()) | 
|  | { | 
|  | if (ResolveFunction (dwarf_cu, die, sc_list)) | 
|  | resolved_dies.insert(die); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_names accelerator table had bad die 0x%8.8x for '%s')", | 
|  | die_offset, name_cstr); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (name_type_mask & eFunctionNameTypeSelector) | 
|  | { | 
|  | if (namespace_decl && *namespace_decl) | 
|  | return 0; // no selectors in namespaces | 
|  |  | 
|  | num_matches = m_apple_names_ap->FindByName (name_cstr, die_offsets); | 
|  | // Now make sure these are actually ObjC methods.  In this case we can simply look up the name, | 
|  | // and if it is an ObjC method name, we're good. | 
|  |  | 
|  | for (uint32_t i = 0; i < num_matches; i++) | 
|  | { | 
|  | const dw_offset_t die_offset = die_offsets[i]; | 
|  | const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu); | 
|  | if (die) | 
|  | { | 
|  | const char *die_name = die->GetName(this, dwarf_cu); | 
|  | if (ObjCLanguageRuntime::IsPossibleObjCMethodName(die_name)) | 
|  | { | 
|  | if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine) | 
|  | continue; | 
|  |  | 
|  | if (resolved_dies.find(die) == resolved_dies.end()) | 
|  | { | 
|  | if (ResolveFunction (dwarf_cu, die, sc_list)) | 
|  | resolved_dies.insert(die); | 
|  | } | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | GetObjectFile()->GetModule()->ReportError ("the DWARF debug information has been modified (.apple_names accelerator table had bad die 0x%8.8x for '%s')", | 
|  | die_offset, name_cstr); | 
|  | } | 
|  | } | 
|  | die_offsets.clear(); | 
|  | } | 
|  |  | 
|  | if (((name_type_mask & eFunctionNameTypeMethod) && !namespace_decl) || name_type_mask & eFunctionNameTypeBase) | 
|  | { | 
|  | // The apple_names table stores just the "base name" of C++ methods in the table.  So we have to | 
|  | // extract the base name, look that up, and if there is any other information in the name we were | 
|  | // passed in we have to post-filter based on that. | 
|  |  | 
|  | // FIXME: Arrange the logic above so that we don't calculate the base name twice: | 
|  | num_matches = m_apple_names_ap->FindByName (name_cstr, die_offsets); | 
|  |  | 
|  | for (uint32_t i = 0; i < num_matches; i++) | 
|  | { | 
|  | const dw_offset_t die_offset = die_offsets[i]; | 
|  | const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu); | 
|  | if (die) | 
|  | { | 
|  | if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine) | 
|  | continue; | 
|  |  | 
|  | if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die)) | 
|  | continue; | 
|  |  | 
|  | // If we get to here, the die is good, and we should add it: | 
|  | if (resolved_dies.find(die) == resolved_dies.end()) | 
|  | if (ResolveFunction (dwarf_cu, die, sc_list)) | 
|  | { | 
|  | bool keep_die = true; | 
|  | if ((name_type_mask & (eFunctionNameTypeBase|eFunctionNameTypeMethod)) != (eFunctionNameTypeBase|eFunctionNameTypeMethod)) | 
|  | { | 
|  | // We are looking for either basenames or methods, so we need to | 
|  | // trim out the ones we won't want by looking at the type | 
|  | SymbolContext sc; | 
|  | if (sc_list.GetLastContext(sc)) | 
|  | { | 
|  | if (sc.block) | 
|  | { | 
|  | // We have an inlined function | 
|  | } | 
|  | else if (sc.function) | 
|  | { | 
|  | Type *type = sc.function->GetType(); | 
|  |  | 
|  | if (type) | 
|  | { | 
|  | clang::DeclContext* decl_ctx = GetClangDeclContextContainingTypeUID (type->GetID()); | 
|  | if (decl_ctx->isRecord()) | 
|  | { | 
|  | if (name_type_mask & eFunctionNameTypeBase) | 
|  | { | 
|  | sc_list.RemoveContextAtIndex(sc_list.GetSize()-1); | 
|  | keep_die = false; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | if (name_type_mask & eFunctionNameTypeMethod) | 
|  | { | 
|  | sc_list.RemoveContextAtIndex(sc_list.GetSize()-1); | 
|  | keep_die = false; | 
|  | } | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | GetObjectFile()->GetModule()->ReportWarning ("function at die offset 0x%8.8x had no function type", | 
|  | die_offset); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | if (keep_die) | 
|  | resolved_dies.insert(die); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_names accelerator table had bad die 0x%8.8x for '%s')", | 
|  | die_offset, name_cstr); | 
|  | } | 
|  | } | 
|  | die_offsets.clear(); | 
|  | } | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  |  | 
|  | // Index the DWARF if we haven't already | 
|  | if (!m_indexed) | 
|  | Index (); | 
|  |  | 
|  | if (name_type_mask & eFunctionNameTypeFull) | 
|  | { | 
|  | FindFunctions (name, m_function_fullname_index, sc_list); | 
|  |  | 
|  | // FIXME Temporary workaround for global/anonymous namespace | 
|  | // functions on FreeBSD and Linux | 
|  | #if defined (__FreeBSD__) || defined (__linux__) | 
|  | // If we didn't find any functions in the global namespace try | 
|  | // looking in the basename index but ignore any returned | 
|  | // functions that have a namespace (ie. mangled names starting with | 
|  | // '_ZN') but keep functions which have an anonymous namespace | 
|  | if (sc_list.GetSize() == 0) | 
|  | { | 
|  | SymbolContextList temp_sc_list; | 
|  | FindFunctions (name, m_function_basename_index, temp_sc_list); | 
|  | if (!namespace_decl) | 
|  | { | 
|  | SymbolContext sc; | 
|  | for (uint32_t i = 0; i < temp_sc_list.GetSize(); i++) | 
|  | { | 
|  | if (temp_sc_list.GetContextAtIndex(i, sc)) | 
|  | { | 
|  | ConstString mangled_name = sc.GetFunctionName(Mangled::ePreferMangled); | 
|  | ConstString demangled_name = sc.GetFunctionName(Mangled::ePreferDemangled); | 
|  | if (strncmp(mangled_name.GetCString(), "_ZN", 3) || | 
|  | !strncmp(demangled_name.GetCString(), "(anonymous namespace)", 21)) | 
|  | { | 
|  | sc_list.Append(sc); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | #endif | 
|  | } | 
|  | DIEArray die_offsets; | 
|  | DWARFCompileUnit *dwarf_cu = NULL; | 
|  |  | 
|  | if (name_type_mask & eFunctionNameTypeBase) | 
|  | { | 
|  | uint32_t num_base = m_function_basename_index.Find(name, die_offsets); | 
|  | for (uint32_t i = 0; i < num_base; i++) | 
|  | { | 
|  | const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (die_offsets[i], &dwarf_cu); | 
|  | if (die) | 
|  | { | 
|  | if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine) | 
|  | continue; | 
|  |  | 
|  | if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die)) | 
|  | continue; | 
|  |  | 
|  | // If we get to here, the die is good, and we should add it: | 
|  | if (resolved_dies.find(die) == resolved_dies.end()) | 
|  | { | 
|  | if (ResolveFunction (dwarf_cu, die, sc_list)) | 
|  | resolved_dies.insert(die); | 
|  | } | 
|  | } | 
|  | } | 
|  | die_offsets.clear(); | 
|  | } | 
|  |  | 
|  | if (name_type_mask & eFunctionNameTypeMethod) | 
|  | { | 
|  | if (namespace_decl && *namespace_decl) | 
|  | return 0; // no methods in namespaces | 
|  |  | 
|  | uint32_t num_base = m_function_method_index.Find(name, die_offsets); | 
|  | { | 
|  | for (uint32_t i = 0; i < num_base; i++) | 
|  | { | 
|  | const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (die_offsets[i], &dwarf_cu); | 
|  | if (die) | 
|  | { | 
|  | if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine) | 
|  | continue; | 
|  |  | 
|  | // If we get to here, the die is good, and we should add it: | 
|  | if (resolved_dies.find(die) == resolved_dies.end()) | 
|  | { | 
|  | if (ResolveFunction (dwarf_cu, die, sc_list)) | 
|  | resolved_dies.insert(die); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | die_offsets.clear(); | 
|  | } | 
|  |  | 
|  | if ((name_type_mask & eFunctionNameTypeSelector) && (!namespace_decl || !*namespace_decl)) | 
|  | { | 
|  | FindFunctions (name, m_function_selector_index, sc_list); | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | // Return the number of variable that were appended to the list | 
|  | const uint32_t num_matches = sc_list.GetSize() - original_size; | 
|  |  | 
|  | if (log && num_matches > 0) | 
|  | { | 
|  | GetObjectFile()->GetModule()->LogMessage (log, | 
|  | "SymbolFileDWARF::FindFunctions (name=\"%s\", name_type_mask=0x%x, append=%u, sc_list) => %u", | 
|  | name.GetCString(), | 
|  | name_type_mask, | 
|  | append, | 
|  | num_matches); | 
|  | } | 
|  | return num_matches; | 
|  | } | 
|  |  | 
|  | uint32_t | 
|  | SymbolFileDWARF::FindFunctions(const RegularExpression& regex, bool include_inlines, bool append, SymbolContextList& sc_list) | 
|  | { | 
|  | Timer scoped_timer (__PRETTY_FUNCTION__, | 
|  | "SymbolFileDWARF::FindFunctions (regex = '%s')", | 
|  | regex.GetText()); | 
|  |  | 
|  | Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); | 
|  |  | 
|  | if (log) | 
|  | { | 
|  | GetObjectFile()->GetModule()->LogMessage (log, | 
|  | "SymbolFileDWARF::FindFunctions (regex=\"%s\", append=%u, sc_list)", | 
|  | regex.GetText(), | 
|  | append); | 
|  | } | 
|  |  | 
|  |  | 
|  | // If we aren't appending the results to this list, then clear the list | 
|  | if (!append) | 
|  | sc_list.Clear(); | 
|  |  | 
|  | // Remember how many sc_list are in the list before we search in case | 
|  | // we are appending the results to a variable list. | 
|  | uint32_t original_size = sc_list.GetSize(); | 
|  |  | 
|  | if (m_using_apple_tables) | 
|  | { | 
|  | if (m_apple_names_ap.get()) | 
|  | FindFunctions (regex, *m_apple_names_ap, sc_list); | 
|  | } | 
|  | else | 
|  | { | 
|  | // Index the DWARF if we haven't already | 
|  | if (!m_indexed) | 
|  | Index (); | 
|  |  | 
|  | FindFunctions (regex, m_function_basename_index, sc_list); | 
|  |  | 
|  | FindFunctions (regex, m_function_fullname_index, sc_list); | 
|  | } | 
|  |  | 
|  | // Return the number of variable that were appended to the list | 
|  | return sc_list.GetSize() - original_size; | 
|  | } | 
|  |  | 
|  | uint32_t | 
|  | SymbolFileDWARF::FindTypes (const SymbolContext& sc, | 
|  | const ConstString &name, | 
|  | const lldb_private::ClangNamespaceDecl *namespace_decl, | 
|  | bool append, | 
|  | uint32_t max_matches, | 
|  | TypeList& types) | 
|  | { | 
|  | DWARFDebugInfo* info = DebugInfo(); | 
|  | if (info == NULL) | 
|  | return 0; | 
|  |  | 
|  | Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); | 
|  |  | 
|  | if (log) | 
|  | { | 
|  | if (namespace_decl) | 
|  | GetObjectFile()->GetModule()->LogMessage (log, | 
|  | "SymbolFileDWARF::FindTypes (sc, name=\"%s\", clang::NamespaceDecl(%p) \"%s\", append=%u, max_matches=%u, type_list)", | 
|  | name.GetCString(), | 
|  | static_cast<void*>(namespace_decl->GetNamespaceDecl()), | 
|  | namespace_decl->GetQualifiedName().c_str(), | 
|  | append, max_matches); | 
|  | else | 
|  | GetObjectFile()->GetModule()->LogMessage (log, | 
|  | "SymbolFileDWARF::FindTypes (sc, name=\"%s\", clang::NamespaceDecl(NULL), append=%u, max_matches=%u, type_list)", | 
|  | name.GetCString(), append, | 
|  | max_matches); | 
|  | } | 
|  |  | 
|  | // If we aren't appending the results to this list, then clear the list | 
|  | if (!append) | 
|  | types.Clear(); | 
|  |  | 
|  | if (!NamespaceDeclMatchesThisSymbolFile(namespace_decl)) | 
|  | return 0; | 
|  |  | 
|  | DIEArray die_offsets; | 
|  |  | 
|  | if (m_using_apple_tables) | 
|  | { | 
|  | if (m_apple_types_ap.get()) | 
|  | { | 
|  | const char *name_cstr = name.GetCString(); | 
|  | m_apple_types_ap->FindByName (name_cstr, die_offsets); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | if (!m_indexed) | 
|  | Index (); | 
|  |  | 
|  | m_type_index.Find (name, die_offsets); | 
|  | } | 
|  |  | 
|  | const size_t num_die_matches = die_offsets.size(); | 
|  |  | 
|  | if (num_die_matches) | 
|  | { | 
|  | const uint32_t initial_types_size = types.GetSize(); | 
|  | DWARFCompileUnit* dwarf_cu = NULL; | 
|  | const DWARFDebugInfoEntry* die = NULL; | 
|  | DWARFDebugInfo* debug_info = DebugInfo(); | 
|  | for (size_t i=0; i<num_die_matches; ++i) | 
|  | { | 
|  | const dw_offset_t die_offset = die_offsets[i]; | 
|  | die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu); | 
|  |  | 
|  | if (die) | 
|  | { | 
|  | if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die)) | 
|  | continue; | 
|  |  | 
|  | Type *matching_type = ResolveType (dwarf_cu, die); | 
|  | if (matching_type) | 
|  | { | 
|  | // We found a type pointer, now find the shared pointer form our type list | 
|  | types.InsertUnique (matching_type->shared_from_this()); | 
|  | if (types.GetSize() >= max_matches) | 
|  | break; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | if (m_using_apple_tables) | 
|  | { | 
|  | GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_types accelerator table had bad die 0x%8.8x for '%s')\n", | 
|  | die_offset, name.GetCString()); | 
|  | } | 
|  | } | 
|  |  | 
|  | } | 
|  | const uint32_t num_matches = types.GetSize() - initial_types_size; | 
|  | if (log && num_matches) | 
|  | { | 
|  | if (namespace_decl) | 
|  | { | 
|  | GetObjectFile()->GetModule()->LogMessage (log, | 
|  | "SymbolFileDWARF::FindTypes (sc, name=\"%s\", clang::NamespaceDecl(%p) \"%s\", append=%u, max_matches=%u, type_list) => %u", | 
|  | name.GetCString(), | 
|  | static_cast<void*>(namespace_decl->GetNamespaceDecl()), | 
|  | namespace_decl->GetQualifiedName().c_str(), | 
|  | append, max_matches, | 
|  | num_matches); | 
|  | } | 
|  | else | 
|  | { | 
|  | GetObjectFile()->GetModule()->LogMessage (log, | 
|  | "SymbolFileDWARF::FindTypes (sc, name=\"%s\", clang::NamespaceDecl(NULL), append=%u, max_matches=%u, type_list) => %u", | 
|  | name.GetCString(), | 
|  | append, max_matches, | 
|  | num_matches); | 
|  | } | 
|  | } | 
|  | return num_matches; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | ClangNamespaceDecl | 
|  | SymbolFileDWARF::FindNamespace (const SymbolContext& sc, | 
|  | const ConstString &name, | 
|  | const lldb_private::ClangNamespaceDecl *parent_namespace_decl) | 
|  | { | 
|  | Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); | 
|  |  | 
|  | if (log) | 
|  | { | 
|  | GetObjectFile()->GetModule()->LogMessage (log, | 
|  | "SymbolFileDWARF::FindNamespace (sc, name=\"%s\")", | 
|  | name.GetCString()); | 
|  | } | 
|  |  | 
|  | if (!NamespaceDeclMatchesThisSymbolFile(parent_namespace_decl)) | 
|  | return ClangNamespaceDecl(); | 
|  |  | 
|  | ClangNamespaceDecl namespace_decl; | 
|  | DWARFDebugInfo* info = DebugInfo(); | 
|  | if (info) | 
|  | { | 
|  | DIEArray die_offsets; | 
|  |  | 
|  | // Index if we already haven't to make sure the compile units | 
|  | // get indexed and make their global DIE index list | 
|  | if (m_using_apple_tables) | 
|  | { | 
|  | if (m_apple_namespaces_ap.get()) | 
|  | { | 
|  | const char *name_cstr = name.GetCString(); | 
|  | m_apple_namespaces_ap->FindByName (name_cstr, die_offsets); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | if (!m_indexed) | 
|  | Index (); | 
|  |  | 
|  | m_namespace_index.Find (name, die_offsets); | 
|  | } | 
|  |  | 
|  | DWARFCompileUnit* dwarf_cu = NULL; | 
|  | const DWARFDebugInfoEntry* die = NULL; | 
|  | const size_t num_matches = die_offsets.size(); | 
|  | if (num_matches) | 
|  | { | 
|  | DWARFDebugInfo* debug_info = DebugInfo(); | 
|  | for (size_t i=0; i<num_matches; ++i) | 
|  | { | 
|  | const dw_offset_t die_offset = die_offsets[i]; | 
|  | die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu); | 
|  |  | 
|  | if (die) | 
|  | { | 
|  | if (parent_namespace_decl && !DIEIsInNamespace (parent_namespace_decl, dwarf_cu, die)) | 
|  | continue; | 
|  |  | 
|  | clang::NamespaceDecl *clang_namespace_decl = ResolveNamespaceDIE (dwarf_cu, die); | 
|  | if (clang_namespace_decl) | 
|  | { | 
|  | namespace_decl.SetASTContext (GetClangASTContext().getASTContext()); | 
|  | namespace_decl.SetNamespaceDecl (clang_namespace_decl); | 
|  | break; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | if (m_using_apple_tables) | 
|  | { | 
|  | GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_namespaces accelerator table had bad die 0x%8.8x for '%s')\n", | 
|  | die_offset, name.GetCString()); | 
|  | } | 
|  | } | 
|  |  | 
|  | } | 
|  | } | 
|  | } | 
|  | if (log && namespace_decl.GetNamespaceDecl()) | 
|  | { | 
|  | GetObjectFile()->GetModule()->LogMessage (log, | 
|  | "SymbolFileDWARF::FindNamespace (sc, name=\"%s\") => clang::NamespaceDecl(%p) \"%s\"", | 
|  | name.GetCString(), | 
|  | static_cast<const void*>(namespace_decl.GetNamespaceDecl()), | 
|  | namespace_decl.GetQualifiedName().c_str()); | 
|  | } | 
|  |  | 
|  | return namespace_decl; | 
|  | } | 
|  |  | 
|  | uint32_t | 
|  | SymbolFileDWARF::FindTypes(std::vector<dw_offset_t> die_offsets, uint32_t max_matches, TypeList& types) | 
|  | { | 
|  | // Remember how many sc_list are in the list before we search in case | 
|  | // we are appending the results to a variable list. | 
|  | uint32_t original_size = types.GetSize(); | 
|  |  | 
|  | const uint32_t num_die_offsets = die_offsets.size(); | 
|  | // Parse all of the types we found from the pubtypes matches | 
|  | uint32_t i; | 
|  | uint32_t num_matches = 0; | 
|  | for (i = 0; i < num_die_offsets; ++i) | 
|  | { | 
|  | Type *matching_type = ResolveTypeUID (die_offsets[i]); | 
|  | if (matching_type) | 
|  | { | 
|  | // We found a type pointer, now find the shared pointer form our type list | 
|  | types.InsertUnique (matching_type->shared_from_this()); | 
|  | ++num_matches; | 
|  | if (num_matches >= max_matches) | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Return the number of variable that were appended to the list | 
|  | return types.GetSize() - original_size; | 
|  | } | 
|  |  | 
|  |  | 
|  | size_t | 
|  | SymbolFileDWARF::ParseChildParameters (const SymbolContext& sc, | 
|  | clang::DeclContext *containing_decl_ctx, | 
|  | DWARFCompileUnit* dwarf_cu, | 
|  | const DWARFDebugInfoEntry *parent_die, | 
|  | bool skip_artificial, | 
|  | bool &is_static, | 
|  | bool &is_variadic, | 
|  | TypeList* type_list, | 
|  | std::vector<ClangASTType>& function_param_types, | 
|  | std::vector<clang::ParmVarDecl*>& function_param_decls, | 
|  | unsigned &type_quals) // , | 
|  | // ClangASTContext::TemplateParameterInfos &template_param_infos)) | 
|  | { | 
|  | if (parent_die == NULL) | 
|  | return 0; | 
|  |  | 
|  | const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize()); | 
|  |  | 
|  | size_t arg_idx = 0; | 
|  | const DWARFDebugInfoEntry *die; | 
|  | for (die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling()) | 
|  | { | 
|  | dw_tag_t tag = die->Tag(); | 
|  | switch (tag) | 
|  | { | 
|  | case DW_TAG_formal_parameter: | 
|  | { | 
|  | DWARFDebugInfoEntry::Attributes attributes; | 
|  | const size_t num_attributes = die->GetAttributes(this, dwarf_cu, fixed_form_sizes, attributes); | 
|  | if (num_attributes > 0) | 
|  | { | 
|  | const char *name = NULL; | 
|  | Declaration decl; | 
|  | dw_offset_t param_type_die_offset = DW_INVALID_OFFSET; | 
|  | bool is_artificial = false; | 
|  | // one of None, Auto, Register, Extern, Static, PrivateExtern | 
|  |  | 
|  | clang::StorageClass storage = clang::SC_None; | 
|  | uint32_t i; | 
|  | for (i=0; i<num_attributes; ++i) | 
|  | { | 
|  | const dw_attr_t attr = attributes.AttributeAtIndex(i); | 
|  | DWARFFormValue form_value; | 
|  | if (attributes.ExtractFormValueAtIndex(this, i, form_value)) | 
|  | { | 
|  | switch (attr) | 
|  | { | 
|  | case DW_AT_decl_file:   decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break; | 
|  | case DW_AT_decl_line:   decl.SetLine(form_value.Unsigned()); break; | 
|  | case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break; | 
|  | case DW_AT_name:        name = form_value.AsCString(&get_debug_str_data()); break; | 
|  | case DW_AT_type:        param_type_die_offset = form_value.Reference(dwarf_cu); break; | 
|  | case DW_AT_artificial:  is_artificial = form_value.Boolean(); break; | 
|  | case DW_AT_location: | 
|  | //                          if (form_value.BlockData()) | 
|  | //                          { | 
|  | //                              const DWARFDataExtractor& debug_info_data = debug_info(); | 
|  | //                              uint32_t block_length = form_value.Unsigned(); | 
|  | //                              DWARFDataExtractor location(debug_info_data, form_value.BlockData() - debug_info_data.GetDataStart(), block_length); | 
|  | //                          } | 
|  | //                          else | 
|  | //                          { | 
|  | //                          } | 
|  | //                          break; | 
|  | case DW_AT_const_value: | 
|  | case DW_AT_default_value: | 
|  | case DW_AT_description: | 
|  | case DW_AT_endianity: | 
|  | case DW_AT_is_optional: | 
|  | case DW_AT_segment: | 
|  | case DW_AT_variable_parameter: | 
|  | default: | 
|  | case DW_AT_abstract_origin: | 
|  | case DW_AT_sibling: | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | bool skip = false; | 
|  | if (skip_artificial) | 
|  | { | 
|  | if (is_artificial) | 
|  | { | 
|  | // In order to determine if a C++ member function is | 
|  | // "const" we have to look at the const-ness of "this"... | 
|  | // Ugly, but that | 
|  | if (arg_idx == 0) | 
|  | { | 
|  | if (DeclKindIsCXXClass(containing_decl_ctx->getDeclKind())) | 
|  | { | 
|  | // Often times compilers omit the "this" name for the | 
|  | // specification DIEs, so we can't rely upon the name | 
|  | // being in the formal parameter DIE... | 
|  | if (name == NULL || ::strcmp(name, "this")==0) | 
|  | { | 
|  | Type *this_type = ResolveTypeUID (param_type_die_offset); | 
|  | if (this_type) | 
|  | { | 
|  | uint32_t encoding_mask = this_type->GetEncodingMask(); | 
|  | if (encoding_mask & Type::eEncodingIsPointerUID) | 
|  | { | 
|  | is_static = false; | 
|  |  | 
|  | if (encoding_mask & (1u << Type::eEncodingIsConstUID)) | 
|  | type_quals |= clang::Qualifiers::Const; | 
|  | if (encoding_mask & (1u << Type::eEncodingIsVolatileUID)) | 
|  | type_quals |= clang::Qualifiers::Volatile; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | skip = true; | 
|  | } | 
|  | else | 
|  | { | 
|  |  | 
|  | // HACK: Objective C formal parameters "self" and "_cmd" | 
|  | // are not marked as artificial in the DWARF... | 
|  | CompileUnit *comp_unit = GetCompUnitForDWARFCompUnit(dwarf_cu, UINT32_MAX); | 
|  | if (comp_unit) | 
|  | { | 
|  | switch (comp_unit->GetLanguage()) | 
|  | { | 
|  | case eLanguageTypeObjC: | 
|  | case eLanguageTypeObjC_plus_plus: | 
|  | if (name && name[0] && (strcmp (name, "self") == 0 || strcmp (name, "_cmd") == 0)) | 
|  | skip = true; | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!skip) | 
|  | { | 
|  | Type *type = ResolveTypeUID(param_type_die_offset); | 
|  | if (type) | 
|  | { | 
|  | function_param_types.push_back (type->GetClangForwardType()); | 
|  |  | 
|  | clang::ParmVarDecl *param_var_decl = GetClangASTContext().CreateParameterDeclaration (name, | 
|  | type->GetClangForwardType(), | 
|  | storage); | 
|  | assert(param_var_decl); | 
|  | function_param_decls.push_back(param_var_decl); | 
|  |  | 
|  | GetClangASTContext().SetMetadataAsUserID (param_var_decl, MakeUserID(die->GetOffset())); | 
|  | } | 
|  | } | 
|  | } | 
|  | arg_idx++; | 
|  | } | 
|  | break; | 
|  |  | 
|  | case DW_TAG_unspecified_parameters: | 
|  | is_variadic = true; | 
|  | break; | 
|  |  | 
|  | case DW_TAG_template_type_parameter: | 
|  | case DW_TAG_template_value_parameter: | 
|  | // The one caller of this was never using the template_param_infos, | 
|  | // and the local variable was taking up a large amount of stack space | 
|  | // in SymbolFileDWARF::ParseType() so this was removed. If we ever need | 
|  | // the template params back, we can add them back. | 
|  | // ParseTemplateDIE (dwarf_cu, die, template_param_infos); | 
|  | break; | 
|  |  | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  | return arg_idx; | 
|  | } | 
|  |  | 
|  | size_t | 
|  | SymbolFileDWARF::ParseChildEnumerators | 
|  | ( | 
|  | const SymbolContext& sc, | 
|  | lldb_private::ClangASTType &clang_type, | 
|  | bool is_signed, | 
|  | uint32_t enumerator_byte_size, | 
|  | DWARFCompileUnit* dwarf_cu, | 
|  | const DWARFDebugInfoEntry *parent_die | 
|  | ) | 
|  | { | 
|  | if (parent_die == NULL) | 
|  | return 0; | 
|  |  | 
|  | size_t enumerators_added = 0; | 
|  | const DWARFDebugInfoEntry *die; | 
|  | const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize()); | 
|  |  | 
|  | for (die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling()) | 
|  | { | 
|  | const dw_tag_t tag = die->Tag(); | 
|  | if (tag == DW_TAG_enumerator) | 
|  | { | 
|  | DWARFDebugInfoEntry::Attributes attributes; | 
|  | const size_t num_child_attributes = die->GetAttributes(this, dwarf_cu, fixed_form_sizes, attributes); | 
|  | if (num_child_attributes > 0) | 
|  | { | 
|  | const char *name = NULL; | 
|  | bool got_value = false; | 
|  | int64_t enum_value = 0; | 
|  | Declaration decl; | 
|  |  | 
|  | uint32_t i; | 
|  | for (i=0; i<num_child_attributes; ++i) | 
|  | { | 
|  | const dw_attr_t attr = attributes.AttributeAtIndex(i); | 
|  | DWARFFormValue form_value; | 
|  | if (attributes.ExtractFormValueAtIndex(this, i, form_value)) | 
|  | { | 
|  | switch (attr) | 
|  | { | 
|  | case DW_AT_const_value: | 
|  | got_value = true; | 
|  | if (is_signed) | 
|  | enum_value = form_value.Signed(); | 
|  | else | 
|  | enum_value = form_value.Unsigned(); | 
|  | break; | 
|  |  | 
|  | case DW_AT_name: | 
|  | name = form_value.AsCString(&get_debug_str_data()); | 
|  | break; | 
|  |  | 
|  | case DW_AT_description: | 
|  | default: | 
|  | case DW_AT_decl_file:   decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break; | 
|  | case DW_AT_decl_line:   decl.SetLine(form_value.Unsigned()); break; | 
|  | case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break; | 
|  | case DW_AT_sibling: | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (name && name[0] && got_value) | 
|  | { | 
|  | clang_type.AddEnumerationValueToEnumerationType (clang_type.GetEnumerationIntegerType(), | 
|  | decl, | 
|  | name, | 
|  | enum_value, | 
|  | enumerator_byte_size * 8); | 
|  | ++enumerators_added; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | return enumerators_added; | 
|  | } | 
|  |  | 
|  | void | 
|  | SymbolFileDWARF::ParseChildArrayInfo | 
|  | ( | 
|  | const SymbolContext& sc, | 
|  | DWARFCompileUnit* dwarf_cu, | 
|  | const DWARFDebugInfoEntry *parent_die, | 
|  | int64_t& first_index, | 
|  | std::vector<uint64_t>& element_orders, | 
|  | uint32_t& byte_stride, | 
|  | uint32_t& bit_stride | 
|  | ) | 
|  | { | 
|  | if (parent_die == NULL) | 
|  | return; | 
|  |  | 
|  | const DWARFDebugInfoEntry *die; | 
|  | const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize()); | 
|  | for (die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling()) | 
|  | { | 
|  | const dw_tag_t tag = die->Tag(); | 
|  | switch (tag) | 
|  | { | 
|  | case DW_TAG_subrange_type: | 
|  | { | 
|  | DWARFDebugInfoEntry::Attributes attributes; | 
|  | const size_t num_child_attributes = die->GetAttributes(this, dwarf_cu, fixed_form_sizes, attributes); | 
|  | if (num_child_attributes > 0) | 
|  | { | 
|  | uint64_t num_elements = 0; | 
|  | uint64_t lower_bound = 0; | 
|  | uint64_t upper_bound = 0; | 
|  | bool upper_bound_valid = false; | 
|  | uint32_t i; | 
|  | for (i=0; i<num_child_attributes; ++i) | 
|  | { | 
|  | const dw_attr_t attr = attributes.AttributeAtIndex(i); | 
|  | DWARFFormValue form_value; | 
|  | if (attributes.ExtractFormValueAtIndex(this, i, form_value)) | 
|  | { | 
|  | switch (attr) | 
|  | { | 
|  | case DW_AT_name: | 
|  | break; | 
|  |  | 
|  | case DW_AT_count: | 
|  | num_elements = form_value.Unsigned(); | 
|  | break; | 
|  |  | 
|  | case DW_AT_bit_stride: | 
|  | bit_stride = form_value.Unsigned(); | 
|  | break; | 
|  |  | 
|  | case DW_AT_byte_stride: | 
|  | byte_stride = form_value.Unsigned(); | 
|  | break; | 
|  |  | 
|  | case DW_AT_lower_bound: | 
|  | lower_bound = form_value.Unsigned(); | 
|  | break; | 
|  |  | 
|  | case DW_AT_upper_bound: | 
|  | upper_bound_valid = true; | 
|  | upper_bound = form_value.Unsigned(); | 
|  | break; | 
|  |  | 
|  | default: | 
|  | case DW_AT_abstract_origin: | 
|  | case DW_AT_accessibility: | 
|  | case DW_AT_allocated: | 
|  | case DW_AT_associated: | 
|  | case DW_AT_data_location: | 
|  | case DW_AT_declaration: | 
|  | case DW_AT_description: | 
|  | case DW_AT_sibling: | 
|  | case DW_AT_threads_scaled: | 
|  | case DW_AT_type: | 
|  | case DW_AT_visibility: | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (num_elements == 0) | 
|  | { | 
|  | if (upper_bound_valid && upper_bound >= lower_bound) | 
|  | num_elements = upper_bound - lower_bound + 1; | 
|  | } | 
|  |  | 
|  | element_orders.push_back (num_elements); | 
|  | } | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | TypeSP | 
|  | SymbolFileDWARF::GetTypeForDIE (DWARFCompileUnit *dwarf_cu, const DWARFDebugInfoEntry* die) | 
|  | { | 
|  | TypeSP type_sp; | 
|  | if (die != NULL) | 
|  | { | 
|  | assert(dwarf_cu != NULL); | 
|  | Type *type_ptr = m_die_to_type.lookup (die); | 
|  | if (type_ptr == NULL) | 
|  | { | 
|  | CompileUnit* lldb_cu = GetCompUnitForDWARFCompUnit(dwarf_cu); | 
|  | assert (lldb_cu); | 
|  | SymbolContext sc(lldb_cu); | 
|  | type_sp = ParseType(sc, dwarf_cu, die, NULL); | 
|  | } | 
|  | else if (type_ptr != DIE_IS_BEING_PARSED) | 
|  | { | 
|  | // Grab the existing type from the master types lists | 
|  | type_sp = type_ptr->shared_from_this(); | 
|  | } | 
|  |  | 
|  | } | 
|  | return type_sp; | 
|  | } | 
|  |  | 
|  | clang::DeclContext * | 
|  | SymbolFileDWARF::GetClangDeclContextContainingDIEOffset (dw_offset_t die_offset) | 
|  | { | 
|  | if (die_offset != DW_INVALID_OFFSET) | 
|  | { | 
|  | DWARFCompileUnitSP cu_sp; | 
|  | const DWARFDebugInfoEntry* die = DebugInfo()->GetDIEPtr(die_offset, &cu_sp); | 
|  | return GetClangDeclContextContainingDIE (cu_sp.get(), die, NULL); | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | clang::DeclContext * | 
|  | SymbolFileDWARF::GetClangDeclContextForDIEOffset (const SymbolContext &sc, dw_offset_t die_offset) | 
|  | { | 
|  | if (die_offset != DW_INVALID_OFFSET) | 
|  | { | 
|  | DWARFDebugInfo* debug_info = DebugInfo(); | 
|  | if (debug_info) | 
|  | { | 
|  | DWARFCompileUnitSP cu_sp; | 
|  | const DWARFDebugInfoEntry* die = debug_info->GetDIEPtr(die_offset, &cu_sp); | 
|  | if (die) | 
|  | return GetClangDeclContextForDIE (sc, cu_sp.get(), die); | 
|  | } | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | clang::NamespaceDecl * | 
|  | SymbolFileDWARF::ResolveNamespaceDIE (DWARFCompileUnit *dwarf_cu, const DWARFDebugInfoEntry *die) | 
|  | { | 
|  | if (die && die->Tag() == DW_TAG_namespace) | 
|  | { | 
|  | // See if we already parsed this namespace DIE and associated it with a | 
|  | // uniqued namespace declaration | 
|  | clang::NamespaceDecl *namespace_decl = static_cast<clang::NamespaceDecl *>(m_die_to_decl_ctx[die]); | 
|  | if (namespace_decl) | 
|  | return namespace_decl; | 
|  | else | 
|  | { | 
|  | const char *namespace_name = die->GetAttributeValueAsString(this, dwarf_cu, DW_AT_name, NULL); | 
|  | clang::DeclContext *containing_decl_ctx = GetClangDeclContextContainingDIE (dwarf_cu, die, NULL); | 
|  | namespace_decl = GetClangASTContext().GetUniqueNamespaceDeclaration (namespace_name, containing_decl_ctx); | 
|  | Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO)); | 
|  | if (log) | 
|  | { | 
|  | if (namespace_name) | 
|  | { | 
|  | GetObjectFile()->GetModule()->LogMessage (log, | 
|  | "ASTContext => %p: 0x%8.8" PRIx64 ": DW_TAG_namespace with DW_AT_name(\"%s\") => clang::NamespaceDecl *%p (original = %p)", | 
|  | static_cast<void*>(GetClangASTContext().getASTContext()), | 
|  | MakeUserID(die->GetOffset()), | 
|  | namespace_name, | 
|  | static_cast<void*>(namespace_decl), | 
|  | static_cast<void*>(namespace_decl->getOriginalNamespace())); | 
|  | } | 
|  | else | 
|  | { | 
|  | GetObjectFile()->GetModule()->LogMessage (log, | 
|  | "ASTContext => %p: 0x%8.8" PRIx64 ": DW_TAG_namespace (anonymous) => clang::NamespaceDecl *%p (original = %p)", | 
|  | static_cast<void*>(GetClangASTContext().getASTContext()), | 
|  | MakeUserID(die->GetOffset()), | 
|  | static_cast<void*>(namespace_decl), | 
|  | static_cast<void*>(namespace_decl->getOriginalNamespace())); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (namespace_decl) | 
|  | LinkDeclContextToDIE((clang::DeclContext*)namespace_decl, die); | 
|  | return namespace_decl; | 
|  | } | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | clang::DeclContext * | 
|  | SymbolFileDWARF::GetClangDeclContextForDIE (const SymbolContext &sc, DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die) | 
|  | { | 
|  | clang::DeclContext *clang_decl_ctx = GetCachedClangDeclContextForDIE (die); | 
|  | if (clang_decl_ctx) | 
|  | return clang_decl_ctx; | 
|  | // If this DIE has a specification, or an abstract origin, then trace to those. | 
|  |  | 
|  | dw_offset_t die_offset = die->GetAttributeValueAsReference(this, cu, DW_AT_specification, DW_INVALID_OFFSET); | 
|  | if (die_offset != DW_INVALID_OFFSET) | 
|  | return GetClangDeclContextForDIEOffset (sc, die_offset); | 
|  |  | 
|  | die_offset = die->GetAttributeValueAsReference(this, cu, DW_AT_abstract_origin, DW_INVALID_OFFSET); | 
|  | if (die_offset != DW_INVALID_OFFSET) | 
|  | return GetClangDeclContextForDIEOffset (sc, die_offset); | 
|  |  | 
|  | Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO)); | 
|  | if (log) | 
|  | GetObjectFile()->GetModule()->LogMessage(log, "SymbolFileDWARF::GetClangDeclContextForDIE (die = 0x%8.8x) %s '%s'", die->GetOffset(), DW_TAG_value_to_name(die->Tag()), die->GetName(this, cu)); | 
|  | // This is the DIE we want.  Parse it, then query our map. | 
|  | bool assert_not_being_parsed = true; | 
|  | ResolveTypeUID (cu, die, assert_not_being_parsed); | 
|  |  | 
|  | clang_decl_ctx = GetCachedClangDeclContextForDIE (die); | 
|  |  | 
|  | return clang_decl_ctx; | 
|  | } | 
|  |  | 
|  | clang::DeclContext * | 
|  | SymbolFileDWARF::GetClangDeclContextContainingDIE (DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die, const DWARFDebugInfoEntry **decl_ctx_die_copy) | 
|  | { | 
|  | if (m_clang_tu_decl == NULL) | 
|  | m_clang_tu_decl = GetClangASTContext().getASTContext()->getTranslationUnitDecl(); | 
|  |  | 
|  | const DWARFDebugInfoEntry *decl_ctx_die = GetDeclContextDIEContainingDIE (cu, die); | 
|  |  | 
|  | if (decl_ctx_die_copy) | 
|  | *decl_ctx_die_copy = decl_ctx_die; | 
|  |  | 
|  | if (decl_ctx_die) | 
|  | { | 
|  |  | 
|  | DIEToDeclContextMap::iterator pos = m_die_to_decl_ctx.find (decl_ctx_die); | 
|  | if (pos != m_die_to_decl_ctx.end()) | 
|  | return pos->second; | 
|  |  | 
|  | switch (decl_ctx_die->Tag()) | 
|  | { | 
|  | case DW_TAG_compile_unit: | 
|  | return m_clang_tu_decl; | 
|  |  | 
|  | case DW_TAG_namespace: | 
|  | return ResolveNamespaceDIE (cu, decl_ctx_die); | 
|  | break; | 
|  |  | 
|  | case DW_TAG_structure_type: | 
|  | case DW_TAG_union_type: | 
|  | case DW_TAG_class_type: | 
|  | { | 
|  | Type* type = ResolveType (cu, decl_ctx_die); | 
|  | if (type) | 
|  | { | 
|  | clang::DeclContext *decl_ctx = type->GetClangForwardType().GetDeclContextForType (); | 
|  | if (decl_ctx) | 
|  | { | 
|  | LinkDeclContextToDIE (decl_ctx, decl_ctx_die); | 
|  | if (decl_ctx) | 
|  | return decl_ctx; | 
|  | } | 
|  | } | 
|  | } | 
|  | break; | 
|  |  | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  | return m_clang_tu_decl; | 
|  | } | 
|  |  | 
|  |  | 
|  | const DWARFDebugInfoEntry * | 
|  | SymbolFileDWARF::GetDeclContextDIEContainingDIE (DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die) | 
|  | { | 
|  | if (cu && die) | 
|  | { | 
|  | const DWARFDebugInfoEntry * const decl_die = die; | 
|  |  | 
|  | while (die != NULL) | 
|  | { | 
|  | // If this is the original DIE that we are searching for a declaration | 
|  | // for, then don't look in the cache as we don't want our own decl | 
|  | // context to be our decl context... | 
|  | if (decl_die != die) | 
|  | { | 
|  | switch (die->Tag()) | 
|  | { | 
|  | case DW_TAG_compile_unit: | 
|  | case DW_TAG_namespace: | 
|  | case DW_TAG_structure_type: | 
|  | case DW_TAG_union_type: | 
|  | case DW_TAG_class_type: | 
|  | return die; | 
|  |  | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | dw_offset_t die_offset = die->GetAttributeValueAsReference(this, cu, DW_AT_specification, DW_INVALID_OFFSET); | 
|  | if (die_offset != DW_INVALID_OFFSET) | 
|  | { | 
|  | DWARFCompileUnit *spec_cu = cu; | 
|  | const DWARFDebugInfoEntry *spec_die = DebugInfo()->GetDIEPtrWithCompileUnitHint (die_offset, &spec_cu); | 
|  | const DWARFDebugInfoEntry *spec_die_decl_ctx_die = GetDeclContextDIEContainingDIE (spec_cu, spec_die); | 
|  | if (spec_die_decl_ctx_die) | 
|  | return spec_die_decl_ctx_die; | 
|  | } | 
|  |  | 
|  | die_offset = die->GetAttributeValueAsReference(this, cu, DW_AT_abstract_origin, DW_INVALID_OFFSET); | 
|  | if (die_offset != DW_INVALID_OFFSET) | 
|  | { | 
|  | DWARFCompileUnit *abs_cu = cu; | 
|  | const DWARFDebugInfoEntry *abs_die = DebugInfo()->GetDIEPtrWithCompileUnitHint (die_offset, &abs_cu); | 
|  | const DWARFDebugInfoEntry *abs_die_decl_ctx_die = GetDeclContextDIEContainingDIE (abs_cu, abs_die); | 
|  | if (abs_die_decl_ctx_die) | 
|  | return abs_die_decl_ctx_die; | 
|  | } | 
|  |  | 
|  | die = die->GetParent(); | 
|  | } | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  |  | 
|  | Symbol * | 
|  | SymbolFileDWARF::GetObjCClassSymbol (const ConstString &objc_class_name) | 
|  | { | 
|  | Symbol *objc_class_symbol = NULL; | 
|  | if (m_obj_file) | 
|  | { | 
|  | Symtab *symtab = m_obj_file->GetSymtab (); | 
|  | if (symtab) | 
|  | { | 
|  | objc_class_symbol = symtab->FindFirstSymbolWithNameAndType (objc_class_name, | 
|  | eSymbolTypeObjCClass, | 
|  | Symtab::eDebugNo, | 
|  | Symtab::eVisibilityAny); | 
|  | } | 
|  | } | 
|  | return objc_class_symbol; | 
|  | } | 
|  |  | 
|  | // Some compilers don't emit the DW_AT_APPLE_objc_complete_type attribute. If they don't | 
|  | // then we can end up looking through all class types for a complete type and never find | 
|  | // the full definition. We need to know if this attribute is supported, so we determine | 
|  | // this here and cache th result. We also need to worry about the debug map DWARF file | 
|  | // if we are doing darwin DWARF in .o file debugging. | 
|  | bool | 
|  | SymbolFileDWARF::Supports_DW_AT_APPLE_objc_complete_type (DWARFCompileUnit *cu) | 
|  | { | 
|  | if (m_supports_DW_AT_APPLE_objc_complete_type == eLazyBoolCalculate) | 
|  | { | 
|  | m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolNo; | 
|  | if (cu && cu->Supports_DW_AT_APPLE_objc_complete_type()) | 
|  | m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolYes; | 
|  | else | 
|  | { | 
|  | DWARFDebugInfo* debug_info = DebugInfo(); | 
|  | const uint32_t num_compile_units = GetNumCompileUnits(); | 
|  | for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) | 
|  | { | 
|  | DWARFCompileUnit* dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx); | 
|  | if (dwarf_cu != cu && dwarf_cu->Supports_DW_AT_APPLE_objc_complete_type()) | 
|  | { | 
|  | m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolYes; | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | if (m_supports_DW_AT_APPLE_objc_complete_type == eLazyBoolNo && GetDebugMapSymfile ()) | 
|  | return m_debug_map_symfile->Supports_DW_AT_APPLE_objc_complete_type (this); | 
|  | } | 
|  | return m_supports_DW_AT_APPLE_objc_complete_type == eLazyBoolYes; | 
|  | } | 
|  |  | 
|  | // This function can be used when a DIE is found that is a forward declaration | 
|  | // DIE and we want to try and find a type that has the complete definition. | 
|  | TypeSP | 
|  | SymbolFileDWARF::FindCompleteObjCDefinitionTypeForDIE (const DWARFDebugInfoEntry *die, | 
|  | const ConstString &type_name, | 
|  | bool must_be_implementation) | 
|  | { | 
|  |  | 
|  | TypeSP type_sp; | 
|  |  | 
|  | if (!type_name || (must_be_implementation && !GetObjCClassSymbol (type_name))) | 
|  | return type_sp; | 
|  |  | 
|  | DIEArray die_offsets; | 
|  |  | 
|  | if (m_using_apple_tables) | 
|  | { | 
|  | if (m_apple_types_ap.get()) | 
|  | { | 
|  | const char *name_cstr = type_name.GetCString(); | 
|  | m_apple_types_ap->FindCompleteObjCClassByName (name_cstr, die_offsets, must_be_implementation); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | if (!m_indexed) | 
|  | Index (); | 
|  |  | 
|  | m_type_index.Find (type_name, die_offsets); | 
|  | } | 
|  |  | 
|  | const size_t num_matches = die_offsets.size(); | 
|  |  | 
|  | DWARFCompileUnit* type_cu = NULL; | 
|  | const DWARFDebugInfoEntry* type_die = NULL; | 
|  | if (num_matches) | 
|  | { | 
|  | DWARFDebugInfo* debug_info = DebugInfo(); | 
|  | for (size_t i=0; i<num_matches; ++i) | 
|  | { | 
|  | const dw_offset_t die_offset = die_offsets[i]; | 
|  | type_die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &type_cu); | 
|  |  | 
|  | if (type_die) | 
|  | { | 
|  | bool try_resolving_type = false; | 
|  |  | 
|  | // Don't try and resolve the DIE we are looking for with the DIE itself! | 
|  | if (type_die != die) | 
|  | { | 
|  | switch (type_die->Tag()) | 
|  | { | 
|  | case DW_TAG_class_type: | 
|  | case DW_TAG_structure_type: | 
|  | try_resolving_type = true; | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (try_resolving_type) | 
|  | { | 
|  | if (must_be_implementation && type_cu->Supports_DW_AT_APPLE_objc_complete_type()) | 
|  | try_resolving_type = type_die->GetAttributeValueAsUnsigned (this, type_cu, DW_AT_APPLE_objc_complete_type, 0); | 
|  |  | 
|  | if (try_resolving_type) | 
|  | { | 
|  | Type *resolved_type = ResolveType (type_cu, type_die, false); | 
|  | if (resolved_type && resolved_type != DIE_IS_BEING_PARSED) | 
|  | { | 
|  | DEBUG_PRINTF ("resolved 0x%8.8" PRIx64 " from %s to 0x%8.8" PRIx64 " (cu 0x%8.8" PRIx64 ")\n", | 
|  | MakeUserID(die->GetOffset()), | 
|  | m_obj_file->GetFileSpec().GetFilename().AsCString(), | 
|  | MakeUserID(type_die->GetOffset()), | 
|  | MakeUserID(type_cu->GetOffset())); | 
|  |  | 
|  | if (die) | 
|  | m_die_to_type[die] = resolved_type; | 
|  | type_sp = resolved_type->shared_from_this(); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | if (m_using_apple_tables) | 
|  | { | 
|  | GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_types accelerator table had bad die 0x%8.8x for '%s')\n", | 
|  | die_offset, type_name.GetCString()); | 
|  | } | 
|  | } | 
|  |  | 
|  | } | 
|  | } | 
|  | return type_sp; | 
|  | } | 
|  |  | 
|  |  | 
|  | //---------------------------------------------------------------------- | 
|  | // This function helps to ensure that the declaration contexts match for | 
|  | // two different DIEs. Often times debug information will refer to a | 
|  | // forward declaration of a type (the equivalent of "struct my_struct;". | 
|  | // There will often be a declaration of that type elsewhere that has the | 
|  | // full definition. When we go looking for the full type "my_struct", we | 
|  | // will find one or more matches in the accelerator tables and we will | 
|  | // then need to make sure the type was in the same declaration context | 
|  | // as the original DIE. This function can efficiently compare two DIEs | 
|  | // and will return true when the declaration context matches, and false | 
|  | // when they don't. | 
|  | //---------------------------------------------------------------------- | 
|  | bool | 
|  | SymbolFileDWARF::DIEDeclContextsMatch (DWARFCompileUnit* cu1, const DWARFDebugInfoEntry *die1, | 
|  | DWARFCompileUnit* cu2, const DWARFDebugInfoEntry *die2) | 
|  | { | 
|  | if (die1 == die2) | 
|  | return true; | 
|  |  | 
|  | #if defined (LLDB_CONFIGURATION_DEBUG) | 
|  | // You can't and shouldn't call this function with a compile unit from | 
|  | // two different SymbolFileDWARF instances. | 
|  | assert (DebugInfo()->ContainsCompileUnit (cu1)); | 
|  | assert (DebugInfo()->ContainsCompileUnit (cu2)); | 
|  | #endif | 
|  |  | 
|  | DWARFDIECollection decl_ctx_1; | 
|  | DWARFDIECollection decl_ctx_2; | 
|  | //The declaration DIE stack is a stack of the declaration context | 
|  | // DIEs all the way back to the compile unit. If a type "T" is | 
|  | // declared inside a class "B", and class "B" is declared inside | 
|  | // a class "A" and class "A" is in a namespace "lldb", and the | 
|  | // namespace is in a compile unit, there will be a stack of DIEs: | 
|  | // | 
|  | //   [0] DW_TAG_class_type for "B" | 
|  | //   [1] DW_TAG_class_type for "A" | 
|  | //   [2] DW_TAG_namespace  for "lldb" | 
|  | //   [3] DW_TAG_compile_unit for the source file. | 
|  | // | 
|  | // We grab both contexts and make sure that everything matches | 
|  | // all the way back to the compiler unit. | 
|  |  | 
|  | // First lets grab the decl contexts for both DIEs | 
|  | die1->GetDeclContextDIEs (this, cu1, decl_ctx_1); | 
|  | die2->GetDeclContextDIEs (this, cu2, decl_ctx_2); | 
|  | // Make sure the context arrays have the same size, otherwise | 
|  | // we are done | 
|  | const size_t count1 = decl_ctx_1.Size(); | 
|  | const size_t count2 = decl_ctx_2.Size(); | 
|  | if (count1 != count2) | 
|  | return false; | 
|  |  | 
|  | // Make sure the DW_TAG values match all the way back up the | 
|  | // compile unit. If they don't, then we are done. | 
|  | const DWARFDebugInfoEntry *decl_ctx_die1; | 
|  | const DWARFDebugInfoEntry *decl_ctx_die2; | 
|  | size_t i; | 
|  | for (i=0; i<count1; i++) | 
|  | { | 
|  | decl_ctx_die1 = decl_ctx_1.GetDIEPtrAtIndex (i); | 
|  | decl_ctx_die2 = decl_ctx_2.GetDIEPtrAtIndex (i); | 
|  | if (decl_ctx_die1->Tag() != decl_ctx_die2->Tag()) | 
|  | return false; | 
|  | } | 
|  | #if defined LLDB_CONFIGURATION_DEBUG | 
|  |  | 
|  | // Make sure the top item in the decl context die array is always | 
|  | // DW_TAG_compile_unit. If it isn't then something went wrong in | 
|  | // the DWARFDebugInfoEntry::GetDeclContextDIEs() function... | 
|  | assert (decl_ctx_1.GetDIEPtrAtIndex (count1 - 1)->Tag() == DW_TAG_compile_unit); | 
|  |  | 
|  | #endif | 
|  | // Always skip the compile unit when comparing by only iterating up to | 
|  | // "count - 1". Here we compare the names as we go. | 
|  | for (i=0; i<count1 - 1; i++) | 
|  | { | 
|  | decl_ctx_die1 = decl_ctx_1.GetDIEPtrAtIndex (i); | 
|  | decl_ctx_die2 = decl_ctx_2.GetDIEPtrAtIndex (i); | 
|  | const char *name1 = decl_ctx_die1->GetName(this, cu1); | 
|  | const char *name2 = decl_ctx_die2->GetName(this, cu2); | 
|  | // If the string was from a DW_FORM_strp, then the pointer will often | 
|  | // be the same! | 
|  | if (name1 == name2) | 
|  | continue; | 
|  |  | 
|  | // Name pointers are not equal, so only compare the strings | 
|  | // if both are not NULL. | 
|  | if (name1 && name2) | 
|  | { | 
|  | // If the strings don't compare, we are done... | 
|  | if (strcmp(name1, name2) != 0) | 
|  | return false; | 
|  | } | 
|  | else | 
|  | { | 
|  | // One name was NULL while the other wasn't | 
|  | return false; | 
|  | } | 
|  | } | 
|  | // We made it through all of the checks and the declaration contexts | 
|  | // are equal. | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // This function can be used when a DIE is found that is a forward declaration | 
|  | // DIE and we want to try and find a type that has the complete definition. | 
|  | // "cu" and "die" must be from this SymbolFileDWARF | 
|  | TypeSP | 
|  | SymbolFileDWARF::FindDefinitionTypeForDIE (DWARFCompileUnit* cu, | 
|  | const DWARFDebugInfoEntry *die, | 
|  | const ConstString &type_name) | 
|  | { | 
|  | TypeSP type_sp; | 
|  |  | 
|  | #if defined (LLDB_CONFIGURATION_DEBUG) | 
|  | // You can't and shouldn't call this function with a compile unit from | 
|  | // another SymbolFileDWARF instance. | 
|  | assert (DebugInfo()->ContainsCompileUnit (cu)); | 
|  | #endif | 
|  |  | 
|  | if (cu == NULL || die == NULL || !type_name) | 
|  | return type_sp; | 
|  |  | 
|  | std::string qualified_name; | 
|  |  | 
|  | Log *log (LogChannelDWARF::GetLogIfAny(DWARF_LOG_TYPE_COMPLETION|DWARF_LOG_LOOKUPS)); | 
|  | if (log) | 
|  | { | 
|  | die->GetQualifiedName(this, cu, qualified_name); | 
|  | GetObjectFile()->GetModule()->LogMessage (log, | 
|  | "SymbolFileDWARF::FindDefinitionTypeForDIE(die=0x%8.8x (%s), name='%s')", | 
|  | die->GetOffset(), | 
|  | qualified_name.c_str(), | 
|  | type_name.GetCString()); | 
|  | } | 
|  |  | 
|  | DIEArray die_offsets; | 
|  |  | 
|  | if (m_using_apple_tables) | 
|  | { | 
|  | if (m_apple_types_ap.get()) | 
|  | { | 
|  | const bool has_tag = m_apple_types_ap->GetHeader().header_data.ContainsAtom (DWARFMappedHash::eAtomTypeTag); | 
|  | const bool has_qualified_name_hash = m_apple_types_ap->GetHeader().header_data.ContainsAtom (DWARFMappedHash::eAtomTypeQualNameHash); | 
|  | if (has_tag && has_qualified_name_hash) | 
|  | { | 
|  | if (qualified_name.empty()) | 
|  | die->GetQualifiedName(this, cu, qualified_name); | 
|  |  | 
|  | const uint32_t qualified_name_hash = MappedHash::HashStringUsingDJB (qualified_name.c_str()); | 
|  | if (log) | 
|  | GetObjectFile()->GetModule()->LogMessage (log,"FindByNameAndTagAndQualifiedNameHash()"); | 
|  | m_apple_types_ap->FindByNameAndTagAndQualifiedNameHash (type_name.GetCString(), die->Tag(), qualified_name_hash, die_offsets); | 
|  | } | 
|  | else if (has_tag) | 
|  | { | 
|  | if (log) | 
|  | GetObjectFile()->GetModule()->LogMessage (log,"FindByNameAndTag()"); | 
|  | m_apple_types_ap->FindByNameAndTag (type_name.GetCString(), die->Tag(), die_offsets); | 
|  | } | 
|  | else | 
|  | { | 
|  | m_apple_types_ap->FindByName (type_name.GetCString(), die_offsets); | 
|  | } | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | if (!m_indexed) | 
|  | Index (); | 
|  |  | 
|  | m_type_index.Find (type_name, die_offsets); | 
|  | } | 
|  |  | 
|  | const size_t num_matches = die_offsets.size(); | 
|  |  | 
|  | const dw_tag_t die_tag = die->Tag(); | 
|  |  | 
|  | DWARFCompileUnit* type_cu = NULL; | 
|  | const DWARFDebugInfoEntry* type_die = NULL; | 
|  | if (num_matches) | 
|  | { | 
|  | DWARFDebugInfo* debug_info = DebugInfo(); | 
|  | for (size_t i=0; i<num_matches; ++i) | 
|  | { | 
|  | const dw_offset_t die_offset = die_offsets[i]; | 
|  | type_die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &type_cu); | 
|  |  | 
|  | if (type_die) | 
|  | { | 
|  | bool try_resolving_type = false; | 
|  |  | 
|  | // Don't try and resolve the DIE we are looking for with the DIE itself! | 
|  | if (type_die != die) | 
|  | { | 
|  | const dw_tag_t type_die_tag = type_die->Tag(); | 
|  | // Make sure the tags match | 
|  | if (type_die_tag == die_tag) | 
|  | { | 
|  | // The tags match, lets try resolving this type | 
|  | try_resolving_type = true; | 
|  | } | 
|  | else | 
|  | { | 
|  | // The tags don't match, but we need to watch our for a | 
|  | // forward declaration for a struct and ("struct foo") | 
|  | // ends up being a class ("class foo { ... };") or | 
|  | // vice versa. | 
|  | switch (type_die_tag) | 
|  | { | 
|  | case DW_TAG_class_type: | 
|  | // We had a "class foo", see if we ended up with a "struct foo { ... };" | 
|  | try_resolving_type = (die_tag == DW_TAG_structure_type); | 
|  | break; | 
|  | case DW_TAG_structure_type: | 
|  | // We had a "struct foo", see if we ended up with a "class foo { ... };" | 
|  | try_resolving_type = (die_tag == DW_TAG_class_type); | 
|  | break; | 
|  | default: | 
|  | // Tags don't match, don't event try to resolve | 
|  | // using this type whose name matches.... | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (try_resolving_type) | 
|  | { | 
|  | if (log) | 
|  | { | 
|  | std::string qualified_name; | 
|  | type_die->GetQualifiedName(this, cu, qualified_name); | 
|  | GetObjectFile()->GetModule()->LogMessage (log, | 
|  | "SymbolFileDWARF::FindDefinitionTypeForDIE(die=0x%8.8x, name='%s') trying die=0x%8.8x (%s)", | 
|  | die->GetOffset(), | 
|  | type_name.GetCString(), | 
|  | type_die->GetOffset(), | 
|  | qualified_name.c_str()); | 
|  | } | 
|  |  | 
|  | // Make sure the decl contexts match all the way up | 
|  | if (DIEDeclContextsMatch(cu, die, type_cu, type_die)) | 
|  | { | 
|  | Type *resolved_type = ResolveType (type_cu, type_die, false); | 
|  | if (resolved_type && resolved_type != DIE_IS_BEING_PARSED) | 
|  | { | 
|  | DEBUG_PRINTF ("resolved 0x%8.8" PRIx64 " (cu 0x%8.8" PRIx64 ") from %s to 0x%8.8" PRIx64 " (cu 0x%8.8" PRIx64 ")\n", | 
|  | MakeUserID(die->GetOffset()), | 
|  | MakeUserID(cu->GetOffset()), | 
|  | m_obj_file->GetFileSpec().GetFilename().AsCString(), | 
|  | MakeUserID(type_die->GetOffset()), | 
|  | MakeUserID(type_cu->GetOffset())); | 
|  |  | 
|  | m_die_to_type[die] = resolved_type; | 
|  | type_sp = resolved_type->shared_from_this(); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | if (log) | 
|  | { | 
|  | std::string qualified_name; | 
|  | type_die->GetQualifiedName(this, cu, qualified_name); | 
|  | GetObjectFile()->GetModule()->LogMessage (log, | 
|  | "SymbolFileDWARF::FindDefinitionTypeForDIE(die=0x%8.8x, name='%s') ignoring die=0x%8.8x (%s)", | 
|  | die->GetOffset(), | 
|  | type_name.GetCString(), | 
|  | type_die->GetOffset(), | 
|  | qualified_name.c_str()); | 
|  | } | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | if (m_using_apple_tables) | 
|  | { | 
|  | GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_types accelerator table had bad die 0x%8.8x for '%s')\n", | 
|  | die_offset, type_name.GetCString()); | 
|  | } | 
|  | } | 
|  |  | 
|  | } | 
|  | } | 
|  | return type_sp; | 
|  | } | 
|  |  | 
|  | TypeSP | 
|  | SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext (const DWARFDeclContext &dwarf_decl_ctx) | 
|  | { | 
|  | TypeSP type_sp; | 
|  |  | 
|  | const uint32_t dwarf_decl_ctx_count = dwarf_decl_ctx.GetSize(); | 
|  | if (dwarf_decl_ctx_count > 0) | 
|  | { | 
|  | const ConstString type_name(dwarf_decl_ctx[0].name); | 
|  | const dw_tag_t tag = dwarf_decl_ctx[0].tag; | 
|  |  | 
|  | if (type_name) | 
|  | { | 
|  | Log *log (LogChannelDWARF::GetLogIfAny(DWARF_LOG_TYPE_COMPLETION|DWARF_LOG_LOOKUPS)); | 
|  | if (log) | 
|  | { | 
|  | GetObjectFile()->GetModule()->LogMessage (log, | 
|  | "SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext(tag=%s, qualified-name='%s')", | 
|  | DW_TAG_value_to_name(dwarf_decl_ctx[0].tag), | 
|  | dwarf_decl_ctx.GetQualifiedName()); | 
|  | } | 
|  |  | 
|  | DIEArray die_offsets; | 
|  |  | 
|  | if (m_using_apple_tables) | 
|  | { | 
|  | if (m_apple_types_ap.get()) | 
|  | { | 
|  | const bool has_tag = m_apple_types_ap->GetHeader().header_data.ContainsAtom (DWARFMappedHash::eAtomTypeTag); | 
|  | const bool has_qualified_name_hash = m_apple_types_ap->GetHeader().header_data.ContainsAtom (DWARFMappedHash::eAtomTypeQualNameHash); | 
|  | if (has_tag && has_qualified_name_hash) | 
|  | { | 
|  | const char *qualified_name = dwarf_decl_ctx.GetQualifiedName(); | 
|  | const uint32_t qualified_name_hash = MappedHash::HashStringUsingDJB (qualified_name); | 
|  | if (log) | 
|  | GetObjectFile()->GetModule()->LogMessage (log,"FindByNameAndTagAndQualifiedNameHash()"); | 
|  | m_apple_types_ap->FindByNameAndTagAndQualifiedNameHash (type_name.GetCString(), tag, qualified_name_hash, die_offsets); | 
|  | } | 
|  | else if (has_tag) | 
|  | { | 
|  | if (log) | 
|  | GetObjectFile()->GetModule()->LogMessage (log,"FindByNameAndTag()"); | 
|  | m_apple_types_ap->FindByNameAndTag (type_name.GetCString(), tag, die_offsets); | 
|  | } | 
|  | else | 
|  | { | 
|  | m_apple_types_ap->FindByName (type_name.GetCString(), die_offsets); | 
|  | } | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | if (!m_indexed) | 
|  | Index (); | 
|  |  | 
|  | m_type_index.Find (type_name, die_offsets); | 
|  | } | 
|  |  | 
|  | const size_t num_matches = die_offsets.size(); | 
|  |  | 
|  |  | 
|  | DWARFCompileUnit* type_cu = NULL; | 
|  | const DWARFDebugInfoEntry* type_die = NULL; | 
|  | if (num_matches) | 
|  | { | 
|  | DWARFDebugInfo* debug_info = DebugInfo(); | 
|  | for (size_t i=0; i<num_matches; ++i) | 
|  | { | 
|  | const dw_offset_t die_offset = die_offsets[i]; | 
|  | type_die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &type_cu); | 
|  |  | 
|  | if (type_die) | 
|  | { | 
|  | bool try_resolving_type = false; | 
|  |  | 
|  | // Don't try and resolve the DIE we are looking for with the DIE itself! | 
|  | const dw_tag_t type_tag = type_die->Tag(); | 
|  | // Make sure the tags match | 
|  | if (type_tag == tag) | 
|  | { | 
|  | // The tags match, lets try resolving this type | 
|  | try_resolving_type = true; | 
|  | } | 
|  | else | 
|  | { | 
|  | // The tags don't match, but we need to watch our for a | 
|  | // forward declaration for a struct and ("struct foo") | 
|  | // ends up being a class ("class foo { ... };") or | 
|  | // vice versa. | 
|  | switch (type_tag) | 
|  | { | 
|  | case DW_TAG_class_type: | 
|  | // We had a "class foo", see if we ended up with a "struct foo { ... };" | 
|  | try_resolving_type = (tag == DW_TAG_structure_type); | 
|  | break; | 
|  | case DW_TAG_structure_type: | 
|  | // We had a "struct foo", see if we ended up with a "class foo { ... };" | 
|  | try_resolving_type = (tag == DW_TAG_class_type); | 
|  | break; | 
|  | default: | 
|  | // Tags don't match, don't event try to resolve | 
|  | // using this type whose name matches.... | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (try_resolving_type) | 
|  | { | 
|  | DWARFDeclContext type_dwarf_decl_ctx; | 
|  | type_die->GetDWARFDeclContext (this, type_cu, type_dwarf_decl_ctx); | 
|  |  | 
|  | if (log) | 
|  | { | 
|  | GetObjectFile()->GetModule()->LogMessage (log, | 
|  | "SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext(tag=%s, qualified-name='%s') trying die=0x%8.8x (%s)", | 
|  | DW_TAG_value_to_name(dwarf_decl_ctx[0].tag), | 
|  | dwarf_decl_ctx.GetQualifiedName(), | 
|  | type_die->GetOffset(), | 
|  | type_dwarf_decl_ctx.GetQualifiedName()); | 
|  | } | 
|  |  | 
|  | // Make sure the decl contexts match all the way up | 
|  | if (dwarf_decl_ctx == type_dwarf_decl_ctx) | 
|  | { | 
|  | Type *resolved_type = ResolveType (type_cu, type_die, false); | 
|  | if (resolved_type && resolved_type != DIE_IS_BEING_PARSED) | 
|  | { | 
|  | type_sp = resolved_type->shared_from_this(); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | if (log) | 
|  | { | 
|  | std::string qualified_name; | 
|  | type_die->GetQualifiedName(this, type_cu, qualified_name); | 
|  | GetObjectFile()->GetModule()->LogMessage (log, | 
|  | "SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext(tag=%s, qualified-name='%s') ignoring die=0x%8.8x (%s)", | 
|  | DW_TAG_value_to_name(dwarf_decl_ctx[0].tag), | 
|  | dwarf_decl_ctx.GetQualifiedName(), | 
|  | type_die->GetOffset(), | 
|  | qualified_name.c_str()); | 
|  | } | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | if (m_using_apple_tables) | 
|  | { | 
|  | GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_types accelerator table had bad die 0x%8.8x for '%s')\n", | 
|  | die_offset, type_name.GetCString()); | 
|  | } | 
|  | } | 
|  |  | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | return type_sp; | 
|  | } | 
|  |  | 
|  | bool | 
|  | SymbolFileDWARF::CopyUniqueClassMethodTypes (SymbolFileDWARF *src_symfile, | 
|  | Type *class_type, | 
|  | DWARFCompileUnit* src_cu, | 
|  | const DWARFDebugInfoEntry *src_class_die, | 
|  | DWARFCompileUnit* dst_cu, | 
|  | const DWARFDebugInfoEntry *dst_class_die, | 
|  | DWARFDIECollection &failures) | 
|  | { | 
|  | if (!class_type || !src_cu || !src_class_die || !dst_cu || !dst_class_die) | 
|  | return false; | 
|  | if (src_class_die->Tag() != dst_class_die->Tag()) | 
|  | return false; | 
|  |  | 
|  | // We need to complete the class type so we can get all of the method types | 
|  | // parsed so we can then unique those types to their equivalent counterparts | 
|  | // in "dst_cu" and "dst_class_die" | 
|  | class_type->GetClangFullType(); | 
|  |  | 
|  | const DWARFDebugInfoEntry *src_die; | 
|  | const DWARFDebugInfoEntry *dst_die; | 
|  | UniqueCStringMap<const DWARFDebugInfoEntry *> src_name_to_die; | 
|  | UniqueCStringMap<const DWARFDebugInfoEntry *> dst_name_to_die; | 
|  | UniqueCStringMap<const DWARFDebugInfoEntry *> src_name_to_die_artificial; | 
|  | UniqueCStringMap<const DWARFDebugInfoEntry *> dst_name_to_die_artificial; | 
|  | for (src_die = src_class_die->GetFirstChild(); src_die != NULL; src_die = src_die->GetSibling()) | 
|  | { | 
|  | if (src_die->Tag() == DW_TAG_subprogram) | 
|  | { | 
|  | // Make sure this is a declaration and not a concrete instance by looking | 
|  | // for DW_AT_declaration set to 1. Sometimes concrete function instances | 
|  | // are placed inside the class definitions and shouldn't be included in | 
|  | // the list of things are are tracking here. | 
|  | if (src_die->GetAttributeValueAsUnsigned(src_symfile, src_cu, DW_AT_declaration, 0) == 1) | 
|  | { | 
|  | const char *src_name = src_die->GetMangledName (src_symfile, src_cu); | 
|  | if (src_name) | 
|  | { | 
|  | ConstString src_const_name(src_name); | 
|  | if (src_die->GetAttributeValueAsUnsigned(src_symfile, src_cu, DW_AT_artificial, 0)) | 
|  | src_name_to_die_artificial.Append(src_const_name.GetCString(), src_die); | 
|  | else | 
|  | src_name_to_die.Append(src_const_name.GetCString(), src_die); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | for (dst_die = dst_class_die->GetFirstChild(); dst_die != NULL; dst_die = dst_die->GetSibling()) | 
|  | { | 
|  | if (dst_die->Tag() == DW_TAG_subprogram) | 
|  | { | 
|  | // Make sure this is a declaration and not a concrete instance by looking | 
|  | // for DW_AT_declaration set to 1. Sometimes concrete function instances | 
|  | // are placed inside the class definitions and shouldn't be included in | 
|  | // the list of things are are tracking here. | 
|  | if (dst_die->GetAttributeValueAsUnsigned(this, dst_cu, DW_AT_declaration, 0) == 1) | 
|  | { | 
|  | const char *dst_name = dst_die->GetMangledName (this, dst_cu); | 
|  | if (dst_name) | 
|  | { | 
|  | ConstString dst_const_name(dst_name); | 
|  | if (dst_die->GetAttributeValueAsUnsigned(this, dst_cu, DW_AT_artificial, 0)) | 
|  | dst_name_to_die_artificial.Append(dst_const_name.GetCString(), dst_die); | 
|  | else | 
|  | dst_name_to_die.Append(dst_const_name.GetCString(), dst_die); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | const uint32_t src_size = src_name_to_die.GetSize (); | 
|  | const uint32_t dst_size = dst_name_to_die.GetSize (); | 
|  | Log *log (LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO | DWARF_LOG_TYPE_COMPLETION)); | 
|  |  | 
|  | // Is everything kosher so we can go through the members at top speed? | 
|  | bool fast_path = true; | 
|  |  | 
|  | if (src_size != dst_size) | 
|  | { | 
|  | if (src_size != 0 && dst_size != 0) | 
|  | { | 
|  | if (log) | 
|  | log->Printf("warning: trying to unique class DIE 0x%8.8x to 0x%8.8x, but they didn't have the same size (src=%d, dst=%d)", | 
|  | src_class_die->GetOffset(), | 
|  | dst_class_die->GetOffset(), | 
|  | src_size, | 
|  | dst_size); | 
|  | } | 
|  |  | 
|  | fast_path = false; | 
|  | } | 
|  |  | 
|  | uint32_t idx; | 
|  |  | 
|  | if (fast_path) | 
|  | { | 
|  | for (idx = 0; idx < src_size; ++idx) | 
|  | { | 
|  | src_die = src_name_to_die.GetValueAtIndexUnchecked (idx); | 
|  | dst_die = dst_name_to_die.GetValueAtIndexUnchecked (idx); | 
|  |  | 
|  | if (src_die->Tag() != dst_die->Tag()) | 
|  | { | 
|  | if (log) | 
|  | log->Printf("warning: tried to unique class DIE 0x%8.8x to 0x%8.8x, but 0x%8.8x (%s) tags didn't match 0x%8.8x (%s)", | 
|  | src_class_die->GetOffset(), | 
|  | dst_class_die->GetOffset(), | 
|  | src_die->GetOffset(), | 
|  | DW_TAG_value_to_name(src_die->Tag()), | 
|  | dst_die->GetOffset(), | 
|  | DW_TAG_value_to_name(src_die->Tag())); | 
|  | fast_path = false; | 
|  | } | 
|  |  | 
|  | const char *src_name = src_die->GetMangledName (src_symfile, src_cu); | 
|  | const char *dst_name = dst_die->GetMangledName (this, dst_cu); | 
|  |  | 
|  | // Make sure the names match | 
|  | if (src_name == dst_name || (strcmp (src_name, dst_name) == 0)) | 
|  | continue; | 
|  |  | 
|  | if (log) | 
|  | log->Printf("warning: tried to unique class DIE 0x%8.8x to 0x%8.8x, but 0x%8.8x (%s) names didn't match 0x%8.8x (%s)", | 
|  | src_class_die->GetOffset(), | 
|  | dst_class_die->GetOffset(), | 
|  | src_die->GetOffset(), | 
|  | src_name, | 
|  | dst_die->GetOffset(), | 
|  | dst_name); | 
|  |  | 
|  | fast_path = false; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Now do the work of linking the DeclContexts and Types. | 
|  | if (fast_path) | 
|  | { | 
|  | // We can do this quickly.  Just run across the tables index-for-index since | 
|  | // we know each node has matching names and tags. | 
|  | for (idx = 0; idx < src_size; ++idx) | 
|  | { | 
|  | src_die = src_name_to_die.GetValueAtIndexUnchecked (idx); | 
|  | dst_die = dst_name_to_die.GetValueAtIndexUnchecked (idx); | 
|  |  | 
|  | clang::DeclContext *src_decl_ctx = src_symfile->m_die_to_decl_ctx[src_die]; | 
|  | if (src_decl_ctx) | 
|  | { | 
|  | if (log) | 
|  | log->Printf ("uniquing decl context %p from 0x%8.8x for 0x%8.8x", | 
|  | static_cast<void*>(src_decl_ctx), | 
|  | src_die->GetOffset(), dst_die->GetOffset()); | 
|  | LinkDeclContextToDIE (src_decl_ctx, dst_die); | 
|  | } | 
|  | else | 
|  | { | 
|  | if (log) | 
|  | log->Printf ("warning: tried to unique decl context from 0x%8.8x for 0x%8.8x, but none was found", | 
|  | src_die->GetOffset(), dst_die->GetOffset()); | 
|  | } | 
|  |  | 
|  | Type *src_child_type = m_die_to_type[src_die]; | 
|  | if (src_child_type) | 
|  | { | 
|  | if (log) | 
|  | log->Printf ("uniquing type %p (uid=0x%" PRIx64 ") from 0x%8.8x for 0x%8.8x", | 
|  | static_cast<void*>(src_child_type), | 
|  | src_child_type->GetID(), | 
|  | src_die->GetOffset(), dst_die->GetOffset()); | 
|  | m_die_to_type[dst_die] = src_child_type; | 
|  | } | 
|  | else | 
|  | { | 
|  | if (log) | 
|  | log->Printf ("warning: tried to unique lldb_private::Type from 0x%8.8x for 0x%8.8x, but none was found", src_die->GetOffset(), dst_die->GetOffset()); | 
|  | } | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | // We must do this slowly.  For each member of the destination, look | 
|  | // up a member in the source with the same name, check its tag, and | 
|  | // unique them if everything matches up.  Report failures. | 
|  |  | 
|  | if (!src_name_to_die.IsEmpty() && !dst_name_to_die.IsEmpty()) | 
|  | { | 
|  | src_name_to_die.Sort(); | 
|  |  | 
|  | for (idx = 0; idx < dst_size; ++idx) | 
|  | { | 
|  | const char *dst_name = dst_name_to_die.GetCStringAtIndex(idx); | 
|  | dst_die = dst_name_to_die.GetValueAtIndexUnchecked(idx); | 
|  | src_die = src_name_to_die.Find(dst_name, NULL); | 
|  |  | 
|  | if (src_die && (src_die->Tag() == dst_die->Tag())) | 
|  | { | 
|  | clang::DeclContext *src_decl_ctx = src_symfile->m_die_to_decl_ctx[src_die]; | 
|  | if (src_decl_ctx) | 
|  | { | 
|  | if (log) | 
|  | log->Printf ("uniquing decl context %p from 0x%8.8x for 0x%8.8x", | 
|  | static_cast<void*>(src_decl_ctx), | 
|  | src_die->GetOffset(), | 
|  | dst_die->GetOffset()); | 
|  | LinkDeclContextToDIE (src_decl_ctx, dst_die); | 
|  | } | 
|  | else | 
|  | { | 
|  | if (log) | 
|  | log->Printf ("warning: tried to unique decl context from 0x%8.8x for 0x%8.8x, but none was found", src_die->GetOffset(), dst_die->GetOffset()); | 
|  | } | 
|  |  | 
|  | Type *src_child_type = m_die_to_type[src_die]; | 
|  | if (src_child_type) | 
|  | { | 
|  | if (log) | 
|  | log->Printf ("uniquing type %p (uid=0x%" PRIx64 ") from 0x%8.8x for 0x%8.8x", | 
|  | static_cast<void*>(src_child_type), | 
|  | src_child_type->GetID(), | 
|  | src_die->GetOffset(), | 
|  | dst_die->GetOffset()); | 
|  | m_die_to_type[dst_die] = src_child_type; | 
|  | } | 
|  | else | 
|  | { | 
|  | if (log) | 
|  | log->Printf ("warning: tried to unique lldb_private::Type from 0x%8.8x for 0x%8.8x, but none was found", src_die->GetOffset(), dst_die->GetOffset()); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | if (log) | 
|  | log->Printf ("warning: couldn't find a match for 0x%8.8x", dst_die->GetOffset()); | 
|  |  | 
|  | failures.Append(dst_die); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | const uint32_t src_size_artificial = src_name_to_die_artificial.GetSize (); | 
|  | const uint32_t dst_size_artificial = dst_name_to_die_artificial.GetSize (); | 
|  |  | 
|  | UniqueCStringMap<const DWARFDebugInfoEntry *> name_to_die_artificial_not_in_src; | 
|  |  | 
|  | if (src_size_artificial && dst_size_artificial) | 
|  | { | 
|  | dst_name_to_die_artificial.Sort(); | 
|  |  | 
|  | for (idx = 0; idx < src_size_artificial; ++idx) | 
|  | { | 
|  | const char *src_name_artificial = src_name_to_die_artificial.GetCStringAtIndex(idx); | 
|  | src_die = src_name_to_die_artificial.GetValueAtIndexUnchecked (idx); | 
|  | dst_die = dst_name_to_die_artificial.Find(src_name_artificial, NULL); | 
|  |  | 
|  | if (dst_die) | 
|  | { | 
|  | // Both classes have the artificial types, link them | 
|  | clang::DeclContext *src_decl_ctx = m_die_to_decl_ctx[src_die]; | 
|  | if (src_decl_ctx) | 
|  | { | 
|  | if (log) | 
|  | log->Printf ("uniquing decl context %p from 0x%8.8x for 0x%8.8x", | 
|  | static_cast<void*>(src_decl_ctx), | 
|  | src_die->GetOffset(), dst_die->GetOffset()); | 
|  | LinkDeclContextToDIE (src_decl_ctx, dst_die); | 
|  | } | 
|  | else | 
|  | { | 
|  | if (log) | 
|  | log->Printf ("warning: tried to unique decl context from 0x%8.8x for 0x%8.8x, but none was found", src_die->GetOffset(), dst_die->GetOffset()); | 
|  | } | 
|  |  | 
|  | Type *src_child_type = m_die_to_type[src_die]; | 
|  | if (src_child_type) | 
|  | { | 
|  | if (log) | 
|  | log->Printf ("uniquing type %p (uid=0x%" PRIx64 ") from 0x%8.8x for 0x%8.8x", | 
|  | static_cast<void*>(src_child_type), | 
|  | src_child_type->GetID(), | 
|  | src_die->GetOffset(), dst_die->GetOffset()); | 
|  | m_die_to_type[dst_die] = src_child_type; | 
|  | } | 
|  | else | 
|  | { | 
|  | if (log) | 
|  | log->Printf ("warning: tried to unique lldb_private::Type from 0x%8.8x for 0x%8.8x, but none was found", src_die->GetOffset(), dst_die->GetOffset()); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (dst_size_artificial) | 
|  | { | 
|  | for (idx = 0; idx < dst_size_artificial; ++idx) | 
|  | { | 
|  | const char *dst_name_artificial = dst_name_to_die_artificial.GetCStringAtIndex(idx); | 
|  | dst_die = dst_name_to_die_artificial.GetValueAtIndexUnchecked (idx); | 
|  | if (log) | 
|  | log->Printf ("warning: need to create artificial method for 0x%8.8x for method '%s'", dst_die->GetOffset(), dst_name_artificial); | 
|  |  | 
|  | failures.Append(dst_die); | 
|  | } | 
|  | } | 
|  |  | 
|  | return (failures.Size() != 0); | 
|  | } | 
|  |  | 
|  | TypeSP | 
|  | SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die, bool *type_is_new_ptr) | 
|  | { | 
|  | TypeSP type_sp; | 
|  |  | 
|  | if (type_is_new_ptr) | 
|  | *type_is_new_ptr = false; | 
|  |  | 
|  | #if defined(LLDB_CONFIGURATION_DEBUG) || defined(LLDB_CONFIGURATION_RELEASE) | 
|  | static DIEStack g_die_stack; | 
|  | DIEStack::ScopedPopper scoped_die_logger(g_die_stack); | 
|  | #endif | 
|  |  | 
|  | AccessType accessibility = eAccessNone; | 
|  | if (die != NULL) | 
|  | { | 
|  | Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO)); | 
|  | if (log) | 
|  | { | 
|  | const DWARFDebugInfoEntry *context_die; | 
|  | clang::DeclContext *context = GetClangDeclContextContainingDIE (dwarf_cu, die, &context_die); | 
|  |  | 
|  | GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::ParseType (die = 0x%8.8x, decl_ctx = %p (die 0x%8.8x)) %s name = '%s')", | 
|  | die->GetOffset(), | 
|  | static_cast<void*>(context), | 
|  | context_die->GetOffset(), | 
|  | DW_TAG_value_to_name(die->Tag()), | 
|  | die->GetName(this, dwarf_cu)); | 
|  |  | 
|  | #if defined(LLDB_CONFIGURATION_DEBUG) || defined(LLDB_CONFIGURATION_RELEASE) | 
|  | scoped_die_logger.Push (dwarf_cu, die); | 
|  | g_die_stack.LogDIEs(log, this); | 
|  | #endif | 
|  | } | 
|  | // | 
|  | //        Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO)); | 
|  | //        if (log && dwarf_cu) | 
|  | //        { | 
|  | //            StreamString s; | 
|  | //            die->DumpLocation (this, dwarf_cu, s); | 
|  | //            GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDwarf::%s %s", __FUNCTION__, s.GetData()); | 
|  | // | 
|  | //        } | 
|  |  | 
|  | Type *type_ptr = m_die_to_type.lookup (die); | 
|  | TypeList* type_list = GetTypeList(); | 
|  | if (type_ptr == NULL) | 
|  | { | 
|  | ClangASTContext &ast = GetClangASTContext(); | 
|  | if (type_is_new_ptr) | 
|  | *type_is_new_ptr = true; | 
|  |  | 
|  | const dw_tag_t tag = die->Tag(); | 
|  |  | 
|  | bool is_forward_declaration = false; | 
|  | DWARFDebugInfoEntry::Attributes attributes; | 
|  | const char *type_name_cstr = NULL; | 
|  | ConstString type_name_const_str; | 
|  | Type::ResolveState resolve_state = Type::eResolveStateUnresolved; | 
|  | uint64_t byte_size = 0; | 
|  | Declaration decl; | 
|  |  | 
|  | Type::EncodingDataType encoding_data_type = Type::eEncodingIsUID; | 
|  | ClangASTType clang_type; | 
|  | DWARFFormValue form_value; | 
|  |  | 
|  | dw_attr_t attr; | 
|  |  | 
|  | switch (tag) | 
|  | { | 
|  | case DW_TAG_base_type: | 
|  | case DW_TAG_pointer_type: | 
|  | case DW_TAG_reference_type: | 
|  | case DW_TAG_rvalue_reference_type: | 
|  | case DW_TAG_typedef: | 
|  | case DW_TAG_const_type: | 
|  | case DW_TAG_restrict_type: | 
|  | case DW_TAG_volatile_type: | 
|  | case DW_TAG_unspecified_type: | 
|  | { | 
|  | // Set a bit that lets us know that we are currently parsing this | 
|  | m_die_to_type[die] = DIE_IS_BEING_PARSED; | 
|  |  | 
|  | const size_t num_attributes = die->GetAttributes(this, dwarf_cu, NULL, attributes); | 
|  | uint32_t encoding = 0; | 
|  | lldb::user_id_t encoding_uid = LLDB_INVALID_UID; | 
|  |  | 
|  | if (num_attributes > 0) | 
|  | { | 
|  | uint32_t i; | 
|  | for (i=0; i<num_attributes; ++i) | 
|  | { | 
|  | attr = attributes.AttributeAtIndex(i); | 
|  | if (attributes.ExtractFormValueAtIndex(this, i, form_value)) | 
|  | { | 
|  | switch (attr) | 
|  | { | 
|  | case DW_AT_decl_file:   decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break; | 
|  | case DW_AT_decl_line:   decl.SetLine(form_value.Unsigned()); break; | 
|  | case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break; | 
|  | case DW_AT_name: | 
|  |  | 
|  | type_name_cstr = form_value.AsCString(&get_debug_str_data()); | 
|  | // Work around a bug in llvm-gcc where they give a name to a reference type which doesn't | 
|  | // include the "&"... | 
|  | if (tag == DW_TAG_reference_type) | 
|  | { | 
|  | if (strchr (type_name_cstr, '&') == NULL) | 
|  | type_name_cstr = NULL; | 
|  | } | 
|  | if (type_name_cstr) | 
|  | type_name_const_str.SetCString(type_name_cstr); | 
|  | break; | 
|  | case DW_AT_byte_size:   byte_size = form_value.Unsigned(); break; | 
|  | case DW_AT_encoding:    encoding = form_value.Unsigned(); break; | 
|  | case DW_AT_type:        encoding_uid = form_value.Reference(dwarf_cu); break; | 
|  | default: | 
|  | case DW_AT_sibling: | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | DEBUG_PRINTF ("0x%8.8" PRIx64 ": %s (\"%s\") type => 0x%8.8lx\n", MakeUserID(die->GetOffset()), DW_TAG_value_to_name(tag), type_name_cstr, encoding_uid); | 
|  |  | 
|  | switch (tag) | 
|  | { | 
|  | default: | 
|  | break; | 
|  |  | 
|  | case DW_TAG_unspecified_type: | 
|  | if (strcmp(type_name_cstr, "nullptr_t") == 0 || | 
|  | strcmp(type_name_cstr, "decltype(nullptr)") == 0 ) | 
|  | { | 
|  | resolve_state = Type::eResolveStateFull; | 
|  | clang_type = ast.GetBasicType(eBasicTypeNullPtr); | 
|  | break; | 
|  | } | 
|  | // Fall through to base type below in case we can handle the type there... | 
|  |  | 
|  | case DW_TAG_base_type: | 
|  | resolve_state = Type::eResolveStateFull; | 
|  | clang_type = ast.GetBuiltinTypeForDWARFEncodingAndBitSize (type_name_cstr, | 
|  | encoding, | 
|  | byte_size * 8); | 
|  | break; | 
|  |  | 
|  | case DW_TAG_pointer_type:           encoding_data_type = Type::eEncodingIsPointerUID;           break; | 
|  | case DW_TAG_reference_type:         encoding_data_type = Type::eEncodingIsLValueReferenceUID;   break; | 
|  | case DW_TAG_rvalue_reference_type:  encoding_data_type = Type::eEncodingIsRValueReferenceUID;   break; | 
|  | case DW_TAG_typedef:                encoding_data_type = Type::eEncodingIsTypedefUID;           break; | 
|  | case DW_TAG_const_type:             encoding_data_type = Type::eEncodingIsConstUID;             break; | 
|  | case DW_TAG_restrict_type:          encoding_data_type = Type::eEncodingIsRestrictUID;          break; | 
|  | case DW_TAG_volatile_type:          encoding_data_type = Type::eEncodingIsVolatileUID;          break; | 
|  | } | 
|  |  | 
|  | if (!clang_type && (encoding_data_type == Type::eEncodingIsPointerUID || encoding_data_type == Type::eEncodingIsTypedefUID) && sc.comp_unit != NULL) | 
|  | { | 
|  | bool translation_unit_is_objc = (sc.comp_unit->GetLanguage() == eLanguageTypeObjC || sc.comp_unit->GetLanguage() == eLanguageTypeObjC_plus_plus); | 
|  |  | 
|  | if (translation_unit_is_objc) | 
|  | { | 
|  | if (type_name_cstr != NULL) | 
|  | { | 
|  | static ConstString g_objc_type_name_id("id"); | 
|  | static ConstString g_objc_type_name_Class("Class"); | 
|  | static ConstString g_objc_type_name_selector("SEL"); | 
|  |  | 
|  | if (type_name_const_str == g_objc_type_name_id) | 
|  | { | 
|  | if (log) | 
|  | GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' is Objective C 'id' built-in type.", | 
|  | die->GetOffset(), | 
|  | DW_TAG_value_to_name(die->Tag()), | 
|  | die->GetName(this, dwarf_cu)); | 
|  | clang_type = ast.GetBasicType(eBasicTypeObjCID); | 
|  | encoding_data_type = Type::eEncodingIsUID; | 
|  | encoding_uid = LLDB_INVALID_UID; | 
|  | resolve_state = Type::eResolveStateFull; | 
|  |  | 
|  | } | 
|  | else if (type_name_const_str == g_objc_type_name_Class) | 
|  | { | 
|  | if (log) | 
|  | GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' is Objective C 'Class' built-in type.", | 
|  | die->GetOffset(), | 
|  | DW_TAG_value_to_name(die->Tag()), | 
|  | die->GetName(this, dwarf_cu)); | 
|  | clang_type = ast.GetBasicType(eBasicTypeObjCClass); | 
|  | encoding_data_type = Type::eEncodingIsUID; | 
|  | encoding_uid = LLDB_INVALID_UID; | 
|  | resolve_state = Type::eResolveStateFull; | 
|  | } | 
|  | else if (type_name_const_str == g_objc_type_name_selector) | 
|  | { | 
|  | if (log) | 
|  | GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' is Objective C 'selector' built-in type.", | 
|  | die->GetOffset(), | 
|  | DW_TAG_value_to_name(die->Tag()), | 
|  | die->GetName(this, dwarf_cu)); | 
|  | clang_type = ast.GetBasicType(eBasicTypeObjCSel); | 
|  | encoding_data_type = Type::eEncodingIsUID; | 
|  | encoding_uid = LLDB_INVALID_UID; | 
|  | resolve_state = Type::eResolveStateFull; | 
|  | } | 
|  | } | 
|  | else if (encoding_data_type == Type::eEncodingIsPointerUID && encoding_uid != LLDB_INVALID_UID) | 
|  | { | 
|  | // Clang sometimes erroneously emits id as objc_object*.  In that case we fix up the type to "id". | 
|  |  | 
|  | DWARFDebugInfoEntry* encoding_die = dwarf_cu->GetDIEPtr(encoding_uid); | 
|  |  | 
|  | if (encoding_die && encoding_die->Tag() == DW_TAG_structure_type) | 
|  | { | 
|  | if (const char *struct_name = encoding_die->GetAttributeValueAsString(this, dwarf_cu, DW_AT_name, NULL)) | 
|  | { | 
|  | if (!strcmp(struct_name, "objc_object")) | 
|  | { | 
|  | if (log) | 
|  | GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' is 'objc_object*', which we overrode to 'id'.", | 
|  | die->GetOffset(), | 
|  | DW_TAG_value_to_name(die->Tag()), | 
|  | die->GetName(this, dwarf_cu)); | 
|  | clang_type = ast.GetBasicType(eBasicTypeObjCID); | 
|  | encoding_data_type = Type::eEncodingIsUID; | 
|  | encoding_uid = LLDB_INVALID_UID; | 
|  | resolve_state = Type::eResolveStateFull; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | type_sp.reset( new Type (MakeUserID(die->GetOffset()), | 
|  | this, | 
|  | type_name_const_str, | 
|  | byte_size, | 
|  | NULL, | 
|  | encoding_uid, | 
|  | encoding_data_type, | 
|  | &decl, | 
|  | clang_type, | 
|  | resolve_state)); | 
|  |  | 
|  | m_die_to_type[die] = type_sp.get(); | 
|  |  | 
|  | //                  Type* encoding_type = GetUniquedTypeForDIEOffset(encoding_uid, type_sp, NULL, 0, 0, false); | 
|  | //                  if (encoding_type != NULL) | 
|  | //                  { | 
|  | //                      if (encoding_type != DIE_IS_BEING_PARSED) | 
|  | //                          type_sp->SetEncodingType(encoding_type); | 
|  | //                      else | 
|  | //                          m_indirect_fixups.push_back(type_sp.get()); | 
|  | //                  } | 
|  | } | 
|  | break; | 
|  |  | 
|  | case DW_TAG_structure_type: | 
|  | case DW_TAG_union_type: | 
|  | case DW_TAG_class_type: | 
|  | { | 
|  | // Set a bit that lets us know that we are currently parsing this | 
|  | m_die_to_type[die] = DIE_IS_BEING_PARSED; | 
|  | bool byte_size_valid = false; | 
|  |  | 
|  | LanguageType class_language = eLanguageTypeUnknown; | 
|  | bool is_complete_objc_class = false; | 
|  | //bool struct_is_class = false; | 
|  | const size_t num_attributes = die->GetAttributes(this, dwarf_cu, NULL, attributes); | 
|  | if (num_attributes > 0) | 
|  | { | 
|  | uint32_t i; | 
|  | for (i=0; i<num_attributes; ++i) | 
|  | { | 
|  | attr = attributes.AttributeAtIndex(i); | 
|  | if (attributes.ExtractFormValueAtIndex(this, i, form_value)) | 
|  | { | 
|  | switch (attr) | 
|  | { | 
|  | case DW_AT_decl_file: | 
|  | if (dwarf_cu->DW_AT_decl_file_attributes_are_invalid()) | 
|  | { | 
|  | // llvm-gcc outputs invalid DW_AT_decl_file attributes that always | 
|  | // point to the compile unit file, so we clear this invalid value | 
|  | // so that we can still unique types efficiently. | 
|  | decl.SetFile(FileSpec ("<invalid>", false)); | 
|  | } | 
|  | else | 
|  | decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); | 
|  | break; | 
|  |  | 
|  | case DW_AT_decl_line: | 
|  | decl.SetLine(form_value.Unsigned()); | 
|  | break; | 
|  |  | 
|  | case DW_AT_decl_column: | 
|  | decl.SetColumn(form_value.Unsigned()); | 
|  | break; | 
|  |  | 
|  | case DW_AT_name: | 
|  | type_name_cstr = form_value.AsCString(&get_debug_str_data()); | 
|  | type_name_const_str.SetCString(type_name_cstr); | 
|  | break; | 
|  |  | 
|  | case DW_AT_byte_size: | 
|  | byte_size = form_value.Unsigned(); | 
|  | byte_size_valid = true; | 
|  | break; | 
|  |  | 
|  | case DW_AT_accessibility: | 
|  | accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned()); | 
|  | break; | 
|  |  | 
|  | case DW_AT_declaration: | 
|  | is_forward_declaration = form_value.Boolean(); | 
|  | break; | 
|  |  | 
|  | case DW_AT_APPLE_runtime_class: | 
|  | class_language = (LanguageType)form_value.Signed(); | 
|  | break; | 
|  |  | 
|  | case DW_AT_APPLE_objc_complete_type: | 
|  | is_complete_objc_class = form_value.Signed(); | 
|  | break; | 
|  |  | 
|  | case DW_AT_allocated: | 
|  | case DW_AT_associated: | 
|  | case DW_AT_data_location: | 
|  | case DW_AT_description: | 
|  | case DW_AT_start_scope: | 
|  | case DW_AT_visibility: | 
|  | default: | 
|  | case DW_AT_sibling: | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // UniqueDWARFASTType is large, so don't create a local variables on the | 
|  | // stack, put it on the heap. This function is often called recursively | 
|  | // and clang isn't good and sharing the stack space for variables in different blocks. | 
|  | std::unique_ptr<UniqueDWARFASTType> unique_ast_entry_ap(new UniqueDWARFASTType()); | 
|  |  | 
|  | // Only try and unique the type if it has a name. | 
|  | if (type_name_const_str && | 
|  | GetUniqueDWARFASTTypeMap().Find (type_name_const_str, | 
|  | this, | 
|  | dwarf_cu, | 
|  | die, | 
|  | decl, | 
|  | byte_size_valid ? byte_size : -1, | 
|  | *unique_ast_entry_ap)) | 
|  | { | 
|  | // We have already parsed this type or from another | 
|  | // compile unit. GCC loves to use the "one definition | 
|  | // rule" which can result in multiple definitions | 
|  | // of the same class over and over in each compile | 
|  | // unit. | 
|  | type_sp = unique_ast_entry_ap->m_type_sp; | 
|  | if (type_sp) | 
|  | { | 
|  | m_die_to_type[die] = type_sp.get(); | 
|  | return type_sp; | 
|  | } | 
|  | } | 
|  |  | 
|  | DEBUG_PRINTF ("0x%8.8" PRIx64 ": %s (\"%s\")\n", MakeUserID(die->GetOffset()), DW_TAG_value_to_name(tag), type_name_cstr); | 
|  |  | 
|  | int tag_decl_kind = -1; | 
|  | AccessType default_accessibility = eAccessNone; | 
|  | if (tag == DW_TAG_structure_type) | 
|  | { | 
|  | tag_decl_kind = clang::TTK_Struct; | 
|  | default_accessibility = eAccessPublic; | 
|  | } | 
|  | else if (tag == DW_TAG_union_type) | 
|  | { | 
|  | tag_decl_kind = clang::TTK_Union; | 
|  | default_accessibility = eAccessPublic; | 
|  | } | 
|  | else if (tag == DW_TAG_class_type) | 
|  | { | 
|  | tag_decl_kind = clang::TTK_Class; | 
|  | default_accessibility = eAccessPrivate; | 
|  | } | 
|  |  | 
|  | if (byte_size_valid && byte_size == 0 && type_name_cstr && | 
|  | die->HasChildren() == false && | 
|  | sc.comp_unit->GetLanguage() == eLanguageTypeObjC) | 
|  | { | 
|  | // Work around an issue with clang at the moment where | 
|  | // forward declarations for objective C classes are emitted | 
|  | // as: | 
|  | //  DW_TAG_structure_type [2] | 
|  | //  DW_AT_name( "ForwardObjcClass" ) | 
|  | //  DW_AT_byte_size( 0x00 ) | 
|  | //  DW_AT_decl_file( "..." ) | 
|  | //  DW_AT_decl_line( 1 ) | 
|  | // | 
|  | // Note that there is no DW_AT_declaration and there are | 
|  | // no children, and the byte size is zero. | 
|  | is_forward_declaration = true; | 
|  | } | 
|  |  | 
|  | if (class_language == eLanguageTypeObjC || | 
|  | class_language == eLanguageTypeObjC_plus_plus) | 
|  | { | 
|  | if (!is_complete_objc_class && Supports_DW_AT_APPLE_objc_complete_type(dwarf_cu)) | 
|  | { | 
|  | // We have a valid eSymbolTypeObjCClass class symbol whose | 
|  | // name matches the current objective C class that we | 
|  | // are trying to find and this DIE isn't the complete | 
|  | // definition (we checked is_complete_objc_class above and | 
|  | // know it is false), so the real definition is in here somewhere | 
|  | type_sp = FindCompleteObjCDefinitionTypeForDIE (die, type_name_const_str, true); | 
|  |  | 
|  | if (!type_sp && GetDebugMapSymfile ()) | 
|  | { | 
|  | // We weren't able to find a full declaration in | 
|  | // this DWARF, see if we have a declaration anywhere | 
|  | // else... | 
|  | type_sp = m_debug_map_symfile->FindCompleteObjCDefinitionTypeForDIE (die, type_name_const_str, true); | 
|  | } | 
|  |  | 
|  | if (type_sp) | 
|  | { | 
|  | if (log) | 
|  | { | 
|  | GetObjectFile()->GetModule()->LogMessage (log, | 
|  | "SymbolFileDWARF(%p) - 0x%8.8x: %s type \"%s\" is an incomplete objc type, complete type is 0x%8.8" PRIx64, | 
|  | static_cast<void*>(this), | 
|  | die->GetOffset(), | 
|  | DW_TAG_value_to_name(tag), | 
|  | type_name_cstr, | 
|  | type_sp->GetID()); | 
|  | } | 
|  |  | 
|  | // We found a real definition for this type elsewhere | 
|  | // so lets use it and cache the fact that we found | 
|  | // a complete type for this die | 
|  | m_die_to_type[die] = type_sp.get(); | 
|  | return type_sp; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | if (is_forward_declaration) | 
|  | { | 
|  | // We have a forward declaration to a type and we need | 
|  | // to try and find a full declaration. We look in the | 
|  | // current type index just in case we have a forward | 
|  | // declaration followed by an actual declarations in the | 
|  | // DWARF. If this fails, we need to look elsewhere... | 
|  | if (log) | 
|  | { | 
|  | GetObjectFile()->GetModule()->LogMessage (log, | 
|  | "SymbolFileDWARF(%p) - 0x%8.8x: %s type \"%s\" is a forward declaration, trying to find complete type", | 
|  | static_cast<void*>(this), | 
|  | die->GetOffset(), | 
|  | DW_TAG_value_to_name(tag), | 
|  | type_name_cstr); | 
|  | } | 
|  |  | 
|  | DWARFDeclContext die_decl_ctx; | 
|  | die->GetDWARFDeclContext(this, dwarf_cu, die_decl_ctx); | 
|  |  | 
|  | //type_sp = FindDefinitionTypeForDIE (dwarf_cu, die, type_name_const_str); | 
|  | type_sp = FindDefinitionTypeForDWARFDeclContext (die_decl_ctx); | 
|  |  | 
|  | if (!type_sp && GetDebugMapSymfile ()) | 
|  | { | 
|  | // We weren't able to find a full declaration in | 
|  | // this DWARF, see if we have a declaration anywhere | 
|  | // else... | 
|  | type_sp = m_debug_map_symfile->FindDefinitionTypeForDWARFDeclContext (die_decl_ctx); | 
|  | } | 
|  |  | 
|  | if (type_sp) | 
|  | { | 
|  | if (log) | 
|  | { | 
|  | GetObjectFile()->GetModule()->LogMessage (log, | 
|  | "SymbolFileDWARF(%p) - 0x%8.8x: %s type \"%s\" is a forward declaration, complete type is 0x%8.8" PRIx64, | 
|  | static_cast<void*>(this), | 
|  | die->GetOffset(), | 
|  | DW_TAG_value_to_name(tag), | 
|  | type_name_cstr, | 
|  | type_sp->GetID()); | 
|  | } | 
|  |  | 
|  | // We found a real definition for this type elsewhere | 
|  | // so lets use it and cache the fact that we found | 
|  | // a complete type for this die | 
|  | m_die_to_type[die] = type_sp.get(); | 
|  | return type_sp; | 
|  | } | 
|  | } | 
|  | assert (tag_decl_kind != -1); | 
|  | bool clang_type_was_created = false; | 
|  | clang_type.SetClangType(ast.getASTContext(), m_forward_decl_die_to_clang_type.lookup (die)); | 
|  | if (!clang_type) | 
|  | { | 
|  | const DWARFDebugInfoEntry *decl_ctx_die; | 
|  |  | 
|  | clang::DeclContext *decl_ctx = GetClangDeclContextContainingDIE (dwarf_cu, die, &decl_ctx_die); | 
|  | if (accessibility == eAccessNone && decl_ctx) | 
|  | { | 
|  | // Check the decl context that contains this class/struct/union. | 
|  | // If it is a class we must give it an accessibility. | 
|  | const clang::Decl::Kind containing_decl_kind = decl_ctx->getDeclKind(); | 
|  | if (DeclKindIsCXXClass (containing_decl_kind)) | 
|  | accessibility = default_accessibility; | 
|  | } | 
|  |  | 
|  | ClangASTMetadata metadata; | 
|  | metadata.SetUserID(MakeUserID(die->GetOffset())); | 
|  | metadata.SetIsDynamicCXXType(ClassOrStructIsVirtual (dwarf_cu, die)); | 
|  |  | 
|  | if (type_name_cstr && strchr (type_name_cstr, '<')) | 
|  | { | 
|  | ClangASTContext::TemplateParameterInfos template_param_infos; | 
|  | if (ParseTemplateParameterInfos (dwarf_cu, die, template_param_infos)) | 
|  | { | 
|  | clang::ClassTemplateDecl *class_template_decl = ParseClassTemplateDecl (decl_ctx, | 
|  | accessibility, | 
|  | type_name_cstr, | 
|  | tag_decl_kind, | 
|  | template_param_infos); | 
|  |  | 
|  | clang::ClassTemplateSpecializationDecl *class_specialization_decl = ast.CreateClassTemplateSpecializationDecl (decl_ctx, | 
|  | class_template_decl, | 
|  | tag_decl_kind, | 
|  | template_param_infos); | 
|  | clang_type = ast.CreateClassTemplateSpecializationType (class_specialization_decl); | 
|  | clang_type_was_created = true; | 
|  |  | 
|  | GetClangASTContext().SetMetadata (class_template_decl, metadata); | 
|  | GetClangASTContext().SetMetadata (class_specialization_decl, metadata); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!clang_type_was_created) | 
|  | { | 
|  | clang_type_was_created = true; | 
|  | clang_type = ast.CreateRecordType (decl_ctx, | 
|  | accessibility, | 
|  | type_name_cstr, | 
|  | tag_decl_kind, | 
|  | class_language, | 
|  | &metadata); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Store a forward declaration to this class type in case any | 
|  | // parameters in any class methods need it for the clang | 
|  | // types for function prototypes. | 
|  | LinkDeclContextToDIE(clang_type.GetDeclContextForType(), die); | 
|  | type_sp.reset (new Type (MakeUserID(die->GetOffset()), | 
|  | this, | 
|  | type_name_const_str, | 
|  | byte_size, | 
|  | NULL, | 
|  | LLDB_INVALID_UID, | 
|  | Type::eEncodingIsUID, | 
|  | &decl, | 
|  | clang_type, | 
|  | Type::eResolveStateForward)); | 
|  |  | 
|  | type_sp->SetIsCompleteObjCClass(is_complete_objc_class); | 
|  |  | 
|  |  | 
|  | // Add our type to the unique type map so we don't | 
|  | // end up creating many copies of the same type over | 
|  | // and over in the ASTContext for our module | 
|  | unique_ast_entry_ap->m_type_sp = type_sp; | 
|  | unique_ast_entry_ap->m_symfile = this; | 
|  | unique_ast_entry_ap->m_cu = dwarf_cu; | 
|  | unique_ast_entry_ap->m_die = die; | 
|  | unique_ast_entry_ap->m_declaration = decl; | 
|  | unique_ast_entry_ap->m_byte_size = byte_size; | 
|  | GetUniqueDWARFASTTypeMap().Insert (type_name_const_str, | 
|  | *unique_ast_entry_ap); | 
|  |  | 
|  | if (is_forward_declaration && die->HasChildren()) | 
|  | { | 
|  | // Check to see if the DIE actually has a definition, some version of GCC will | 
|  | // emit DIEs with DW_AT_declaration set to true, but yet still have subprogram, | 
|  | // members, or inheritance, so we can't trust it | 
|  | const DWARFDebugInfoEntry *child_die = die->GetFirstChild(); | 
|  | while (child_die) | 
|  | { | 
|  | switch (child_die->Tag()) | 
|  | { | 
|  | case DW_TAG_inheritance: | 
|  | case DW_TAG_subprogram: | 
|  | case DW_TAG_member: | 
|  | case DW_TAG_APPLE_property: | 
|  | case DW_TAG_class_type: | 
|  | case DW_TAG_structure_type: | 
|  | case DW_TAG_enumeration_type: | 
|  | case DW_TAG_typedef: | 
|  | case DW_TAG_union_type: | 
|  | child_die = NULL; | 
|  | is_forward_declaration = false; | 
|  | break; | 
|  | default: | 
|  | child_die = child_die->GetSibling(); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!is_forward_declaration) | 
|  | { | 
|  | // Always start the definition for a class type so that | 
|  | // if the class has child classes or types that require | 
|  | // the class to be created for use as their decl contexts | 
|  | // the class will be ready to accept these child definitions. | 
|  | if (die->HasChildren() == false) | 
|  | { | 
|  | // No children for this struct/union/class, lets finish it | 
|  | clang_type.StartTagDeclarationDefinition (); | 
|  | clang_type.CompleteTagDeclarationDefinition (); | 
|  |  | 
|  | if (tag == DW_TAG_structure_type) // this only applies in C | 
|  | { | 
|  | clang::RecordDecl *record_decl = clang_type.GetAsRecordDecl(); | 
|  |  | 
|  | if (record_decl) | 
|  | m_record_decl_to_layout_map.insert(std::make_pair(record_decl, LayoutInfo())); | 
|  | } | 
|  | } | 
|  | else if (clang_type_was_created) | 
|  | { | 
|  | // Start the definition if the class is not objective C since | 
|  | // the underlying decls respond to isCompleteDefinition(). Objective | 
|  | // C decls don't respond to isCompleteDefinition() so we can't | 
|  | // start the declaration definition right away. For C++ class/union/structs | 
|  | // we want to start the definition in case the class is needed as the | 
|  | // declaration context for a contained class or type without the need | 
|  | // to complete that type.. | 
|  |  | 
|  | if (class_language != eLanguageTypeObjC && | 
|  | class_language != eLanguageTypeObjC_plus_plus) | 
|  | clang_type.StartTagDeclarationDefinition (); | 
|  |  | 
|  | // Leave this as a forward declaration until we need | 
|  | // to know the details of the type. lldb_private::Type | 
|  | // will automatically call the SymbolFile virtual function | 
|  | // "SymbolFileDWARF::ResolveClangOpaqueTypeDefinition(Type *)" | 
|  | // When the definition needs to be defined. | 
|  | m_forward_decl_die_to_clang_type[die] = clang_type.GetOpaqueQualType(); | 
|  | m_forward_decl_clang_type_to_die[clang_type.RemoveFastQualifiers().GetOpaqueQualType()] = die; | 
|  | clang_type.SetHasExternalStorage (true); | 
|  | } | 
|  | } | 
|  |  | 
|  | } | 
|  | break; | 
|  |  | 
|  | case DW_TAG_enumeration_type: | 
|  | { | 
|  | // Set a bit that lets us know that we are currently parsing this | 
|  | m_die_to_type[die] = DIE_IS_BEING_PARSED; | 
|  |  | 
|  | lldb::user_id_t encoding_uid = DW_INVALID_OFFSET; | 
|  |  | 
|  | const size_t num_attributes = die->GetAttributes(this, dwarf_cu, NULL, attributes); | 
|  | if (num_attributes > 0) | 
|  | { | 
|  | uint32_t i; | 
|  |  | 
|  | for (i=0; i<num_attributes; ++i) | 
|  | { | 
|  | attr = attributes.AttributeAtIndex(i); | 
|  | if (attributes.ExtractFormValueAtIndex(this, i, form_value)) | 
|  | { | 
|  | switch (attr) | 
|  | { | 
|  | case DW_AT_decl_file:       decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break; | 
|  | case DW_AT_decl_line:       decl.SetLine(form_value.Unsigned()); break; | 
|  | case DW_AT_decl_column:     decl.SetColumn(form_value.Unsigned()); break; | 
|  | case DW_AT_name: | 
|  | type_name_cstr = form_value.AsCString(&get_debug_str_data()); | 
|  | type_name_const_str.SetCString(type_name_cstr); | 
|  | break; | 
|  | case DW_AT_type:            encoding_uid = form_value.Reference(dwarf_cu); break; | 
|  | case DW_AT_byte_size:       byte_size = form_value.Unsigned(); break; | 
|  | case DW_AT_accessibility:   break; //accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned()); break; | 
|  | case DW_AT_declaration:     break; //is_forward_declaration = form_value.Boolean(); break; | 
|  | case DW_AT_allocated: | 
|  | case DW_AT_associated: | 
|  | case DW_AT_bit_stride: | 
|  | case DW_AT_byte_stride: | 
|  | case DW_AT_data_location: | 
|  | case DW_AT_description: | 
|  | case DW_AT_start_scope: | 
|  | case DW_AT_visibility: | 
|  | case DW_AT_specification: | 
|  | case DW_AT_abstract_origin: | 
|  | case DW_AT_sibling: | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | DEBUG_PRINTF ("0x%8.8" PRIx64 ": %s (\"%s\")\n", MakeUserID(die->GetOffset()), DW_TAG_value_to_name(tag), type_name_cstr); | 
|  |  | 
|  | ClangASTType enumerator_clang_type; | 
|  | clang_type.SetClangType (ast.getASTContext(), m_forward_decl_die_to_clang_type.lookup (die)); | 
|  | if (!clang_type) | 
|  | { | 
|  | if (encoding_uid != DW_INVALID_OFFSET) | 
|  | { | 
|  | Type *enumerator_type = ResolveTypeUID(encoding_uid); | 
|  | if (enumerator_type) | 
|  | enumerator_clang_type = enumerator_type->GetClangFullType(); | 
|  | } | 
|  |  | 
|  | if (!enumerator_clang_type) | 
|  | enumerator_clang_type = ast.GetBuiltinTypeForDWARFEncodingAndBitSize (NULL, | 
|  | DW_ATE_signed, | 
|  | byte_size * 8); | 
|  |  | 
|  | clang_type = ast.CreateEnumerationType (type_name_cstr, | 
|  | GetClangDeclContextContainingDIE (dwarf_cu, die, NULL), | 
|  | decl, | 
|  | enumerator_clang_type); | 
|  | } | 
|  | else | 
|  | { | 
|  | enumerator_clang_type = clang_type.GetEnumerationIntegerType (); | 
|  | } | 
|  |  | 
|  | LinkDeclContextToDIE(clang_type.GetDeclContextForType(), die); | 
|  |  | 
|  | type_sp.reset( new Type (MakeUserID(die->GetOffset()), | 
|  | this, | 
|  | type_name_const_str, | 
|  | byte_size, | 
|  | NULL, | 
|  | encoding_uid, | 
|  | Type::eEncodingIsUID, | 
|  | &decl, | 
|  | clang_type, | 
|  | Type::eResolveStateForward)); | 
|  |  | 
|  | clang_type.StartTagDeclarationDefinition (); | 
|  | if (die->HasChildren()) | 
|  | { | 
|  | SymbolContext cu_sc(GetCompUnitForDWARFCompUnit(dwarf_cu)); | 
|  | bool is_signed = false; | 
|  | enumerator_clang_type.IsIntegerType(is_signed); | 
|  | ParseChildEnumerators(cu_sc, clang_type, is_signed, type_sp->GetByteSize(), dwarf_cu, die); | 
|  | } | 
|  | clang_type.CompleteTagDeclarationDefinition (); | 
|  | } | 
|  | } | 
|  | break; | 
|  |  | 
|  | case DW_TAG_inlined_subroutine: | 
|  | case DW_TAG_subprogram: | 
|  | case DW_TAG_subroutine_type: | 
|  | { | 
|  | // Set a bit that lets us know that we are currently parsing this | 
|  | m_die_to_type[die] = DIE_IS_BEING_PARSED; | 
|  |  | 
|  | //const char *mangled = NULL; | 
|  | dw_offset_t type_die_offset = DW_INVALID_OFFSET; | 
|  | bool is_variadic = false; | 
|  | bool is_inline = false; | 
|  | bool is_static = false; | 
|  | bool is_virtual = false; | 
|  | bool is_explicit = false; | 
|  | bool is_artificial = false; | 
|  | dw_offset_t specification_die_offset = DW_INVALID_OFFSET; | 
|  | dw_offset_t abstract_origin_die_offset = DW_INVALID_OFFSET; | 
|  | dw_offset_t object_pointer_die_offset = DW_INVALID_OFFSET; | 
|  |  | 
|  | unsigned type_quals = 0; | 
|  | clang::StorageClass storage = clang::SC_None;//, Extern, Static, PrivateExtern | 
|  |  | 
|  |  | 
|  | const size_t num_attributes = die->GetAttributes(this, dwarf_cu, NULL, attributes); | 
|  | if (num_attributes > 0) | 
|  | { | 
|  | uint32_t i; | 
|  | for (i=0; i<num_attributes; ++i) | 
|  | { | 
|  | attr = attributes.AttributeAtIndex(i); | 
|  | if (attributes.ExtractFormValueAtIndex(this, i, form_value)) | 
|  | { | 
|  | switch (attr) | 
|  | { | 
|  | case DW_AT_decl_file:   decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break; | 
|  | case DW_AT_decl_line:   decl.SetLine(form_value.Unsigned()); break; | 
|  | case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break; | 
|  | case DW_AT_name: | 
|  | type_name_cstr = form_value.AsCString(&get_debug_str_data()); | 
|  | type_name_const_str.SetCString(type_name_cstr); | 
|  | break; | 
|  |  | 
|  | case DW_AT_linkage_name: | 
|  | case DW_AT_MIPS_linkage_name:   break; // mangled = form_value.AsCString(&get_debug_str_data()); break; | 
|  | case DW_AT_type:                type_die_offset = form_value.Reference(dwarf_cu); break; | 
|  | case DW_AT_accessibility:       accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned()); break; | 
|  | case DW_AT_declaration:         break; // is_forward_declaration = form_value.Boolean(); break; | 
|  | case DW_AT_inline:              is_inline = form_value.Boolean(); break; | 
|  | case DW_AT_virtuality:          is_virtual = form_value.Boolean();  break; | 
|  | case DW_AT_explicit:            is_explicit = form_value.Boolean();  break; | 
|  | case DW_AT_artificial:          is_artificial = form_value.Boolean();  break; | 
|  |  | 
|  |  | 
|  | case DW_AT_external: | 
|  | if (form_value.Unsigned()) | 
|  | { | 
|  | if (storage == clang::SC_None) | 
|  | storage = clang::SC_Extern; | 
|  | else | 
|  | storage = clang::SC_PrivateExtern; | 
|  | } | 
|  | break; | 
|  |  | 
|  | case DW_AT_specification: | 
|  | specification_die_offset = form_value.Reference(dwarf_cu); | 
|  | break; | 
|  |  | 
|  | case DW_AT_abstract_origin: | 
|  | abstract_origin_die_offset = form_value.Reference(dwarf_cu); | 
|  | break; | 
|  |  | 
|  | case DW_AT_object_pointer: | 
|  | object_pointer_die_offset = form_value.Reference(dwarf_cu); | 
|  | break; | 
|  |  | 
|  | case DW_AT_allocated: | 
|  | case DW_AT_associated: | 
|  | case DW_AT_address_class: | 
|  | case DW_AT_calling_convention: | 
|  | case DW_AT_data_location: | 
|  | case DW_AT_elemental: | 
|  | case DW_AT_entry_pc: | 
|  | case DW_AT_frame_base: | 
|  | case DW_AT_high_pc: | 
|  | case DW_AT_low_pc: | 
|  | case DW_AT_prototyped: | 
|  | case DW_AT_pure: | 
|  | case DW_AT_ranges: | 
|  | case DW_AT_recursive: | 
|  | case DW_AT_return_addr: | 
|  | case DW_AT_segment: | 
|  | case DW_AT_start_scope: | 
|  | case DW_AT_static_link: | 
|  | case DW_AT_trampoline: | 
|  | case DW_AT_visibility: | 
|  | case DW_AT_vtable_elem_location: | 
|  | case DW_AT_description: | 
|  | case DW_AT_sibling: | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | std::string object_pointer_name; | 
|  | if (object_pointer_die_offset != DW_INVALID_OFFSET) | 
|  | { | 
|  | // Get the name from the object pointer die | 
|  | StreamString s; | 
|  | if (DWARFDebugInfoEntry::GetName (this, dwarf_cu, object_pointer_die_offset, s)) | 
|  | { | 
|  | object_pointer_name.assign(s.GetData()); | 
|  | } | 
|  | } | 
|  |  | 
|  | DEBUG_PRINTF ("0x%8.8" PRIx64 ": %s (\"%s\")\n", MakeUserID(die->GetOffset()), DW_TAG_value_to_name(tag), type_name_cstr); | 
|  |  | 
|  | ClangASTType return_clang_type; | 
|  | Type *func_type = NULL; | 
|  |  | 
|  | if (type_die_offset != DW_INVALID_OFFSET) | 
|  | func_type = ResolveTypeUID(type_die_offset); | 
|  |  | 
|  | if (func_type) | 
|  | return_clang_type = func_type->GetClangForwardType(); | 
|  | else | 
|  | return_clang_type = ast.GetBasicType(eBasicTypeVoid); | 
|  |  | 
|  |  | 
|  | std::vector<ClangASTType> function_param_types; | 
|  | std::vector<clang::ParmVarDecl*> function_param_decls; | 
|  |  | 
|  | // Parse the function children for the parameters | 
|  |  | 
|  | const DWARFDebugInfoEntry *decl_ctx_die = NULL; | 
|  | clang::DeclContext *containing_decl_ctx = GetClangDeclContextContainingDIE (dwarf_cu, die, &decl_ctx_die); | 
|  | const clang::Decl::Kind containing_decl_kind = containing_decl_ctx->getDeclKind(); | 
|  |  | 
|  | const bool is_cxx_method = DeclKindIsCXXClass (containing_decl_kind); | 
|  | // Start off static. This will be set to false in ParseChildParameters(...) | 
|  | // if we find a "this" parameters as the first parameter | 
|  | if (is_cxx_method) | 
|  | is_static = true; | 
|  |  | 
|  | if (die->HasChildren()) | 
|  | { | 
|  | bool skip_artificial = true; | 
|  | ParseChildParameters (sc, | 
|  | containing_decl_ctx, | 
|  | dwarf_cu, | 
|  | die, | 
|  | skip_artificial, | 
|  | is_static, | 
|  | is_variadic, | 
|  | type_list, | 
|  | function_param_types, | 
|  | function_param_decls, | 
|  | type_quals); | 
|  | } | 
|  |  | 
|  | // clang_type will get the function prototype clang type after this call | 
|  | clang_type = ast.CreateFunctionType (return_clang_type, | 
|  | function_param_types.data(), | 
|  | function_param_types.size(), | 
|  | is_variadic, | 
|  | type_quals); | 
|  |  | 
|  | bool ignore_containing_context = false; | 
|  |  | 
|  | if (type_name_cstr) | 
|  | { | 
|  | bool type_handled = false; | 
|  | if (tag == DW_TAG_subprogram) | 
|  | { | 
|  | ObjCLanguageRuntime::MethodName objc_method (type_name_cstr, true); | 
|  | if (objc_method.IsValid(true)) | 
|  | { | 
|  | ClangASTType class_opaque_type; | 
|  | ConstString class_name(objc_method.GetClassName()); | 
|  | if (class_name) | 
|  | { | 
|  | TypeSP complete_objc_class_type_sp (FindCompleteObjCDefinitionTypeForDIE (NULL, class_name, false)); | 
|  |  | 
|  | if (complete_objc_class_type_sp) | 
|  | { | 
|  | ClangASTType type_clang_forward_type = complete_objc_class_type_sp->GetClangForwardType(); | 
|  | if (type_clang_forward_type.IsObjCObjectOrInterfaceType ()) | 
|  | class_opaque_type = type_clang_forward_type; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (class_opaque_type) | 
|  | { | 
|  | // If accessibility isn't set to anything valid, assume public for | 
|  | // now... | 
|  | if (accessibility == eAccessNone) | 
|  | accessibility = eAccessPublic; | 
|  |  | 
|  | clang::ObjCMethodDecl *objc_method_decl = class_opaque_type.AddMethodToObjCObjectType (type_name_cstr, | 
|  | clang_type, | 
|  | accessibility, | 
|  | is_artificial); | 
|  | type_handled = objc_method_decl != NULL; | 
|  | if (type_handled) | 
|  | { | 
|  | LinkDeclContextToDIE(ClangASTContext::GetAsDeclContext(objc_method_decl), die); | 
|  | GetClangASTContext().SetMetadataAsUserID (objc_method_decl, MakeUserID(die->GetOffset())); | 
|  | } | 
|  | else | 
|  | { | 
|  | GetObjectFile()->GetModule()->ReportError ("{0x%8.8x}: invalid Objective-C method 0x%4.4x (%s), please file a bug and attach the file at the start of this error message", | 
|  | die->GetOffset(), | 
|  | tag, | 
|  | DW_TAG_value_to_name(tag)); | 
|  | } | 
|  | } | 
|  | } | 
|  | else if (is_cxx_method) | 
|  | { | 
|  | // Look at the parent of this DIE and see if is is | 
|  | // a class or struct and see if this is actually a | 
|  | // C++ method | 
|  | Type *class_type = ResolveType (dwarf_cu, decl_ctx_die); | 
|  | if (class_type) | 
|  | { | 
|  | if (class_type->GetID() != MakeUserID(decl_ctx_die->GetOffset())) | 
|  | { | 
|  | // We uniqued the parent class of this function to another class | 
|  | // so we now need to associate all dies under "decl_ctx_die" to | 
|  | // DIEs in the DIE for "class_type"... | 
|  | SymbolFileDWARF *class_symfile = NULL; | 
|  | DWARFCompileUnitSP class_type_cu_sp; | 
|  | const DWARFDebugInfoEntry *class_type_die = NULL; | 
|  |  | 
|  | SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile(); | 
|  | if (debug_map_symfile) | 
|  | { | 
|  | class_symfile = debug_map_symfile->GetSymbolFileByOSOIndex(SymbolFileDWARFDebugMap::GetOSOIndexFromUserID(class_type->GetID())); | 
|  | class_type_die = class_symfile->DebugInfo()->GetDIEPtr(class_type->GetID(), &class_type_cu_sp); | 
|  | } | 
|  | else | 
|  | { | 
|  | class_symfile = this; | 
|  | class_type_die = DebugInfo()->GetDIEPtr(class_type->GetID(), &class_type_cu_sp); | 
|  | } | 
|  | if (class_type_die) | 
|  | { | 
|  | DWARFDIECollection failures; | 
|  |  | 
|  | CopyUniqueClassMethodTypes (class_symfile, | 
|  | class_type, | 
|  | class_type_cu_sp.get(), | 
|  | class_type_die, | 
|  | dwarf_cu, | 
|  | decl_ctx_die, | 
|  | failures); | 
|  |  | 
|  | // FIXME do something with these failures that's smarter than | 
|  | // just dropping them on the ground.  Unfortunately classes don't | 
|  | // like having stuff added to them after their definitions are | 
|  | // complete... | 
|  |  | 
|  | type_ptr = m_die_to_type[die]; | 
|  | if (type_ptr && type_ptr != DIE_IS_BEING_PARSED) | 
|  | { | 
|  | type_sp = type_ptr->shared_from_this(); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (specification_die_offset != DW_INVALID_OFFSET) | 
|  | { | 
|  | // We have a specification which we are going to base our function | 
|  | // prototype off of, so we need this type to be completed so that the | 
|  | // m_die_to_decl_ctx for the method in the specification has a valid | 
|  | // clang decl context. | 
|  | class_type->GetClangForwardType(); | 
|  | // If we have a specification, then the function type should have been | 
|  | // made with the specification and not with this die. | 
|  | DWARFCompileUnitSP spec_cu_sp; | 
|  | const DWARFDebugInfoEntry* spec_die = DebugInfo()->GetDIEPtr(specification_die_offset, &spec_cu_sp); | 
|  | clang::DeclContext *spec_clang_decl_ctx = GetClangDeclContextForDIE (sc, dwarf_cu, spec_die); | 
|  | if (spec_clang_decl_ctx) | 
|  | { | 
|  | LinkDeclContextToDIE(spec_clang_decl_ctx, die); | 
|  | } | 
|  | else | 
|  | { | 
|  | GetObjectFile()->GetModule()->ReportWarning ("0x%8.8" PRIx64 ": DW_AT_specification(0x%8.8x) has no decl\n", | 
|  | MakeUserID(die->GetOffset()), | 
|  | specification_die_offset); | 
|  | } | 
|  | type_handled = true; | 
|  | } | 
|  | else if (abstract_origin_die_offset != DW_INVALID_OFFSET) | 
|  | { | 
|  | // We have a specification which we are going to base our function | 
|  | // prototype off of, so we need this type to be completed so that the | 
|  | // m_die_to_decl_ctx for the method in the abstract origin has a valid | 
|  | // clang decl context. | 
|  | class_type->GetClangForwardType(); | 
|  |  | 
|  | DWARFCompileUnitSP abs_cu_sp; | 
|  | const DWARFDebugInfoEntry* abs_die = DebugInfo()->GetDIEPtr(abstract_origin_die_offset, &abs_cu_sp); | 
|  | clang::DeclContext *abs_clang_decl_ctx = GetClangDeclContextForDIE (sc, dwarf_cu, abs_die); | 
|  | if (abs_clang_decl_ctx) | 
|  | { | 
|  | LinkDeclContextToDIE (abs_clang_decl_ctx, die); | 
|  | } | 
|  | else | 
|  | { | 
|  | GetObjectFile()->GetModule()->ReportWarning ("0x%8.8" PRIx64 ": DW_AT_abstract_origin(0x%8.8x) has no decl\n", | 
|  | MakeUserID(die->GetOffset()), | 
|  | abstract_origin_die_offset); | 
|  | } | 
|  | type_handled = true; | 
|  | } | 
|  | else | 
|  | { | 
|  | ClangASTType class_opaque_type = class_type->GetClangForwardType(); | 
|  | if (class_opaque_type.IsCXXClassType ()) | 
|  | { | 
|  | if (class_opaque_type.IsBeingDefined ()) | 
|  | { | 
|  | // Neither GCC 4.2 nor clang++ currently set a valid accessibility | 
|  | // in the DWARF for C++ methods... Default to public for now... | 
|  | if (accessibility == eAccessNone) | 
|  | accessibility = eAccessPublic; | 
|  |  | 
|  | if (!is_static && !die->HasChildren()) | 
|  | { | 
|  | // We have a C++ member function with no children (this pointer!) | 
|  | // and clang will get mad if we try and make a function that isn't | 
|  | // well formed in the DWARF, so we will just skip it... | 
|  | type_handled = true; | 
|  | } | 
|  | else | 
|  | { | 
|  | clang::CXXMethodDecl *cxx_method_decl; | 
|  | // REMOVE THE CRASH DESCRIPTION BELOW | 
|  | Host::SetCrashDescriptionWithFormat ("SymbolFileDWARF::ParseType() is adding a method %s to class %s in DIE 0x%8.8" PRIx64 " from %s", | 
|  | type_name_cstr, | 
|  | class_type->GetName().GetCString(), | 
|  | MakeUserID(die->GetOffset()), | 
|  | m_obj_file->GetFileSpec().GetPath().c_str()); | 
|  |  | 
|  | const bool is_attr_used = false; | 
|  |  | 
|  | cxx_method_decl = class_opaque_type.AddMethodToCXXRecordType (type_name_cstr, | 
|  | clang_type, | 
|  | accessibility, | 
|  | is_virtual, | 
|  | is_static, | 
|  | is_inline, | 
|  | is_explicit, | 
|  | is_attr_used, | 
|  | is_artificial); | 
|  |  | 
|  | type_handled = cxx_method_decl != NULL; | 
|  |  | 
|  | if (type_handled) | 
|  | { | 
|  | LinkDeclContextToDIE(ClangASTContext::GetAsDeclContext(cxx_method_decl), die); | 
|  |  | 
|  | Host::SetCrashDescription (NULL); | 
|  |  | 
|  |  | 
|  | ClangASTMetadata metadata; | 
|  | metadata.SetUserID(MakeUserID(die->GetOffset())); | 
|  |  | 
|  | if (!object_pointer_name.empty()) | 
|  | { | 
|  | metadata.SetObjectPtrName(object_pointer_name.c_str()); | 
|  | if (log) | 
|  | log->Printf ("Setting object pointer name: %s on method object %p.\n", | 
|  | object_pointer_name.c_str(), | 
|  | static_cast<void*>(cxx_method_decl)); | 
|  | } | 
|  | GetClangASTContext().SetMetadata (cxx_method_decl, metadata); | 
|  | } | 
|  | else | 
|  | { | 
|  | ignore_containing_context = true; | 
|  | } | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | // We were asked to parse the type for a method in a class, yet the | 
|  | // class hasn't been asked to complete itself through the | 
|  | // clang::ExternalASTSource protocol, so we need to just have the | 
|  | // class complete itself and do things the right way, then our | 
|  | // DIE should then have an entry in the m_die_to_type map. First | 
|  | // we need to modify the m_die_to_type so it doesn't think we are | 
|  | // trying to parse this DIE anymore... | 
|  | m_die_to_type[die] = NULL; | 
|  |  | 
|  | // Now we get the full type to force our class type to complete itself | 
|  | // using the clang::ExternalASTSource protocol which will parse all | 
|  | // base classes and all methods (including the method for this DIE). | 
|  | class_type->GetClangFullType(); | 
|  |  | 
|  | // The type for this DIE should have been filled in the function call above | 
|  | type_ptr = m_die_to_type[die]; | 
|  | if (type_ptr && type_ptr != DIE_IS_BEING_PARSED) | 
|  | { | 
|  | type_sp = type_ptr->shared_from_this(); | 
|  | break; | 
|  | } | 
|  |  | 
|  | // FIXME This is fixing some even uglier behavior but we really need to | 
|  | // uniq the methods of each class as well as the class itself. | 
|  | // <rdar://problem/11240464> | 
|  | type_handled = true; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!type_handled) | 
|  | { | 
|  | // We just have a function that isn't part of a class | 
|  | clang::FunctionDecl *function_decl = ast.CreateFunctionDeclaration (ignore_containing_context ? GetClangASTContext().GetTranslationUnitDecl() : containing_decl_ctx, | 
|  | type_name_cstr, | 
|  | clang_type, | 
|  | storage, | 
|  | is_inline); | 
|  |  | 
|  | //                            if (template_param_infos.GetSize() > 0) | 
|  | //                            { | 
|  | //                                clang::FunctionTemplateDecl *func_template_decl = ast.CreateFunctionTemplateDecl (containing_decl_ctx, | 
|  | //                                                                                                                  function_decl, | 
|  | //                                                                                                                  type_name_cstr, | 
|  | //                                                                                                                  template_param_infos); | 
|  | // | 
|  | //                                ast.CreateFunctionTemplateSpecializationInfo (function_decl, | 
|  | //                                                                              func_template_decl, | 
|  | //                                                                              template_param_infos); | 
|  | //                            } | 
|  | // Add the decl to our DIE to decl context map | 
|  | assert (function_decl); | 
|  | LinkDeclContextToDIE(function_decl, die); | 
|  | if (!function_param_decls.empty()) | 
|  | ast.SetFunctionParameters (function_decl, | 
|  | &function_param_decls.front(), | 
|  | function_param_decls.size()); | 
|  |  | 
|  | ClangASTMetadata metadata; | 
|  | metadata.SetUserID(MakeUserID(die->GetOffset())); | 
|  |  | 
|  | if (!object_pointer_name.empty()) | 
|  | { | 
|  | metadata.SetObjectPtrName(object_pointer_name.c_str()); | 
|  | if (log) | 
|  | log->Printf ("Setting object pointer name: %s on function object %p.", | 
|  | object_pointer_name.c_str(), | 
|  | static_cast<void*>(function_decl)); | 
|  | } | 
|  | GetClangASTContext().SetMetadata (function_decl, metadata); | 
|  | } | 
|  | } | 
|  | type_sp.reset( new Type (MakeUserID(die->GetOffset()), | 
|  | this, | 
|  | type_name_const_str, | 
|  | 0, | 
|  | NULL, | 
|  | LLDB_INVALID_UID, | 
|  | Type::eEncodingIsUID, | 
|  | &decl, | 
|  | clang_type, | 
|  | Type::eResolveStateFull)); | 
|  | assert(type_sp.get()); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case DW_TAG_array_type: | 
|  | { | 
|  | // Set a bit that lets us know that we are currently parsing this | 
|  | m_die_to_type[die] = DIE_IS_BEING_PARSED; | 
|  |  | 
|  | lldb::user_id_t type_die_offset = DW_INVALID_OFFSET; | 
|  | int64_t first_index = 0; | 
|  | uint32_t byte_stride = 0; | 
|  | uint32_t bit_stride = 0; | 
|  | bool is_vector = false; | 
|  | const size_t num_attributes = die->GetAttributes(this, dwarf_cu, NULL, attributes); | 
|  |  | 
|  | if (num_attributes > 0) | 
|  | { | 
|  | uint32_t i; | 
|  | for (i=0; i<num_attributes; ++i) | 
|  | { | 
|  | attr = attributes.AttributeAtIndex(i); | 
|  | if (attributes.ExtractFormValueAtIndex(this, i, form_value)) | 
|  | { | 
|  | switch (attr) | 
|  | { | 
|  | case DW_AT_decl_file:   decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break; | 
|  | case DW_AT_decl_line:   decl.SetLine(form_value.Unsigned()); break; | 
|  | case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break; | 
|  | case DW_AT_name: | 
|  | type_name_cstr = form_value.AsCString(&get_debug_str_data()); | 
|  | type_name_const_str.SetCString(type_name_cstr); | 
|  | break; | 
|  |  | 
|  | case DW_AT_type:            type_die_offset = form_value.Reference(dwarf_cu); break; | 
|  | case DW_AT_byte_size:       break; // byte_size = form_value.Unsigned(); break; | 
|  | case DW_AT_byte_stride:     byte_stride = form_value.Unsigned(); break; | 
|  | case DW_AT_bit_stride:      bit_stride = form_value.Unsigned(); break; | 
|  | case DW_AT_GNU_vector:      is_vector = form_value.Boolean(); break; | 
|  | case DW_AT_accessibility:   break; // accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned()); break; | 
|  | case DW_AT_declaration:     break; // is_forward_declaration = form_value.Boolean(); break; | 
|  | case DW_AT_allocated: | 
|  | case DW_AT_associated: | 
|  | case DW_AT_data_location: | 
|  | case DW_AT_description: | 
|  | case DW_AT_ordering: | 
|  | case DW_AT_start_scope: | 
|  | case DW_AT_visibility: | 
|  | case DW_AT_specification: | 
|  | case DW_AT_abstract_origin: | 
|  | case DW_AT_sibling: | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | DEBUG_PRINTF ("0x%8.8" PRIx64 ": %s (\"%s\")\n", MakeUserID(die->GetOffset()), DW_TAG_value_to_name(tag), type_name_cstr); | 
|  |  | 
|  | Type *element_type = ResolveTypeUID(type_die_offset); | 
|  |  | 
|  | if (element_type) | 
|  | { | 
|  | std::vector<uint64_t> element_orders; | 
|  | ParseChildArrayInfo(sc, dwarf_cu, die, first_index, element_orders, byte_stride, bit_stride); | 
|  | if (byte_stride == 0 && bit_stride == 0) | 
|  | byte_stride = element_type->GetByteSize(); | 
|  | ClangASTType array_element_type = element_type->GetClangForwardType(); | 
|  | uint64_t array_element_bit_stride = byte_stride * 8 + bit_stride; | 
|  | uint64_t num_elements = 0; | 
|  | std::vector<uint64_t>::const_reverse_iterator pos; | 
|  | std::vector<uint64_t>::const_reverse_iterator end = element_orders.rend(); | 
|  | for (pos = element_orders.rbegin(); pos != end; ++pos) | 
|  | { | 
|  | num_elements = *pos; | 
|  | clang_type = ast.CreateArrayType (array_element_type, | 
|  | num_elements, | 
|  | is_vector); | 
|  | array_element_type = clang_type; | 
|  | array_element_bit_stride = num_elements ? array_element_bit_stride * num_elements : array_element_bit_stride; | 
|  | } | 
|  | ConstString empty_name; | 
|  | type_sp.reset( new Type (MakeUserID(die->GetOffset()), | 
|  | this, | 
|  | empty_name, | 
|  | array_element_bit_stride / 8, | 
|  | NULL, | 
|  | type_die_offset, | 
|  | Type::eEncodingIsUID, | 
|  | &decl, | 
|  | clang_type, | 
|  | Type::eResolveStateFull)); | 
|  | type_sp->SetEncodingType (element_type); | 
|  | } | 
|  | } | 
|  | } | 
|  | break; | 
|  |  | 
|  | case DW_TAG_ptr_to_member_type: | 
|  | { | 
|  | dw_offset_t type_die_offset = DW_INVALID_OFFSET; | 
|  | dw_offset_t containing_type_die_offset = DW_INVALID_OFFSET; | 
|  |  | 
|  | const size_t num_attributes = die->GetAttributes(this, dwarf_cu, NULL, attributes); | 
|  |  | 
|  | if (num_attributes > 0) { | 
|  | uint32_t i; | 
|  | for (i=0; i<num_attributes; ++i) | 
|  | { | 
|  | attr = attributes.AttributeAtIndex(i); | 
|  | if (attributes.ExtractFormValueAtIndex(this, i, form_value)) | 
|  | { | 
|  | switch (attr) | 
|  | { | 
|  | case DW_AT_type: | 
|  | type_die_offset = form_value.Reference(dwarf_cu); break; | 
|  | case DW_AT_containing_type: | 
|  | containing_type_die_offset = form_value.Reference(dwarf_cu); break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | Type *pointee_type = ResolveTypeUID(type_die_offset); | 
|  | Type *class_type = ResolveTypeUID(containing_type_die_offset); | 
|  |  | 
|  | ClangASTType pointee_clang_type = pointee_type->GetClangForwardType(); | 
|  | ClangASTType class_clang_type = class_type->GetClangLayoutType(); | 
|  |  | 
|  | clang_type = pointee_clang_type.CreateMemberPointerType(class_clang_type); | 
|  |  | 
|  | byte_size = clang_type.GetByteSize(); | 
|  |  | 
|  | type_sp.reset( new Type (MakeUserID(die->GetOffset()), | 
|  | this, | 
|  | type_name_const_str, | 
|  | byte_size, | 
|  | NULL, | 
|  | LLDB_INVALID_UID, | 
|  | Type::eEncodingIsUID, | 
|  | NULL, | 
|  | clang_type, | 
|  | Type::eResolveStateForward)); | 
|  | } | 
|  |  | 
|  | break; | 
|  | } | 
|  | default: | 
|  | GetObjectFile()->GetModule()->ReportError ("{0x%8.8x}: unhandled type tag 0x%4.4x (%s), please file a bug and attach the file at the start of this error message", | 
|  | die->GetOffset(), | 
|  | tag, | 
|  | DW_TAG_value_to_name(tag)); | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (type_sp.get()) | 
|  | { | 
|  | const DWARFDebugInfoEntry *sc_parent_die = GetParentSymbolContextDIE(die); | 
|  | dw_tag_t sc_parent_tag = sc_parent_die ? sc_parent_die->Tag() : 0; | 
|  |  | 
|  | SymbolContextScope * symbol_context_scope = NULL; | 
|  | if (sc_parent_tag == DW_TAG_compile_unit) | 
|  | { | 
|  | symbol_context_scope = sc.comp_unit; | 
|  | } | 
|  | else if (sc.function != NULL) | 
|  | { | 
|  | symbol_context_scope = sc.function->GetBlock(true).FindBlockByID(MakeUserID(sc_parent_die->GetOffset())); | 
|  | if (symbol_context_scope == NULL) | 
|  | symbol_context_scope = sc.function; | 
|  | } | 
|  |  | 
|  | if (symbol_context_scope != NULL) | 
|  | { | 
|  | type_sp->SetSymbolContextScope(symbol_context_scope); | 
|  | } | 
|  |  | 
|  | // We are ready to put this type into the uniqued list up at the module level | 
|  | type_list->Insert (type_sp); | 
|  |  | 
|  | m_die_to_type[die] = type_sp.get(); | 
|  | } | 
|  | } | 
|  | else if (type_ptr != DIE_IS_BEING_PARSED) | 
|  | { | 
|  | type_sp = type_ptr->shared_from_this(); | 
|  | } | 
|  | } | 
|  | return type_sp; | 
|  | } | 
|  |  | 
|  | size_t | 
|  | SymbolFileDWARF::ParseTypes | 
|  | ( | 
|  | const SymbolContext& sc, | 
|  | DWARFCompileUnit* dwarf_cu, | 
|  | const DWARFDebugInfoEntry *die, | 
|  | bool parse_siblings, | 
|  | bool parse_children | 
|  | ) | 
|  | { | 
|  | size_t types_added = 0; | 
|  | while (die != NULL) | 
|  | { | 
|  | bool type_is_new = false; | 
|  | if (ParseType(sc, dwarf_cu, die, &type_is_new).get()) | 
|  | { | 
|  | if (type_is_new) | 
|  | ++types_added; | 
|  | } | 
|  |  | 
|  | if (parse_children && die->HasChildren()) | 
|  | { | 
|  | if (die->Tag() == DW_TAG_subprogram) | 
|  | { | 
|  | SymbolContext child_sc(sc); | 
|  | child_sc.function = sc.comp_unit->FindFunctionByUID(MakeUserID(die->GetOffset())).get(); | 
|  | types_added += ParseTypes(child_sc, dwarf_cu, die->GetFirstChild(), true, true); | 
|  | } | 
|  | else | 
|  | types_added += ParseTypes(sc, dwarf_cu, die->GetFirstChild(), true, true); | 
|  | } | 
|  |  | 
|  | if (parse_siblings) | 
|  | die = die->GetSibling(); | 
|  | else | 
|  | die = NULL; | 
|  | } | 
|  | return types_added; | 
|  | } | 
|  |  | 
|  |  | 
|  | size_t | 
|  | SymbolFileDWARF::ParseFunctionBlocks (const SymbolContext &sc) | 
|  | { | 
|  | assert(sc.comp_unit && sc.function); | 
|  | size_t functions_added = 0; | 
|  | DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); | 
|  | if (dwarf_cu) | 
|  | { | 
|  | dw_offset_t function_die_offset = sc.function->GetID(); | 
|  | const DWARFDebugInfoEntry *function_die = dwarf_cu->GetDIEPtr(function_die_offset); | 
|  | if (function_die) | 
|  | { | 
|  | ParseFunctionBlocks(sc, &sc.function->GetBlock (false), dwarf_cu, function_die, LLDB_INVALID_ADDRESS, 0); | 
|  | } | 
|  | } | 
|  |  | 
|  | return functions_added; | 
|  | } | 
|  |  | 
|  |  | 
|  | size_t | 
|  | SymbolFileDWARF::ParseTypes (const SymbolContext &sc) | 
|  | { | 
|  | // At least a compile unit must be valid | 
|  | assert(sc.comp_unit); | 
|  | size_t types_added = 0; | 
|  | DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); | 
|  | if (dwarf_cu) | 
|  | { | 
|  | if (sc.function) | 
|  | { | 
|  | dw_offset_t function_die_offset = sc.function->GetID(); | 
|  | const DWARFDebugInfoEntry *func_die = dwarf_cu->GetDIEPtr(function_die_offset); | 
|  | if (func_die && func_die->HasChildren()) | 
|  | { | 
|  | types_added = ParseTypes(sc, dwarf_cu, func_die->GetFirstChild(), true, true); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | const DWARFDebugInfoEntry *dwarf_cu_die = dwarf_cu->DIE(); | 
|  | if (dwarf_cu_die && dwarf_cu_die->HasChildren()) | 
|  | { | 
|  | types_added = ParseTypes(sc, dwarf_cu, dwarf_cu_die->GetFirstChild(), true, true); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return types_added; | 
|  | } | 
|  |  | 
|  | size_t | 
|  | SymbolFileDWARF::ParseVariablesForContext (const SymbolContext& sc) | 
|  | { | 
|  | if (sc.comp_unit != NULL) | 
|  | { | 
|  | DWARFDebugInfo* info = DebugInfo(); | 
|  | if (info == NULL) | 
|  | return 0; | 
|  |  | 
|  | if (sc.function) | 
|  | { | 
|  | DWARFCompileUnit* dwarf_cu = info->GetCompileUnitContainingDIE(sc.function->GetID()).get(); | 
|  |  | 
|  | if (dwarf_cu == NULL) | 
|  | return 0; | 
|  |  | 
|  | const DWARFDebugInfoEntry *function_die = dwarf_cu->GetDIEPtr(sc.function->GetID()); | 
|  |  | 
|  | dw_addr_t func_lo_pc = function_die->GetAttributeValueAsUnsigned (this, dwarf_cu, DW_AT_low_pc, LLDB_INVALID_ADDRESS); | 
|  | if (func_lo_pc != LLDB_INVALID_ADDRESS) | 
|  | { | 
|  | const size_t num_variables = ParseVariables(sc, dwarf_cu, func_lo_pc, function_die->GetFirstChild(), true, true); | 
|  |  | 
|  | // Let all blocks know they have parse all their variables | 
|  | sc.function->GetBlock (false).SetDidParseVariables (true, true); | 
|  | return num_variables; | 
|  | } | 
|  | } | 
|  | else if (sc.comp_unit) | 
|  | { | 
|  | DWARFCompileUnit* dwarf_cu = info->GetCompileUnit(sc.comp_unit->GetID()).get(); | 
|  |  | 
|  | if (dwarf_cu == NULL) | 
|  | return 0; | 
|  |  | 
|  | uint32_t vars_added = 0; | 
|  | VariableListSP variables (sc.comp_unit->GetVariableList(false)); | 
|  |  | 
|  | if (variables.get() == NULL) | 
|  | { | 
|  | variables.reset(new VariableList()); | 
|  | sc.comp_unit->SetVariableList(variables); | 
|  |  | 
|  | DWARFCompileUnit* match_dwarf_cu = NULL; | 
|  | const DWARFDebugInfoEntry* die = NULL; | 
|  | DIEArray die_offsets; | 
|  | if (m_using_apple_tables) | 
|  | { | 
|  | if (m_apple_names_ap.get()) | 
|  | { | 
|  | DWARFMappedHash::DIEInfoArray hash_data_array; | 
|  | if (m_apple_names_ap->AppendAllDIEsInRange (dwarf_cu->GetOffset(), | 
|  | dwarf_cu->GetNextCompileUnitOffset(), | 
|  | hash_data_array)) | 
|  | { | 
|  | DWARFMappedHash::ExtractDIEArray (hash_data_array, die_offsets); | 
|  | } | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | // Index if we already haven't to make sure the compile units | 
|  | // get indexed and make their global DIE index list | 
|  | if (!m_indexed) | 
|  | Index (); | 
|  |  | 
|  | m_global_index.FindAllEntriesForCompileUnit (dwarf_cu->GetOffset(), | 
|  | dwarf_cu->GetNextCompileUnitOffset(), | 
|  | die_offsets); | 
|  | } | 
|  |  | 
|  | const size_t num_matches = die_offsets.size(); | 
|  | if (num_matches) | 
|  | { | 
|  | DWARFDebugInfo* debug_info = DebugInfo(); | 
|  | for (size_t i=0; i<num_matches; ++i) | 
|  | { | 
|  | const dw_offset_t die_offset = die_offsets[i]; | 
|  | die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &match_dwarf_cu); | 
|  | if (die) | 
|  | { | 
|  | VariableSP var_sp (ParseVariableDIE(sc, dwarf_cu, die, LLDB_INVALID_ADDRESS)); | 
|  | if (var_sp) | 
|  | { | 
|  | variables->AddVariableIfUnique (var_sp); | 
|  | ++vars_added; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | if (m_using_apple_tables) | 
|  | { | 
|  | GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_names accelerator table had bad die 0x%8.8x)\n", die_offset); | 
|  | } | 
|  | } | 
|  |  | 
|  | } | 
|  | } | 
|  | } | 
|  | return vars_added; | 
|  | } | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | VariableSP | 
|  | SymbolFileDWARF::ParseVariableDIE | 
|  | ( | 
|  | const SymbolContext& sc, | 
|  | DWARFCompileUnit* dwarf_cu, | 
|  | const DWARFDebugInfoEntry *die, | 
|  | const lldb::addr_t func_low_pc | 
|  | ) | 
|  | { | 
|  |  | 
|  | VariableSP var_sp (m_die_to_variable_sp[die]); | 
|  | if (var_sp) | 
|  | return var_sp;  // Already been parsed! | 
|  |  | 
|  | const dw_tag_t tag = die->Tag(); | 
|  | ModuleSP module = GetObjectFile()->GetModule(); | 
|  |  | 
|  | if ((tag == DW_TAG_variable) || | 
|  | (tag == DW_TAG_constant) || | 
|  | (tag == DW_TAG_formal_parameter && sc.function)) | 
|  | { | 
|  | DWARFDebugInfoEntry::Attributes attributes; | 
|  | const size_t num_attributes = die->GetAttributes(this, dwarf_cu, NULL, attributes); | 
|  | if (num_attributes > 0) | 
|  | { | 
|  | const char *name = NULL; | 
|  | const char *mangled = NULL; | 
|  | Declaration decl; | 
|  | uint32_t i; | 
|  | lldb::user_id_t type_uid = LLDB_INVALID_UID; | 
|  | DWARFExpression location; | 
|  | bool is_external = false; | 
|  | bool is_artificial = false; | 
|  | bool location_is_const_value_data = false; | 
|  | bool has_explicit_location = false; | 
|  | DWARFFormValue const_value; | 
|  | //AccessType accessibility = eAccessNone; | 
|  |  | 
|  | for (i=0; i<num_attributes; ++i) | 
|  | { | 
|  | dw_attr_t attr = attributes.AttributeAtIndex(i); | 
|  | DWARFFormValue form_value; | 
|  | if (attributes.ExtractFormValueAtIndex(this, i, form_value)) | 
|  | { | 
|  | switch (attr) | 
|  | { | 
|  | case DW_AT_decl_file:   decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break; | 
|  | case DW_AT_decl_line:   decl.SetLine(form_value.Unsigned()); break; | 
|  | case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break; | 
|  | case DW_AT_name:        name = form_value.AsCString(&get_debug_str_data()); break; | 
|  | case DW_AT_linkage_name: | 
|  | case DW_AT_MIPS_linkage_name: mangled = form_value.AsCString(&get_debug_str_data()); break; | 
|  | case DW_AT_type:        type_uid = form_value.Reference(dwarf_cu); break; | 
|  | case DW_AT_external:    is_external = form_value.Boolean(); break; | 
|  | case DW_AT_const_value: | 
|  | // If we have already found a DW_AT_location attribute, ignore this attribute. | 
|  | if (!has_explicit_location) | 
|  | { | 
|  | location_is_const_value_data = true; | 
|  | // The constant value will be either a block, a data value or a string. | 
|  | const DWARFDataExtractor& debug_info_data = get_debug_info_data(); | 
|  | if (DWARFFormValue::IsBlockForm(form_value.Form())) | 
|  | { | 
|  | // Retrieve the value as a block expression. | 
|  | uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart(); | 
|  | uint32_t block_length = form_value.Unsigned(); | 
|  | location.CopyOpcodeData(module, debug_info_data, block_offset, block_length); | 
|  | } | 
|  | else if (DWARFFormValue::IsDataForm(form_value.Form())) | 
|  | { | 
|  | // Retrieve the value as a data expression. | 
|  | const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize()); | 
|  | uint32_t data_offset = attributes.DIEOffsetAtIndex(i); | 
|  | uint32_t data_length = fixed_form_sizes[form_value.Form()]; | 
|  | if (data_length == 0) | 
|  | { | 
|  | const uint8_t *data_pointer = form_value.BlockData(); | 
|  | if (data_pointer) | 
|  | { | 
|  | data_length = form_value.Unsigned(); | 
|  | } | 
|  | else if (DWARFFormValue::IsDataForm(form_value.Form())) | 
|  | { | 
|  | // we need to get the byte size of the type later after we create the variable | 
|  | const_value = form_value; | 
|  | } | 
|  | } | 
|  | else | 
|  | location.CopyOpcodeData(module, debug_info_data, data_offset, data_length); | 
|  | } | 
|  | else | 
|  | { | 
|  | // Retrieve the value as a string expression. | 
|  | if (form_value.Form() == DW_FORM_strp) | 
|  | { | 
|  | const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize()); | 
|  | uint32_t data_offset = attributes.DIEOffsetAtIndex(i); | 
|  | uint32_t data_length = fixed_form_sizes[form_value.Form()]; | 
|  | location.CopyOpcodeData(module, debug_info_data, data_offset, data_length); | 
|  | } | 
|  | else | 
|  | { | 
|  | const char *str = form_value.AsCString(&debug_info_data); | 
|  | uint32_t string_offset = str - (const char *)debug_info_data.GetDataStart(); | 
|  | uint32_t string_length = strlen(str) + 1; | 
|  | location.CopyOpcodeData(module, debug_info_data, string_offset, string_length); | 
|  | } | 
|  | } | 
|  | } | 
|  | break; | 
|  | case DW_AT_location: | 
|  | { | 
|  | location_is_const_value_data = false; | 
|  | has_explicit_location = true; | 
|  | if (form_value.BlockData()) | 
|  | { | 
|  | const DWARFDataExtractor& debug_info_data = get_debug_info_data(); | 
|  |  | 
|  | uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart(); | 
|  | uint32_t block_length = form_value.Unsigned(); | 
|  | location.CopyOpcodeData(module, get_debug_info_data(), block_offset, block_length); | 
|  | } | 
|  | else | 
|  | { | 
|  | const DWARFDataExtractor&    debug_loc_data = get_debug_loc_data(); | 
|  | const dw_offset_t debug_loc_offset = form_value.Unsigned(); | 
|  |  | 
|  | size_t loc_list_length = DWARFLocationList::Size(debug_loc_data, debug_loc_offset); | 
|  | if (loc_list_length > 0) | 
|  | { | 
|  | location.CopyOpcodeData(module, debug_loc_data, debug_loc_offset, loc_list_length); | 
|  | assert (func_low_pc != LLDB_INVALID_ADDRESS); | 
|  | location.SetLocationListSlide (func_low_pc - dwarf_cu->GetBaseAddress()); | 
|  | } | 
|  | } | 
|  | } | 
|  | break; | 
|  |  | 
|  | case DW_AT_artificial:      is_artificial = form_value.Boolean(); break; | 
|  | case DW_AT_accessibility:   break; //accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned()); break; | 
|  | case DW_AT_declaration: | 
|  | case DW_AT_description: | 
|  | case DW_AT_endianity: | 
|  | case DW_AT_segment: | 
|  | case DW_AT_start_scope: | 
|  | case DW_AT_visibility: | 
|  | default: | 
|  | case DW_AT_abstract_origin: | 
|  | case DW_AT_sibling: | 
|  | case DW_AT_specification: | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | ValueType scope = eValueTypeInvalid; | 
|  |  | 
|  | const DWARFDebugInfoEntry *sc_parent_die = GetParentSymbolContextDIE(die); | 
|  | dw_tag_t parent_tag = sc_parent_die ? sc_parent_die->Tag() : 0; | 
|  | SymbolContextScope * symbol_context_scope = NULL; | 
|  |  | 
|  | // DWARF doesn't specify if a DW_TAG_variable is a local, global | 
|  | // or static variable, so we have to do a little digging by | 
|  | // looking at the location of a variable to see if it contains | 
|  | // a DW_OP_addr opcode _somewhere_ in the definition. I say | 
|  | // somewhere because clang likes to combine small global variables | 
|  | // into the same symbol and have locations like: | 
|  | // DW_OP_addr(0x1000), DW_OP_constu(2), DW_OP_plus | 
|  | // So if we don't have a DW_TAG_formal_parameter, we can look at | 
|  | // the location to see if it contains a DW_OP_addr opcode, and | 
|  | // then we can correctly classify  our variables. | 
|  | if (tag == DW_TAG_formal_parameter) | 
|  | scope = eValueTypeVariableArgument; | 
|  | else | 
|  | { | 
|  | bool op_error = false; | 
|  | // Check if the location has a DW_OP_addr with any address value... | 
|  | lldb::addr_t location_DW_OP_addr = LLDB_INVALID_ADDRESS; | 
|  | if (!location_is_const_value_data) | 
|  | { | 
|  | location_DW_OP_addr = location.GetLocation_DW_OP_addr (0, op_error); | 
|  | if (op_error) | 
|  | { | 
|  | StreamString strm; | 
|  | location.DumpLocationForAddress (&strm, eDescriptionLevelFull, 0, 0, NULL); | 
|  | GetObjectFile()->GetModule()->ReportError ("0x%8.8x: %s has an invalid location: %s", die->GetOffset(), DW_TAG_value_to_name(die->Tag()), strm.GetString().c_str()); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (location_DW_OP_addr != LLDB_INVALID_ADDRESS) | 
|  | { | 
|  | if (is_external) | 
|  | scope = eValueTypeVariableGlobal; | 
|  | else | 
|  | scope = eValueTypeVariableStatic; | 
|  |  | 
|  |  | 
|  | SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile (); | 
|  |  | 
|  | if (debug_map_symfile) | 
|  | { | 
|  | // When leaving the DWARF in the .o files on darwin, | 
|  | // when we have a global variable that wasn't initialized, | 
|  | // the .o file might not have allocated a virtual | 
|  | // address for the global variable. In this case it will | 
|  | // have created a symbol for the global variable | 
|  | // that is undefined/data and external and the value will | 
|  | // be the byte size of the variable. When we do the | 
|  | // address map in SymbolFileDWARFDebugMap we rely on | 
|  | // having an address, we need to do some magic here | 
|  | // so we can get the correct address for our global | 
|  | // variable. The address for all of these entries | 
|  | // will be zero, and there will be an undefined symbol | 
|  | // in this object file, and the executable will have | 
|  | // a matching symbol with a good address. So here we | 
|  | // dig up the correct address and replace it in the | 
|  | // location for the variable, and set the variable's | 
|  | // symbol context scope to be that of the main executable | 
|  | // so the file address will resolve correctly. | 
|  | bool linked_oso_file_addr = false; | 
|  | if (is_external && location_DW_OP_addr == 0) | 
|  | { | 
|  | // we have a possible uninitialized extern global | 
|  | ConstString const_name(mangled ? mangled : name); | 
|  | ObjectFile *debug_map_objfile = debug_map_symfile->GetObjectFile(); | 
|  | if (debug_map_objfile) | 
|  | { | 
|  | Symtab *debug_map_symtab = debug_map_objfile->GetSymtab(); | 
|  | if (debug_map_symtab) | 
|  | { | 
|  | Symbol *exe_symbol = debug_map_symtab->FindFirstSymbolWithNameAndType (const_name, | 
|  | eSymbolTypeData, | 
|  | Symtab::eDebugYes, | 
|  | Symtab::eVisibilityExtern); | 
|  | if (exe_symbol) | 
|  | { | 
|  | if (exe_symbol->ValueIsAddress()) | 
|  | { | 
|  | const addr_t exe_file_addr = exe_symbol->GetAddress().GetFileAddress(); | 
|  | if (exe_file_addr != LLDB_INVALID_ADDRESS) | 
|  | { | 
|  | if (location.Update_DW_OP_addr (exe_file_addr)) | 
|  | { | 
|  | linked_oso_file_addr = true; | 
|  | symbol_context_scope = exe_symbol; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!linked_oso_file_addr) | 
|  | { | 
|  | // The DW_OP_addr is not zero, but it contains a .o file address which | 
|  | // needs to be linked up correctly. | 
|  | const lldb::addr_t exe_file_addr = debug_map_symfile->LinkOSOFileAddress(this, location_DW_OP_addr); | 
|  | if (exe_file_addr != LLDB_INVALID_ADDRESS) | 
|  | { | 
|  | // Update the file address for this variable | 
|  | location.Update_DW_OP_addr (exe_file_addr); | 
|  | } | 
|  | else | 
|  | { | 
|  | // Variable didn't make it into the final executable | 
|  | return var_sp; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | scope = eValueTypeVariableLocal; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (symbol_context_scope == NULL) | 
|  | { | 
|  | switch (parent_tag) | 
|  | { | 
|  | case DW_TAG_subprogram: | 
|  | case DW_TAG_inlined_subroutine: | 
|  | case DW_TAG_lexical_block: | 
|  | if (sc.function) | 
|  | { | 
|  | symbol_context_scope = sc.function->GetBlock(true).FindBlockByID(MakeUserID(sc_parent_die->GetOffset())); | 
|  | if (symbol_context_scope == NULL) | 
|  | symbol_context_scope = sc.function; | 
|  | } | 
|  | break; | 
|  |  | 
|  | default: | 
|  | symbol_context_scope = sc.comp_unit; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (symbol_context_scope) | 
|  | { | 
|  | SymbolFileTypeSP type_sp(new SymbolFileType(*this, type_uid)); | 
|  |  | 
|  | if (const_value.Form() && type_sp && type_sp->GetType()) | 
|  | location.CopyOpcodeData(const_value.Unsigned(), type_sp->GetType()->GetByteSize(), dwarf_cu->GetAddressByteSize()); | 
|  |  | 
|  | var_sp.reset (new Variable (MakeUserID(die->GetOffset()), | 
|  | name, | 
|  | mangled, | 
|  | type_sp, | 
|  | scope, | 
|  | symbol_context_scope, | 
|  | &decl, | 
|  | location, | 
|  | is_external, | 
|  | is_artificial)); | 
|  |  | 
|  | var_sp->SetLocationIsConstantValueData (location_is_const_value_data); | 
|  | } | 
|  | else | 
|  | { | 
|  | // Not ready to parse this variable yet. It might be a global | 
|  | // or static variable that is in a function scope and the function | 
|  | // in the symbol context wasn't filled in yet | 
|  | return var_sp; | 
|  | } | 
|  | } | 
|  | // Cache var_sp even if NULL (the variable was just a specification or | 
|  | // was missing vital information to be able to be displayed in the debugger | 
|  | // (missing location due to optimization, etc)) so we don't re-parse | 
|  | // this DIE over and over later... | 
|  | m_die_to_variable_sp[die] = var_sp; | 
|  | } | 
|  | return var_sp; | 
|  | } | 
|  |  | 
|  |  | 
|  | const DWARFDebugInfoEntry * | 
|  | SymbolFileDWARF::FindBlockContainingSpecification (dw_offset_t func_die_offset, | 
|  | dw_offset_t spec_block_die_offset, | 
|  | DWARFCompileUnit **result_die_cu_handle) | 
|  | { | 
|  | // Give the concrete function die specified by "func_die_offset", find the | 
|  | // concrete block whose DW_AT_specification or DW_AT_abstract_origin points | 
|  | // to "spec_block_die_offset" | 
|  | DWARFDebugInfo* info = DebugInfo(); | 
|  |  | 
|  | const DWARFDebugInfoEntry *die = info->GetDIEPtrWithCompileUnitHint(func_die_offset, result_die_cu_handle); | 
|  | if (die) | 
|  | { | 
|  | assert (*result_die_cu_handle); | 
|  | return FindBlockContainingSpecification (*result_die_cu_handle, die, spec_block_die_offset, result_die_cu_handle); | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  |  | 
|  | const DWARFDebugInfoEntry * | 
|  | SymbolFileDWARF::FindBlockContainingSpecification(DWARFCompileUnit* dwarf_cu, | 
|  | const DWARFDebugInfoEntry *die, | 
|  | dw_offset_t spec_block_die_offset, | 
|  | DWARFCompileUnit **result_die_cu_handle) | 
|  | { | 
|  | if (die) | 
|  | { | 
|  | switch (die->Tag()) | 
|  | { | 
|  | case DW_TAG_subprogram: | 
|  | case DW_TAG_inlined_subroutine: | 
|  | case DW_TAG_lexical_block: | 
|  | { | 
|  | if (die->GetAttributeValueAsReference (this, dwarf_cu, DW_AT_specification, DW_INVALID_OFFSET) == spec_block_die_offset) | 
|  | { | 
|  | *result_die_cu_handle = dwarf_cu; | 
|  | return die; | 
|  | } | 
|  |  | 
|  | if (die->GetAttributeValueAsReference (this, dwarf_cu, DW_AT_abstract_origin, DW_INVALID_OFFSET) == spec_block_die_offset) | 
|  | { | 
|  | *result_die_cu_handle = dwarf_cu; | 
|  | return die; | 
|  | } | 
|  | } | 
|  | break; | 
|  | } | 
|  |  | 
|  | // Give the concrete function die specified by "func_die_offset", find the | 
|  | // concrete block whose DW_AT_specification or DW_AT_abstract_origin points | 
|  | // to "spec_block_die_offset" | 
|  | for (const DWARFDebugInfoEntry *child_die = die->GetFirstChild(); child_die != NULL; child_die = child_die->GetSibling()) | 
|  | { | 
|  | const DWARFDebugInfoEntry *result_die = FindBlockContainingSpecification (dwarf_cu, | 
|  | child_die, | 
|  | spec_block_die_offset, | 
|  | result_die_cu_handle); | 
|  | if (result_die) | 
|  | return result_die; | 
|  | } | 
|  | } | 
|  |  | 
|  | *result_die_cu_handle = NULL; | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | size_t | 
|  | SymbolFileDWARF::ParseVariables | 
|  | ( | 
|  | const SymbolContext& sc, | 
|  | DWARFCompileUnit* dwarf_cu, | 
|  | const lldb::addr_t func_low_pc, | 
|  | const DWARFDebugInfoEntry *orig_die, | 
|  | bool parse_siblings, | 
|  | bool parse_children, | 
|  | VariableList* cc_variable_list | 
|  | ) | 
|  | { | 
|  | if (orig_die == NULL) | 
|  | return 0; | 
|  |  | 
|  | VariableListSP variable_list_sp; | 
|  |  | 
|  | size_t vars_added = 0; | 
|  | const DWARFDebugInfoEntry *die = orig_die; | 
|  | while (die != NULL) | 
|  | { | 
|  | dw_tag_t tag = die->Tag(); | 
|  |  | 
|  | // Check to see if we have already parsed this variable or constant? | 
|  | if (m_die_to_variable_sp[die]) | 
|  | { | 
|  | if (cc_variable_list) | 
|  | cc_variable_list->AddVariableIfUnique (m_die_to_variable_sp[die]); | 
|  | } | 
|  | else | 
|  | { | 
|  | // We haven't already parsed it, lets do that now. | 
|  | if ((tag == DW_TAG_variable) || | 
|  | (tag == DW_TAG_constant) || | 
|  | (tag == DW_TAG_formal_parameter && sc.function)) | 
|  | { | 
|  | if (variable_list_sp.get() == NULL) | 
|  | { | 
|  | const DWARFDebugInfoEntry *sc_parent_die = GetParentSymbolContextDIE(orig_die); | 
|  | dw_tag_t parent_tag = sc_parent_die ? sc_parent_die->Tag() : 0; | 
|  | switch (parent_tag) | 
|  | { | 
|  | case DW_TAG_compile_unit: | 
|  | if (sc.comp_unit != NULL) | 
|  | { | 
|  | variable_list_sp = sc.comp_unit->GetVariableList(false); | 
|  | if (variable_list_sp.get() == NULL) | 
|  | { | 
|  | variable_list_sp.reset(new VariableList()); | 
|  | sc.comp_unit->SetVariableList(variable_list_sp); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | GetObjectFile()->GetModule()->ReportError ("parent 0x%8.8" PRIx64 " %s with no valid compile unit in symbol context for 0x%8.8" PRIx64 " %s.\n", | 
|  | MakeUserID(sc_parent_die->GetOffset()), | 
|  | DW_TAG_value_to_name (parent_tag), | 
|  | MakeUserID(orig_die->GetOffset()), | 
|  | DW_TAG_value_to_name (orig_die->Tag())); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case DW_TAG_subprogram: | 
|  | case DW_TAG_inlined_subroutine: | 
|  | case DW_TAG_lexical_block: | 
|  | if (sc.function != NULL) | 
|  | { | 
|  | // Check to see if we already have parsed the variables for the given scope | 
|  |  | 
|  | Block *block = sc.function->GetBlock(true).FindBlockByID(MakeUserID(sc_parent_die->GetOffset())); | 
|  | if (block == NULL) | 
|  | { | 
|  | // This must be a specification or abstract origin with | 
|  | // a concrete block counterpart in the current function. We need | 
|  | // to find the concrete block so we can correctly add the | 
|  | // variable to it | 
|  | DWARFCompileUnit *concrete_block_die_cu = dwarf_cu; | 
|  | const DWARFDebugInfoEntry *concrete_block_die = FindBlockContainingSpecification (sc.function->GetID(), | 
|  | sc_parent_die->GetOffset(), | 
|  | &concrete_block_die_cu); | 
|  | if (concrete_block_die) | 
|  | block = sc.function->GetBlock(true).FindBlockByID(MakeUserID(concrete_block_die->GetOffset())); | 
|  | } | 
|  |  | 
|  | if (block != NULL) | 
|  | { | 
|  | const bool can_create = false; | 
|  | variable_list_sp = block->GetBlockVariableList (can_create); | 
|  | if (variable_list_sp.get() == NULL) | 
|  | { | 
|  | variable_list_sp.reset(new VariableList()); | 
|  | block->SetVariableList(variable_list_sp); | 
|  | } | 
|  | } | 
|  | } | 
|  | break; | 
|  |  | 
|  | default: | 
|  | GetObjectFile()->GetModule()->ReportError ("didn't find appropriate parent DIE for variable list for 0x%8.8" PRIx64 " %s.\n", | 
|  | MakeUserID(orig_die->GetOffset()), | 
|  | DW_TAG_value_to_name (orig_die->Tag())); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (variable_list_sp) | 
|  | { | 
|  | VariableSP var_sp (ParseVariableDIE(sc, dwarf_cu, die, func_low_pc)); | 
|  | if (var_sp) | 
|  | { | 
|  | variable_list_sp->AddVariableIfUnique (var_sp); | 
|  | if (cc_variable_list) | 
|  | cc_variable_list->AddVariableIfUnique (var_sp); | 
|  | ++vars_added; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | bool skip_children = (sc.function == NULL && tag == DW_TAG_subprogram); | 
|  |  | 
|  | if (!skip_children && parse_children && die->HasChildren()) | 
|  | { | 
|  | vars_added += ParseVariables(sc, dwarf_cu, func_low_pc, die->GetFirstChild(), true, true, cc_variable_list); | 
|  | } | 
|  |  | 
|  | if (parse_siblings) | 
|  | die = die->GetSibling(); | 
|  | else | 
|  | die = NULL; | 
|  | } | 
|  | return vars_added; | 
|  | } | 
|  |  | 
|  | //------------------------------------------------------------------ | 
|  | // PluginInterface protocol | 
|  | //------------------------------------------------------------------ | 
|  | ConstString | 
|  | SymbolFileDWARF::GetPluginName() | 
|  | { | 
|  | return GetPluginNameStatic(); | 
|  | } | 
|  |  | 
|  | uint32_t | 
|  | SymbolFileDWARF::GetPluginVersion() | 
|  | { | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | void | 
|  | SymbolFileDWARF::CompleteTagDecl (void *baton, clang::TagDecl *decl) | 
|  | { | 
|  | SymbolFileDWARF *symbol_file_dwarf = (SymbolFileDWARF *)baton; | 
|  | ClangASTType clang_type = symbol_file_dwarf->GetClangASTContext().GetTypeForDecl (decl); | 
|  | if (clang_type) | 
|  | symbol_file_dwarf->ResolveClangOpaqueTypeDefinition (clang_type); | 
|  | } | 
|  |  | 
|  | void | 
|  | SymbolFileDWARF::CompleteObjCInterfaceDecl (void *baton, clang::ObjCInterfaceDecl *decl) | 
|  | { | 
|  | SymbolFileDWARF *symbol_file_dwarf = (SymbolFileDWARF *)baton; | 
|  | ClangASTType clang_type = symbol_file_dwarf->GetClangASTContext().GetTypeForDecl (decl); | 
|  | if (clang_type) | 
|  | symbol_file_dwarf->ResolveClangOpaqueTypeDefinition (clang_type); | 
|  | } | 
|  |  | 
|  | void | 
|  | SymbolFileDWARF::DumpIndexes () | 
|  | { | 
|  | StreamFile s(stdout, false); | 
|  |  | 
|  | s.Printf ("DWARF index for (%s) '%s':", | 
|  | GetObjectFile()->GetModule()->GetArchitecture().GetArchitectureName(), | 
|  | GetObjectFile()->GetFileSpec().GetPath().c_str()); | 
|  | s.Printf("\nFunction basenames:\n");    m_function_basename_index.Dump (&s); | 
|  | s.Printf("\nFunction fullnames:\n");    m_function_fullname_index.Dump (&s); | 
|  | s.Printf("\nFunction methods:\n");      m_function_method_index.Dump (&s); | 
|  | s.Printf("\nFunction selectors:\n");    m_function_selector_index.Dump (&s); | 
|  | s.Printf("\nObjective C class selectors:\n");    m_objc_class_selectors_index.Dump (&s); | 
|  | s.Printf("\nGlobals and statics:\n");   m_global_index.Dump (&s); | 
|  | s.Printf("\nTypes:\n");                 m_type_index.Dump (&s); | 
|  | s.Printf("\nNamepaces:\n");             m_namespace_index.Dump (&s); | 
|  | } | 
|  |  | 
|  | void | 
|  | SymbolFileDWARF::SearchDeclContext (const clang::DeclContext *decl_context, | 
|  | const char *name, | 
|  | llvm::SmallVectorImpl <clang::NamedDecl *> *results) | 
|  | { | 
|  | DeclContextToDIEMap::iterator iter = m_decl_ctx_to_die.find(decl_context); | 
|  |  | 
|  | if (iter == m_decl_ctx_to_die.end()) | 
|  | return; | 
|  |  | 
|  | for (DIEPointerSet::iterator pos = iter->second.begin(), end = iter->second.end(); pos != end; ++pos) | 
|  | { | 
|  | const DWARFDebugInfoEntry *context_die = *pos; | 
|  |  | 
|  | if (!results) | 
|  | return; | 
|  |  | 
|  | DWARFDebugInfo* info = DebugInfo(); | 
|  |  | 
|  | DIEArray die_offsets; | 
|  |  | 
|  | DWARFCompileUnit* dwarf_cu = NULL; | 
|  | const DWARFDebugInfoEntry* die = NULL; | 
|  |  | 
|  | if (m_using_apple_tables) | 
|  | { | 
|  | if (m_apple_types_ap.get()) | 
|  | m_apple_types_ap->FindByName (name, die_offsets); | 
|  | } | 
|  | else | 
|  | { | 
|  | if (!m_indexed) | 
|  | Index (); | 
|  |  | 
|  | m_type_index.Find (ConstString(name), die_offsets); | 
|  | } | 
|  |  | 
|  | const size_t num_matches = die_offsets.size(); | 
|  |  | 
|  | if (num_matches) | 
|  | { | 
|  | for (size_t i = 0; i < num_matches; ++i) | 
|  | { | 
|  | const dw_offset_t die_offset = die_offsets[i]; | 
|  | die = info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu); | 
|  |  | 
|  | if (die->GetParent() != context_die) | 
|  | continue; | 
|  |  | 
|  | Type *matching_type = ResolveType (dwarf_cu, die); | 
|  |  | 
|  | clang::QualType qual_type = matching_type->GetClangForwardType().GetQualType(); | 
|  |  | 
|  | if (const clang::TagType *tag_type = llvm::dyn_cast<clang::TagType>(qual_type.getTypePtr())) | 
|  | { | 
|  | clang::TagDecl *tag_decl = tag_type->getDecl(); | 
|  | results->push_back(tag_decl); | 
|  | } | 
|  | else if (const clang::TypedefType *typedef_type = llvm::dyn_cast<clang::TypedefType>(qual_type.getTypePtr())) | 
|  | { | 
|  | clang::TypedefNameDecl *typedef_decl = typedef_type->getDecl(); | 
|  | results->push_back(typedef_decl); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | SymbolFileDWARF::FindExternalVisibleDeclsByName (void *baton, | 
|  | const clang::DeclContext *decl_context, | 
|  | clang::DeclarationName decl_name, | 
|  | llvm::SmallVectorImpl <clang::NamedDecl *> *results) | 
|  | { | 
|  |  | 
|  | switch (decl_context->getDeclKind()) | 
|  | { | 
|  | case clang::Decl::Namespace: | 
|  | case clang::Decl::TranslationUnit: | 
|  | { | 
|  | SymbolFileDWARF *symbol_file_dwarf = (SymbolFileDWARF *)baton; | 
|  | symbol_file_dwarf->SearchDeclContext (decl_context, decl_name.getAsString().c_str(), results); | 
|  | } | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | bool | 
|  | SymbolFileDWARF::LayoutRecordType (void *baton, | 
|  | const clang::RecordDecl *record_decl, | 
|  | uint64_t &size, | 
|  | uint64_t &alignment, | 
|  | llvm::DenseMap <const clang::FieldDecl *, uint64_t> &field_offsets, | 
|  | llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets, | 
|  | llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets) | 
|  | { | 
|  | SymbolFileDWARF *symbol_file_dwarf = (SymbolFileDWARF *)baton; | 
|  | return symbol_file_dwarf->LayoutRecordType (record_decl, size, alignment, field_offsets, base_offsets, vbase_offsets); | 
|  | } | 
|  |  | 
|  |  | 
|  | bool | 
|  | SymbolFileDWARF::LayoutRecordType (const clang::RecordDecl *record_decl, | 
|  | uint64_t &bit_size, | 
|  | uint64_t &alignment, | 
|  | llvm::DenseMap <const clang::FieldDecl *, uint64_t> &field_offsets, | 
|  | llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets, | 
|  | llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets) | 
|  | { | 
|  | Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO)); | 
|  | RecordDeclToLayoutMap::iterator pos = m_record_decl_to_layout_map.find (record_decl); | 
|  | bool success = false; | 
|  | base_offsets.clear(); | 
|  | vbase_offsets.clear(); | 
|  | if (pos != m_record_decl_to_layout_map.end()) | 
|  | { | 
|  | bit_size = pos->second.bit_size; | 
|  | alignment = pos->second.alignment; | 
|  | field_offsets.swap(pos->second.field_offsets); | 
|  | base_offsets.swap (pos->second.base_offsets); | 
|  | vbase_offsets.swap (pos->second.vbase_offsets); | 
|  | m_record_decl_to_layout_map.erase(pos); | 
|  | success = true; | 
|  | } | 
|  | else | 
|  | { | 
|  | bit_size = 0; | 
|  | alignment = 0; | 
|  | field_offsets.clear(); | 
|  | } | 
|  |  | 
|  | if (log) | 
|  | GetObjectFile()->GetModule()->LogMessage (log, | 
|  | "SymbolFileDWARF::LayoutRecordType (record_decl = %p, bit_size = %" PRIu64 ", alignment = %" PRIu64 ", field_offsets[%u],base_offsets[%u], vbase_offsets[%u]) success = %i", | 
|  | static_cast<const void*>(record_decl), | 
|  | bit_size, alignment, | 
|  | static_cast<uint32_t>(field_offsets.size()), | 
|  | static_cast<uint32_t>(base_offsets.size()), | 
|  | static_cast<uint32_t>(vbase_offsets.size()), | 
|  | success); | 
|  | return success; | 
|  | } | 
|  |  | 
|  |  | 
|  | SymbolFileDWARFDebugMap * | 
|  | SymbolFileDWARF::GetDebugMapSymfile () | 
|  | { | 
|  | if (m_debug_map_symfile == NULL && !m_debug_map_module_wp.expired()) | 
|  | { | 
|  | lldb::ModuleSP module_sp (m_debug_map_module_wp.lock()); | 
|  | if (module_sp) | 
|  | { | 
|  | SymbolVendor *sym_vendor = module_sp->GetSymbolVendor(); | 
|  | if (sym_vendor) | 
|  | m_debug_map_symfile = (SymbolFileDWARFDebugMap *)sym_vendor->GetSymbolFile(); | 
|  | } | 
|  | } | 
|  | return m_debug_map_symfile; | 
|  | } | 
|  |  | 
|  |  |