Example #1
0
void EHStreamer::computePadMap(
    const SmallVectorImpl<const LandingPadInfo *> &LandingPads,
    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 so we can put them in the LSDA.
  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) {
      MCSymbol *BeginLabel = LandingPad->BeginLabels[j];
      assert(!PadMap.count(BeginLabel) && "Duplicate landing pad labels!");
      PadRange P = { i, j };
      PadMap[BeginLabel] = P;
    }
  }
}
/// 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 then 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 reverse indexed base 1.
void DwarfException::EmitExceptionTable() {
  const std::vector<const GlobalVariable *> &TypeInfos = MMI->getTypeInfos();
  const std::vector<unsigned> &FilterIds = MMI->getFilterIds();
  const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads();

  // Sort the landing pads in order of their type ids.  This is used to fold
  // duplicate actions.
  SmallVector<const LandingPadInfo *, 64> 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);

  // Compute the actions table and gather the first action index for each
  // landing pad site.
  SmallVector<ActionEntry, 32> Actions;
  SmallVector<unsigned, 64> FirstActions;
  unsigned SizeActions=ComputeActionsTable(LandingPads, Actions, FirstActions);

  // 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 when using DWARF exception handling.
  RangeMapType PadMap;
  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) {
      MCSymbol *BeginLabel = LandingPad->BeginLabels[j];
      assert(!PadMap.count(BeginLabel) && "Duplicate landing pad labels!");
      PadRange P = { i, j };
      PadMap[BeginLabel] = P;
    }
  }

  // Compute the call-site table.
  SmallVector<CallSiteEntry, 64> CallSites;
  ComputeCallSiteTable(CallSites, PadMap, LandingPads, FirstActions);

  // Final tallies.

  // Call sites.
  bool IsSJLJ = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::SjLj;
  bool HaveTTData = IsSJLJ ? (!TypeInfos.empty() || !FilterIds.empty()) : true;

  unsigned CallSiteTableLength;
  if (IsSJLJ)
    CallSiteTableLength = 0;
  else {
    unsigned SiteStartSize  = 4; // dwarf::DW_EH_PE_udata4
    unsigned SiteLengthSize = 4; // dwarf::DW_EH_PE_udata4
    unsigned LandingPadSize = 4; // dwarf::DW_EH_PE_udata4
    CallSiteTableLength =
      CallSites.size() * (SiteStartSize + SiteLengthSize + LandingPadSize);
  }

  for (unsigned i = 0, e = CallSites.size(); i < e; ++i) {
    CallSiteTableLength += MCAsmInfo::getULEB128Size(CallSites[i].Action);
    if (IsSJLJ)
      CallSiteTableLength += MCAsmInfo::getULEB128Size(i);
  }

  // Type infos.
  const MCSection *LSDASection = Asm->getObjFileLowering().getLSDASection();
  unsigned TTypeEncoding;
  unsigned TypeFormatSize;

  if (!HaveTTData) {
    // For SjLj exceptions, if there is no TypeInfo, then we just explicitly say
    // that we're omitting that bit.
    TTypeEncoding = dwarf::DW_EH_PE_omit;
    // dwarf::DW_EH_PE_absptr
    TypeFormatSize = Asm->getDataLayout().getPointerSize();
  } else {
    // Okay, we have actual filters or typeinfos to emit.  As such, we need to
    // pick a type encoding for them.  We're about to emit a list of pointers to
    // typeinfo objects at the end of the LSDA.  However, unless we're in static
    // mode, this reference will require a relocation by the dynamic linker.
    //
    // Because of this, we have a couple of options:
    //
    //   1) If we are in -static mode, we can always use an absolute reference
    //      from the LSDA, because the static linker will resolve it.
    //
    //   2) Otherwise, if the LSDA section is writable, we can output the direct
    //      reference to the typeinfo and allow the dynamic linker to relocate
    //      it.  Since it is in a writable section, the dynamic linker won't
    //      have a problem.
    //
    //   3) Finally, if we're in PIC mode and the LDSA section isn't writable,
    //      we need to use some form of indirection.  For example, on Darwin,
    //      we can output a statically-relocatable reference to a dyld stub. The
    //      offset to the stub is constant, but the contents are in a section
    //      that is updated by the dynamic linker.  This is easy enough, but we
    //      need to tell the personality function of the unwinder to indirect
    //      through the dyld stub.
    //
    // FIXME: When (3) is actually implemented, we'll have to emit the stubs
    // somewhere.  This predicate should be moved to a shared location that is
    // in target-independent code.
    //
    TTypeEncoding = Asm->getObjFileLowering().getTTypeEncoding();
    TypeFormatSize = Asm->GetSizeOfEncodedValue(TTypeEncoding);
  }

  // Begin the exception table.
  // Sometimes we want not to emit the data into separate section (e.g. ARM
  // EHABI). In this case LSDASection will be NULL.
  if (LSDASection)
    Asm->OutStreamer.SwitchSection(LSDASection);
  Asm->EmitAlignment(2);

  // Emit the LSDA.
  MCSymbol *GCCETSym =
    Asm->OutContext.GetOrCreateSymbol(Twine("GCC_except_table")+
                                      Twine(Asm->getFunctionNumber()));
  Asm->OutStreamer.EmitLabel(GCCETSym);
  Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("exception",
                                                Asm->getFunctionNumber()));

  if (IsSJLJ)
    Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("_LSDA_",
                                                  Asm->getFunctionNumber()));

  // Emit the LSDA header.
  Asm->EmitEncodingByte(dwarf::DW_EH_PE_omit, "@LPStart");
  Asm->EmitEncodingByte(TTypeEncoding, "@TType");

  // The type infos need to be aligned. GCC does this by inserting padding just
  // before the type infos. However, this changes the size of the exception
  // table, so you need to take this into account when you output the exception
  // table size. However, the size is output using a variable length encoding.
  // So by increasing the size by inserting padding, you may increase the number
  // of bytes used for writing the size. If it increases, say by one byte, then
  // you now need to output one less byte of padding to get the type infos
  // aligned. However this decreases the size of the exception table. This
  // changes the value you have to output for the exception table size. Due to
  // the variable length encoding, the number of bytes used for writing the
  // length may decrease. If so, you then have to increase the amount of
  // padding. And so on. If you look carefully at the GCC code you will see that
  // it indeed does this in a loop, going on and on until the values stabilize.
  // We chose another solution: don't output padding inside the table like GCC
  // does, instead output it before the table.
  unsigned SizeTypes = TypeInfos.size() * TypeFormatSize;
  unsigned CallSiteTableLengthSize =
    MCAsmInfo::getULEB128Size(CallSiteTableLength);
  unsigned TTypeBaseOffset =
    sizeof(int8_t) +                            // Call site format
    CallSiteTableLengthSize +                   // Call site table length size
    CallSiteTableLength +                       // Call site table length
    SizeActions +                               // Actions size
    SizeTypes;
  unsigned TTypeBaseOffsetSize = MCAsmInfo::getULEB128Size(TTypeBaseOffset);
  unsigned TotalSize =
    sizeof(int8_t) +                            // LPStart format
    sizeof(int8_t) +                            // TType format
    (HaveTTData ? TTypeBaseOffsetSize : 0) +    // TType base offset size
    TTypeBaseOffset;                            // TType base offset
  unsigned SizeAlign = (4 - TotalSize) & 3;

  if (HaveTTData) {
    // Account for any extra padding that will be added to the call site table
    // length.
    Asm->EmitULEB128(TTypeBaseOffset, "@TType base offset", SizeAlign);
    SizeAlign = 0;
  }

  bool VerboseAsm = Asm->OutStreamer.isVerboseAsm();

  // SjLj Exception handling
  if (IsSJLJ) {
    Asm->EmitEncodingByte(dwarf::DW_EH_PE_udata4, "Call site");

    // Add extra padding if it wasn't added to the TType base offset.
    Asm->EmitULEB128(CallSiteTableLength, "Call site table length", SizeAlign);

    // Emit the landing pad site information.
    unsigned idx = 0;
    for (SmallVectorImpl<CallSiteEntry>::const_iterator
         I = CallSites.begin(), E = CallSites.end(); I != E; ++I, ++idx) {
      const CallSiteEntry &S = *I;

      // Offset of the landing pad, counted in 16-byte bundles relative to the
      // @LPStart address.
      if (VerboseAsm) {
        Asm->OutStreamer.AddComment(">> Call Site " + Twine(idx) + " <<");
        Asm->OutStreamer.AddComment("  On exception at call site "+Twine(idx));
      }
      Asm->EmitULEB128(idx);

      // Offset of the first associated action record, relative to the start of
      // the action table. This value is biased by 1 (1 indicates the start of
      // the action table), and 0 indicates that there are no actions.
      if (VerboseAsm) {
        if (S.Action == 0)
          Asm->OutStreamer.AddComment("  Action: cleanup");
        else
          Asm->OutStreamer.AddComment("  Action: " +
                                      Twine((S.Action - 1) / 2 + 1));
      }
      Asm->EmitULEB128(S.Action);
    }
  } else {
    // DWARF Exception handling
    assert(Asm->MAI->isExceptionHandlingDwarf());

    // The call-site table is a list of all call sites that may throw an
    // exception (including C++ 'throw' statements) in the procedure
    // fragment. It immediately follows the LSDA header. Each entry indicates,
    // for a given call, the first corresponding action record and corresponding
    // landing pad.
    //
    // The table begins with the number of bytes, stored as an LEB128
    // compressed, unsigned integer. The records immediately follow the record
    // count. They are sorted in increasing call-site address. Each record
    // indicates:
    //
    //   * The position of the call-site.
    //   * The position of the landing pad.
    //   * The first action record for that call site.
    //
    // A missing entry in the call-site table indicates that a call is not
    // supposed to throw.

    // Emit the landing pad call site table.
    Asm->EmitEncodingByte(dwarf::DW_EH_PE_udata4, "Call site");

    // Add extra padding if it wasn't added to the TType base offset.
    Asm->EmitULEB128(CallSiteTableLength, "Call site table length", SizeAlign);

    unsigned Entry = 0;
    for (SmallVectorImpl<CallSiteEntry>::const_iterator
         I = CallSites.begin(), E = CallSites.end(); I != E; ++I) {
      const CallSiteEntry &S = *I;

      MCSymbol *EHFuncBeginSym =
        Asm->GetTempSymbol("eh_func_begin", Asm->getFunctionNumber());

      MCSymbol *BeginLabel = S.BeginLabel;
      if (BeginLabel == 0)
        BeginLabel = EHFuncBeginSym;
      MCSymbol *EndLabel = S.EndLabel;
      if (EndLabel == 0)
        EndLabel = Asm->GetTempSymbol("eh_func_end", Asm->getFunctionNumber());


      // Offset of the call site relative to the previous call site, counted in
      // number of 16-byte bundles. The first call site is counted relative to
      // the start of the procedure fragment.
      if (VerboseAsm)
        Asm->OutStreamer.AddComment(">> Call Site " + Twine(++Entry) + " <<");
      Asm->EmitLabelDifference(BeginLabel, EHFuncBeginSym, 4);
      if (VerboseAsm)
        Asm->OutStreamer.AddComment(Twine("  Call between ") +
                                    BeginLabel->getName() + " and " +
                                    EndLabel->getName());
      Asm->EmitLabelDifference(EndLabel, BeginLabel, 4);

      // Offset of the landing pad, counted in 16-byte bundles relative to the
      // @LPStart address.
      if (!S.PadLabel) {
        if (VerboseAsm)
          Asm->OutStreamer.AddComment("    has no landing pad");
        Asm->OutStreamer.EmitIntValue(0, 4/*size*/, 0/*addrspace*/);
      } else {
        if (VerboseAsm)
          Asm->OutStreamer.AddComment(Twine("    jumps to ") +
                                      S.PadLabel->getName());
        Asm->EmitLabelDifference(S.PadLabel, EHFuncBeginSym, 4);
      }

      // Offset of the first associated action record, relative to the start of
      // the action table. This value is biased by 1 (1 indicates the start of
      // the action table), and 0 indicates that there are no actions.
      if (VerboseAsm) {
        if (S.Action == 0)
          Asm->OutStreamer.AddComment("  On action: cleanup");
        else
          Asm->OutStreamer.AddComment("  On action: " +
                                      Twine((S.Action - 1) / 2 + 1));
      }
      Asm->EmitULEB128(S.Action);
    }
  }

  // Emit the Action Table.
  int Entry = 0;
  for (SmallVectorImpl<ActionEntry>::const_iterator
         I = Actions.begin(), E = Actions.end(); I != E; ++I) {
    const ActionEntry &Action = *I;

    if (VerboseAsm) {
      // Emit comments that decode the action table.
      Asm->OutStreamer.AddComment(">> Action Record " + Twine(++Entry) + " <<");
    }

    // Type Filter
    //
    //   Used by the runtime to match the type of the thrown exception to the
    //   type of the catch clauses or the types in the exception specification.
    if (VerboseAsm) {
      if (Action.ValueForTypeID > 0)
        Asm->OutStreamer.AddComment("  Catch TypeInfo " +
                                    Twine(Action.ValueForTypeID));
      else if (Action.ValueForTypeID < 0)
        Asm->OutStreamer.AddComment("  Filter TypeInfo " +
                                    Twine(Action.ValueForTypeID));
      else
        Asm->OutStreamer.AddComment("  Cleanup");
    }
    Asm->EmitSLEB128(Action.ValueForTypeID);

    // Action Record
    //
    //   Self-relative signed displacement in bytes of the next action record,
    //   or 0 if there is no next action record.
    if (VerboseAsm) {
      if (Action.NextAction == 0) {
        Asm->OutStreamer.AddComment("  No further actions");
      } else {
        unsigned NextAction = Entry + (Action.NextAction + 1) / 2;
        Asm->OutStreamer.AddComment("  Continue to action "+Twine(NextAction));
      }
    }
    Asm->EmitSLEB128(Action.NextAction);
  }

  // Emit the Catch TypeInfos.
  if (VerboseAsm && !TypeInfos.empty()) {
    Asm->OutStreamer.AddComment(">> Catch TypeInfos <<");
    Asm->OutStreamer.AddBlankLine();
    Entry = TypeInfos.size();
  }

  for (std::vector<const GlobalVariable *>::const_reverse_iterator
         I = TypeInfos.rbegin(), E = TypeInfos.rend(); I != E; ++I) {
    const GlobalVariable *GV = *I;
    if (VerboseAsm)
      Asm->OutStreamer.AddComment("TypeInfo " + Twine(Entry--));
    if (GV)
      Asm->EmitReference(GV, TTypeEncoding);
    else
      Asm->OutStreamer.EmitIntValue(0,Asm->GetSizeOfEncodedValue(TTypeEncoding),
                                    0);
  }

  // Emit the Exception Specifications.
  if (VerboseAsm && !FilterIds.empty()) {
    Asm->OutStreamer.AddComment(">> Filter TypeInfos <<");
    Asm->OutStreamer.AddBlankLine();
    Entry = 0;
  }
  for (std::vector<unsigned>::const_iterator
         I = FilterIds.begin(), E = FilterIds.end(); I < E; ++I) {
    unsigned TypeID = *I;
    if (VerboseAsm) {
      --Entry;
      if (TypeID != 0)
        Asm->OutStreamer.AddComment("FilterInfo " + Twine(Entry));
    }

    Asm->EmitULEB128(TypeID);
  }

  Asm->EmitAlignment(2);
}
/// ComputeCallSiteTable - 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.
void DwarfException::
ComputeCallSiteTable(SmallVectorImpl<CallSiteEntry> &CallSites,
                     const RangeMapType &PadMap,
                     const SmallVectorImpl<const LandingPadInfo *> &LandingPads,
                     const SmallVectorImpl<unsigned> &FirstActions) {
  // The end label of the previous invoke or nounwind try-range.
  MCSymbol *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 = Asm->MF->begin(), E = Asm->MF->end();
       I != E; ++I) {
    for (MachineBasicBlock::const_iterator MI = I->begin(), E = I->end();
         MI != E; ++MI) {
      if (!MI->isLabel()) {
        if (MI->isCall())
          SawPotentiallyThrowing |= !CallToNoUnwindFunction(MI);
        continue;
      }

      // End of the previous try-range?
      MCSymbol *BeginLabel = MI->getOperand(0).getMCSymbol();
      if (BeginLabel == LastLabel)
        SawPotentiallyThrowing = false;

      // Beginning of a new try-range?
      RangeMapType::const_iterator L = PadMap.find(BeginLabel);
      if (L == PadMap.end())
        // Nope, it was just some random label.
        continue;

      const PadRange &P = L->second;
      const LandingPadInfo *LandingPad = LandingPads[P.PadIndex];
      assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] &&
             "Inconsistent landing pad map!");

      // For Dwarf exception handling (SjLj handling doesn't use this). 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 && Asm->MAI->isExceptionHandlingDwarf()) {
        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) {
        // Create a gap.
        PreviousIsInvoke = false;
      } else {
        // This try-range is for an invoke.
        CallSiteEntry Site = {
          BeginLabel,
          LastLabel,
          LandingPad->LandingPadLabel,
          FirstActions[P.PadIndex]
        };

        // Try to merge with the previous call-site. SJLJ doesn't do this
        if (PreviousIsInvoke && Asm->MAI->isExceptionHandlingDwarf()) {
          CallSiteEntry &Prev = CallSites.back();
          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.
        if (Asm->MAI->isExceptionHandlingDwarf())
          CallSites.push_back(Site);
        else {
          // SjLj EH must maintain the call sites in the order assigned
          // to them by the SjLjPrepare pass.
          unsigned SiteNo = MMI->getCallSiteBeginLabel(BeginLabel);
          if (CallSites.size() < SiteNo)
            CallSites.resize(SiteNo);
          CallSites[SiteNo - 1] = Site;
        }
        PreviousIsInvoke = true;
      }
    }
  }

  // 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 && Asm->MAI->isExceptionHandlingDwarf()) {
    CallSiteEntry Site = { LastLabel, 0, 0, 0 };
    CallSites.push_back(Site);
  }
}
Example #4
0
void WinException::extendIP2StateTable(const MachineFunction *MF,
                                       const Function *ParentF,
                                       WinEHFuncInfo &FuncInfo) {
  const Function *F = MF->getFunction();

  // The Itanium LSDA table sorts similar landing pads together to simplify the
  // actions table, but we don't need that.
  SmallVector<const LandingPadInfo *, 64> LandingPads;
  const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads();
  LandingPads.reserve(PadInfos.size());
  for (const auto &LP : PadInfos)
    LandingPads.push_back(&LP);

  RangeMapType PadMap;
  computePadMap(LandingPads, PadMap);

  // The end label of the previous invoke or nounwind try-range.
  MCSymbol *LastLabel = Asm->getFunctionBegin();

  // 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;

  int LastEHState = -2;

  // The parent function and the catch handlers contribute to the 'ip2state'
  // table.

  // Include ip2state entries for the beginning of the main function and
  // for catch handler functions.
  if (F == ParentF) {
    FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel, -1));
    LastEHState = -1;
  } else if (FuncInfo.HandlerBaseState.count(F)) {
    FuncInfo.IPToStateList.push_back(
        std::make_pair(LastLabel, FuncInfo.HandlerBaseState[F]));
    LastEHState = FuncInfo.HandlerBaseState[F];
  }
  for (const auto &MBB : *MF) {
    for (const auto &MI : MBB) {
      if (!MI.isEHLabel()) {
        if (MI.isCall())
          SawPotentiallyThrowing |= !callToNoUnwindFunction(&MI);
        continue;
      }

      // End of the previous try-range?
      MCSymbol *BeginLabel = MI.getOperand(0).getMCSymbol();
      if (BeginLabel == LastLabel)
        SawPotentiallyThrowing = false;

      // Beginning of a new try-range?
      RangeMapType::const_iterator L = PadMap.find(BeginLabel);
      if (L == PadMap.end())
        // Nope, it was just some random label.
        continue;

      const PadRange &P = L->second;
      const LandingPadInfo *LandingPad = LandingPads[P.PadIndex];
      assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] &&
             "Inconsistent landing pad map!");

      // FIXME: Should this be using FuncInfo.HandlerBaseState?
      if (SawPotentiallyThrowing && LastEHState != -1) {
        FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel, -1));
        SawPotentiallyThrowing = false;
        LastEHState = -1;
      }

      if (LandingPad->WinEHState != LastEHState)
        FuncInfo.IPToStateList.push_back(
            std::make_pair(BeginLabel, LandingPad->WinEHState));
      LastEHState = LandingPad->WinEHState;
      LastLabel = LandingPad->EndLabels[P.RangeIndex];
    }
  }
}
Example #5
0
void Win64Exception::emitCXXFrameHandler3Table(const MachineFunction *MF) {
    const Function *F = MF->getFunction();
    const Function *ParentF = MMI->getWinEHParent(F);
    auto &OS = *Asm->OutStreamer;
    WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(ParentF);

    StringRef ParentLinkageName =
        GlobalValue::getRealLinkageName(ParentF->getName());

    MCSymbol *FuncInfoXData =
        Asm->OutContext.getOrCreateSymbol(Twine("$cppxdata$", ParentLinkageName));
    OS.EmitValue(createImageRel32(FuncInfoXData), 4);

    // The Itanium LSDA table sorts similar landing pads together to simplify the
    // actions table, but we don't need that.
    SmallVector<const LandingPadInfo *, 64> LandingPads;
    const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads();
    LandingPads.reserve(PadInfos.size());
    for (const auto &LP : PadInfos)
        LandingPads.push_back(&LP);

    RangeMapType PadMap;
    computePadMap(LandingPads, PadMap);

    // The end label of the previous invoke or nounwind try-range.
    MCSymbol *LastLabel = Asm->getFunctionBegin();

    // 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;

    int LastEHState = -2;

    // The parent function and the catch handlers contribute to the 'ip2state'
    // table.

    // Include ip2state entries for the beginning of the main function and
    // for catch handler functions.
    if (F == ParentF) {
        FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel, -1));
        LastEHState = -1;
    } else if (FuncInfo.HandlerBaseState.count(F)) {
        FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel,
                                         FuncInfo.HandlerBaseState[F]));
        LastEHState = FuncInfo.HandlerBaseState[F];
    }
    for (const auto &MBB : *MF) {
        for (const auto &MI : MBB) {
            if (!MI.isEHLabel()) {
                if (MI.isCall())
                    SawPotentiallyThrowing |= !callToNoUnwindFunction(&MI);
                continue;
            }

            // End of the previous try-range?
            MCSymbol *BeginLabel = MI.getOperand(0).getMCSymbol();
            if (BeginLabel == LastLabel)
                SawPotentiallyThrowing = false;

            // Beginning of a new try-range?
            RangeMapType::const_iterator L = PadMap.find(BeginLabel);
            if (L == PadMap.end())
                // Nope, it was just some random label.
                continue;

            const PadRange &P = L->second;
            const LandingPadInfo *LandingPad = LandingPads[P.PadIndex];
            assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] &&
                   "Inconsistent landing pad map!");

            // FIXME: Should this be using FuncInfo.HandlerBaseState?
            if (SawPotentiallyThrowing && LastEHState != -1) {
                FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel, -1));
                SawPotentiallyThrowing = false;
                LastEHState = -1;
            }

            if (LandingPad->WinEHState != LastEHState)
                FuncInfo.IPToStateList.push_back(
                    std::make_pair(BeginLabel, LandingPad->WinEHState));
            LastEHState = LandingPad->WinEHState;
            LastLabel = LandingPad->EndLabels[P.RangeIndex];
        }
    }

    // Defer emission until we've visited the parent function and all the catch
    // handlers.  Cleanups don't contribute to the ip2state table yet, so don't
    // count them.
    if (ParentF != F && !FuncInfo.CatchHandlerMaxState.count(F))
        return;
    ++FuncInfo.NumIPToStateFuncsVisited;
    if (FuncInfo.NumIPToStateFuncsVisited != FuncInfo.CatchHandlerMaxState.size())
        return;

    MCSymbol *UnwindMapXData = nullptr;
    MCSymbol *TryBlockMapXData = nullptr;
    MCSymbol *IPToStateXData = nullptr;
    if (!FuncInfo.UnwindMap.empty())
        UnwindMapXData = Asm->OutContext.getOrCreateSymbol(
                             Twine("$stateUnwindMap$", ParentLinkageName));
    if (!FuncInfo.TryBlockMap.empty())
        TryBlockMapXData = Asm->OutContext.getOrCreateSymbol(
                               Twine("$tryMap$", ParentLinkageName));
    if (!FuncInfo.IPToStateList.empty())
        IPToStateXData = Asm->OutContext.getOrCreateSymbol(
                             Twine("$ip2state$", ParentLinkageName));

    // FuncInfo {
    //   uint32_t           MagicNumber
    //   int32_t            MaxState;
    //   UnwindMapEntry    *UnwindMap;
    //   uint32_t           NumTryBlocks;
    //   TryBlockMapEntry  *TryBlockMap;
    //   uint32_t           IPMapEntries;
    //   IPToStateMapEntry *IPToStateMap;
    //   uint32_t           UnwindHelp; // (x64/ARM only)
    //   ESTypeList        *ESTypeList;
    //   int32_t            EHFlags;
    // }
    // EHFlags & 1 -> Synchronous exceptions only, no async exceptions.
    // EHFlags & 2 -> ???
    // EHFlags & 4 -> The function is noexcept(true), unwinding can't continue.
    OS.EmitLabel(FuncInfoXData);
    OS.EmitIntValue(0x19930522, 4);                      // MagicNumber
    OS.EmitIntValue(FuncInfo.UnwindMap.size(), 4);       // MaxState
    OS.EmitValue(createImageRel32(UnwindMapXData), 4);   // UnwindMap
    OS.EmitIntValue(FuncInfo.TryBlockMap.size(), 4);     // NumTryBlocks
    OS.EmitValue(createImageRel32(TryBlockMapXData), 4); // TryBlockMap
    OS.EmitIntValue(FuncInfo.IPToStateList.size(), 4);   // IPMapEntries
    OS.EmitValue(createImageRel32(IPToStateXData), 4);   // IPToStateMap
    OS.EmitIntValue(FuncInfo.UnwindHelpFrameOffset, 4);  // UnwindHelp
    OS.EmitIntValue(0, 4);                               // ESTypeList
    OS.EmitIntValue(1, 4);                               // EHFlags

    // UnwindMapEntry {
    //   int32_t ToState;
    //   void  (*Action)();
    // };
    if (UnwindMapXData) {
        OS.EmitLabel(UnwindMapXData);
        for (const WinEHUnwindMapEntry &UME : FuncInfo.UnwindMap) {
            OS.EmitIntValue(UME.ToState, 4);                // ToState
            OS.EmitValue(createImageRel32(UME.Cleanup), 4); // Action
        }
    }

    // TryBlockMap {
    //   int32_t      TryLow;
    //   int32_t      TryHigh;
    //   int32_t      CatchHigh;
    //   int32_t      NumCatches;
    //   HandlerType *HandlerArray;
    // };
    if (TryBlockMapXData) {
        OS.EmitLabel(TryBlockMapXData);
        SmallVector<MCSymbol *, 1> HandlerMaps;
        for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) {
            WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I];
            MCSymbol *HandlerMapXData = nullptr;

            if (!TBME.HandlerArray.empty())
                HandlerMapXData =
                    Asm->OutContext.getOrCreateSymbol(Twine("$handlerMap$")
                                                      .concat(Twine(I))
                                                      .concat("$")
                                                      .concat(ParentLinkageName));

            HandlerMaps.push_back(HandlerMapXData);

            int CatchHigh = -1;
            for (WinEHHandlerType &HT : TBME.HandlerArray)
                CatchHigh =
                    std::max(CatchHigh, FuncInfo.CatchHandlerMaxState[HT.Handler]);

            assert(TBME.TryLow <= TBME.TryHigh);
            OS.EmitIntValue(TBME.TryLow, 4);                    // TryLow
            OS.EmitIntValue(TBME.TryHigh, 4);                   // TryHigh
            OS.EmitIntValue(CatchHigh, 4);                      // CatchHigh
            OS.EmitIntValue(TBME.HandlerArray.size(), 4);       // NumCatches
            OS.EmitValue(createImageRel32(HandlerMapXData), 4); // HandlerArray
        }

        for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) {
            WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I];
            MCSymbol *HandlerMapXData = HandlerMaps[I];
            if (!HandlerMapXData)
                continue;
            // HandlerType {
            //   int32_t         Adjectives;
            //   TypeDescriptor *Type;
            //   int32_t         CatchObjOffset;
            //   void          (*Handler)();
            //   int32_t         ParentFrameOffset; // x64 only
            // };
            OS.EmitLabel(HandlerMapXData);
            for (const WinEHHandlerType &HT : TBME.HandlerArray) {
                MCSymbol *ParentFrameOffset =
                    Asm->OutContext.getOrCreateParentFrameOffsetSymbol(
                        GlobalValue::getRealLinkageName(HT.Handler->getName()));
                const MCSymbolRefExpr *ParentFrameOffsetRef = MCSymbolRefExpr::Create(
                            ParentFrameOffset, MCSymbolRefExpr::VK_None, Asm->OutContext);

                // Get the frame escape label with the offset of the catch object. If
                // the index is -1, then there is no catch object, and we should emit an
                // offset of zero, indicating that no copy will occur.
                const MCExpr *FrameAllocOffsetRef = nullptr;
                if (HT.CatchObjRecoverIdx >= 0) {
                    MCSymbol *FrameAllocOffset =
                        Asm->OutContext.getOrCreateFrameAllocSymbol(
                            GlobalValue::getRealLinkageName(ParentF->getName()),
                            HT.CatchObjRecoverIdx);
                    FrameAllocOffsetRef = MCSymbolRefExpr::Create(
                                              FrameAllocOffset, MCSymbolRefExpr::VK_None, Asm->OutContext);
                } else {
                    FrameAllocOffsetRef = MCConstantExpr::Create(0, Asm->OutContext);
                }

                OS.EmitIntValue(HT.Adjectives, 4);                    // Adjectives
                OS.EmitValue(createImageRel32(HT.TypeDescriptor), 4); // Type
                OS.EmitValue(FrameAllocOffsetRef, 4);                 // CatchObjOffset
                OS.EmitValue(createImageRel32(HT.Handler), 4);        // Handler
                OS.EmitValue(ParentFrameOffsetRef, 4);                // ParentFrameOffset
            }
        }
    }

    // IPToStateMapEntry {
    //   void   *IP;
    //   int32_t State;
    // };
    if (IPToStateXData) {
        OS.EmitLabel(IPToStateXData);
        for (auto &IPStatePair : FuncInfo.IPToStateList) {
            OS.EmitValue(createImageRel32(IPStatePair.first), 4); // IP
            OS.EmitIntValue(IPStatePair.second, 4);               // State
        }
    }
}
Example #6
0
unsigned char* JITDwarfEmitter::EmitExceptionTable(MachineFunction* MF,
                                         unsigned char* StartFunction,
                                         unsigned char* EndFunction) const {
  assert(MMI && "MachineModuleInfo not registered!");

  // Map all labels and get rid of any dead landing pads.
  MMI->TidyLandingPads(JCE->getLabelLocations());

  const std::vector<const GlobalVariable *> &TypeInfos = MMI->getTypeInfos();
  const std::vector<unsigned> &FilterIds = MMI->getFilterIds();
  const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads();
  if (PadInfos.empty()) return 0;

  // Sort the landing pads in order of their type ids.  This is used to fold
  // duplicate actions.
  SmallVector<const LandingPadInfo *, 64> 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<int, 16> FilterOffsets;
  FilterOffsets.reserve(FilterIds.size());
  int Offset = -1;
  for(std::vector<unsigned>::const_iterator I = FilterIds.begin(),
    E = FilterIds.end(); I != E; ++I) {
    FilterOffsets.push_back(Offset);
    Offset -= MCAsmInfo::getULEB128Size(*I);
  }

  // Compute the actions table and gather the first action index for each
  // landing pad site.
  SmallVector<ActionEntry, 32> Actions;
  SmallVector<unsigned, 64> 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<int> &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 = MCAsmInfo::getSLEB128Size(PrevAction->NextAction) +
          MCAsmInfo::getSLEB128Size(PrevAction->ValueForTypeID);
        for (unsigned j = NumShared; j != SizePrevIds; ++j) {
          SizeAction -= MCAsmInfo::getSLEB128Size(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 = MCAsmInfo::getSLEB128Size(ValueForTypeID);

        int NextAction = SizeAction ? -(SizeAction + SizeTypeID) : 0;
        SizeAction = SizeTypeID + MCAsmInfo::getSLEB128Size(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.  Entries must be ordered by address.
  SmallVector<CallSiteEntry, 64> CallSites;

  RangeMapType PadMap;
  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) {
      MCSymbol *BeginLabel = LandingPad->BeginLabels[j];
      assert(!PadMap.count(BeginLabel) && "Duplicate landing pad labels!");
      PadRange P = { i, j };
      PadMap[BeginLabel] = P;
    }
  }

  bool MayThrow = false;
  MCSymbol *LastLabel = 0;
  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->isLabel()) {
        MayThrow |= MI->getDesc().isCall();
        continue;
      }

      MCSymbol *BeginLabel = MI->getOperand(0).getMCSymbol();
      assert(BeginLabel && "Invalid label!");

      if (BeginLabel == LastLabel)
        MayThrow = false;

      RangeMapType::iterator L = PadMap.find(BeginLabel);

      if (L == PadMap.end())
        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 (MayThrow) {
        CallSiteEntry Site = {LastLabel, BeginLabel, 0, 0};
        CallSites.push_back(Site);
      }

      LastLabel = LandingPad->EndLabels[P.RangeIndex];
      CallSiteEntry Site = {BeginLabel, LastLabel,
        LandingPad->LandingPadLabel, FirstActions[P.PadIndex]};

      assert(Site.BeginLabel && Site.EndLabel && Site.PadLabel &&
              "Invalid landing pad!");

      // Try to merge with the previous call-site.
      if (CallSites.size()) {
        CallSiteEntry &Prev = CallSites.back();
        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);
    }
  }
  // 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 (MayThrow) {
    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 += MCAsmInfo::getULEB128Size(CallSites[i].Action);

  unsigned SizeTypes = TypeInfos.size() * TD->getPointerSize();

  unsigned TypeOffset = sizeof(int8_t) + // Call site format
                        // Call-site table length
                        MCAsmInfo::getULEB128Size(SizeSites) + 
                        SizeSites + SizeActions + SizeTypes;

  // Begin the exception table.
  JCE->emitAlignmentWithFill(4, 0);
  // Asm->EOL("Padding");

  unsigned char* DwarfExceptionTable = (unsigned char*)JCE->getCurrentPCValue();

  // Emit the header.
  JCE->emitByte(dwarf::DW_EH_PE_omit);
  // Asm->EOL("LPStart format (DW_EH_PE_omit)");
  JCE->emitByte(dwarf::DW_EH_PE_absptr);
  // Asm->EOL("TType format (DW_EH_PE_absptr)");
  JCE->emitULEB128Bytes(TypeOffset);
  // Asm->EOL("TType base offset");
  JCE->emitByte(dwarf::DW_EH_PE_udata4);
  // Asm->EOL("Call site format (DW_EH_PE_udata4)");
  JCE->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];
    intptr_t BeginLabelPtr = 0;
    intptr_t EndLabelPtr = 0;

    if (!S.BeginLabel) {
      BeginLabelPtr = (intptr_t)StartFunction;
      JCE->emitInt32(0);
    } else {
      BeginLabelPtr = JCE->getLabelAddress(S.BeginLabel);
      JCE->emitInt32(BeginLabelPtr - (intptr_t)StartFunction);
    }

    // Asm->EOL("Region start");

    if (!S.EndLabel)
      EndLabelPtr = (intptr_t)EndFunction;
    else
      EndLabelPtr = JCE->getLabelAddress(S.EndLabel);

    JCE->emitInt32(EndLabelPtr - BeginLabelPtr);
    //Asm->EOL("Region length");

    if (!S.PadLabel) {
      JCE->emitInt32(0);
    } else {
      unsigned PadLabelPtr = JCE->getLabelAddress(S.PadLabel);
      JCE->emitInt32(PadLabelPtr - (intptr_t)StartFunction);
    }
    // Asm->EOL("Landing pad");

    JCE->emitULEB128Bytes(S.Action);
    // Asm->EOL("Action");
  }

  // Emit the actions.
  for (unsigned I = 0, N = Actions.size(); I != N; ++I) {
    ActionEntry &Action = Actions[I];

    JCE->emitSLEB128Bytes(Action.ValueForTypeID);
    //Asm->EOL("TypeInfo index");
    JCE->emitSLEB128Bytes(Action.NextAction);
    //Asm->EOL("Next action");
  }

  // Emit the type ids.
  for (unsigned M = TypeInfos.size(); M; --M) {
    const GlobalVariable *GV = TypeInfos[M - 1];
    
    if (GV) {
      if (TD->getPointerSize() == sizeof(int32_t))
        JCE->emitInt32((intptr_t)Jit.getOrEmitGlobalVariable(GV));
      else
        JCE->emitInt64((intptr_t)Jit.getOrEmitGlobalVariable(GV));
    } else {
      if (TD->getPointerSize() == sizeof(int32_t))
        JCE->emitInt32(0);
      else
        JCE->emitInt64(0);
    }
    // Asm->EOL("TypeInfo");
  }

  // Emit the filter typeids.
  for (unsigned j = 0, M = FilterIds.size(); j < M; ++j) {
    unsigned TypeID = FilterIds[j];
    JCE->emitULEB128Bytes(TypeID);
    //Asm->EOL("Filter TypeInfo index");
  }

  JCE->emitAlignmentWithFill(4, 0);

  return DwarfExceptionTable;
}
Example #7
0
/// 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.
void EHStreamer::
computeCallSiteTable(SmallVectorImpl<CallSiteEntry> &CallSites,
                     const SmallVectorImpl<const LandingPadInfo *> &LandingPads,
                     const SmallVectorImpl<unsigned> &FirstActions) {
  // 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 so we can put them in the LSDA.
  RangeMapType PadMap;
  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) {
      MCSymbol *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.
  MCSymbol *LastLabel = nullptr;

  // 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;

  bool IsSJLJ = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::SjLj;

  // Visit all instructions in order of address.
  for (const auto &MBB : *Asm->MF) {
    for (const auto &MI : MBB) {
      if (!MI.isEHLabel()) {
        if (MI.isCall())
          SawPotentiallyThrowing |= !callToNoUnwindFunction(&MI);
        continue;
      }

      // End of the previous try-range?
      MCSymbol *BeginLabel = MI.getOperand(0).getMCSymbol();
      if (BeginLabel == LastLabel)
        SawPotentiallyThrowing = false;

      // Beginning of a new try-range?
      RangeMapType::const_iterator L = PadMap.find(BeginLabel);
      if (L == PadMap.end())
        // Nope, it was just some random label.
        continue;

      const PadRange &P = L->second;
      const LandingPadInfo *LandingPad = LandingPads[P.PadIndex];
      assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] &&
             "Inconsistent landing pad map!");

      // For Dwarf exception handling (SjLj handling doesn't use this). 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 && !IsSJLJ) {
        CallSiteEntry Site = { LastLabel, BeginLabel, nullptr, 0 };
        CallSites.push_back(Site);
        PreviousIsInvoke = false;
      }

      LastLabel = LandingPad->EndLabels[P.RangeIndex];
      assert(BeginLabel && LastLabel && "Invalid landing pad!");

      if (!LandingPad->LandingPadLabel) {
        // Create a gap.
        PreviousIsInvoke = false;
      } else {
        // This try-range is for an invoke.
        CallSiteEntry Site = {
          BeginLabel,
          LastLabel,
          LandingPad->LandingPadLabel,
          FirstActions[P.PadIndex]
        };

        // Try to merge with the previous call-site. SJLJ doesn't do this
        if (PreviousIsInvoke && !IsSJLJ) {
          CallSiteEntry &Prev = CallSites.back();
          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.
        if (!IsSJLJ)
          CallSites.push_back(Site);
        else {
          // SjLj EH must maintain the call sites in the order assigned
          // to them by the SjLjPrepare pass.
          unsigned SiteNo = MMI->getCallSiteBeginLabel(BeginLabel);
          if (CallSites.size() < SiteNo)
            CallSites.resize(SiteNo);
          CallSites[SiteNo - 1] = Site;
        }
        PreviousIsInvoke = true;
      }
    }
  }

  // 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 && !IsSJLJ) {
    CallSiteEntry Site = { LastLabel, nullptr, nullptr, 0 };
    CallSites.push_back(Site);
  }
}
Example #8
0
/// 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.
void DwarfException::EmitExceptionTable() {
    const std::vector<GlobalVariable *> &TypeInfos = MMI->getTypeInfos();
    const std::vector<unsigned> &FilterIds = MMI->getFilterIds();
    const std::vector<LandingPadInfo> &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<const LandingPadInfo *, 64> 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);

    // Compute the actions table and gather the first action index for each
    // landing pad site.
    SmallVector<ActionEntry, 32> Actions;
    SmallVector<unsigned, 64> FirstActions;
    unsigned SizeActions = ComputeActionsTable(LandingPads, Actions, FirstActions);

    // 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 when using Dwarf exception handling.
    RangeMapType PadMap;
    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;
        }
    }

    // Compute the call-site table.
    SmallVector<CallSiteEntry, 64> CallSites;
    ComputeCallSiteTable(CallSites, PadMap, LandingPads, FirstActions);

    // Final tallies.

    // 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;

    bool HaveTTData = (TAI->getExceptionHandlingType() == ExceptionHandling::SjLj)
                      ? (!TypeInfos.empty() || !FilterIds.empty()) : true;


    if (TAI->getExceptionHandlingType() == ExceptionHandling::SjLj) {
        SizeSites = 0;
    } else
        SizeSites = CallSites.size() *
                    (SiteStartSize + SiteLengthSize + LandingPadSize);
    for (unsigned i = 0, e = CallSites.size(); i < e; ++i) {
        SizeSites += TargetAsmInfo::getULEB128Size(CallSites[i].Action);
        if (TAI->getExceptionHandlingType() == ExceptionHandling::SjLj)
            SizeSites += TargetAsmInfo::getULEB128Size(i);
    }
    // Type infos.
    const unsigned TypeInfoSize = TD->getPointerSize(); // DW_EH_PE_absptr
    unsigned SizeTypes = TypeInfos.size() * TypeInfoSize;

    unsigned TypeOffset = sizeof(int8_t) + // Call site format
                          TargetAsmInfo::getULEB128Size(SizeSites) + // Call-site table length
                          SizeSites + SizeActions + SizeTypes;

    unsigned TotalSize = sizeof(int8_t) + // LPStart format
                         sizeof(int8_t) + // TType format
                         (HaveTTData ?
                          TargetAsmInfo::getULEB128Size(TypeOffset) : 0) + // TType base offset
                         TypeOffset;

    unsigned SizeAlign = (4 - TotalSize) & 3;

    // Begin the exception table.
    const MCSection *LSDASection = Asm->getObjFileLowering().getLSDASection();
    Asm->OutStreamer.SwitchSection(LSDASection);
    Asm->EmitAlignment(2, 0, 0, false);
    O << "GCC_except_table" << SubprogramCount << ":\n";

    for (unsigned i = 0; i != SizeAlign; ++i) {
        Asm->EmitInt8(0);
        Asm->EOL("Padding");
    }

    EmitLabel("exception", SubprogramCount);
    if (TAI->getExceptionHandlingType() == ExceptionHandling::SjLj) {
        std::string SjLjName = "_lsda_";
        SjLjName += MF->getFunction()->getName().str();
        EmitLabel(SjLjName.c_str(), 0);
    }

    // Emit the header.
    Asm->EmitInt8(dwarf::DW_EH_PE_omit);
    Asm->EOL("@LPStart format (DW_EH_PE_omit)");

