| /* 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 <iostream> |
| |
| 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) { |
| // Ignore compiler generated temporaries. |
| if (DECL_IGNORED_P(decl)) |
| return; |
| |
| // 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<Value *, 2> 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<DebugInfoDesc *> &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<DebugInfoDesc *> &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<DebugInfoDesc *> &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<DebugInfoDesc *> &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; |
| } |
| |
| /// readLLVMDebugInfo - Read debug info from PCH file. TheModule already |
| /// represents module read from PCH file. Restore AnchorDesc from PCH file. |
| void DebugInfo::readLLVMDebugInfo() { |
| MachineModuleInfo MMI; |
| MMI.AnalyzeModule(*TheModule); |
| |
| std::vector<SubprogramDesc *> Subprograms = |
| MMI.getAnchoredDescriptors<SubprogramDesc>(*TheModule); |
| |
| if (!Subprograms.empty()) |
| SubprogramAnchor = Subprograms[0]->getAnchor(); |
| |
| std::vector<CompileUnitDesc *> CUs = |
| MMI.getAnchoredDescriptors<CompileUnitDesc>(*TheModule); |
| |
| if (!CUs.empty()) |
| CompileUnitAnchor = CUs[0]->getAnchor(); |
| |
| std::vector<GlobalVariableDesc *> GVs = |
| MMI.getAnchoredDescriptors<GlobalVariableDesc>(*TheModule); |
| |
| if (!GVs.empty()) |
| GlobalVariableAnchor = GVs[0]->getAnchor(); |
| |
| const std::map<GlobalVariable *, DebugInfoDesc *> &GlobalDescs |
| = MMI.getDIDeserializer()->getGlobalDescs(); |
| for (std::map<GlobalVariable *, DebugInfoDesc *>::const_iterator |
| I = GlobalDescs.begin(), E = GlobalDescs.end(); I != E; ++I) |
| SR.addDescriptor(I->second, I->first); |
| } |
| |
| /* APPLE LOCAL end LLVM (ENTIRE FILE!) */ |
| |