Fix the source line debug information for the Windows platform.
[oota-llvm.git] / lib / CodeGen / DwarfWriter.cpp
index 74df79002f4b4a2d57fd850b1cfc7ee1349c2dc4..784bf930b584db7690734a66ba13d83a43c8323b 100644 (file)
@@ -296,6 +296,7 @@ public:
     isString,
     isLabel,
     isAsIsLabel,
+    isSectionOffset,
     isDelta,
     isEntry,
     isBlock
@@ -504,6 +505,56 @@ public:
 #endif
 };
 
+//===----------------------------------------------------------------------===//
+/// DIESectionOffset - A section offset DIE.
+//
+class DIESectionOffset : public DIEValue {
+public:
+  const DWLabel Label;
+  const DWLabel Section;
+  bool IsEH : 1;
+  bool UseSet : 1;
+  
+  DIESectionOffset(const DWLabel &Lab, const DWLabel &Sec,
+                   bool isEH = false, bool useSet = true)
+  : DIEValue(isSectionOffset), Label(Lab), Section(Sec),
+                               IsEH(isEH), UseSet(useSet) {}
+
+  // Implement isa/cast/dyncast.
+  static bool classof(const DIESectionOffset *)  { return true; }
+  static bool classof(const DIEValue *D) { return D->Type == isSectionOffset; }
+  
+  /// EmitValue - Emit section offset.
+  ///
+  virtual void EmitValue(DwarfDebug &DD, unsigned Form);
+  
+  /// SizeOf - Determine size of section offset value in bytes.
+  ///
+  virtual unsigned SizeOf(const DwarfDebug &DD, unsigned Form) const;
+  
+  /// Profile - Used to gather unique data for the value folding set.
+  ///
+  static void Profile(FoldingSetNodeID &ID, const DWLabel &Label,
+                                            const DWLabel &Section) {
+    ID.AddInteger(isSectionOffset);
+    Label.Profile(ID);
+    Section.Profile(ID);
+    // IsEH and UseSet are specific to the Label/Section that we will emit
+    // the offset for; so Label/Section are enough for uniqueness.
+  }
+  virtual void Profile(FoldingSetNodeID &ID) { Profile(ID, Label, Section); }
+
+#ifndef NDEBUG
+  virtual void print(std::ostream &O) {
+    O << "Off: ";
+    Label.print(O);
+    O << "-";
+    Section.print(O);
+    O << "-" << IsEH << "-" << UseSet;
+  }
+#endif
+};
+
 //===----------------------------------------------------------------------===//
 /// DIEDelta - A simple label difference DIE.
 /// 
@@ -1275,6 +1326,24 @@ public:
     Die->AddValue(Attribute, Form, Value);
   }
       