#if 0
    if (TypeInfos.empty() && FilterIds.empty()) {
        // If there are no typeinfos or filters, there is nothing to emit, optimize
        // by specifying the "omit" encoding.
        Asm->EmitInt8(dwarf::DW_EH_PE_omit);
        Asm->EOL("@TType format (DW_EH_PE_omit)");
    } else {
        // Okay, we have actual filters or typeinfos to emit.  As such, we need to
        // pick a type encoding for them.  We're about to emit a list of pointers to
        // typeinfo objects at the end of the LSDA.  However, unless we're in static
        // mode, this reference will require a relocation by the dynamic linker.
        //
        // Because of this, we have a couple of options:
        //   1) If we are in -static mode, we can always use an absolute reference
        //      from the LSDA, because the static linker will resolve it.
        //   2) Otherwise, if the LSDA section is writable, we can output the direct
        //      reference to the typeinfo and allow the dynamic linker to relocate
        //      it.  Since it is in a writable section, the dynamic linker won't
        //      have a problem.
        //   3) Finally, if we're in PIC mode and the LDSA section isn't writable,
        //      we need to use some form of indirection.  For example, on Darwin,
        //      we can output a statically-relocatable reference to a dyld stub. The
        //      offset to the stub is constant, but the contents are in a section
        //      that is updated by the dynamic linker.  This is easy enough, but we
        //      need to tell the personality function of the unwinder to indirect
        //      through the dyld stub.
        //
        // FIXME: When this is actually implemented, we'll have to emit the stubs
        // somewhere.  This predicate should be moved to a shared location that is
        // in target-independent code.
        //
        if (LSDASection->isWritable() ||
                Asm->TM.getRelocationModel() == Reloc::Static) {
            Asm->EmitInt8(DW_EH_PE_absptr);
            Asm->EOL("TType format (DW_EH_PE_absptr)");
        } else {
            Asm->EmitInt8(DW_EH_PE_pcrel | DW_EH_PE_indirect | DW_EH_PE_sdata4);
            Asm->EOL("TType format (DW_EH_PE_pcrel | DW_EH_PE_indirect"
                     " | DW_EH_PE_sdata4)");
        }
        Asm->EmitULEB128Bytes(TypeOffset);
        Asm->EOL("TType base offset");
    }
