Example #1
0
/*
 * Lookup a catch trace for the given TCA, returning nullptr if none was
 * found. Will abort if a nullptr catch trace was registered, meaning this call
 * isn't allowed to throw.
 */
TCA lookup_catch_trace(TCA rip, _Unwind_Exception* exn) {
  if (auto catchTraceOpt = mcg->getCatchTrace(rip)) {
    if (auto catchTrace = *catchTraceOpt) return 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;
    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),
                       typeInfoFromUnwindException(exn).name(),
                       rip);
  }

  return nullptr;
}
Example #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 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;
}
Example #3
0
// XED callback function to get a symbol from an address
static int addressToSymbol(xed_uint64_t  address,
                           char*         symbolBuffer,
                           xed_uint32_t  bufferLength,
                           xed_uint64_t* offset,
                           void*         context) {
  auto name = boost::trim_copy(getNativeFunctionName((void*)address));
  if (boost::starts_with(name, "0x")) {
    return 0;
  }
  auto pos = name.find_first_of('(');
  auto copyLength = pos != std::string::npos
    ? std::min(pos, size_t(bufferLength - 1))
    : bufferLength - 1;
  strncpy(symbolBuffer, name.c_str(), copyLength);
  symbolBuffer[copyLength] = '\0';
  *offset = 0;
  return 1;
}