[llvm-commits] [llvm] r80625 - in /llvm/trunk: include/llvm/Analysis/DebugInfo.h lib/CodeGen/AsmPrinter/DwarfDebug.cpp lib/CodeGen/AsmPrinter/DwarfDebug.h

Caroline Tice ctice at apple.com
Mon Aug 31 14:19:38 PDT 2009


Author: ctice
Date: Mon Aug 31 16:19:37 2009
New Revision: 80625

URL: http://llvm.org/viewvc/llvm-project?rev=80625&view=rev
Log:
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.

Modified:
    llvm/trunk/include/llvm/Analysis/DebugInfo.h
    llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
    llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h

Modified: llvm/trunk/include/llvm/Analysis/DebugInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/DebugInfo.h?rev=80625&r1=80624&r2=80625&view=diff

==============================================================================
--- llvm/trunk/include/llvm/Analysis/DebugInfo.h (original)
+++ llvm/trunk/include/llvm/Analysis/DebugInfo.h Mon Aug 31 16:19:37 2009
@@ -191,7 +191,8 @@
       FlagPrivate    = 1 << 0,
       FlagProtected  = 1 << 1,
       FlagFwdDecl    = 1 << 2,
-      FlagAppleBlock = 1 << 3
+      FlagAppleBlock = 1 << 3,
+      FlagBlockByrefStruct = 1 << 4
     };
 
   protected:
@@ -235,6 +236,9 @@
     bool isAppleBlockExtension() const {
       return (getFlags() & FlagAppleBlock) != 0; 
     }
+    bool isBlockByrefStruct() const {
+      return (getFlags() & FlagBlockByrefStruct) != 0;
+    }
 
     /// dump - print type.
     void dump() const;
@@ -401,6 +405,12 @@
     /// Verify - Verify that a variable descriptor is well formed.
     bool Verify() const;
 
+    /// isBlockByrefVariable - Return true if the variable was declared as
+    /// a "__block" variable (Apple Blocks).
+    bool isBlockByrefVariable() const { 
+      return getType().isBlockByrefStruct(); 
+    }
+
     /// dump - print variable.
     void dump() const;
   };

Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp?rev=80625&r1=80624&r2=80625&view=diff

==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp Mon Aug 31 16:19:37 2009
@@ -500,6 +500,238 @@
   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 @@
   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 @@
     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;

Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h?rev=80625&r1=80624&r2=80625&view=diff

==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h Mon Aug 31 16:19:37 2009
@@ -287,6 +287,14 @@
   void AddAddress(DIE *Die, unsigned Attribute,
                   const MachineLocation &Location);
 
+  /// 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.
+  ///
+  void AddBlockByrefAddress(DbgVariable *&DV, DIE *Die, unsigned Attribute,
+                            const MachineLocation &Location);
+
   /// AddType - Add a new type attribute to the specified entity.
   void AddType(CompileUnit *DW_Unit, DIE *Entity, DIType Ty);
 
@@ -454,6 +462,11 @@
 
   void ConstructSubprogram(MDNode *N);
 
+  /// Find the type the programmer originally declared the variable to be
+  /// and return that type.
+  ///
+  DIType GetBlockByrefType(DIType Ty, std::string Name);
+
 public:
   //===--------------------------------------------------------------------===//
   // Main entry points.





More information about the llvm-commits mailing list