X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FCodeGen%2FDwarfWriter.cpp;h=8cc7f30979b8e9d5d81667b82d35a04bac883216;hb=420cdebbcb95f3881ab3518fd3bb670837669e43;hp=2b9cf74f88af614db82ae8c3ed73f8460bb9afd5;hpb=c1c47c3fa4d6d21b65924c02ab2f228e6285152d;p=oota-llvm.git diff --git a/lib/CodeGen/DwarfWriter.cpp b/lib/CodeGen/DwarfWriter.cpp index 2b9cf74f88a..8cc7f30979b 100644 --- a/lib/CodeGen/DwarfWriter.cpp +++ b/lib/CodeGen/DwarfWriter.cpp @@ -2,8 +2,8 @@ // // The LLVM Compiler Infrastructure // -// This file was developed by James M. Laskey and is distributed under the -// University of Illinois Open Source License. See LICENSE.TXT for details. +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // @@ -13,6 +13,7 @@ #include "llvm/CodeGen/DwarfWriter.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/UniqueVector.h" @@ -22,14 +23,17 @@ #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineLocation.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/Mangler.h" +#include "llvm/System/Path.h" #include "llvm/Target/TargetAsmInfo.h" -#include "llvm/Target/MRegisterInfo.h" +#include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetFrameInfo.h" +#include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" #include @@ -55,9 +59,9 @@ class DIEValue; //===----------------------------------------------------------------------===// /// DWLabel - Labels are used to track locations in the assembler file. -/// Labels appear in the form debug_, where the tag is a -/// category of label (Ex. location) and number is a value unique in that -/// category. +/// Labels appear in the form @verbatim @endverbatim, +/// where the tag is a category of label (Ex. location) and number is a value +/// unique in that category. class DWLabel { public: /// Tag - Label category tag. Should always be a staticly declared C string. @@ -80,7 +84,7 @@ public: if (O) print(*O); } void print(std::ostream &O) const { - O << ".debug_" << Tag; + O << "." << Tag; if (Number) O << Number; } #endif @@ -218,7 +222,7 @@ protected: std::vector Values; public: - DIE(unsigned Tag) + explicit DIE(unsigned Tag) : Abbrev(Tag, DW_CHILDREN_no) , Offset(0) , Size(0) @@ -236,7 +240,7 @@ public: unsigned getOffset() const { return Offset; } unsigned getSize() const { return Size; } const std::vector &getChildren() const { return Children; } - const std::vector &getValues() const { return Values; } + std::vector &getValues() { return Values; } void setTag(unsigned Tag) { Abbrev.setTag(Tag); } void setOffset(unsigned O) { Offset = O; } void setSize(unsigned S) { Size = S; } @@ -301,7 +305,7 @@ public: /// unsigned Type; - DIEValue(unsigned T) + explicit DIEValue(unsigned T) : Type(T) {} virtual ~DIEValue() {} @@ -314,7 +318,7 @@ public: /// EmitValue - Emit value via the Dwarf writer. /// - virtual void EmitValue(const DwarfDebug &DD, unsigned Form) const = 0; + virtual void EmitValue(DwarfDebug &DD, unsigned Form) = 0; /// SizeOf - Return the size of a value in bytes. /// @@ -341,7 +345,7 @@ private: uint64_t Integer; public: - DIEInteger(uint64_t I) : DIEValue(isInteger), Integer(I) {} + explicit DIEInteger(uint64_t I) : DIEValue(isInteger), Integer(I) {} // Implement isa/cast/dyncast. static bool classof(const DIEInteger *) { return true; } @@ -364,7 +368,7 @@ public: /// EmitValue - Emit integer of appropriate size. /// - virtual void EmitValue(const DwarfDebug &DD, unsigned Form) const; + virtual void EmitValue(DwarfDebug &DD, unsigned Form); /// SizeOf - Determine size of integer value in bytes. /// @@ -393,7 +397,7 @@ class DIEString : public DIEValue { public: const std::string String; - DIEString(const std::string &S) : DIEValue(isString), String(S) {} + explicit DIEString(const std::string &S) : DIEValue(isString), String(S) {} // Implement isa/cast/dyncast. static bool classof(const DIEString *) { return true; } @@ -401,7 +405,7 @@ public: /// EmitValue - Emit string value. /// - virtual void EmitValue(const DwarfDebug &DD, unsigned Form) const; + virtual void EmitValue(DwarfDebug &DD, unsigned Form); /// SizeOf - Determine size of string value in bytes. /// @@ -432,7 +436,7 @@ public: const DWLabel Label; - DIEDwarfLabel(const DWLabel &L) : DIEValue(isLabel), Label(L) {} + explicit DIEDwarfLabel(const DWLabel &L) : DIEValue(isLabel), Label(L) {} // Implement isa/cast/dyncast. static bool classof(const DIEDwarfLabel *) { return true; } @@ -440,7 +444,7 @@ public: /// EmitValue - Emit label value. /// - virtual void EmitValue(const DwarfDebug &DD, unsigned Form) const; + virtual void EmitValue(DwarfDebug &DD, unsigned Form); /// SizeOf - Determine size of label value in bytes. /// @@ -470,7 +474,8 @@ class DIEObjectLabel : public DIEValue { public: const std::string Label; - DIEObjectLabel(const std::string &L) : DIEValue(isAsIsLabel), Label(L) {} + explicit DIEObjectLabel(const std::string &L) + : DIEValue(isAsIsLabel), Label(L) {} // Implement isa/cast/dyncast. static bool classof(const DIEObjectLabel *) { return true; } @@ -478,7 +483,7 @@ public: /// EmitValue - Emit label value. /// - virtual void EmitValue(const DwarfDebug &DD, unsigned Form) const; + virtual void EmitValue(DwarfDebug &DD, unsigned Form); /// SizeOf - Determine size of label value in bytes. /// @@ -516,7 +521,7 @@ public: /// EmitValue - Emit delta value. /// - virtual void EmitValue(const DwarfDebug &DD, unsigned Form) const; + virtual void EmitValue(DwarfDebug &DD, unsigned Form); /// SizeOf - Determine size of delta value in bytes. /// @@ -550,7 +555,7 @@ class DIEntry : public DIEValue { public: DIE *Entry; - DIEntry(DIE *E) : DIEValue(isEntry), Entry(E) {} + explicit DIEntry(DIE *E) : DIEValue(isEntry), Entry(E) {} // Implement isa/cast/dyncast. static bool classof(const DIEntry *) { return true; } @@ -558,7 +563,7 @@ public: /// EmitValue - Emit debug information entry offset. /// - virtual void EmitValue(const DwarfDebug &DD, unsigned Form) const; + virtual void EmitValue(DwarfDebug &DD, unsigned Form); /// SizeOf - Determine size of debug information entry in bytes. /// @@ -623,7 +628,7 @@ public: /// EmitValue - Emit block data. /// - virtual void EmitValue(const DwarfDebug &DD, unsigned Form) const; + virtual void EmitValue(DwarfDebug &DD, unsigned Form); /// SizeOf - Determine size of block data in bytes. /// @@ -777,7 +782,7 @@ protected: const TargetData *TD; /// RI - Register Information. - const MRegisterInfo *RI; + const TargetRegisterInfo *RI; /// M - Current module. /// @@ -791,19 +796,17 @@ protected: /// MachineModuleInfo *MMI; - /// didInitial - Flag to indicate if initial emission has been done. - /// - bool didInitial; - - /// shouldEmit - Flag to indicate if debug information should be emitted. - /// - bool shouldEmit; - /// SubprogramCount - The running count of functions being compiled. /// unsigned SubprogramCount; - Dwarf(std::ostream &OS, AsmPrinter *A, const TargetAsmInfo *T) + /// Flavor - A unique string indicating what dwarf producer this is, used to + /// unique labels. + const char * const Flavor; + + unsigned SetCounter; + Dwarf(std::ostream &OS, AsmPrinter *A, const TargetAsmInfo *T, + const char *flavor) : O(OS) , Asm(A) , TAI(T) @@ -812,9 +815,9 @@ protected: , M(NULL) , MF(NULL) , MMI(NULL) - , didInitial(false) - , shouldEmit(false) , SubprogramCount(0) + , Flavor(flavor) + , SetCounter(1) { } @@ -824,11 +827,237 @@ public: // Accessors. // AsmPrinter *getAsm() const { return Asm; } + MachineModuleInfo *getMMI() const { return MMI; } const TargetAsmInfo *getTargetAsmInfo() const { return TAI; } + const TargetData *getTargetData() const { return TD; } - /// ShouldEmitDwarf - Returns true if Dwarf declarations should be made. + void PrintRelDirective(bool Force32Bit = false, bool isInSection = false) + const { + if (isInSection && TAI->getDwarfSectionOffsetDirective()) + O << TAI->getDwarfSectionOffsetDirective(); + else if (Force32Bit || TD->getPointerSize() == sizeof(int32_t)) + O << TAI->getData32bitsDirective(); + else + O << TAI->getData64bitsDirective(); + } + + /// PrintLabelName - Print label name in form used by Dwarf writer. /// - bool ShouldEmitDwarf() const { return shouldEmit; } + void PrintLabelName(DWLabel Label) const { + PrintLabelName(Label.Tag, Label.Number); + } + void PrintLabelName(const char *Tag, unsigned Number) const { + O << TAI->getPrivateGlobalPrefix() << Tag; + if (Number) O << Number; + } + + void PrintLabelName(const char *Tag, unsigned Number, + const char *Suffix) const { + O << TAI->getPrivateGlobalPrefix() << Tag; + if (Number) O << Number; + O << Suffix; + } + + /// EmitLabel - Emit location label for internal use by Dwarf. + /// + void EmitLabel(DWLabel Label) const { + EmitLabel(Label.Tag, Label.Number); + } + void EmitLabel(const char *Tag, unsigned Number) const { + PrintLabelName(Tag, Number); + O << ":\n"; + } + + /// EmitReference - Emit a reference to a label. + /// + void EmitReference(DWLabel Label, bool IsPCRelative = false, + bool Force32Bit = false) const { + EmitReference(Label.Tag, Label.Number, IsPCRelative, Force32Bit); + } + void EmitReference(const char *Tag, unsigned Number, + bool IsPCRelative = false, bool Force32Bit = false) const { + PrintRelDirective(Force32Bit); + PrintLabelName(Tag, Number); + + if (IsPCRelative) O << "-" << TAI->getPCSymbol(); + } + void EmitReference(const std::string &Name, bool IsPCRelative = false, + bool Force32Bit = false) const { + PrintRelDirective(Force32Bit); + + O << Name; + + if (IsPCRelative) O << "-" << TAI->getPCSymbol(); + } + + /// EmitDifference - Emit the difference between two labels. Some + /// assemblers do not behave with absolute expressions with data directives, + /// so there is an option (needsSet) to use an intermediary set expression. + void EmitDifference(DWLabel LabelHi, DWLabel LabelLo, + bool IsSmall = false) { + EmitDifference(LabelHi.Tag, LabelHi.Number, + LabelLo.Tag, LabelLo.Number, + IsSmall); + } + void EmitDifference(const char *TagHi, unsigned NumberHi, + const char *TagLo, unsigned NumberLo, + bool IsSmall = false) { + if (TAI->needsSet()) { + O << "\t.set\t"; + PrintLabelName("set", SetCounter, Flavor); + O << ","; + PrintLabelName(TagHi, NumberHi); + O << "-"; + PrintLabelName(TagLo, NumberLo); + O << "\n"; + + PrintRelDirective(IsSmall); + PrintLabelName("set", SetCounter, Flavor); + ++SetCounter; + } else { + PrintRelDirective(IsSmall); + + PrintLabelName(TagHi, NumberHi); + O << "-"; + PrintLabelName(TagLo, NumberLo); + } + } + + void EmitSectionOffset(const char* Label, const char* Section, + unsigned LabelNumber, unsigned SectionNumber, + bool IsSmall = false, bool isEH = false) { + bool printAbsolute = false; + if (TAI->needsSet()) { + O << "\t.set\t"; + PrintLabelName("set", SetCounter, Flavor); + O << ","; + PrintLabelName(Label, LabelNumber); + + if (isEH) + printAbsolute = TAI->isAbsoluteEHSectionOffsets(); + else + printAbsolute = TAI->isAbsoluteDebugSectionOffsets(); + + if (!printAbsolute) { + O << "-"; + PrintLabelName(Section, SectionNumber); + } + O << "\n"; + + PrintRelDirective(IsSmall); + + PrintLabelName("set", SetCounter, Flavor); + ++SetCounter; + } else { + PrintRelDirective(IsSmall, true); + + PrintLabelName(Label, LabelNumber); + + if (isEH) + printAbsolute = TAI->isAbsoluteEHSectionOffsets(); + else + printAbsolute = TAI->isAbsoluteDebugSectionOffsets(); + + if (!printAbsolute) { + O << "-"; + PrintLabelName(Section, SectionNumber); + } + } + } + + /// EmitFrameMoves - Emit frame instructions to describe the layout of the + /// frame. + void EmitFrameMoves(const char *BaseLabel, unsigned BaseLabelID, + const std::vector &Moves, bool isEH) { + int stackGrowth = + Asm->TM.getFrameInfo()->getStackGrowthDirection() == + TargetFrameInfo::StackGrowsUp ? + TD->getPointerSize() : -TD->getPointerSize(); + bool IsLocal = BaseLabel && strcmp(BaseLabel, "label") == 0; + + for (unsigned i = 0, N = Moves.size(); i < N; ++i) { + const MachineMove &Move = Moves[i]; + unsigned LabelID = Move.getLabelID(); + + if (LabelID) { + LabelID = MMI->MappedLabel(LabelID); + + // Throw out move if the label is invalid. + if (!LabelID) continue; + } + + const MachineLocation &Dst = Move.getDestination(); + const MachineLocation &Src = Move.getSource(); + + // Advance row if new location. + if (BaseLabel && LabelID && (BaseLabelID != LabelID || !IsLocal)) { + Asm->EmitInt8(DW_CFA_advance_loc4); + Asm->EOL("DW_CFA_advance_loc4"); + EmitDifference("label", LabelID, BaseLabel, BaseLabelID, true); + Asm->EOL(); + + BaseLabelID = LabelID; + BaseLabel = "label"; + IsLocal = true; + } + + // If advancing cfa. + if (Dst.isRegister() && Dst.getRegister() == MachineLocation::VirtualFP) { + if (!Src.isRegister()) { + if (Src.getRegister() == MachineLocation::VirtualFP) { + Asm->EmitInt8(DW_CFA_def_cfa_offset); + Asm->EOL("DW_CFA_def_cfa_offset"); + } else { + Asm->EmitInt8(DW_CFA_def_cfa); + Asm->EOL("DW_CFA_def_cfa"); + Asm->EmitULEB128Bytes(RI->getDwarfRegNum(Src.getRegister(), isEH)); + Asm->EOL("Register"); + } + + int Offset = -Src.getOffset(); + + Asm->EmitULEB128Bytes(Offset); + Asm->EOL("Offset"); + } else { + assert(0 && "Machine move no supported yet."); + } + } else if (Src.isRegister() && + Src.getRegister() == MachineLocation::VirtualFP) { + if (Dst.isRegister()) { + Asm->EmitInt8(DW_CFA_def_cfa_register); + Asm->EOL("DW_CFA_def_cfa_register"); + Asm->EmitULEB128Bytes(RI->getDwarfRegNum(Dst.getRegister(), isEH)); + Asm->EOL("Register"); + } else { + assert(0 && "Machine move no supported yet."); + } + } else { + unsigned Reg = RI->getDwarfRegNum(Src.getRegister(), isEH); + int Offset = Dst.getOffset() / stackGrowth; + + if (Offset < 0) { + Asm->EmitInt8(DW_CFA_offset_extended_sf); + Asm->EOL("DW_CFA_offset_extended_sf"); + Asm->EmitULEB128Bytes(Reg); + Asm->EOL("Reg"); + Asm->EmitSLEB128Bytes(Offset); + Asm->EOL("Offset"); + } else if (Reg < 64) { + Asm->EmitInt8(DW_CFA_offset + Reg); + Asm->EOL("DW_CFA_offset + Reg (" + utostr(Reg) + ")"); + Asm->EmitULEB128Bytes(Offset); + Asm->EOL("Offset"); + } else { + Asm->EmitInt8(DW_CFA_offset_extended); + Asm->EOL("DW_CFA_offset_extended"); + Asm->EmitULEB128Bytes(Reg); + Asm->EOL("Reg"); + Asm->EmitULEB128Bytes(Offset); + Asm->EOL("Offset"); + } + } + } + } }; @@ -878,96 +1107,30 @@ private: /// std::vector > SectionSourceLines; - -public: - - /// PrintLabelName - Print label name in form used by Dwarf writer. + /// didInitial - Flag to indicate if initial emission has been done. /// - void PrintLabelName(DWLabel Label) const { - PrintLabelName(Label.Tag, Label.Number); - } - void PrintLabelName(const char *Tag, unsigned Number) const { - O << TAI->getPrivateGlobalPrefix() - << "debug_" - << Tag; - if (Number) O << Number; - } + bool didInitial; - /// EmitLabel - Emit location label for internal use by Dwarf. + /// shouldEmit - Flag to indicate if debug information should be emitted. /// - void EmitLabel(DWLabel Label) const { - EmitLabel(Label.Tag, Label.Number); - } - void EmitLabel(const char *Tag, unsigned Number) const { - PrintLabelName(Tag, Number); - O << ":\n"; - } + bool shouldEmit; + + struct FunctionDebugFrameInfo { + unsigned Number; + std::vector Moves; + + FunctionDebugFrameInfo(unsigned Num, const std::vector &M): + Number(Num), Moves(M) { } + }; + + std::vector DebugFrames; - /// EmitReference - Emit a reference to a label. +public: + + /// ShouldEmitDwarf - Returns true if Dwarf declarations should be made. /// - void EmitReference(DWLabel Label) const { - EmitReference(Label.Tag, Label.Number); - } - void EmitReference(const char *Tag, unsigned Number) const { - if (TAI->getAddressSize() == sizeof(int32_t)) - O << TAI->getData32bitsDirective(); - else - O << TAI->getData64bitsDirective(); - - PrintLabelName(Tag, Number); - } - void EmitReference(const std::string &Name) const { - if (TAI->getAddressSize() == sizeof(int32_t)) - O << TAI->getData32bitsDirective(); - else - O << TAI->getData64bitsDirective(); - - O << Name; - } + bool ShouldEmitDwarf() const { return shouldEmit; } - /// EmitDifference - Emit the difference between two labels. Some - /// assemblers do not behave with absolute expressions with data directives, - /// so there is an option (needsSet) to use an intermediary set expression. - void EmitDifference(DWLabel LabelHi, DWLabel LabelLo, - bool IsSmall = false) const { - EmitDifference(LabelHi.Tag, LabelHi.Number, - LabelLo.Tag, LabelLo.Number, - IsSmall); - } - void EmitDifference(const char *TagHi, unsigned NumberHi, - const char *TagLo, unsigned NumberLo, - bool IsSmall = false) const { - if (TAI->needsSet()) { - static unsigned SetCounter = 0; - - O << "\t.set\t"; - PrintLabelName("set", SetCounter); - O << ","; - PrintLabelName(TagHi, NumberHi); - O << "-"; - PrintLabelName(TagLo, NumberLo); - O << "\n"; - - if (IsSmall || TAI->getAddressSize() == sizeof(int32_t)) - O << TAI->getData32bitsDirective(); - else - O << TAI->getData64bitsDirective(); - - PrintLabelName("set", SetCounter); - - ++SetCounter; - } else { - if (IsSmall || TAI->getAddressSize() == sizeof(int32_t)) - O << TAI->getData32bitsDirective(); - else - O << TAI->getData64bitsDirective(); - - PrintLabelName(TagHi, NumberHi); - O << "-"; - PrintLabelName(TagLo, NumberLo); - } - } - /// AssignAbbrevNumber - Define a unique number for the abbreviation. /// void AssignAbbrevNumber(DIEAbbrev &Abbrev) { @@ -1152,7 +1315,9 @@ public: ValuesSet.InsertNode(Value, Where); Values.push_back(Value); } else { + // Already exists, reuse the previous one. delete Block; + Block = cast(Value); } Die->AddValue(Attribute, Block->BestForm(), Value); @@ -1175,7 +1340,7 @@ private: /// provided. void AddAddress(DIE *Die, unsigned Attribute, const MachineLocation &Location) { - unsigned Reg = RI->getDwarfRegNum(Location.getRegister()); + unsigned Reg = RI->getDwarfRegNum(Location.getRegister(), false); DIEBlock *Block = new DIEBlock(); if (Location.isRegister()) { @@ -1230,7 +1395,7 @@ private: /// DIE *ConstructPointerType(CompileUnit *Unit, const std::string &Name) { DIE Buffer(DW_TAG_pointer_type); - AddUInt(&Buffer, DW_AT_byte_size, 0, TAI->getAddressSize()); + AddUInt(&Buffer, DW_AT_byte_size, 0, TD->getPointerSize()); if (!Name.empty()) AddString(&Buffer, DW_AT_name, DW_FORM_string, Name); return Unit->AddDie(Buffer); } @@ -1386,7 +1551,7 @@ private: break; } - FromTy = dyn_cast(FromTy)->getFromType(); + FromTy = cast(FromTy)->getFromType(); } // Unless we have a bit field. @@ -1553,8 +1718,11 @@ private: CompileUnit *NewCompileUnit(CompileUnitDesc *UnitDesc, unsigned ID) { // Construct debug information entry. DIE *Die = new DIE(DW_TAG_compile_unit); - AddDelta(Die, DW_AT_stmt_list, DW_FORM_data4, DWLabel("section_line", 0), - DWLabel("section_line", 0)); + 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)); 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()); @@ -1707,7 +1875,8 @@ private: // Add variable address. MachineLocation Location; - RI->getLocation(*MF, DV->getFrameIndex(), Location); + Location.set(RI->getFrameRegister(*MF), + RI->getFrameIndexOffset(*MF, DV->getFrameIndex())); AddAddress(VariableDie, DW_AT_location, Location); return VariableDie; @@ -1749,14 +1918,14 @@ private: // Add the scope bounds. if (StartID) { AddLabel(ScopeDie, DW_AT_low_pc, DW_FORM_addr, - DWLabel("loc", StartID)); + DWLabel("label", StartID)); } else { AddLabel(ScopeDie, DW_AT_low_pc, DW_FORM_addr, DWLabel("func_begin", SubprogramCount)); } if (EndID) { AddLabel(ScopeDie, DW_AT_high_pc, DW_FORM_addr, - DWLabel("loc", EndID)); + DWLabel("label", EndID)); } else { AddLabel(ScopeDie, DW_AT_high_pc, DW_FORM_addr, DWLabel("func_end", SubprogramCount)); @@ -1804,9 +1973,9 @@ private: didInitial = true; // Dwarf sections base addresses. - if (TAI->getDwarfRequiresFrameSection()) { + if (TAI->doesDwarfRequireFrameSection()) { Asm->SwitchToDataSection(TAI->getDwarfFrameSection()); - EmitLabel("section_frame", 0); + EmitLabel("section_debug_frame", 0); } Asm->SwitchToDataSection(TAI->getDwarfInfoSection()); EmitLabel("section_info", 0); @@ -1831,19 +2000,16 @@ private: EmitLabel("text_begin", 0); Asm->SwitchToDataSection(TAI->getDataSection()); EmitLabel("data_begin", 0); - - // Emit common frame information. - EmitInitialDebugFrame(); } /// EmitDIE - Recusively Emits a debug information entry. /// - void EmitDIE(DIE *Die) const { + void EmitDIE(DIE *Die) { // Get the abbreviation for this DIE. unsigned AbbrevNumber = Die->getAbbrevNumber(); const DIEAbbrev *Abbrev = Abbreviations[AbbrevNumber - 1]; - Asm->EOL(""); + Asm->EOL(); // Emit the code (index) for the abbreviation. Asm->EmitULEB128Bytes(AbbrevNumber); @@ -1853,7 +2019,7 @@ private: ":0x" + utohexstr(Die->getSize()) + " " + TagString(Abbrev->getTag()))); - const std::vector &Values = Die->getValues(); + std::vector &Values = Die->getValues(); const std::vector &AbbrevData = Abbrev->getData(); // Emit the DIE attribute values. @@ -1950,101 +2116,9 @@ private: SizeAndOffsetDie(Unit->getDie(), Offset, true); } - /// EmitFrameMoves - Emit frame instructions to describe the layout of the - /// frame. - void EmitFrameMoves(const char *BaseLabel, unsigned BaseLabelID, - std::vector &Moves) { - int stackGrowth = - Asm->TM.getFrameInfo()->getStackGrowthDirection() == - TargetFrameInfo::StackGrowsUp ? - TAI->getAddressSize() : -TAI->getAddressSize(); - - for (unsigned i = 0, N = Moves.size(); i < N; ++i) { - MachineMove &Move = Moves[i]; - unsigned LabelID = Move.getLabelID(); - - if (LabelID) { - LabelID = MMI->MappedLabel(LabelID); - - // Throw out move if the label is invalid. - if (!LabelID) continue; - } - - const MachineLocation &Dst = Move.getDestination(); - const MachineLocation &Src = Move.getSource(); - - // Advance row if new location. - if (BaseLabel && LabelID && BaseLabelID != LabelID) { - Asm->EmitInt8(DW_CFA_advance_loc4); - Asm->EOL("DW_CFA_advance_loc4"); - EmitDifference("loc", LabelID, BaseLabel, BaseLabelID, true); - Asm->EOL(""); - - BaseLabelID = LabelID; - BaseLabel = "loc"; - } - - // If advancing cfa. - if (Dst.isRegister() && Dst.getRegister() == MachineLocation::VirtualFP) { - if (!Src.isRegister()) { - if (Src.getRegister() == MachineLocation::VirtualFP) { - Asm->EmitInt8(DW_CFA_def_cfa_offset); - Asm->EOL("DW_CFA_def_cfa_offset"); - } else { - Asm->EmitInt8(DW_CFA_def_cfa); - Asm->EOL("DW_CFA_def_cfa"); - Asm->EmitULEB128Bytes(RI->getDwarfRegNum(Src.getRegister())); - Asm->EOL("Register"); - } - - int Offset = Src.getOffset() / stackGrowth; - - Asm->EmitULEB128Bytes(Offset); - Asm->EOL("Offset"); - } else { - assert(0 && "Machine move no supported yet."); - } - } else if (Src.isRegister() && - Src.getRegister() == MachineLocation::VirtualFP) { - if (Dst.isRegister()) { - Asm->EmitInt8(DW_CFA_def_cfa_register); - Asm->EOL("DW_CFA_def_cfa_register"); - Asm->EmitULEB128Bytes(RI->getDwarfRegNum(Dst.getRegister())); - Asm->EOL("Register"); - } else { - assert(0 && "Machine move no supported yet."); - } - } else { - unsigned Reg = RI->getDwarfRegNum(Src.getRegister()); - int Offset = Dst.getOffset() / stackGrowth; - - if (Offset < 0) { - Asm->EmitInt8(DW_CFA_offset_extended_sf); - Asm->EOL("DW_CFA_offset_extended_sf"); - Asm->EmitULEB128Bytes(Reg); - Asm->EOL("Reg"); - Asm->EmitSLEB128Bytes(Offset); - Asm->EOL("Offset"); - } else if (Reg < 64) { - Asm->EmitInt8(DW_CFA_offset + Reg); - Asm->EOL("DW_CFA_offset + Reg"); - Asm->EmitULEB128Bytes(Offset); - Asm->EOL("Offset"); - } else { - Asm->EmitInt8(DW_CFA_offset_extended); - Asm->EOL("DW_CFA_offset_extended"); - Asm->EmitULEB128Bytes(Reg); - Asm->EOL("Reg"); - Asm->EmitULEB128Bytes(Offset); - Asm->EOL("Offset"); - } - } - } - } - /// EmitDebugInfo - Emit the debug info section. /// - void EmitDebugInfo() const { + void EmitDebugInfo() { // Start debug info section. Asm->SwitchToDataSection(TAI->getDwarfInfoSection()); @@ -2061,9 +2135,9 @@ private: Asm->EmitInt32(ContentSize); Asm->EOL("Length of Compilation Unit Info"); Asm->EmitInt16(DWARF_VERSION); Asm->EOL("DWARF version number"); - EmitDifference("abbrev_begin", 0, "section_abbrev", 0, true); + EmitSectionOffset("abbrev_begin", "section_abbrev", 0, 0, true, false); Asm->EOL("Offset Into Abbrev. Section"); - Asm->EmitInt8(TAI->getAddressSize()); Asm->EOL("Address Size (in bytes)"); + Asm->EmitInt8(TD->getPointerSize()); Asm->EOL("Address Size (in bytes)"); EmitDIE(Die); // FIXME - extra padding for gdb bug. @@ -2073,7 +2147,7 @@ private: Asm->EmitInt8(0); Asm->EOL("Extra Pad For GDB"); EmitLabel("info_end", Unit->getID()); - Asm->EOL(""); + Asm->EOL(); } /// EmitAbbreviations - Emit the abbreviation section. @@ -2098,18 +2172,26 @@ private: // Emit the abbreviations data. Abbrev->Emit(*this); - Asm->EOL(""); + Asm->EOL(); } + // Mark end of abbreviations. + Asm->EmitULEB128Bytes(0); Asm->EOL("EOM(3)"); + EmitLabel("abbrev_end", 0); - Asm->EOL(""); + Asm->EOL(); } } /// EmitDebugLines - Emit source line information. /// - void EmitDebugLines() const { + void EmitDebugLines() { + // If there are no lines to emit (such as when we're using .loc directives + // to emit .debug_line information) don't emit a .debug_line header. + if (SectionSourceLines.empty()) + return; + // Minimum line delta, thus ranging from -10..(255-10). const int MinLineDelta = -(DW_LNS_fixed_advance_pc + 1); // Maximum line delta, thus ranging from -10..(255-10). @@ -2206,9 +2288,9 @@ private: // Define the line address. Asm->EmitInt8(0); Asm->EOL("Extended Op"); - Asm->EmitInt8(TAI->getAddressSize() + 1); Asm->EOL("Op size"); + Asm->EmitInt8(TD->getPointerSize() + 1); Asm->EOL("Op size"); Asm->EmitInt8(DW_LNE_set_address); Asm->EOL("DW_LNE_set_address"); - EmitReference("loc", LabelID); Asm->EOL("Location label"); + EmitReference("label", LabelID); Asm->EOL("Location label"); // If change of source, then switch to the new source. if (Source != LineInfo.getSourceID()) { @@ -2244,41 +2326,41 @@ private: // Define last address of section. Asm->EmitInt8(0); Asm->EOL("Extended Op"); - Asm->EmitInt8(TAI->getAddressSize() + 1); Asm->EOL("Op size"); + Asm->EmitInt8(TD->getPointerSize() + 1); Asm->EOL("Op size"); Asm->EmitInt8(DW_LNE_set_address); Asm->EOL("DW_LNE_set_address"); EmitReference("section_end", j + 1); Asm->EOL("Section end label"); // Mark end of matrix. Asm->EmitInt8(0); Asm->EOL("DW_LNE_end_sequence"); - Asm->EmitULEB128Bytes(1); Asm->EOL(""); - Asm->EmitInt8(1); Asm->EOL(""); + Asm->EmitULEB128Bytes(1); Asm->EOL(); + Asm->EmitInt8(1); Asm->EOL(); } EmitLabel("line_end", 0); - Asm->EOL(""); + Asm->EOL(); } - /// EmitInitialDebugFrame - Emit common frame info into a debug frame section. + /// EmitCommonDebugFrame - Emit common frame info into a debug frame section. /// - void EmitInitialDebugFrame() { - if (!TAI->getDwarfRequiresFrameSection()) + void EmitCommonDebugFrame() { + if (!TAI->doesDwarfRequireFrameSection()) return; int stackGrowth = Asm->TM.getFrameInfo()->getStackGrowthDirection() == TargetFrameInfo::StackGrowsUp ? - TAI->getAddressSize() : -TAI->getAddressSize(); + TD->getPointerSize() : -TD->getPointerSize(); // Start the dwarf frame section. Asm->SwitchToDataSection(TAI->getDwarfFrameSection()); - EmitLabel("frame_common", 0); - EmitDifference("frame_common_end", 0, - "frame_common_begin", 0, true); + EmitLabel("debug_frame_common", 0); + EmitDifference("debug_frame_common_end", 0, + "debug_frame_common_begin", 0, true); Asm->EOL("Length of Common Information Entry"); - EmitLabel("frame_common_begin", 0); + EmitLabel("debug_frame_common_begin", 0); Asm->EmitInt32((int)DW_CIE_ID); Asm->EOL("CIE Identifier Tag"); Asm->EmitInt8(DW_CIE_VERSION); @@ -2289,51 +2371,51 @@ private: Asm->EOL("CIE Code Alignment Factor"); Asm->EmitSLEB128Bytes(stackGrowth); Asm->EOL("CIE Data Alignment Factor"); - Asm->EmitInt8(RI->getDwarfRegNum(RI->getRARegister())); + Asm->EmitInt8(RI->getDwarfRegNum(RI->getRARegister(), false)); Asm->EOL("CIE RA Column"); std::vector Moves; RI->getInitialFrameState(Moves); - EmitFrameMoves(NULL, 0, Moves); + + EmitFrameMoves(NULL, 0, Moves, false); Asm->EmitAlignment(2); - EmitLabel("frame_common_end", 0); + EmitLabel("debug_frame_common_end", 0); - Asm->EOL(""); + Asm->EOL(); } /// EmitFunctionDebugFrame - Emit per function frame info into a debug frame /// section. - void EmitFunctionDebugFrame() { - if (!TAI->getDwarfRequiresFrameSection()) + void EmitFunctionDebugFrame(const FunctionDebugFrameInfo &DebugFrameInfo) { + if (!TAI->doesDwarfRequireFrameSection()) return; // Start the dwarf frame section. Asm->SwitchToDataSection(TAI->getDwarfFrameSection()); - EmitDifference("frame_end", SubprogramCount, - "frame_begin", SubprogramCount, true); + EmitDifference("debug_frame_end", DebugFrameInfo.Number, + "debug_frame_begin", DebugFrameInfo.Number, true); Asm->EOL("Length of Frame Information Entry"); - EmitLabel("frame_begin", SubprogramCount); - - EmitDifference("frame_common", 0, "section_frame", 0, true); + EmitLabel("debug_frame_begin", DebugFrameInfo.Number); + + EmitSectionOffset("debug_frame_common", "section_debug_frame", + 0, 0, true, false); Asm->EOL("FDE CIE offset"); - EmitReference("func_begin", SubprogramCount); + EmitReference("func_begin", DebugFrameInfo.Number); Asm->EOL("FDE initial location"); - EmitDifference("func_end", SubprogramCount, - "func_begin", SubprogramCount); + EmitDifference("func_end", DebugFrameInfo.Number, + "func_begin", DebugFrameInfo.Number); Asm->EOL("FDE address range"); - std::vector &Moves = MMI->getFrameMoves(); - - EmitFrameMoves("func_begin", SubprogramCount, Moves); + EmitFrameMoves("func_begin", DebugFrameInfo.Number, DebugFrameInfo.Moves, false); Asm->EmitAlignment(2); - EmitLabel("frame_end", SubprogramCount); + EmitLabel("debug_frame_end", DebugFrameInfo.Number); - Asm->EOL(""); + Asm->EOL(); } /// EmitDebugPubNames - Emit visible names into a debug pubnames section. @@ -2351,8 +2433,9 @@ private: EmitLabel("pubnames_begin", Unit->getID()); Asm->EmitInt16(DWARF_VERSION); Asm->EOL("DWARF Version"); - - EmitDifference("info_begin", Unit->getID(), "section_info", 0, true); + + EmitSectionOffset("info_begin", "section_info", + Unit->getID(), 0, true, false); Asm->EOL("Offset of Compilation Unit Info"); EmitDifference("info_end", Unit->getID(), "info_begin", Unit->getID(),true); @@ -2373,7 +2456,7 @@ private: Asm->EmitInt32(0); Asm->EOL("End Mark"); EmitLabel("pubnames_end", Unit->getID()); - Asm->EOL(""); + Asm->EOL(); } /// EmitDebugStr - Emit visible names into a debug str section. @@ -2391,10 +2474,10 @@ private: EmitLabel("string", StringID); // Emit the string itself. const std::string &String = StringPool[StringID]; - Asm->EmitString(String); Asm->EOL(""); + Asm->EmitString(String); Asm->EOL(); } - Asm->EOL(""); + Asm->EOL(); } } @@ -2404,7 +2487,7 @@ private: // Start the dwarf loc section. Asm->SwitchToDataSection(TAI->getDwarfLocSection()); - Asm->EOL(""); + Asm->EOL(); } /// EmitDebugARanges - Emit visible names into a debug aranges section. @@ -2425,7 +2508,7 @@ private: EmitReference("info_begin", Unit->getID()); Asm->EOL("Offset of Compilation Unit Info"); - Asm->EmitInt8(TAI->getAddressSize()); Asm->EOL("Size of Address"); + Asm->EmitInt8(TD->getPointerSize()); Asm->EOL("Size of Address"); Asm->EmitInt8(0); Asm->EOL("Size of Segment Descriptor"); @@ -2438,9 +2521,9 @@ private: Asm->EmitInt32(0); Asm->EOL("EOM (1)"); Asm->EmitInt32(0); Asm->EOL("EOM (2)"); - - Asm->EOL(""); #endif + + Asm->EOL(); } /// EmitDebugRanges - Emit visible names into a debug ranges section. @@ -2449,7 +2532,7 @@ private: // Start the dwarf ranges section. Asm->SwitchToDataSection(TAI->getDwarfRangesSection()); - Asm->EOL(""); + Asm->EOL(); } /// EmitDebugMacInfo - Emit visible names into a debug macinfo section. @@ -2458,7 +2541,7 @@ private: // Start the dwarf macinfo section. Asm->SwitchToDataSection(TAI->getDwarfMacInfoSection()); - Asm->EOL(""); + Asm->EOL(); } /// ConstructCompileUnitDIEs - Create a compile unit DIE for each source and @@ -2502,7 +2585,7 @@ public: // Main entry points. // DwarfDebug(std::ostream &OS, AsmPrinter *A, const TargetAsmInfo *T) - : Dwarf(OS, A, T) + : Dwarf(OS, A, T, "dbg") , CompileUnits() , AbbreviationsSet(InitAbbreviationsSetSize) , Abbreviations() @@ -2512,6 +2595,8 @@ public: , DescToUnitMap() , SectionMap() , SectionSourceLines() + , didInitial(false) + , shouldEmit(false) { } virtual ~DwarfDebug() { @@ -2529,9 +2614,6 @@ public: MMI = mmi; shouldEmit = true; - // Emit initial sections - EmitInitial(); - // Create all the compile unit DIEs. ConstructCompileUnitDIEs(); @@ -2543,6 +2625,23 @@ public: // Prime section data. SectionMap.insert(TAI->getTextSection()); + + // Print out .file directives to specify files for .loc directives. These + // are printed out early so that they precede any .loc directives. + if (TAI->hasDotLocAndDotFile()) { + const UniqueVector &SourceFiles = MMI->getSourceFiles(); + const UniqueVector &Directories = MMI->getDirectories(); + for (unsigned i = 1, e = SourceFiles.size(); i <= e; ++i) { + sys::Path FullPath(Directories[SourceFiles[i].getDirectoryID()]); + bool AppendOk = FullPath.appendComponent(SourceFiles[i].getName()); + assert(AppendOk && "Could not append filename to directory!"); + Asm->EmitFile(i, FullPath.toString()); + Asm->EOL(); + } + } + + // Emit initial sections + EmitInitial(); } } @@ -2570,7 +2669,15 @@ public: Asm->SwitchToTextSection(SectionMap[i].c_str()); EmitLabel("section_end", i); } - + + // Emit common frame information. + EmitCommonDebugFrame(); + + // Emit function debug frame information + for (std::vector::iterator I = DebugFrames.begin(), + E = DebugFrames.end(); I != E; ++I) + EmitFunctionDebugFrame(*I); + // Compute DIE offsets and sizes. SizeAndOffsets(); @@ -2614,21 +2721,20 @@ public: // Assumes in correct section after the entry point. EmitLabel("func_begin", ++SubprogramCount); + + // Emit label for the implicitly defined dbg.stoppoint at the start of + // the function. + const SourceLineInfo &LineInfo = MMI->getSourceLines()[0]; + Asm->printLabel(LineInfo.getLabelID()); } - /// PreExceptionEndFunction - Close off function before exception handling - /// tables. - void PreExceptionEndFunction() { - if (!ShouldEmitDwarf()) return; - - // Define end label for subprogram. - EmitLabel("func_end", SubprogramCount); - } - /// EndFunction - Gather and emit post-function debug information. /// void EndFunction() { if (!ShouldEmitDwarf()) return; + + // Define end label for subprogram. + EmitLabel("func_end", SubprogramCount); // Get function line info. const std::vector &LineInfos = MMI->getSourceLines(); @@ -2645,15 +2751,9 @@ public: // Construct scopes for subprogram. ConstructRootScope(MMI->getRootScope()); - - // Emit function frame information. - EmitFunctionDebugFrame(); - - // Reset the line numbers for the next function. - MMI->ClearLineInfo(); - // Clear function debug information. - MMI->EndFunction(); + DebugFrames.push_back(FunctionDebugFrameInfo(SubprogramCount, + MMI->getFrameMoves())); } }; @@ -2662,12 +2762,616 @@ public: /// class DwarfException : public Dwarf { +private: + struct FunctionEHFrameInfo { + std::string FnName; + unsigned Number; + unsigned PersonalityIndex; + bool hasCalls; + bool hasLandingPads; + std::vector Moves; + const Function * function; + + FunctionEHFrameInfo(const std::string &FN, unsigned Num, unsigned P, + bool hC, bool hL, + const std::vector &M, + const Function *f): + FnName(FN), Number(Num), PersonalityIndex(P), + hasCalls(hC), hasLandingPads(hL), Moves(M), function (f) { } + }; + + std::vector EHFrames; + + /// shouldEmit - Flag to indicate if debug information should be emitted. + /// + bool shouldEmit; + + /// EmitCommonEHFrame - Emit the common eh unwind frame. + /// + void EmitCommonEHFrame(const Function *Personality, unsigned Index) { + // Size and sign of stack growth. + int stackGrowth = + Asm->TM.getFrameInfo()->getStackGrowthDirection() == + TargetFrameInfo::StackGrowsUp ? + TD->getPointerSize() : -TD->getPointerSize(); + + // Begin eh frame section. + Asm->SwitchToTextSection(TAI->getDwarfEHFrameSection()); + O << "EH_frame" << Index << ":\n"; + EmitLabel("section_eh_frame", Index); + + // 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); + Asm->EOL("Length of Common Information Entry"); + + // EH frame header. + EmitLabel("eh_frame_common_begin", Index); + Asm->EmitInt32((int)0); + 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->EmitInt8(RI->getDwarfRegNum(RI->getRARegister(), true)); + Asm->EOL("CIE RA 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()) + Asm->EmitInt8(DW_EH_PE_pcrel | DW_EH_PE_sdata4 | DW_EH_PE_indirect); + else + Asm->EmitInt8(DW_EH_PE_pcrel | DW_EH_PE_sdata4); + + Asm->EOL("Personality (pcrel sdata4 indirect)"); + + PrintRelDirective(TAI->getShortenEHDataOn64Bit()); + O << TAI->getPersonalityPrefix(); + Asm->EmitExternalGlobal((const GlobalVariable *)(Personality)); + O << TAI->getPersonalitySuffix(); + if (!TAI->getShortenEHDataOn64Bit()) { + 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)"); + } else { + Asm->EmitULEB128Bytes(1); + Asm->EOL("Augmentation Size"); + Asm->EmitULEB128Bytes(DW_EH_PE_pcrel); + Asm->EOL("FDE Encoding (pcrel)"); + } + + // Indicate locations of general callee saved registers in frame. + std::vector Moves; + RI->getInitialFrameState(Moves); + EmitFrameMoves(NULL, 0, Moves, true); + + Asm->EmitAlignment(2); + EmitLabel("eh_frame_common_end", Index); + + Asm->EOL(); + } + + /// EmitEHFrame - Emit function exception frame information. + /// + void EmitEHFrame(const FunctionEHFrameInfo &EHFrameInfo) { + Function::LinkageTypes linkage = EHFrameInfo.function->getLinkage(); + + Asm->SwitchToTextSection(TAI->getDwarfEHFrameSection()); + + // Externally visible entry into the functions eh frame info. + // If the corresponding function is static, this should not be + // externally visible. + if (linkage != Function::InternalLinkage) { + if (const char *GlobalEHDirective = TAI->getGlobalEHDirective()) + O << GlobalEHDirective << EHFrameInfo.FnName << "\n"; + } + + // If corresponding function is weak definition, this should be too. + if ((linkage == Function::WeakLinkage || + linkage == Function::LinkOnceLinkage) && + TAI->getWeakDefDirective()) + O << TAI->getWeakDefDirective() << EHFrameInfo.FnName << "\n"; + + // If there are no calls then you can't unwind. This may mean we can + // omit the EH Frame, but some environments do not handle weak absolute + // symbols. + if (!EHFrameInfo.hasCalls && + ((linkage != Function::WeakLinkage && + linkage != Function::LinkOnceLinkage) || + !TAI->getWeakDefDirective() || + TAI->getSupportsWeakOmittedEHFrame())) + { + O << EHFrameInfo.FnName << " = 0\n"; + // This name has no connection to the function, so it might get + // dead-stripped when the function is not, erroneously. Prohibit + // dead-stripping unconditionally. + if (const char *UsedDirective = TAI->getUsedDirective()) + O << UsedDirective << EHFrameInfo.FnName << "\n\n"; + } else { + O << EHFrameInfo.FnName << ":\n"; + + // EH frame header. + EmitDifference("eh_frame_end", EHFrameInfo.Number, + "eh_frame_begin", EHFrameInfo.Number, true); + Asm->EOL("Length of Frame Information Entry"); + + EmitLabel("eh_frame_begin", EHFrameInfo.Number); + + EmitSectionOffset("eh_frame_begin", "eh_frame_common", + EHFrameInfo.Number, EHFrameInfo.PersonalityIndex, + true, true); + Asm->EOL("FDE CIE offset"); + + EmitReference("eh_func_begin", EHFrameInfo.Number, true); + Asm->EOL("FDE initial location"); + EmitDifference("eh_func_end", EHFrameInfo.Number, + "eh_func_begin", EHFrameInfo.Number); + 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->EOL("Augmentation size"); + + if (EHFrameInfo.hasLandingPads) { + EmitReference("exception", EHFrameInfo.Number, true); + } else if (TD->getPointerSize() == 8) { + Asm->EmitInt64((int)0); + } 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); + + Asm->EmitAlignment(2); + EmitLabel("eh_frame_end", EHFrameInfo.Number); + + // If the function is marked used, this table should be also. We cannot + // make the mark unconditional in this case, since retaining the table + // also retains the function in this case, and there is code around + // that depends on unused functions (calling undefined externals) being + // dead-stripped to link correctly. Yes, there really is. + if (MMI->getUsedFunctions().count(EHFrameInfo.function)) + if (const char *UsedDirective = TAI->getUsedDirective()) + O << UsedDirective << EHFrameInfo.FnName << "\n\n"; + } + } + + /// EmitExceptionTable - Emit landing pads and actions. + /// + /// The general organization of the table is complex, but the basic concepts + /// are easy. First there is a header which describes the location and + /// organization of the three components that follow. + /// 1. The landing pad site information describes the range of code covered + /// by the try. In our case it's an accumulation of the ranges covered + /// by the invokes in the try. There is also a reference to the landing + /// pad that handles the exception once processed. Finally an index into + /// the actions table. + /// 2. The action table, in our case, is composed of pairs of type ids + /// and next action offset. Starting with the action index from the + /// landing pad site, each type Id is checked for a match to the current + /// exception. If it matches then the exception and type id are passed + /// on to the landing pad. Otherwise the next action is looked up. This + /// chain is terminated with a next action of zero. If no type id is + /// found the the frame is unwound and handling continues. + /// 3. Type id table contains references to all the C++ typeinfo for all + /// catches in the function. This tables is reversed indexed base 1. + + /// SharedTypeIds - How many leading type ids two landing pads have in common. + static unsigned SharedTypeIds(const LandingPadInfo *L, + const LandingPadInfo *R) { + const std::vector &LIds = L->TypeIds, &RIds = R->TypeIds; + unsigned LSize = LIds.size(), RSize = RIds.size(); + unsigned MinSize = LSize < RSize ? LSize : RSize; + unsigned Count = 0; + + for (; Count != MinSize; ++Count) + if (LIds[Count] != RIds[Count]) + return Count; + + return Count; + } + + /// PadLT - Order landing pads lexicographically by type id. + static bool PadLT(const LandingPadInfo *L, const LandingPadInfo *R) { + const std::vector &LIds = L->TypeIds, &RIds = R->TypeIds; + unsigned LSize = LIds.size(), RSize = RIds.size(); + unsigned MinSize = LSize < RSize ? LSize : RSize; + + for (unsigned i = 0; i != MinSize; ++i) + if (LIds[i] != RIds[i]) + return LIds[i] < RIds[i]; + + return LSize < RSize; + } + + struct KeyInfo { + static inline unsigned getEmptyKey() { return -1U; } + static inline unsigned getTombstoneKey() { return -2U; } + static unsigned getHashValue(const unsigned &Key) { return Key; } + static bool isEqual(unsigned LHS, unsigned RHS) { return LHS == RHS; } + static bool isPod() { return true; } + }; + + /// ActionEntry - Structure describing an entry in the actions table. + struct ActionEntry { + int ValueForTypeID; // The value to write - may not be equal to the type id. + int NextAction; + struct ActionEntry *Previous; + }; + + /// PadRange - Structure holding a try-range and the associated landing pad. + struct PadRange { + // The index of the landing pad. + unsigned PadIndex; + // The index of the begin and end labels in the landing pad's label lists. + unsigned RangeIndex; + }; + + typedef DenseMap RangeMapType; + + /// CallSiteEntry - Structure describing an entry in the call-site table. + struct CallSiteEntry { + // The 'try-range' is BeginLabel .. EndLabel. + unsigned BeginLabel; // zero indicates the start of the function. + unsigned EndLabel; // zero indicates the end of the function. + // The landing pad starts at PadLabel. + unsigned PadLabel; // zero indicates that there is no landing pad. + unsigned Action; + }; + + void EmitExceptionTable() { + // Map all labels and get rid of any dead landing pads. + MMI->TidyLandingPads(); + + const std::vector &TypeInfos = MMI->getTypeInfos(); + const std::vector &FilterIds = MMI->getFilterIds(); + const std::vector &PadInfos = MMI->getLandingPads(); + if (PadInfos.empty()) return; + + // Sort the landing pads in order of their type ids. This is used to fold + // duplicate actions. + SmallVector LandingPads; + LandingPads.reserve(PadInfos.size()); + for (unsigned i = 0, N = PadInfos.size(); i != N; ++i) + LandingPads.push_back(&PadInfos[i]); + std::sort(LandingPads.begin(), LandingPads.end(), PadLT); + + // Negative type ids index into FilterIds, positive type ids index into + // TypeInfos. The value written for a positive type id is just the type + // id itself. For a negative type id, however, the value written is the + // (negative) byte offset of the corresponding FilterIds entry. The byte + // offset is usually equal to the type id, because the FilterIds entries + // are written using a variable width encoding which outputs one byte per + // entry as long as the value written is not too large, but can differ. + // This kind of complication does not occur for positive type ids because + // type infos are output using a fixed width encoding. + // FilterOffsets[i] holds the byte offset corresponding to FilterIds[i]. + SmallVector FilterOffsets; + FilterOffsets.reserve(FilterIds.size()); + int Offset = -1; + for(std::vector::const_iterator I = FilterIds.begin(), + E = FilterIds.end(); I != E; ++I) { + FilterOffsets.push_back(Offset); + Offset -= Asm->SizeULEB128(*I); + } + + // Compute the actions table and gather the first action index for each + // landing pad site. + SmallVector Actions; + SmallVector FirstActions; + FirstActions.reserve(LandingPads.size()); + + int FirstAction = 0; + unsigned SizeActions = 0; + for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) { + const LandingPadInfo *LP = LandingPads[i]; + const std::vector &TypeIds = LP->TypeIds; + const unsigned NumShared = i ? SharedTypeIds(LP, LandingPads[i-1]) : 0; + unsigned SizeSiteActions = 0; + + if (NumShared < TypeIds.size()) { + unsigned SizeAction = 0; + ActionEntry *PrevAction = 0; + + if (NumShared) { + const unsigned SizePrevIds = LandingPads[i-1]->TypeIds.size(); + assert(Actions.size()); + PrevAction = &Actions.back(); + SizeAction = Asm->SizeSLEB128(PrevAction->NextAction) + + Asm->SizeSLEB128(PrevAction->ValueForTypeID); + for (unsigned j = NumShared; j != SizePrevIds; ++j) { + SizeAction -= Asm->SizeSLEB128(PrevAction->ValueForTypeID); + SizeAction += -PrevAction->NextAction; + PrevAction = PrevAction->Previous; + } + } + + // Compute the actions. + for (unsigned I = NumShared, M = TypeIds.size(); I != M; ++I) { + int TypeID = TypeIds[I]; + assert(-1-TypeID < (int)FilterOffsets.size() && "Unknown filter id!"); + int ValueForTypeID = TypeID < 0 ? FilterOffsets[-1 - TypeID] : TypeID; + unsigned SizeTypeID = Asm->SizeSLEB128(ValueForTypeID); + + int NextAction = SizeAction ? -(SizeAction + SizeTypeID) : 0; + SizeAction = SizeTypeID + Asm->SizeSLEB128(NextAction); + SizeSiteActions += SizeAction; + + ActionEntry Action = {ValueForTypeID, NextAction, PrevAction}; + Actions.push_back(Action); + + PrevAction = &Actions.back(); + } + + // Record the first action of the landing pad site. + FirstAction = SizeActions + SizeSiteActions - SizeAction + 1; + } // else identical - re-use previous FirstAction + + FirstActions.push_back(FirstAction); + + // Compute this sites contribution to size. + SizeActions += SizeSiteActions; + } + + // Compute the call-site table. The entry for an invoke has a try-range + // containing the call, a non-zero landing pad and an appropriate action. + // The entry for an ordinary call has a try-range containing the call and + // zero for the landing pad and the action. Calls marked 'nounwind' have + // no entry and must not be contained in the try-range of any entry - they + // form gaps in the table. Entries must be ordered by try-range address. + SmallVector CallSites; + + RangeMapType PadMap; + // Invokes and nounwind calls have entries in PadMap (due to being bracketed + // by try-range labels when lowered). Ordinary calls do not, so appropriate + // try-ranges for them need be deduced. + for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) { + const LandingPadInfo *LandingPad = LandingPads[i]; + for (unsigned j = 0, E = LandingPad->BeginLabels.size(); j != E; ++j) { + unsigned BeginLabel = LandingPad->BeginLabels[j]; + assert(!PadMap.count(BeginLabel) && "Duplicate landing pad labels!"); + PadRange P = { i, j }; + PadMap[BeginLabel] = P; + } + } + + // The end label of the previous invoke or nounwind try-range. + unsigned LastLabel = 0; + + // Whether there is a potentially throwing instruction (currently this means + // an ordinary call) between the end of the previous try-range and now. + bool SawPotentiallyThrowing = false; + + // Whether the last callsite entry was for an invoke. + bool PreviousIsInvoke = false; + + // Visit all instructions in order of address. + for (MachineFunction::const_iterator I = MF->begin(), E = MF->end(); + I != E; ++I) { + for (MachineBasicBlock::const_iterator MI = I->begin(), E = I->end(); + MI != E; ++MI) { + if (MI->getOpcode() != TargetInstrInfo::LABEL) { + SawPotentiallyThrowing |= MI->getDesc().isCall(); + continue; + } + + unsigned BeginLabel = MI->getOperand(0).getImm(); + assert(BeginLabel && "Invalid label!"); + + // End of the previous try-range? + if (BeginLabel == LastLabel) + SawPotentiallyThrowing = false; + + // Beginning of a new try-range? + RangeMapType::iterator L = PadMap.find(BeginLabel); + if (L == PadMap.end()) + // Nope, it was just some random label. + continue; + + PadRange P = L->second; + const LandingPadInfo *LandingPad = LandingPads[P.PadIndex]; + + assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] && + "Inconsistent landing pad map!"); + + // If some instruction between the previous try-range and this one may + // throw, create a call-site entry with no landing pad for the region + // between the try-ranges. + if (SawPotentiallyThrowing) { + CallSiteEntry Site = {LastLabel, BeginLabel, 0, 0}; + CallSites.push_back(Site); + PreviousIsInvoke = false; + } + + LastLabel = LandingPad->EndLabels[P.RangeIndex]; + assert(BeginLabel && LastLabel && "Invalid landing pad!"); + + if (LandingPad->LandingPadLabel) { + // This try-range is for an invoke. + CallSiteEntry Site = {BeginLabel, LastLabel, + LandingPad->LandingPadLabel, FirstActions[P.PadIndex]}; + + // Try to merge with the previous call-site. + if (PreviousIsInvoke) { + CallSiteEntry &Prev = CallSites[CallSites.size()-1]; + if (Site.PadLabel == Prev.PadLabel && Site.Action == Prev.Action) { + // Extend the range of the previous entry. + Prev.EndLabel = Site.EndLabel; + continue; + } + } + + // Otherwise, create a new call-site. + CallSites.push_back(Site); + PreviousIsInvoke = true; + } else { + // Create a gap. + PreviousIsInvoke = false; + } + } + } + // If some instruction between the previous try-range and the end of the + // function may throw, create a call-site entry with no landing pad for the + // region following the try-range. + if (SawPotentiallyThrowing) { + CallSiteEntry Site = {LastLabel, 0, 0, 0}; + CallSites.push_back(Site); + } + + // Final tallies. + unsigned SizeSites = CallSites.size() * (sizeof(int32_t) + // Site start. + sizeof(int32_t) + // Site length. + sizeof(int32_t)); // Landing pad. + for (unsigned i = 0, e = CallSites.size(); i < e; ++i) + SizeSites += Asm->SizeULEB128(CallSites[i].Action); + + unsigned SizeTypes = TypeInfos.size() * TD->getPointerSize(); + + unsigned TypeOffset = sizeof(int8_t) + // Call site format + Asm->SizeULEB128(SizeSites) + // Call-site table length + SizeSites + SizeActions + SizeTypes; + + unsigned TotalSize = sizeof(int8_t) + // LPStart format + sizeof(int8_t) + // TType format + Asm->SizeULEB128(TypeOffset) + // TType base offset + TypeOffset; + + unsigned SizeAlign = (4 - TotalSize) & 3; + + // Begin the exception table. + Asm->SwitchToDataSection(TAI->getDwarfExceptionSection()); + O << "GCC_except_table" << SubprogramCount << ":\n"; + Asm->EmitAlignment(2); + for (unsigned i = 0; i != SizeAlign; ++i) { + Asm->EmitInt8(0); + Asm->EOL("Padding"); + } + EmitLabel("exception", SubprogramCount); + + // Emit the header. + Asm->EmitInt8(DW_EH_PE_omit); + Asm->EOL("LPStart format (DW_EH_PE_omit)"); + Asm->EmitInt8(DW_EH_PE_absptr); + Asm->EOL("TType format (DW_EH_PE_absptr)"); + Asm->EmitULEB128Bytes(TypeOffset); + Asm->EOL("TType base offset"); + Asm->EmitInt8(DW_EH_PE_udata4); + Asm->EOL("Call site format (DW_EH_PE_udata4)"); + Asm->EmitULEB128Bytes(SizeSites); + Asm->EOL("Call-site table length"); + + // Emit the landing pad site information. + for (unsigned i = 0; i < CallSites.size(); ++i) { + CallSiteEntry &S = CallSites[i]; + const char *BeginTag; + unsigned BeginNumber; + + if (!S.BeginLabel) { + BeginTag = "eh_func_begin"; + BeginNumber = SubprogramCount; + } else { + BeginTag = "label"; + BeginNumber = S.BeginLabel; + } + + EmitSectionOffset(BeginTag, "eh_func_begin", BeginNumber, SubprogramCount, + TAI->getShortenEHDataOn64Bit(), true); + Asm->EOL("Region start"); + + if (!S.EndLabel) { + EmitDifference("eh_func_end", SubprogramCount, BeginTag, BeginNumber, + TAI->getShortenEHDataOn64Bit()); + } else { + EmitDifference("label", S.EndLabel, BeginTag, BeginNumber, + TAI->getShortenEHDataOn64Bit()); + } + Asm->EOL("Region length"); + + if (!S.PadLabel) { + if (TD->getPointerSize() == sizeof(int32_t) || TAI->getShortenEHDataOn64Bit()) + Asm->EmitInt32(0); + else + Asm->EmitInt64(0); + } else { + EmitSectionOffset("label", "eh_func_begin", S.PadLabel, SubprogramCount, + TAI->getShortenEHDataOn64Bit(), true); + } + Asm->EOL("Landing pad"); + + Asm->EmitULEB128Bytes(S.Action); + Asm->EOL("Action"); + } + + // Emit the actions. + for (unsigned I = 0, N = Actions.size(); I != N; ++I) { + ActionEntry &Action = Actions[I]; + + Asm->EmitSLEB128Bytes(Action.ValueForTypeID); + Asm->EOL("TypeInfo index"); + Asm->EmitSLEB128Bytes(Action.NextAction); + Asm->EOL("Next action"); + } + + // Emit the type ids. + for (unsigned M = TypeInfos.size(); M; --M) { + GlobalVariable *GV = TypeInfos[M - 1]; + + PrintRelDirective(); + + if (GV) + O << Asm->getGlobalLinkName(GV); + else + O << "0"; + + Asm->EOL("TypeInfo"); + } + + // Emit the filter typeids. + for (unsigned j = 0, M = FilterIds.size(); j < M; ++j) { + unsigned TypeID = FilterIds[j]; + Asm->EmitULEB128Bytes(TypeID); + Asm->EOL("Filter TypeInfo index"); + } + + Asm->EmitAlignment(2); + } + public: //===--------------------------------------------------------------------===// // Main entry points. // DwarfException(std::ostream &OS, AsmPrinter *A, const TargetAsmInfo *T) - : Dwarf(OS, A, T) + : Dwarf(OS, A, T, "eh") + , shouldEmit(false) {} virtual ~DwarfException() {} @@ -2675,25 +3379,27 @@ public: /// SetModuleInfo - Set machine module information when it's known that pass /// manager has created it. Set by the target AsmPrinter. void SetModuleInfo(MachineModuleInfo *mmi) { - // Make sure initial declarations are made. - if (!MMI && ExceptionHandling && TAI->getSupportsExceptionHandling()) { - MMI = mmi; - shouldEmit = true; - } + MMI = mmi; } /// BeginModule - Emit all exception information that should come prior to the /// content. void BeginModule(Module *M) { this->M = M; - - if (!ShouldEmitDwarf()) return; } /// EndModule - Emit all exception information that should come after the /// content. void EndModule() { - if (!ShouldEmitDwarf()) return; + if (!shouldEmit) return; + + const std::vector Personalities = MMI->getPersonalities(); + for (unsigned i =0; i < Personalities.size(); ++i) + EmitCommonEHFrame(Personalities[i], i); + + for (std::vector::iterator I = EHFrames.begin(), + E = EHFrames.end(); I != E; ++I) + EmitEHFrame(*I); } /// BeginFunction - Gather pre-function exception information. Assumes being @@ -2701,22 +3407,32 @@ public: void BeginFunction(MachineFunction *MF) { this->MF = MF; - if (!ShouldEmitDwarf()) return; + if (MMI && + ExceptionHandling && + TAI->doesSupportExceptionHandling()) { + shouldEmit = true; + // Assumes in correct section after the entry point. + EmitLabel("eh_func_begin", ++SubprogramCount); + } } /// EndFunction - Gather and emit post-function exception information. /// void EndFunction() { - if (!ShouldEmitDwarf()) return; -#if 0 - if (const char *GlobalDirective = TAI->getGlobalDirective()) - O << GlobalDirective << getAsm()->CurrentFnName << ".eh\n"; - - O << getAsm()->CurrentFnName << ".eh = 0\n"; - - if (const char *UsedDirective = TAI->getUsedDirective()) - O << UsedDirective << getAsm()->CurrentFnName << ".eh\n"; -#endif + if (!shouldEmit) return; + + EmitLabel("eh_func_end", SubprogramCount); + EmitExceptionTable(); + + // Save EH frame information + EHFrames. + push_back(FunctionEHFrameInfo(getAsm()->getCurrentFunctionEHName(MF), + SubprogramCount, + MMI->getPersonalityIndex(), + MF->getFrameInfo()->hasCalls(), + !MMI->getLandingPads().empty(), + MMI->getFrameMoves(), + MF->getFunction())); } }; @@ -2786,7 +3502,7 @@ void DIEValue::dump() { /// EmitValue - Emit integer of appropriate size. /// -void DIEInteger::EmitValue(const DwarfDebug &DD, unsigned Form) const { +void DIEInteger::EmitValue(DwarfDebug &DD, unsigned Form) { switch (Form) { case DW_FORM_flag: // Fall thru case DW_FORM_ref1: // Fall thru @@ -2827,7 +3543,7 @@ unsigned DIEInteger::SizeOf(const DwarfDebug &DD, unsigned Form) const { /// EmitValue - Emit string value. /// -void DIEString::EmitValue(const DwarfDebug &DD, unsigned Form) const { +void DIEString::EmitValue(DwarfDebug &DD, unsigned Form) { DD.getAsm()->EmitString(String); } @@ -2835,35 +3551,39 @@ void DIEString::EmitValue(const DwarfDebug &DD, unsigned Form) const { /// EmitValue - Emit label value. /// -void DIEDwarfLabel::EmitValue(const DwarfDebug &DD, unsigned Form) const { - DD.EmitReference(Label); +void DIEDwarfLabel::EmitValue(DwarfDebug &DD, unsigned Form) { + bool IsSmall = Form == DW_FORM_data4; + DD.EmitReference(Label, false, IsSmall); } /// SizeOf - Determine size of label value in bytes. /// unsigned DIEDwarfLabel::SizeOf(const DwarfDebug &DD, unsigned Form) const { - return DD.getTargetAsmInfo()->getAddressSize(); + if (Form == DW_FORM_data4) return 4; + return DD.getTargetData()->getPointerSize(); } //===----------------------------------------------------------------------===// /// EmitValue - Emit label value. /// -void DIEObjectLabel::EmitValue(const DwarfDebug &DD, unsigned Form) const { - DD.EmitReference(Label); +void DIEObjectLabel::EmitValue(DwarfDebug &DD, unsigned Form) { + bool IsSmall = Form == DW_FORM_data4; + DD.EmitReference(Label, false, IsSmall); } /// SizeOf - Determine size of label value in bytes. /// unsigned DIEObjectLabel::SizeOf(const DwarfDebug &DD, unsigned Form) const { - return DD.getTargetAsmInfo()->getAddressSize(); + if (Form == DW_FORM_data4) return 4; + return DD.getTargetData()->getPointerSize(); } //===----------------------------------------------------------------------===// /// EmitValue - Emit delta value. /// -void DIEDelta::EmitValue(const DwarfDebug &DD, unsigned Form) const { +void DIEDelta::EmitValue(DwarfDebug &DD, unsigned Form) { bool IsSmall = Form == DW_FORM_data4; DD.EmitDifference(LabelHi, LabelLo, IsSmall); } @@ -2872,14 +3592,14 @@ void DIEDelta::EmitValue(const DwarfDebug &DD, unsigned Form) const { /// unsigned DIEDelta::SizeOf(const DwarfDebug &DD, unsigned Form) const { if (Form == DW_FORM_data4) return 4; - return DD.getTargetAsmInfo()->getAddressSize(); + return DD.getTargetData()->getPointerSize(); } //===----------------------------------------------------------------------===// /// EmitValue - Emit debug information entry offset. /// -void DIEntry::EmitValue(const DwarfDebug &DD, unsigned Form) const { +void DIEntry::EmitValue(DwarfDebug &DD, unsigned Form) { DD.getAsm()->EmitInt32(Entry->getOffset()); } @@ -2900,7 +3620,7 @@ unsigned DIEBlock::ComputeSize(DwarfDebug &DD) { /// EmitValue - Emit block data. /// -void DIEBlock::EmitValue(const DwarfDebug &DD, unsigned Form) const { +void DIEBlock::EmitValue(DwarfDebug &DD, unsigned Form) { switch (Form) { case DW_FORM_block1: DD.getAsm()->EmitInt8(Size); break; case DW_FORM_block2: DD.getAsm()->EmitInt16(Size); break; @@ -2912,7 +3632,7 @@ void DIEBlock::EmitValue(const DwarfDebug &DD, unsigned Form) const { const std::vector &AbbrevData = Abbrev.getData(); for (unsigned i = 0, N = Values.size(); i < N; ++i) { - DD.getAsm()->EOL(""); + DD.getAsm()->EOL(); Values[i]->EmitValue(DD, AbbrevData[i].getForm()); } } @@ -3031,8 +3751,8 @@ DwarfWriter::~DwarfWriter() { /// SetModuleInfo - Set machine module info when it's known that pass manager /// has created it. Set by the target AsmPrinter. void DwarfWriter::SetModuleInfo(MachineModuleInfo *MMI) { - DE->SetModuleInfo(MMI); DD->SetModuleInfo(MMI); + DE->SetModuleInfo(MMI); } /// BeginModule - Emit all Dwarf sections that should come prior to the @@ -3059,7 +3779,11 @@ void DwarfWriter::BeginFunction(MachineFunction *MF) { /// EndFunction - Gather and emit post-function debug information. /// void DwarfWriter::EndFunction() { - DD->PreExceptionEndFunction(); - DE->EndFunction(); DD->EndFunction(); + DE->EndFunction(); + + if (MachineModuleInfo *MMI = DD->getMMI() ? DD->getMMI() : DE->getMMI()) { + // Clear function debug information. + MMI->EndFunction(); + } }