#else
    // For SjLj exceptions, if there is no TypeInfo, then we just explicitly
    // say that we're omitting that bit.
    // FIXME: does this apply to Dwarf also? The above #if 0 implies yes?
    if (!HaveTTData) {
        Asm->EmitInt8(dwarf::DW_EH_PE_omit);
        Asm->EOL("@TType format (DW_EH_PE_omit)");
    } else {
        Asm->EmitInt8(dwarf::DW_EH_PE_absptr);
        Asm->EOL("@TType format (DW_EH_PE_absptr)");
        Asm->EmitULEB128Bytes(TypeOffset);
        Asm->EOL("@TType base offset");
    }
#endif

    // SjLj Exception handilng
    if (TAI->getExceptionHandlingType() == ExceptionHandling::SjLj) {
        Asm->EmitInt8(dwarf::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.
        unsigned idx = 0;
        for (SmallVectorImpl<CallSiteEntry>::const_iterator
                I = CallSites.begin(), E = CallSites.end(); I != E; ++I, ++idx) {
            const CallSiteEntry &S = *I;

            // Offset of the landing pad, counted in 16-byte bundles relative to the
            // @LPStart address.
            Asm->EmitULEB128Bytes(idx);
            Asm->EOL("Landing pad");

            // Offset of the first associated action record, relative to the start of
            // the action table. This value is biased by 1 (1 indicates the start of
            // the action table), and 0 indicates that there are no actions.
            Asm->EmitULEB128Bytes(S.Action);
            Asm->EOL("Action");
        }
    } else {
        // DWARF Exception handling
        assert(TAI->getExceptionHandlingType() == ExceptionHandling::Dwarf);

        // The call-site table is a list of all call sites that may throw an
        // exception (including C++ 'throw' statements) in the procedure
        // fragment. It immediately follows the LSDA header. Each entry indicates,
        // for a given call, the first corresponding action record and corresponding
        // landing pad.
        //
        // The table begins with the number of bytes, stored as an LEB128
        // compressed, unsigned integer. The records immediately follow the record
        // count. They are sorted in increasing call-site address. Each record
        // indicates:
        //
        //   * The position of the call-site.
        //   * The position of the landing pad.
        //   * The first action record for that call site.
        //
        // A missing entry in the call-site table indicates that a call is not
        // supposed to throw. Such calls include:
        //
        //   * Calls to destructors within cleanup code. C++ semantics forbids these
        //     calls to throw.
        //   * Calls to intrinsic routines in the standard library which are known
        //     not to throw (sin, memcpy, et al).
        //
        // If the runtime does not find the call-site entry for a given call, it
        // will call `terminate()'.

        // Emit the landing pad call site table.
        Asm->EmitInt8(dwarf::DW_EH_PE_udata4);
        Asm->EOL("Call site format (DW_EH_PE_udata4)");
        Asm->EmitULEB128Bytes(SizeSites);
        Asm->EOL("Call site table size");

        for (SmallVectorImpl<CallSiteEntry>::const_iterator
                I = CallSites.begin(), E = CallSites.end(); I != E; ++I) {
            const CallSiteEntry &S = *I;
            const char *BeginTag;
            unsigned BeginNumber;

            if (!S.BeginLabel) {
                BeginTag = "eh_func_begin";
                BeginNumber = SubprogramCount;
            } else {
                BeginTag = "label";
                BeginNumber = S.BeginLabel;
            }

            // Offset of the call site relative to the previous call site, counted in
            // number of 16-byte bundles. The first call site is counted relative to
            // the start of the procedure fragment.
            EmitSectionOffset(BeginTag, "eh_func_begin", BeginNumber, SubprogramCount,
                              true, true);
            Asm->EOL("Region start");

            if (!S.EndLabel)
                EmitDifference("eh_func_end", SubprogramCount, BeginTag, BeginNumber,
                               true);
            else
                EmitDifference("label", S.EndLabel, BeginTag, BeginNumber, true);

            Asm->EOL("Region length");

            // Offset of the landing pad, counted in 16-byte bundles relative to the
            // @LPStart address.
            if (!S.PadLabel)
                Asm->EmitInt32(0);
            else
                EmitSectionOffset("label", "eh_func_begin", S.PadLabel, SubprogramCount,
                                  true, true);

            Asm->EOL("Landing pad");

            // Offset of the first associated action record, relative to the start of
            // the action table. This value is biased by 1 (1 indicates the start of
            // the action table), and 0 indicates that there are no actions.
            Asm->EmitULEB128Bytes(S.Action);
            Asm->EOL("Action");
        }
    }

    // Emit the Action Table.
    for (SmallVectorImpl<ActionEntry>::const_iterator
            I = Actions.begin(), E = Actions.end(); I != E; ++I) {
        const ActionEntry &Action = *I;

        // Type Filter
        //
        //   Used by the runtime to match the type of the thrown exception to the
        //   type of the catch clauses or the types in the exception specification.

        Asm->EmitSLEB128Bytes(Action.ValueForTypeID);
        Asm->EOL("TypeInfo index");

        // Action Record
        //
        //   Self-relative signed displacement in bytes of the next action record,
        //   or 0 if there is no next action record.

        Asm->EmitSLEB128Bytes(Action.NextAction);
        Asm->EOL("Next action");
    }

    // Emit the Catch Clauses. The code for the catch clauses following the same
    // try is similar to a switch statement. The catch clause action record
    // informs the runtime about the type of a catch clause and about the
    // associated switch value.
    //
    //  Action Record Fields:
    //
    //   * Filter Value
    //     Positive value, starting at 1. Index in the types table of the
    //     __typeinfo for the catch-clause type. 1 is the first word preceding
    //     TTBase, 2 is the second word, and so on. Used by the runtime to check
    //     if the thrown exception type matches the catch-clause type. Back-end
    //     generated switch statements check against this value.
    //
    //   * Next
    //     Signed offset, in bytes from the start of this field, to the next
    //     chained action record, or zero if none.
    //
    // The order of the action records determined by the next field is the order
    // of the catch clauses as they appear in the source code, and must be kept in
    // the same order. As a result, changing the order of the catch clause would
    // change the semantics of the program.
    for (std::vector<GlobalVariable *>::const_reverse_iterator
            I = TypeInfos.rbegin(), E = TypeInfos.rend(); I != E; ++I) {
        const GlobalVariable *GV = *I;
        PrintRelDirective();

        if (GV) {
            std::string GLN;
            O << Asm->getGlobalLinkName(GV, GLN);
        } else {
            O << "0";
        }

        Asm->EOL("TypeInfo");
    }

    // Emit the Type Table.
    for (std::vector<unsigned>::const_iterator
            I = FilterIds.begin(), E = FilterIds.end(); I < E; ++I) {
        unsigned TypeID = *I;
        Asm->EmitULEB128Bytes(TypeID);
        Asm->EOL("Filter TypeInfo index");
    }

    Asm->EmitAlignment(2, 0, 0, false);
}
Example #9
0
/// PrepareMonoLSDA - Collect information needed by EmitMonoLSDA
///
///   This function collects information available only during EndFunction which is needed
/// by EmitMonoLSDA and stores it into EHFrameInfo. It is the same as the
/// beginning of EmitExceptionTable.
///
void DwarfMonoException::PrepareMonoLSDA(FunctionEHFrameInfo *EHFrameInfo) {
  const std::vector<const GlobalVariable *> &TypeInfos = MMI->getTypeInfos();
  const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads();
  const MachineFunction *MF = Asm->MF;

  // Sort the landing pads in order of their type ids.  This is used to fold
  // duplicate actions.
  SmallVector<const LandingPadInfo *, 64> 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(),
          [](const LandingPadInfo *L,
			 const LandingPadInfo *R) { return L->TypeIds < R->TypeIds; });

  // 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 when using DWARF exception handling.
  RangeMapType PadMap;
  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) {
      MCSymbol *BeginLabel = LandingPad->BeginLabels[j];
      assert(!PadMap.count(BeginLabel) && "Duplicate landing pad labels!");
      PadRange P = { i, j };
      PadMap[BeginLabel] = P;
    }
  }

  // Compute the call-site table.
  SmallVector<MonoCallSiteEntry, 64> CallSites;

  MCSymbol *LastLabel = 0;
  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->isLabel()) {
        continue;
      }

      MCSymbol *BeginLabel = MI->getOperand(0).getMCSymbol();
      assert(BeginLabel && "Invalid label!");

      RangeMapType::iterator L = PadMap.find(BeginLabel);

      if (L == PadMap.end())
        continue;

      PadRange P = L->second;
      const LandingPadInfo *LandingPad = LandingPads[P.PadIndex];

      assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] &&
              "Inconsistent landing pad map!");

      // Mono emits one landing pad for each CLR exception clause,
      // and the type info contains the clause index
      assert (LandingPad->TypeIds.size() == 1);
      assert (LandingPad->LandingPadLabel);

      LastLabel = LandingPad->EndLabels[P.RangeIndex];
      MonoCallSiteEntry Site = {BeginLabel, LastLabel,
							LandingPad->LandingPadLabel, LandingPad->TypeIds [0]};

      assert(Site.BeginLabel && Site.EndLabel && Site.PadLabel &&
              "Invalid landing pad!");

	  // FIXME: This doesn't work because it includes ranges outside clauses