+  /// AddSectionOffset - Add a section offset label attribute data and value.
+  ///
+  void AddSectionOffset(DIE *Die, unsigned Attribute, unsigned Form,
+                        const DWLabel &Label, const DWLabel &Section,
+                        bool isEH = false, bool useSet = true) {
+    FoldingSetNodeID ID;
+    DIESectionOffset::Profile(ID, Label, Section);
+    void *Where;
+    DIEValue *Value = ValuesSet.FindNodeOrInsertPos(ID, Where);
+    if (!Value) {
+      Value = new DIESectionOffset(Label, Section, isEH, useSet);
+      ValuesSet.InsertNode(Value, Where);
+      Values.push_back(Value);
+    }
+  
+    Die->AddValue(Attribute, Form, Value);
+  }
+      
   /// AddDelta - Add a label delta attribute data and value.
   ///
   void AddDelta(DIE *Die, unsigned Attribute, unsigned Form,
@@ -1714,11 +1783,8 @@ private:
   CompileUnit *NewCompileUnit(CompileUnitDesc *UnitDesc, unsigned ID) {
     // Construct debug information entry.
     DIE *Die = new DIE(DW_TAG_compile_unit);
-    if (TAI->isAbsoluteDebugSectionOffsets())
-      AddLabel(Die, DW_AT_stmt_list, DW_FORM_data4, DWLabel("section_line", 0));
-    else
-      AddDelta(Die, DW_AT_stmt_list, DW_FORM_data4, DWLabel("section_line", 0),
-               DWLabel("section_line", 0));      
+    AddSectionOffset(Die, DW_AT_stmt_list, DW_FORM_data4,
+              DWLabel("section_line", 0), DWLabel("section_line", 0), false);
     AddString(Die, DW_AT_producer,  DW_FORM_string, UnitDesc->getProducer());
     AddUInt  (Die, DW_AT_language,  DW_FORM_data1,  UnitDesc->getLanguage());
     AddString(Die, DW_AT_name,      DW_FORM_string, UnitDesc->getFileName());
@@ -2796,7 +2862,7 @@ private:
   /// shouldEmitFrameModule - Per-module flag to indicate if frame moves 
   /// should be emitted.
   bool shouldEmitMovesModule;
-  
+
   /// EmitCommonEHFrame - Emit the common eh unwind frame.
   ///
   void EmitCommonEHFrame(const Function *Personality, unsigned Index) {
@@ -2813,7 +2879,7 @@ private:
 
     // Define base labels.
     EmitLabel("eh_frame_common", Index);
-    
+
     // Define the eh frame length.
     EmitDifference("eh_frame_common_end", Index,
                    "eh_frame_common_begin", Index, true);
@@ -2825,50 +2891,50 @@ private:
     Asm->EOL("CIE Identifier Tag");
     Asm->EmitInt8(DW_CIE_VERSION);
     Asm->EOL("CIE Version");
-    
+
     // The personality presence indicates that language specific information
     // will show up in the eh frame.
     Asm->EmitString(Personality ? "zPLR" : "zR");
     Asm->EOL("CIE Augmentation");
-    
+
     // Round out reader.
     Asm->EmitULEB128Bytes(1);
     Asm->EOL("CIE Code Alignment Factor");
     Asm->EmitSLEB128Bytes(stackGrowth);
-    Asm->EOL("CIE Data Alignment Factor");   
+    Asm->EOL("CIE Data Alignment Factor");
     Asm->EmitInt8(RI->getDwarfRegNum(RI->getRARegister(), true));
-    Asm->EOL("CIE RA Column");
-    
+    Asm->EOL("CIE Return Address Column");
+
     // If there is a personality, we need to indicate the functions location.
     if (Personality) {
       Asm->EmitULEB128Bytes(7);
       Asm->EOL("Augmentation Size");
 
-      if (TAI->getNeedsIndirectEncoding())
+      if (TAI->getNeedsIndirectEncoding()) {
         Asm->EmitInt8(DW_EH_PE_pcrel | DW_EH_PE_sdata4 | DW_EH_PE_indirect);
-      else
+        Asm->EOL("Personality (pcrel sdata4 indirect)");
+      } else {
         Asm->EmitInt8(DW_EH_PE_pcrel | DW_EH_PE_sdata4);
+        Asm->EOL("Personality (pcrel sdata4)");
+      }
 
-      Asm->EOL("Personality (pcrel sdata4 indirect)");
-      
-      PrintRelDirective(TAI->getShortenEHDataOn64Bit());
+      PrintRelDirective(true);
       O << TAI->getPersonalityPrefix();
       Asm->EmitExternalGlobal((const GlobalVariable *)(Personality));
       O << TAI->getPersonalitySuffix();
-      if (!TAI->getShortenEHDataOn64Bit()) {
+      if (strcmp(TAI->getPersonalitySuffix(), "+4@GOTPCREL"))
         O << "-" << TAI->getPCSymbol();
-      }
       Asm->EOL("Personality");
 
-      Asm->EmitULEB128Bytes(DW_EH_PE_pcrel);
-      Asm->EOL("LSDA Encoding (pcrel)");
-      Asm->EmitULEB128Bytes(DW_EH_PE_pcrel);
-      Asm->EOL("FDE Encoding (pcrel)");
+      Asm->EmitInt8(DW_EH_PE_pcrel | DW_EH_PE_sdata4);
+      Asm->EOL("LSDA Encoding (pcrel sdata4)");
+      Asm->EmitInt8(DW_EH_PE_pcrel | DW_EH_PE_sdata4);
+      Asm->EOL("FDE Encoding (pcrel sdata4)");
    } else {
       Asm->EmitULEB128Bytes(1);
       Asm->EOL("Augmentation Size");
-      Asm->EmitULEB128Bytes(DW_EH_PE_pcrel);
-      Asm->EOL("FDE Encoding (pcrel)");
+      Asm->EmitInt8(DW_EH_PE_pcrel | DW_EH_PE_sdata4);
+      Asm->EOL("FDE Encoding (pcrel sdata4)");
     }
 
     // Indicate locations of general callee saved registers in frame.
@@ -2876,13 +2942,16 @@ private:
     RI->getInitialFrameState(Moves);
     EmitFrameMoves(NULL, 0, Moves, true);
 
+    // On Darwin the linker honors the alignment of eh_frame, which means it
+    // must be 8-byte on 64-bit targets to match what gcc does.  Otherwise
+    // you get holes which confuse readers of eh_frame.
     Asm->EmitAlignment(TD->getPointerSize() == sizeof(int32_t) ? 2 : 3, 
                        0, 0, false);
     EmitLabel("eh_frame_common_end", Index);
-    
+
     Asm->EOL();
   }
-  
+
   /// EmitEHFrame - Emit function exception frame information.
   ///
   void EmitEHFrame(const FunctionEHFrameInfo &EHFrameInfo) {
@@ -2937,35 +3006,35 @@ private:
                         true, true, false);
       Asm->EOL("FDE CIE offset");
 
-      EmitReference("eh_func_begin", EHFrameInfo.Number, true);
+      EmitReference("eh_func_begin", EHFrameInfo.Number, true, true);
       Asm->EOL("FDE initial location");
       EmitDifference("eh_func_end", EHFrameInfo.Number,
-                     "eh_func_begin", EHFrameInfo.Number);
+                     "eh_func_begin", EHFrameInfo.Number, true);
       Asm->EOL("FDE address range");
-      
+
       // If there is a personality and landing pads then point to the language
       // specific data area in the exception table.
       if (EHFrameInfo.PersonalityIndex) {
-        Asm->EmitULEB128Bytes(TAI->getShortenEHDataOn64Bit() ? 8 : 4);
+        Asm->EmitULEB128Bytes(4);
         Asm->EOL("Augmentation size");
-        
-        if (EHFrameInfo.hasLandingPads) {
-          EmitReference("exception", EHFrameInfo.Number, true);
-        } else if (TD->getPointerSize() == 8) {
-          Asm->EmitInt64((int)0);
-        } else {
+
+        if (EHFrameInfo.hasLandingPads)
+          EmitReference("exception", EHFrameInfo.Number, true, true);
+        else
           Asm->EmitInt32((int)0);
-        }
         Asm->EOL("Language Specific Data Area");
       } else {
         Asm->EmitULEB128Bytes(0);
         Asm->EOL("Augmentation size");
       }
-      
+
       // Indicate locations of function specific  callee saved registers in
       // frame.
       EmitFrameMoves("eh_func_begin", EHFrameInfo.Number, EHFrameInfo.Moves, true);
       
+      // On Darwin the linker honors the alignment of eh_frame, which means it
+      // must be 8-byte on 64-bit targets to match what gcc does.  Otherwise
+      // you get holes which confuse readers of eh_frame.
       Asm->EmitAlignment(TD->getPointerSize() == sizeof(int32_t) ? 2 : 3, 
                          0, 0, false);
       EmitLabel("eh_frame_end", EHFrameInfo.Number);
@@ -3261,13 +3330,20 @@ private:
     }
 
     // Final tallies.
