Esempio n. 1
0
bool install_catch_trace(_Unwind_Context* ctx, _Unwind_Exception* exn,
                         bool do_side_exit, TypedValue unwinder_tv) {
  auto const rip = (TCA)_Unwind_GetIP(ctx);
  auto catchTraceOpt = mcg->getCatchTrace(rip);
  FTRACE(1, "No catch trace entry for ip {}; bailing\n", rip);
  if (!catchTraceOpt) return false;

  auto catchTrace = *catchTraceOpt;
  if (!catchTrace) {
    // A few of our optimization passes must be aware of every path out of the
    // trace, so throwing through jitted code without a catch block is very
    // bad. This is indicated with a present but nullptr entry in the catch
    // trace map.
    const size_t kCallSize = 5;
    const uint8_t kCallOpcode = 0xe8;

    auto callAddr = rip - kCallSize;
    TCA helperAddr = nullptr;
    std::string helperName;
    if (*callAddr == kCallOpcode) {
      helperAddr = rip + *reinterpret_cast<int32_t*>(callAddr + 1);
    }

    always_assert_flog(false,
                       "Translated call to {} threw '{}' without "
                       "catch block, return address: {}\n",
                       getNativeFunctionName(helperAddr),
                       exceptionFromUnwindException(exn)->what(),
                       rip);
    return false;
  }

  FTRACE(1, "installing catch trace {} for call {} with tv {}, "
         "returning _URC_INSTALL_CONTEXT\n",
         catchTrace, rip, unwinder_tv.pretty());

  // In theory the unwind api will let us set registers in the frame
  // before executing our landing pad. In practice, trying to use
  // their recommended scratch registers results in a SEGV inside
  // _Unwind_SetGR, so we pass things to the handler using the
  // RDS. This also simplifies the handler code because it doesn't
  // have to worry about saving its arguments somewhere while
  // executing the exit trace.
  unwindRdsInfo->unwinderScratch = (int64_t)exn;
  unwindRdsInfo->doSideExit = do_side_exit;
  if (do_side_exit) {
    unwindRdsInfo->unwinderTv = unwinder_tv;
  }
  _Unwind_SetIP(ctx, (uint64_t)catchTrace);
  tl_regState = VMRegState::DIRTY;

  return true;
}
Esempio n. 2
0
bool install_catch_trace(_Unwind_Context* ctx, _Unwind_Exception* exn,
                         bool do_side_exit, TypedValue unwinder_tv) {
  auto const rip = (TCA)_Unwind_GetIP(ctx);
  auto catchTrace = lookup_catch_trace(rip, exn);
  if (!catchTrace) {
    FTRACE(1, "No catch trace entry for ip {}; bailing\n", rip);
    return false;
  }

  FTRACE(1, "installing catch trace {} for call {} with tv {}, "
         "returning _URC_INSTALL_CONTEXT\n",
         catchTrace, rip, unwinder_tv.pretty());

  // If the catch trace isn't going to finish by calling _Unwind_Resume, we
  // consume the exception here. Otherwise, we leave a pointer to it in RDS so
  // endCatchHelper can pass it to _Unwind_Resume when it's done.
  if (do_side_exit) {
    unwindRdsInfo->exn = nullptr;
#ifndef _MSC_VER
    __cxxabiv1::__cxa_begin_catch(exn);
    __cxxabiv1::__cxa_end_catch();
#endif
  } else {
    unwindRdsInfo->exn = exn;
  }

  // In theory the unwind api will let us set registers in the frame before
  // executing our landing pad. In practice, trying to use their recommended
  // scratch registers results in a SEGV inside _Unwind_SetGR, so we pass
  // things to the handler using the RDS. This also simplifies the handler code
  // because it doesn't have to worry about saving its arguments somewhere
  // while executing the exit trace.
  unwindRdsInfo->doSideExit = do_side_exit;
  if (do_side_exit) unwindRdsInfo->unwinderTv = unwinder_tv;
  _Unwind_SetIP(ctx, (uint64_t)catchTrace);
  tl_regState = VMRegState::DIRTY;

  return true;
}