#if 0
      // Try to merge with the previous call-site.
      if (CallSites.size()) {
        MonoCallSiteEntry &Prev = CallSites.back();
        if (Site.PadLabel == Prev.PadLabel && Site.TypeID == Prev.TypeID) {
          // Extend the range of the previous entry.
          Prev.EndLabel = Site.EndLabel;
          continue;
        }
      }
#endif

      // Otherwise, create a new call-site.
      CallSites.push_back(Site);
    }
  }

  //
  // Compute a mapping from method names to their AOT method index
  //
  if (FuncIndexes.size () == 0) {
    const Module *m = MMI->getModule ();
    NamedMDNode *indexes = m->getNamedMetadata ("mono.function_indexes");
	if (indexes) {
      for (unsigned int i = 0; i < indexes->getNumOperands (); ++i) {
        MDNode *n = indexes->getOperand (i);
        MDString *s = (MDString*)n->getOperand (0);
        ConstantInt *idx = (ConstantInt*)n->getOperand (1);
        FuncIndexes.GetOrCreateValue (s->getString (), (int)idx->getLimitedValue () + 1);
      }
    }
  }

  MonoEHFrameInfo *MonoEH = &EHFrameInfo->MonoEH;

  // Save information for EmitMonoLSDA
  MonoEH->MF = Asm->MF;
  MonoEH->FunctionNumber = Asm->getFunctionNumber();
  MonoEH->CallSites.insert(MonoEH->CallSites.begin(), CallSites.begin(), CallSites.end());
  MonoEH->TypeInfos = TypeInfos;
  MonoEH->PadInfos = PadInfos;
  MonoEH->MonoMethodIdx = FuncIndexes.lookup (Asm->MF->getFunction ()->getName ()) - 1;
  //outs()<<"A:"<<Asm->MF->getFunction()->getName() << " " << MonoEH->MonoMethodIdx << "\n";

  int ThisSlot = Asm->MF->getMonoInfo()->getThisStackSlot();

  if (ThisSlot != -1) {
    unsigned FrameReg;
    MonoEH->ThisOffset = Asm->MF->getTarget ().getSubtargetImpl ()->getFrameLowering ()->getFrameIndexReference (*Asm->MF, ThisSlot, FrameReg);
    MonoEH->FrameReg = Asm->MF->getTarget ().getSubtargetImpl ()->getRegisterInfo ()->getDwarfRegNum (FrameReg, true);
  } else {
    MonoEH->FrameReg = -1;
  }
}