/* APPLE LOCAL begin LLVM (ENTIRE FILE!) */ /* High-level LLVM backend interface Copyright (C) 2005 Free Software Foundation, Inc. Contributed by Jim Laskey (jlaskey@apple.com) This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ //===----------------------------------------------------------------------===// // This is a C++ source file that implements the debug information gathering. //===----------------------------------------------------------------------===// #include "llvm-debug.h" #include "llvm-abi.h" #include "llvm-internal.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" #include "llvm/Instructions.h" #include "llvm/Intrinsics.h" #include "llvm/Module.h" #include "llvm/Support/Dwarf.h" #include "llvm/Target/TargetMachine.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include extern "C" { #include "langhooks.h" #include "toplev.h" #include "tree.h" #include "version.h" } using namespace llvm; using namespace llvm::dwarf; #ifndef LLVMTESTDEBUG #define DEBUGASSERT(S) ((void)0) #else #define DEBUGASSERT(S) assert(S) #endif /// DirectoryAndFile - Extract the directory and file name from a path. If no /// directory is specified, then use the source working directory. static void DirectoryAndFile(const std::string &FullPath, std::string &Directory, std::string &FileName) { // Look for the directory slash. size_t Slash = FullPath.rfind('/'); // If no slash if (Slash == std::string::npos) { // The entire path is the file name. Directory = ""; FileName = FullPath; } else { // Separate the directory from the file name. Directory = FullPath.substr(0, Slash); FileName = FullPath.substr(Slash + 1); } // If no directory present then use source working directory. if (Directory.empty() || Directory[0] != '/') { Directory = std::string(get_src_pwd()) + "/" + Directory; } } /// NodeSizeInBits - Returns the size in bits stored in a tree node regardless /// of whether the node is a TYPE or DECL. static uint64_t NodeSizeInBits(tree Node) { if (TREE_CODE(Node) == ERROR_MARK) { return BITS_PER_WORD; } else if (TYPE_P(Node)) { if (TYPE_SIZE(Node) == NULL_TREE) return 0; else if (host_integerp (TYPE_SIZE(Node), 1)) return tree_low_cst (TYPE_SIZE(Node), 1); else return TYPE_ALIGN(Node); } else if (DECL_P(Node)) { if (DECL_SIZE(Node) == NULL_TREE) return 0; else if (host_integerp (DECL_SIZE(Node), 1)) return tree_low_cst (DECL_SIZE(Node), 1); else return DECL_ALIGN(Node); } return 0; } /// NodeAlignInBits - Returns the alignment in bits stored in a tree node /// regardless of whether the node is a TYPE or DECL. static uint64_t NodeAlignInBits(tree Node) { if (TREE_CODE(Node) == ERROR_MARK) return BITS_PER_WORD; if (TYPE_P(Node)) return TYPE_ALIGN(Node); if (DECL_P(Node)) return DECL_ALIGN(Node); return BITS_PER_WORD; } /// FieldType - Returns the type node of a structure member field. /// static tree FieldType(tree Field) { if (TREE_CODE (Field) == ERROR_MARK) return integer_type_node; tree type = DECL_BIT_FIELD_TYPE (Field); if (type == NULL_TREE) type = TREE_TYPE (Field); return type; } /// GetNodeName - Returns the name stored in a node regardless of whether the /// node is a TYPE or DECL. static const char *GetNodeName(tree Node) { tree Name = NULL; if (DECL_P(Node)) { Name = DECL_NAME(Node); } else if (TYPE_P(Node)) { Name = TYPE_NAME(Node); } if (Name) { if (TREE_CODE(Name) == IDENTIFIER_NODE) { return IDENTIFIER_POINTER(Name); } else if (TREE_CODE(Name) == TYPE_DECL && !DECL_IGNORED_P(Name)) { return IDENTIFIER_POINTER(DECL_NAME(Name)); } } return ""; } /// GetNodeLocation - Returns the location stored in a node regardless of /// whether the node is a TYPE or DECL. UseStub is true if we should consider /// the type stub as the actually location (ignored in struct/unions/enums.) static expanded_location GetNodeLocation(tree Node, bool UseStub = true) { expanded_location Location = { NULL, 0 }; tree Name = NULL; if (DECL_P(Node)) { Name = DECL_NAME(Node); } else if (TYPE_P(Node)) { Name = TYPE_NAME(Node); } if (Name) { if (TYPE_STUB_DECL(Name)) { tree Stub = TYPE_STUB_DECL(Name); Location = expand_location(DECL_SOURCE_LOCATION(Stub)); } else if (DECL_P(Name)) { Location = expand_location(DECL_SOURCE_LOCATION(Name)); } } if (!Location.line) { if (UseStub && TYPE_STUB_DECL(Node)) { tree Stub = TYPE_STUB_DECL(Node); Location = expand_location(DECL_SOURCE_LOCATION(Stub)); } else if (DECL_P(Node)) { Location = expand_location(DECL_SOURCE_LOCATION(Node)); } } return Location; } /// GetGlobalNames - Sets the names for a global descriptor. /// static void GetGlobalNames(tree Node, GlobalDesc *Global) { tree decl_name = DECL_NAME(Node); if (decl_name != NULL && IDENTIFIER_POINTER (decl_name) != NULL) { Global->setName(lang_hooks.decl_printable_name (Node, 0)); Global->setFullName(lang_hooks.decl_printable_name (Node, 1)); if (TREE_PUBLIC(Node) && DECL_ASSEMBLER_NAME(Node) != DECL_NAME(Node) && !DECL_ABSTRACT(Node)) { Global->setLinkageName(IDENTIFIER_POINTER(DECL_ASSEMBLER_NAME(Node))); } } } DebugInfo::DebugInfo(Module *m) : M(m) , SR() , CurFullPath("") , CurLineNo(0) , PrevFullPath("") , PrevLineNo(0) , PrevBB(NULL) , CompileUnitCache() , StopPointFn(NULL) , FuncStartFn(NULL) , RegionStartFn(NULL) , RegionEndFn(NULL) , DeclareFn(NULL) , CompileUnitAnchor(NULL) , GlobalVariableAnchor(NULL) , SubprogramAnchor(NULL) , RegionStack() , Subprogram(NULL) { // uint64_t and int64_t are used in the debug descriptors for sizes and // offsets. So, we should make sure we don't lose any accuracy. DEBUGASSERT(sizeof(HOST_WIDE_INT) <= sizeof(int64_t) && "Bit size exceeds values stored in debug descriptors"); // Let the debug serializer know where the module lives. SR.setModule(M); } /// getValueFor - Return a llvm representation for a given debug information /// descriptor. Value *DebugInfo::getValueFor(DebugInfoDesc *DD) { return SR.Serialize(DD); } /// getCastValueFor - Return a llvm representation for a given debug information /// descriptor cast to an empty struct pointer. Value *DebugInfo::getCastValueFor(DebugInfoDesc *DD) { return ConstantExpr::getBitCast(SR.Serialize(DD), SR.getEmptyStructPtrType()); } /// EmitFunctionStart - Constructs the debug code for entering a function - /// "llvm.dbg.func.start." void DebugInfo::EmitFunctionStart(tree FnDecl, Function *Fn, BasicBlock *CurBB) { PrevFullPath = ""; PrevLineNo = 0; PrevBB = NULL; // Create subprogram descriptor. Subprogram = new SubprogramDesc(); // Make sure we have an anchor. if (!SubprogramAnchor) { SubprogramAnchor = new AnchorDesc(Subprogram); } // Get name information. GetGlobalNames(FnDecl, Subprogram); // Gather location information. CompileUnitDesc *Unit = getOrCreateCompileUnit(CurFullPath); // Get function type. TypeDesc *SPTy = getOrCreateType(TREE_TYPE(TREE_TYPE(FnDecl)), Unit); Subprogram->setAnchor(SubprogramAnchor); Subprogram->setContext(Unit); Subprogram->setFile(Unit); Subprogram->setLine(CurLineNo); Subprogram->setType(SPTy); Subprogram->setIsStatic(Fn->hasInternalLinkage()); Subprogram->setIsDefinition(true); // Lazily construct llvm.dbg.func.start. if (!FuncStartFn) FuncStartFn = Intrinsic::getDeclaration(M, Intrinsic::dbg_func_start); // Call llvm.dbg.func.start. new CallInst(FuncStartFn, getCastValueFor(Subprogram), "", CurBB); // Provide an entry stop point. EmitStopPoint(Fn, CurBB); // Push function on region stack. RegionStack.push_back(Subprogram); } /// EmitRegionStart- Constructs the debug code for entering a declarative /// region - "llvm.dbg.region.start." void DebugInfo::EmitRegionStart(Function *Fn, BasicBlock *CurBB) { BlockDesc *Block = new BlockDesc(); Block->setContext(RegionStack.back()); RegionStack.push_back(Block); // Lazily construct llvm.dbg.region.start function. if (!RegionStartFn) RegionStartFn = Intrinsic::getDeclaration(M, Intrinsic::dbg_region_start); // Call llvm.dbg.func.start. new CallInst(RegionStartFn, getCastValueFor(Block), "", CurBB); } /// EmitRegionEnd - Constructs the debug code for exiting a declarative /// region - "llvm.dbg.region.end." void DebugInfo::EmitRegionEnd(Function *Fn, BasicBlock *CurBB) { // Lazily construct llvm.dbg.region.end function. if (!RegionEndFn) RegionEndFn = Intrinsic::getDeclaration(M, Intrinsic::dbg_region_end); // Provide an region stop point. EmitStopPoint(Fn, CurBB); // Call llvm.dbg.func.end. new CallInst(RegionEndFn, getCastValueFor(RegionStack.back()), "", CurBB); RegionStack.pop_back(); } /// EmitDeclare - Constructs the debug code for allocation of a new variable. /// region - "llvm.dbg.declare." void DebugInfo::EmitDeclare(tree decl, unsigned Tag, const char *Name, tree type, Value *AI, BasicBlock *CurBB) { // Lazily construct llvm.dbg.declare function. const PointerType *EmpPtr = SR.getEmptyStructPtrType(); if (!DeclareFn) DeclareFn = Intrinsic::getDeclaration(M, Intrinsic::dbg_declare); // Get type information. CompileUnitDesc *Unit = getOrCreateCompileUnit(CurFullPath); TypeDesc *TyDesc = getOrCreateType(type, Unit); expanded_location Loc = GetNodeLocation(decl, false); CompileUnitDesc *File = Loc.line ? getOrCreateCompileUnit(Loc.file) : NULL; // Construct variable. VariableDesc *Variable = new VariableDesc(Tag); Variable->setContext(RegionStack.back()); Variable->setName(Name); Variable->setFile(File); Variable->setLine(Loc.line); Variable->setType(TyDesc); // Cast the AllocA result to a {}* for the call to llvm.dbg.declare. Since // only pointer types are involved, this is always a BitCast Value *AllocACast = new BitCastInst(AI, EmpPtr, Name, CurBB); // Call llvm.dbg.declare. SmallVector Args; Args.push_back(AllocACast); Args.push_back(getCastValueFor(Variable)); new CallInst(DeclareFn, Args.begin(), Args.end(), "", CurBB); } /// EmitStopPoint - Emit a call to llvm.dbg.stoppoint to indicate a change of /// source line - "llvm.dbg.stoppoint." void DebugInfo::EmitStopPoint(Function *Fn, BasicBlock *CurBB) { // Don't bother if things are the same as last time. if (PrevLineNo == CurLineNo && PrevBB == CurBB && (PrevFullPath == CurFullPath || !strcmp(PrevFullPath, CurFullPath))) return; if (!CurFullPath[0] || CurLineNo == 0) return; // Update last state. PrevFullPath = CurFullPath; PrevLineNo = CurLineNo; PrevBB = CurBB; // Get the appropriate compile unit. CompileUnitDesc *Unit = getOrCreateCompileUnit(CurFullPath); // Lazily construct llvm.dbg.stoppoint function. if (!StopPointFn) StopPointFn = Intrinsic::getDeclaration(M, Intrinsic::dbg_stoppoint); // Invoke llvm.dbg.stoppoint Value *Args[3] = { ConstantInt::get(Type::Int32Ty, CurLineNo), ConstantInt::get(Type::Int32Ty, 0), getCastValueFor(Unit) }; new CallInst(StopPointFn, Args, Args+3, "", CurBB); } /// EmitGlobalVariable - Emit information about a global variable. /// void DebugInfo::EmitGlobalVariable(GlobalVariable *GV, tree decl) { // FIXME - lots to do here. // Create global variable debug descriptor. GlobalVariableDesc *Global = new GlobalVariableDesc(); // Make sure we have an anchor. if (!GlobalVariableAnchor) { GlobalVariableAnchor = new AnchorDesc(Global); } // Get name information. GetGlobalNames(decl, Global); // Gather location information. expanded_location location = expand_location(DECL_SOURCE_LOCATION(decl)); CompileUnitDesc *Unit = getOrCreateCompileUnit(location.file); TypeDesc *TyD = getOrCreateType(TREE_TYPE(decl), Unit); // Fill in the blanks. Global->setAnchor(GlobalVariableAnchor); Global->setContext(Unit); Global->setFile(Unit); Global->setLine(location.line); Global->setType(TyD); Global->setIsDefinition(true); Global->setIsStatic(GV->hasInternalLinkage()); Global->setGlobalVariable(GV); // Make sure global is created if needed. getValueFor(Global); } /// AddTypeQualifiers - Add const/volatile qualifiers prior to the type /// descriptor. static TypeDesc *AddTypeQualifiers(tree_node *type, CompileUnitDesc *Unit, TypeDesc *TyDesc) { if (TYPE_READONLY(type)) { DerivedTypeDesc *DerivedTy = new DerivedTypeDesc(DW_TAG_const_type); DerivedTy->setContext(Unit); DerivedTy->setFromType(TyDesc); TyDesc = DerivedTy; } if (TYPE_VOLATILE(type)) { DerivedTypeDesc *DerivedTy = new DerivedTypeDesc(DW_TAG_volatile_type); DerivedTy->setContext(Unit); DerivedTy->setFromType(TyDesc); TyDesc = DerivedTy; } // FIXME - Add private/public/protected. return TyDesc; } /// getOrCreateType - Get the type from the cache or create a new type if /// necessary. /// FIXME - I hate jumbo methods - split up. TypeDesc *DebugInfo::getOrCreateType(tree_node *type, CompileUnitDesc *Unit) { DEBUGASSERT(type != NULL_TREE && type != error_mark_node && "Not a type."); if (type == NULL_TREE || type == error_mark_node) return NULL; // Should only be void if a pointer/reference/return type. Returning NULL // allows the caller to produce a non-derived type. if (TREE_CODE(type) == VOID_TYPE) return NULL; // Check to see if the compile unit already has created this type. TypeDesc *&Slot = TypeCache[type]; if (Slot) return Slot; // Ty will have contain the resulting type. TypeDesc *Ty = NULL; // Get the name and location early to assist debugging. const char *TypeName = GetNodeName(type); expanded_location Loc = GetNodeLocation(type); // Bit size, align and offset of the type. uint64_t Size = NodeSizeInBits(type); uint64_t Align = NodeAlignInBits(type); uint64_t Offset = 0; // Do we have a typedef? if (tree Name = TYPE_NAME(type)) { if (TREE_CODE(Name) == TYPE_DECL && DECL_ORIGINAL_TYPE(Name)) { // typedefs are derived from some other type. DerivedTypeDesc *DerivedTy = new DerivedTypeDesc(DW_TAG_typedef); // Set the slot early to prevent recursion difficulties. Slot = Ty = DerivedTy; // Handle derived type. TypeDesc *FromTy = getOrCreateType(DECL_ORIGINAL_TYPE(Name), Unit); DerivedTy->setFromType(FromTy); // typedefs size should be fetched from the derived type. Size = Align = 0; } } // If no result so far. if (!Ty) { // Work out details of type. switch (TREE_CODE(type)) { case FILE_TYPE: case ERROR_MARK: case LANG_TYPE: default: { DEBUGASSERT(0 && "Unsupported type"); return NULL; } case POINTER_TYPE: case REFERENCE_TYPE: { // type* and type& unsigned T = TREE_CODE(type) == POINTER_TYPE ? DW_TAG_pointer_type : DW_TAG_reference_type; DerivedTypeDesc *DerivedTy = new DerivedTypeDesc(T); Ty = DerivedTy; // Set the slot early to prevent recursion difficulties. // Any other use of the type should include the qualifiers. Slot = AddTypeQualifiers(type, Unit, DerivedTy); // Handle the derived type. TypeDesc *FromTy = getOrCreateType(TREE_TYPE(type), Unit); DerivedTy->setFromType(FromTy); break; } case OFFSET_TYPE: { // gen_type_die(TYPE_OFFSET_BASETYPE(type), context_die); // gen_type_die(TREE_TYPE(type), context_die); // gen_ptr_to_mbr_type_die(type, context_die); break; } case FUNCTION_TYPE: case METHOD_TYPE: { CompositeTypeDesc *SubrTy = new CompositeTypeDesc(DW_TAG_subroutine_type); Ty = SubrTy; // Set the slot early to prevent recursion difficulties. // Any other use of the type should include the qualifiers. Slot = AddTypeQualifiers(type, Unit, SubrTy); // Prepare to add the arguments for the subroutine. std::vector &Elements = SubrTy->getElements(); // Get result type. TypeDesc *ArgTy = getOrCreateType(TREE_TYPE(type), Unit); Elements.push_back(ArgTy); // Set up remainder of arguments. for (tree arg = TYPE_ARG_TYPES(type); arg; arg = TREE_CHAIN(arg)) { tree formal_type = TREE_VALUE(arg); if (formal_type == void_type_node) break; ArgTy = getOrCreateType(formal_type, Unit); Elements.push_back(ArgTy); } break; } case VECTOR_TYPE: case ARRAY_TYPE: { // type[n][m]...[p] if (TYPE_STRING_FLAG(type) && TREE_CODE(TREE_TYPE(type)) == CHAR_TYPE) { DEBUGASSERT(0 && "Don't support pascal strings"); return NULL; } CompositeTypeDesc *ArrayTy; if (TREE_CODE(type) == VECTOR_TYPE) { Ty = ArrayTy = new CompositeTypeDesc(DW_TAG_vector_type); // Set the slot early to prevent recursion difficulties. // Any other use of the type should include the qualifiers. Slot = AddTypeQualifiers(type, Unit, ArrayTy); // Use the element type of the from this point. type = TREE_TYPE(TYPE_FIELDS(TYPE_DEBUG_REPRESENTATION_TYPE(type))); } else { Ty = ArrayTy = new CompositeTypeDesc(DW_TAG_array_type); // Set the slot early to prevent recursion difficulties. // Any other use of the type should include the qualifiers. Slot = AddTypeQualifiers(type, Unit, ArrayTy); } // Prepare to add the dimensions of the array. std::vector &Elements = ArrayTy->getElements(); // There will be ARRAY_TYPE nodes for each rank. Followed by the derived // type. for (; TREE_CODE(type) == ARRAY_TYPE; type = TREE_TYPE(type)) { tree Domain = TYPE_DOMAIN(type); SubrangeDesc *Subrange = new SubrangeDesc(); if (Domain) { // FIXME - handle dynamic ranges tree MinValue = TYPE_MIN_VALUE(Domain); tree MaxValue = TYPE_MAX_VALUE(Domain); if (MinValue && MaxValue && host_integerp(MinValue, 0) && host_integerp(MaxValue, 0)) { Subrange->setLo(tree_low_cst(MinValue, 0)); Subrange->setHi(tree_low_cst(MaxValue, 0)); } } Elements.push_back(Subrange); } // Now handle the derived type. ArrayTy->setFromType(getOrCreateType(type, Unit)); break; } case ENUMERAL_TYPE: { // enum { a, b, ..., z }; CompositeTypeDesc *Enum = new CompositeTypeDesc(DW_TAG_enumeration_type); Ty = Enum; // Any other use of the type should include the qualifiers. Slot = AddTypeQualifiers(type, Unit, Enum); // Prepare to add the enumeration values. std::vector &Elements = Enum->getElements(); if (TYPE_SIZE(type)) { for (tree Link = TYPE_VALUES(type); Link; Link = TREE_CHAIN(Link)) { EnumeratorDesc *EnumDesc = new EnumeratorDesc(); tree EnumValue = TREE_VALUE(Link); int64_t Value = tree_low_cst(EnumValue, tree_int_cst_sgn(EnumValue) > 0); const char *EnumName = IDENTIFIER_POINTER(TREE_PURPOSE(Link)); EnumDesc->setName(EnumName); EnumDesc->setValue(Value); Elements.push_back(EnumDesc); } } break; } case RECORD_TYPE: case UNION_TYPE: case QUAL_UNION_TYPE: { // struct { a; b; ... z; }; | union { a; b; ... z; }; unsigned Tag = TREE_CODE(type) == RECORD_TYPE ? DW_TAG_structure_type : DW_TAG_union_type; CompositeTypeDesc *StructTy = new CompositeTypeDesc(Tag); Ty = StructTy; // Set the slot early to prevent recursion difficulties. // Any other use of the type should include the qualifiers. Slot = AddTypeQualifiers(type, Unit, StructTy); // Prepare to add the fields. std::vector &Elements = StructTy->getElements(); if (tree binfo = TYPE_BINFO(type)) { VEC (tree) *accesses = BINFO_BASE_ACCESSES (binfo); for (unsigned i = 0, e = BINFO_N_BASE_BINFOS(binfo); i != e; ++i) { tree BInfo = BINFO_BASE_BINFO(binfo, i); tree BInfoType = BINFO_TYPE (BInfo); TypeDesc *BaseClass = getOrCreateType(BInfoType, Unit); DerivedTypeDesc *MemberDesc = new DerivedTypeDesc(DW_TAG_inheritance); MemberDesc->setFromType(BaseClass); if (accesses) { tree access = VEC_index(tree, accesses, i); if (access == access_protected_node) { MemberDesc->setIsProtected(); } else if (access == access_private_node) { MemberDesc->setIsPrivate(); } } MemberDesc->setOffset(tree_low_cst(BINFO_OFFSET(BInfo), 0)); Elements.push_back(MemberDesc); } } // Now add members of this class. for (tree Member = TYPE_FIELDS(type); Member; Member = TREE_CHAIN(Member)) { // Should we skip. if (DECL_P(Member) && DECL_IGNORED_P(Member)) continue; // Get the location of the member. expanded_location MemLoc = GetNodeLocation(Member, false); CompileUnitDesc *MemFile = MemLoc.line ? getOrCreateCompileUnit(MemLoc.file) : NULL; if (TREE_CODE(Member) == FIELD_DECL) { if (DECL_FIELD_OFFSET(Member) == 0 || TREE_CODE(DECL_FIELD_OFFSET(Member)) != INTEGER_CST) // FIXME: field with variable position, skip it for now. continue; DerivedTypeDesc *MemberDesc = new DerivedTypeDesc(DW_TAG_member); // Field type is the declared type of the field. tree FieldNodeType = FieldType(Member); TypeDesc *MemberType = getOrCreateType(FieldNodeType, Unit); const char *MemberName = GetNodeName(Member); MemberDesc->setName(MemberName); MemberDesc->setFile(MemFile); MemberDesc->setLine(MemLoc.line); MemberDesc->setFromType(MemberType); MemberDesc->setSize(NodeSizeInBits(Member)); MemberDesc->setAlign(NodeAlignInBits(FieldNodeType)); MemberDesc->setOffset(int_bit_position(Member)); if (TREE_PROTECTED(Member)) { MemberDesc->setIsProtected(); } else if (TREE_PRIVATE(Member)) { MemberDesc->setIsPrivate(); } Elements.push_back(MemberDesc); } else if (TREE_CODE(Member) == VAR_DECL) { GlobalVariableDesc *Static = new GlobalVariableDesc(); // Get name information. GetGlobalNames(Member, Static); TypeDesc *TyD = getOrCreateType(TREE_TYPE(Member), Unit); // Fill in the blanks. Static->setContext(Unit); Static->setFile(MemFile); Static->setLine(MemLoc.line); Static->setType(TyD); Static->setIsDefinition(false); Static->setIsStatic(!TREE_PUBLIC(Member)); Elements.push_back(Static); } else { // FIXME - ignoring others for the time being. } } for (tree Member = TYPE_METHODS(type); Member; Member = TREE_CHAIN(Member)) { if (DECL_ABSTRACT_ORIGIN (Member)) continue; // Create subprogram descriptor. Subprogram = new SubprogramDesc(); // Get name information. GetGlobalNames(Member, Subprogram); // Get function type. TypeDesc *SPTy = getOrCreateType(TREE_TYPE(Member), Unit); if (TREE_PROTECTED(Member)) { SPTy->setIsProtected(); } else if (TREE_PRIVATE(Member)) { SPTy->setIsPrivate(); } Subprogram->setContext(Unit); Subprogram->setFile(Unit); Subprogram->setLine(CurLineNo); Subprogram->setType(SPTy); Subprogram->setIsStatic(!TREE_PUBLIC(Member)); Subprogram->setIsDefinition(false); Elements.push_back(Subprogram); } break; } case INTEGER_TYPE: case CHAR_TYPE: case REAL_TYPE: case COMPLEX_TYPE: case BOOLEAN_TYPE: { // char, short, int, long long, bool, float, double. BasicTypeDesc *BTy = new BasicTypeDesc(); Ty = BTy; // Any other use of the type should include the qualifiers. Slot = AddTypeQualifiers(type, Unit, BTy); // The encoding specific to the type. unsigned Encoding = 0; switch (TREE_CODE(type)) { case INTEGER_TYPE: // Unless is smells like a char use integer, if (!(TYPE_PRECISION(type) == CHAR_TYPE_SIZE && (type == char_type_node || !strcmp (TypeName, "signed char") || !strcmp (TypeName, "unsigned char")))) { Encoding = TYPE_UNSIGNED(type) ? DW_ATE_unsigned : DW_ATE_signed; break; } // fall through case CHAR_TYPE: Encoding = TYPE_UNSIGNED(type) ? DW_ATE_unsigned_char : DW_ATE_signed_char; break; case REAL_TYPE: Encoding = DW_ATE_float; break; case COMPLEX_TYPE: Encoding = TREE_CODE(TREE_TYPE(type)) == REAL_TYPE ? DW_ATE_complex_float : DW_ATE_lo_user; break; case BOOLEAN_TYPE: Encoding = DW_ATE_boolean; break; default: { DEBUGASSERT(0 && "Basic type case missing"); Encoding = DW_ATE_signed; Size = BITS_PER_WORD; Align = BITS_PER_WORD; break; } } BTy->setEncoding(Encoding); // Don't associate basic type with a location. Loc.line = 0; } } } // If the type is defined, fill in teh details. if (Ty) { CompileUnitDesc *File = Loc.line ? getOrCreateCompileUnit(Loc.file) : NULL; Ty->setContext(Unit); Ty->setName(TypeName); Ty->setFile(File); Ty->setLine(Loc.line); Ty->setSize(Size); Ty->setAlign(Align); Ty->setOffset(Offset); } DEBUGASSERT(Slot && "Unimplemented type"); return Slot; } /// getOrCreateCompileUnit - Get the compile unit from the cache or create a new /// one if necessary. CompileUnitDesc *DebugInfo::getOrCreateCompileUnit(const std::string &FullPath){ // See if this compile unit has been used before. CompileUnitDesc *&Slot = CompileUnitCache[FullPath]; if (Slot) return Slot; // Create new compile unit. CompileUnitDesc *Unit = new CompileUnitDesc(); // Make sure we have an anchor. if (!CompileUnitAnchor) { CompileUnitAnchor = new AnchorDesc(Unit); } // Get source file information. std::string Directory; std::string FileName; DirectoryAndFile(FullPath, Directory, FileName); Unit->setAnchor(CompileUnitAnchor); Unit->setFileName(FileName); Unit->setDirectory(Directory); // Set up producer name. Unit->setProducer(version_string); // Set up Language number. unsigned Language; const std::string LanguageName(lang_hooks.name); if (LanguageName == "GNU C") Unit->setLanguage(DW_LANG_C89); else if (LanguageName == "GNU C++") Unit->setLanguage(DW_LANG_C_plus_plus); else if (LanguageName == "GNU Ada") Unit->setLanguage(DW_LANG_Ada95); else if (LanguageName == "GNU F77") Unit->setLanguage(DW_LANG_Fortran77); else if (LanguageName == "GNU Pascal") Unit->setLanguage(DW_LANG_Pascal83); else if (LanguageName == "GNU Java") Unit->setLanguage(DW_LANG_Java); else Unit->setLanguage(DW_LANG_C89); // Update cache. Slot = Unit; return Unit; } /* APPLE LOCAL end LLVM (ENTIRE FILE!) */