-    unsigned SizeSites = CallSites.size() * (sizeof(int32_t) + // Site start.
-                                             sizeof(int32_t) + // Site length.
-                                             sizeof(int32_t)); // Landing pad.
+
+    // Call sites.
+    const unsigned SiteStartSize  = sizeof(int32_t); // DW_EH_PE_udata4
+    const unsigned SiteLengthSize = sizeof(int32_t); // DW_EH_PE_udata4
+    const unsigned LandingPadSize = sizeof(int32_t); // DW_EH_PE_udata4
+    unsigned SizeSites = CallSites.size() * (SiteStartSize +
+                                             SiteLengthSize +
+                                             LandingPadSize);
     for (unsigned i = 0, e = CallSites.size(); i < e; ++i)
       SizeSites += Asm->SizeULEB128(CallSites[i].Action);
 
-    unsigned SizeTypes = TypeInfos.size() * TD->getPointerSize();
+    // Type infos.
+    const unsigned TypeInfoSize = TD->getPointerSize(); // DW_EH_PE_absptr
+    unsigned SizeTypes = TypeInfos.size() * TypeInfoSize;
 
     unsigned TypeOffset = sizeof(int8_t) + // Call site format
                           Asm->SizeULEB128(SizeSites) + // Call-site table length
@@ -3317,27 +3393,22 @@ private:
       }
 
       EmitSectionOffset(BeginTag, "eh_func_begin", BeginNumber, SubprogramCount,
-                        TAI->getShortenEHDataOn64Bit(), true);
+                        true, true);
       Asm->EOL("Region start");
 
       if (!S.EndLabel) {
         EmitDifference("eh_func_end", SubprogramCount, BeginTag, BeginNumber,
-                       TAI->getShortenEHDataOn64Bit());
+                       true);
       } else {
-        EmitDifference("label", S.EndLabel, BeginTag, BeginNumber, 
-                       TAI->getShortenEHDataOn64Bit());
+        EmitDifference("label", S.EndLabel, BeginTag, BeginNumber, true);
       }
       Asm->EOL("Region length");
 
