aboutsummaryrefslogtreecommitdiffstats
path: root/lib/CodeGen
diff options
context:
space:
mode:
authorCaroline Tice <ctice@apple.com>2009-08-31 21:19:37 +0000
committerCaroline Tice <ctice@apple.com>2009-08-31 21:19:37 +0000
commitdc8f6049d11ee73835c7b7e9b7c6d0b9e6a2c9b1 (patch)
tree389b40bb51c33a90478b8ed76858c339185d79af /lib/CodeGen
parent42214899082bfb5b6f8c6a09d355fec9ef4a0e82 (diff)
downloadexternal_llvm-dc8f6049d11ee73835c7b7e9b7c6d0b9e6a2c9b1.zip
external_llvm-dc8f6049d11ee73835c7b7e9b7c6d0b9e6a2c9b1.tar.gz
external_llvm-dc8f6049d11ee73835c7b7e9b7c6d0b9e6a2c9b1.tar.bz2
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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@80625 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen')
-rw-r--r--lib/CodeGen/AsmPrinter/DwarfDebug.cpp243
-rw-r--r--lib/CodeGen/AsmPrinter/DwarfDebug.h13
2 files changed, 254 insertions, 2 deletions
diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index 0e8521e..40ff3e4 100644
--- a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/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;
diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.h b/lib/CodeGen/AsmPrinter/DwarfDebug.h
index 917d6ef..44fef29 100644
--- a/lib/CodeGen/AsmPrinter/DwarfDebug.h
+++ b/lib/CodeGen/AsmPrinter/DwarfDebug.h
@@ -287,6 +287,14 @@ class VISIBILITY_HIDDEN DwarfDebug : public Dwarf {
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 @@ class VISIBILITY_HIDDEN DwarfDebug : public Dwarf {
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.