diff options
| author | Caroline Tice <ctice@apple.com> | 2009-08-31 21:19:37 +0000 | 
|---|---|---|
| committer | Caroline Tice <ctice@apple.com> | 2009-08-31 21:19:37 +0000 | 
| commit | c87c1e2cfd37338ae241dd99ad410d8ca96fec26 (patch) | |
| tree | a1d19d1ab91c6f43af636bf0e756945b9e2dfd76 /llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp | |
| parent | fbc1823451449005dd486e978460feb5de87b333 (diff) | |
| download | bcm5719-llvm-c87c1e2cfd37338ae241dd99ad410d8ca96fec26.tar.gz bcm5719-llvm-c87c1e2cfd37338ae241dd99ad410d8ca96fec26.zip | |
Add flag to mark structs for Apple Block "byref" variables; also add code to
modify the type and location debug information for these variables to match the
programmer's expectations.
llvm-svn: 80625
Diffstat (limited to 'llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp')
| -rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 243 | 
1 files changed, 241 insertions, 2 deletions
| diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 0e8521e83e5..40ff3e49cf7 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -500,6 +500,238 @@ void DwarfDebug::AddSourceLine(DIE *Die, const DIType *Ty) {    AddUInt(Die, dwarf::DW_AT_decl_line, 0, Line);  } +/* Byref variables, in Blocks, are declared by the programmer as +   "SomeType VarName;", but the compiler creates a +   __Block_byref_x_VarName struct, and gives the variable VarName +   either the struct, or a pointer to the struct, as its type.  This +   is necessary for various behind-the-scenes things the compiler +   needs to do with by-reference variables in blocks. + +   However, as far as the original *programmer* is concerned, the +   variable should still have type 'SomeType', as originally declared. + +   The following function dives into the __Block_byref_x_VarName +   struct to find the original type of the variable.  This will be +   passed back to the code generating the type for the Debug +   Information Entry for the variable 'VarName'.  'VarName' will then +   have the original type 'SomeType' in its debug information. + +   The original type 'SomeType' will be the type of the field named +   'VarName' inside the __Block_byref_x_VarName struct. + +   NOTE: In order for this to not completely fail on the debugger +   side, the Debug Information Entry for the variable VarName needs to +   have a DW_AT_location that tells the debugger how to unwind through +   the pointers and __Block_byref_x_VarName struct to find the actual +   value of the variable.  The function AddBlockByrefType does this.  */ + +/// Find the type the programmer originally declared the variable to be +/// and return that type. +/// +DIType DwarfDebug::GetBlockByrefType(DIType Ty, std::string Name) { + +  DIType subType = Ty; +  unsigned tag = Ty.getTag(); + +  if (tag == dwarf::DW_TAG_pointer_type) { +    DIDerivedType DTy = DIDerivedType (Ty.getNode()); +    subType = DTy.getTypeDerivedFrom(); +  } + +  DICompositeType blockStruct = DICompositeType(subType.getNode()); + +  DIArray Elements = blockStruct.getTypeArray(); + +  if (Elements.isNull()) +    return Ty; + +  for (unsigned i = 0, N = Elements.getNumElements(); i < N; ++i) { +    DIDescriptor Element = Elements.getElement(i); +    DIDerivedType DT = DIDerivedType(Element.getNode()); +    std::string Name2; +    DT.getName(Name2); +    if (Name == Name2) +      return (DT.getTypeDerivedFrom()); +  } + +  return Ty; +} + +/* Byref variables, in Blocks, are declared by the programmer as "SomeType +   VarName;", but the compiler creates a __Block_byref_x_VarName struct, and +   gives the variable VarName either the struct, or a pointer to the struct, as +   its type.  This is necessary for various behind-the-scenes things the +   compiler needs to do with by-reference variables in Blocks. + +   However, as far as the original *programmer* is concerned, the variable +   should still have type 'SomeType', as originally declared. + +   The function GetBlockByrefType dives into the __Block_byref_x_VarName +   struct to find the original type of the variable, which is then assigned to +   the variable's Debug Information Entry as its real type.  So far, so good. +   However now the debugger will expect the variable VarName to have the type +   SomeType.  So we need the location attribute for the variable to be an +   expression that explains to the debugger how to navigate through the  +   pointers and struct to find the actual variable of type SomeType. + +   The following function does just that.  We start by getting +   the "normal" location for the variable. This will be the location +   of either the struct __Block_byref_x_VarName or the pointer to the +   struct __Block_byref_x_VarName. + +   The struct will look something like: + +   struct __Block_byref_x_VarName { +     ... <various fields> +     struct __Block_byref_x_VarName *forwarding; +     ... <various other fields> +     SomeType VarName; +     ... <maybe more fields> +   }; + +   If we are given the struct directly (as our starting point) we +   need to tell the debugger to: + +   1).  Add the offset of the forwarding field. + +   2).  Follow that pointer to get the the real __Block_byref_x_VarName +   struct to use (the real one may have been copied onto the heap). + +   3).  Add the offset for the field VarName, to find the actual variable. + +   If we started with a pointer to the struct, then we need to +   dereference that pointer first, before the other steps. +   Translating this into DWARF ops, we will need to append the following +   to the current location description for the variable: + +   DW_OP_deref                    -- optional, if we start with a pointer +   DW_OP_plus_uconst <forward_fld_offset> +   DW_OP_deref +   DW_OP_plus_uconst <varName_fld_offset> + +   That is what this function does.  */ + +/// AddBlockByrefAddress - Start with the address based on the location +/// provided, and generate the DWARF information necessary to find the +/// actual Block variable (navigating the Block struct) based on the +/// starting location.  Add the DWARF information to the die.  For +/// more information, read large comment just above here. +/// +void DwarfDebug::AddBlockByrefAddress(DbgVariable *&DV, DIE *Die,  +                                       unsigned Attribute, +                                       const MachineLocation &Location) { +  const DIVariable &VD = DV->getVariable(); +  DIType Ty = VD.getType(); +  DIType TmpTy = Ty; +  unsigned Tag = Ty.getTag(); +  bool isPointer = false; + +  std::string varName; +  VD.getName(varName); + +  if (Tag == dwarf::DW_TAG_pointer_type) { +    DIDerivedType DTy = DIDerivedType (Ty.getNode()); +    TmpTy = DTy.getTypeDerivedFrom(); +    isPointer = true; +  } + +  DICompositeType blockStruct = DICompositeType(TmpTy.getNode()); + +  std::string typeName; +  blockStruct.getName(typeName); + +   assert(typeName.find ("__Block_byref_") == 0 +          && "Attempting to get Block location of non-Block variable!"); + +   // Find the __forwarding field and the variable field in the __Block_byref +   // struct. +    +   DIArray Fields = blockStruct.getTypeArray(); +   DIDescriptor varField = DIDescriptor(); +   DIDescriptor forwardingField = DIDescriptor(); + + +   for (unsigned i = 0, N = Fields.getNumElements(); i < N; ++i) { +     DIDescriptor Element = Fields.getElement(i); +     DIDerivedType DT = DIDerivedType(Element.getNode()); +     std::string fieldName; +     DT.getName(fieldName); +     if (fieldName == "__forwarding") +       forwardingField = Element; +     else if (fieldName == varName) +       varField = Element; +   } +      +   assert (!varField.isNull() && "Can't find byref variable in Block struct"); +   assert (!forwardingField.isNull()  +           && "Can't find forwarding field in Block struct"); + +   // Get the offsets for the forwarding field and the variable field. + +   unsigned int forwardingFieldOffset =  +     DIDerivedType(forwardingField.getNode()).getOffsetInBits() >> 3; +   unsigned int varFieldOffset =  +     DIDerivedType(varField.getNode()).getOffsetInBits() >> 3; + +   // Decode the original location, and use that as the start of the  +   // byref variable's location. + +   unsigned Reg = RI->getDwarfRegNum(Location.getReg(), false); +   DIEBlock *Block = new DIEBlock(); + +   if (Location.isReg()) { +     if (Reg < 32) +       AddUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_reg0 + Reg); +     else { +       Reg = Reg - dwarf::DW_OP_reg0; +       AddUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_breg0 + Reg); +       AddUInt(Block, 0, dwarf::DW_FORM_udata, Reg); +     } +   } else { +     if (Reg < 32) +       AddUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_breg0 + Reg); +     else { +       AddUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_bregx); +       AddUInt(Block, 0, dwarf::DW_FORM_udata, Reg); +     } + +     AddUInt(Block, 0, dwarf::DW_FORM_sdata, Location.getOffset()); +   } + +   // If we started with a pointer to the__Block_byref... struct, then +   // the first thing we need to do is dereference the pointer (DW_OP_deref). + +   if (isPointer) +     AddUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_deref); + +   // Next add the offset for the '__forwarding' field: +   // DW_OP_plus_uconst ForwardingFieldOffset.  Note there's no point in +   // adding the offset if it's 0. + +   if (forwardingFieldOffset > 0) { +     AddUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_plus_uconst); +     AddUInt(Block, 0, dwarf::DW_FORM_udata, forwardingFieldOffset); +   } + +   // Now dereference the __forwarding field to get to the real __Block_byref +   // struct:  DW_OP_deref. + +   AddUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_deref); + +   // Now that we've got the real __Block_byref... struct, add the offset +   // for the variable's field to get to the location of the actual variable: +   // DW_OP_plus_uconst varFieldOffset.  Again, don't add if it's 0. + +   if (varFieldOffset > 0) { +     AddUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_plus_uconst); +     AddUInt(Block, 0, dwarf::DW_FORM_udata, varFieldOffset); +   } + +   // Now attach the location information to the DIE. + +   AddBlock(Die, Attribute, 0, Block); +} +  /// AddAddress - Add an address attribute to a die based on the location  /// provided.  void DwarfDebug::AddAddress(DIE *Die, unsigned Attribute, @@ -961,7 +1193,10 @@ DIE *DwarfDebug::CreateDbgScopeVariable(DbgVariable *DV, CompileUnit *Unit) {    AddSourceLine(VariableDie, &VD);    // Add variable type. -  AddType(Unit, VariableDie, VD.getType()); +  if (VD.isBlockByrefVariable()) +    AddType(Unit, VariableDie, GetBlockByrefType(VD.getType(), Name)); +  else +    AddType(Unit, VariableDie, VD.getType());    // Add variable address.    if (!DV->isInlinedFnVar()) { @@ -970,7 +1205,11 @@ DIE *DwarfDebug::CreateDbgScopeVariable(DbgVariable *DV, CompileUnit *Unit) {      MachineLocation Location;      Location.set(RI->getFrameRegister(*MF),                   RI->getFrameIndexOffset(*MF, DV->getFrameIndex())); -    AddAddress(VariableDie, dwarf::DW_AT_location, Location); + +    if (VD.isBlockByrefVariable()) +      AddBlockByrefAddress (DV, VariableDie, dwarf::DW_AT_location, Location); +    else +      AddAddress(VariableDie, dwarf::DW_AT_location, Location);    }    return VariableDie; | 