-      if (!S.PadLabel) {
-        if (TD->getPointerSize() == sizeof(int32_t) || TAI->getShortenEHDataOn64Bit())
-          Asm->EmitInt32(0);
-        else
-          Asm->EmitInt64(0);
-      } else {
+      if (!S.PadLabel)
+        Asm->EmitInt32(0);
+      else
         EmitSectionOffset("label", "eh_func_begin", S.PadLabel, SubprogramCount,
-                          TAI->getShortenEHDataOn64Bit(), true);
-      }
+                          true, true);
       Asm->EOL("Landing pad");
 
       Asm->EmitULEB128Bytes(S.Action);
@@ -3610,6 +3681,23 @@ unsigned DIEObjectLabel::SizeOf(const DwarfDebug &DD, unsigned Form) const {
     
 //===----------------------------------------------------------------------===//
 
+/// EmitValue - Emit delta value.
+///
+void DIESectionOffset::EmitValue(DwarfDebug &DD, unsigned Form) {
+  bool IsSmall = Form == DW_FORM_data4;
+  DD.EmitSectionOffset(Label.Tag, Section.Tag,
+                       Label.Number, Section.Number, IsSmall, IsEH, UseSet);
+}
+
+/// SizeOf - Determine size of delta value in bytes.
+///
+unsigned DIESectionOffset::SizeOf(const DwarfDebug &DD, unsigned Form) const {
+  if (Form == DW_FORM_data4) return 4;
+  return DD.getTargetData()->getPointerSize();
+}
+    
+//===----------------------------------------------------------------------===//
+
 /// EmitValue - Emit delta value.
 ///
 void DIEDelta::EmitValue(DwarfDebug &DD, unsigned Form) {