Пример #1
0
static inline NORETURN void resume(unw_cursor_t* cursor, const uint8_t* landing_pad, int64_t switch_value,
                                   const ExcInfo* exc_data) {
    checkExcInfo(exc_data);
    assert(landing_pad);
    if (VERBOSITY("cxx_unwind") >= 4)
        printf("  * RESUMED: ip %p  switch_value %ld\n", (const void*)landing_pad, (long)switch_value);

    if (0 != switch_value) {
        // The exception handler will call __cxa_begin_catch, which stops this timer and logs it.
        per_thread_resume_catch_timer.restart("resume_catch", 20);
    } else {
        // The cleanup code will call _Unwind_Resume, which will stop this timer and log it.
        // TODO: am I sure cleanup code can't raise exceptions? maybe have an assert!
        per_thread_cleanup_timer.restart("cleanup", 20);
#ifndef NDEBUG
        in_cleanup_code = true;
#endif
    }

    // set rax to pointer to exception object
    // set rdx to the switch_value (0 for cleanup, otherwise an index indicating which exception handler to use)
    //
    // NB. assumes x86-64. maybe I should use __builtin_eh_return_data_regno() here?
    // but then, need to translate into UNW_* values somehow. not clear how.
    check(unw_set_reg(cursor, UNW_X86_64_RAX, (unw_word_t)exc_data));
    check(unw_set_reg(cursor, UNW_X86_64_RDX, switch_value));

    // resume!
    check(unw_set_reg(cursor, UNW_REG_IP, (unw_word_t)landing_pad));
    unw_resume(cursor);
    RELEASE_ASSERT(0, "unw_resume returned!");
}
Пример #2
0
void
jffi_longjmp (jmp_buf env, int val)
{
    extern int _jffi_longjmp_cont;
    unw_context_t uc;
    unw_cursor_t c;
    unw_word_t sp, ip, bp = 0;
    uintptr_t *wp = (uintptr_t *) env;
    int i, setjmp_frame;

    if (unw_getcontext (&uc) < 0 || unw_init_local (&c, &uc) < 0) {
        debug("failed to get context");
        abort ();
    }
#ifdef __x86_86__
# define UNW_REG_BP UNW_X86_64_RBP
#else
# define UNW_REG_BP UNW_X86_EBP
#endif
    setjmp_frame = 0;

    do {
        char name[256];
        unw_proc_info_t pi;
        unw_word_t off;
        if (unw_get_reg (&c, UNW_REG_BP, &bp) < 0) {
            abort();
        }
        if (unw_get_reg (&c, UNW_REG_SP, &sp) < 0) {
            abort();
        }
        if (unw_get_reg (&c, UNW_REG_IP, &ip) < 0) {
            abort();
        }
        unw_get_proc_name(&c, name, sizeof(name), &off);
        unw_get_proc_info(&c, &pi);
//        debug("frame %s ip=%llx sp=%llx bp=%llx wp[RP]=%p wp[SP]=%p, pi.start_ip=%llx, pi.end_ip=%llx",
//            name, (long long) ip, (long long) sp, (long long) bp, (void *) wp[JB_RP], (void *) wp[JB_SP],
//            pi.start_ip, pi.end_ip);

        if (wp[JB_SP] > sp || wp[JB_RP] < pi.start_ip || wp[JB_RP] > pi.end_ip) continue;

        /* found the right frame: */
//        debug("found frame to jump back to");
        assert (UNW_NUM_EH_REGS >= 2);
        if (unw_set_reg (&c, UNW_REG_EH + 0, wp[JB_RP]) < 0
            || unw_set_reg (&c, UNW_REG_EH + 1, val) < 0
            || unw_set_reg (&c, UNW_REG_IP, (unw_word_t) (uintptr_t) &_jffi_longjmp_cont))
            abort ();

        unw_resume (&c);
        // should not reach here
        abort ();
    } while (unw_step (&c) > 0);
//    debug("failed to find correct frame to jmp to");
}
Пример #3
0
static void
restore_context (MonoContext *ctx)
{
	int res;
	unw_word_t ip;

	res = unw_get_reg (&ctx->cursor, UNW_IA64_IP, &ip);
	g_assert (res == 0);

	/* Set this to 0 to tell OP_START_HANDLER that it doesn't have to set the frame pointer */
	res = unw_set_reg (&ctx->cursor, UNW_IA64_GR + 15, 0);
	g_assert (res == 0);

	unw_resume (&ctx->cursor);
}
Пример #4
0
void
_longjmp (jmp_buf env, int val)
{
  extern int _UI_longjmp_cont;
  unw_context_t uc;
  unw_cursor_t c;
  unw_word_t sp;
  unw_word_t *wp = (unw_word_t *) env;

  if (unw_getcontext (&uc) < 0 || unw_init_local (&c, &uc) < 0)
    abort ();

  do
    {
      if (unw_get_reg (&c, UNW_REG_SP, &sp) < 0)
	abort ();
#ifdef __FreeBSD__
      if (sp != wp[JB_SP] + sizeof(unw_word_t))
#else
      if (sp != wp[JB_SP])
#endif
	continue;

      if (!bsp_match (&c, wp))
	continue;

      /* found the right frame: */

      assert (UNW_NUM_EH_REGS >= 2);

      if (unw_set_reg (&c, UNW_REG_EH + 0, wp[JB_RP]) < 0
	  || unw_set_reg (&c, UNW_REG_EH + 1, val) < 0
	  || unw_set_reg (&c, UNW_REG_IP,
			  (unw_word_t) (uintptr_t) &_UI_longjmp_cont))
	abort ();

      unw_resume (&c);

      abort ();
    }
  while (unw_step (&c) > 0);

  abort ();
}
Пример #5
0
static void
sighandler (int signal)
{
  unw_cursor_t cursor, cursor2;
  unw_word_t ip;
  unw_context_t uc;

  if (verbose)
    printf ("caught signal %d\n", signal);

  unw_getcontext (&uc);
  if (unw_init_local (&cursor, &uc) < 0)
    panic ("unw_init() failed!\n");

  /* get cursor for caller of sighandler: */
  if (unw_step (&cursor) < 0)
    panic ("unw_step() failed!\n");

  cursor2 = cursor;
  while (!unw_is_signal_frame (&cursor2))
    if (unw_step (&cursor2) < 0)
      panic ("failed to find signal frame!\n");

  if (unw_step (&cursor2) < 0)
    panic ("unw_step() failed!\n");

  if (unw_get_reg (&cursor2, UNW_REG_IP, &ip) < 0)
    panic ("failed to get IP!\n");

  /* skip faulting instruction (doesn't handle MLX template) */
  ++ip;
  if ((ip & 0x3) == 0x3)
    ip += 13;

  if (unw_set_reg (&cursor2, UNW_REG_IP, ip) < 0)
    panic ("failed to set IP!\n");

  unw_resume (&cursor);	/* update context & return to caller of sighandler() */

  panic ("unexpected return from unw_resume()!\n");
}
// called by test function
// we unwind through the test function
// and resume at caller (unwind_tester)
void uwind_to_main () {
    /* Invoke our handler with our current thread state; we use this state to try to roll back the tests
     * and verify that the expected registers are restored. */
    if (plcrash_async_thread_state_current(unwind_current_state, NULL) != PLCRASH_ESUCCESS) {
        __builtin_trap();
    }

    /* Now use libunwind to verify that our test data can be unwound sucessfully. This will unwind the current
     * thread to the unwind_tester, and we'll never return from this function */
#ifdef LIBUNWIND_VERIFICATION
    if (global_harness_state.test_case->skip_libunwind_verification)
        return;

    unw_cursor_t cursor;
	unw_context_t uc;
	
	unw_getcontext(&uc);
	unw_init_local(&cursor, &uc);
    
    /* Walk the frames until we hit the test function. Unlike our unwinder, the first frame is implicitly
     * available -- a step isn't required, and so we skip one call to unw_step(). */
    for (uint32_t i = 1; i < global_harness_state.test_case->intermediate_frames; i++) {
        int ret;
        if ((ret = unw_step(&cursor)) <= 0) {
            PLCF_DEBUG("Step %" PRIu32 " failed: %d", i, ret);
            __builtin_trap();
        }
    }


    /* Once inside the test implementation, resume */
    if (unw_step(&cursor) > 0) {
        unw_resume(&cursor);
    }

	/* This should be unreachable */
	__builtin_trap();
#endif
}
Пример #7
0
static int
unwind_and_resume (long iteration, int (*next_func[])())
{
  unw_context_t uc;
  unw_cursor_t c;
  unw_word_t ip;
  int i, ret;

  if (verbose)
    printf (" %s(iteration=%ld, next_func=%p)\n",
	    __FUNCTION__, iteration, next_func);

  unw_getcontext (&uc);
  if ((ret = unw_init_local (&c, &uc)) < 0)
    panic ("unw_init_local (ret=%d)", ret);

  for (i = 0; i < unwind_count; ++i)
    if ((ret = unw_step (&c)) < 0)
      panic ("unw_step (ret=%d)", ret);

  if (unw_get_reg (&c, UNW_REG_IP, &ip) < 0
      || unw_set_reg (&c, UNW_REG_IP, (unw_word_t) &resumption_point_label) < 0
      || unw_set_reg (&c, UNW_REG_EH + 0, 0)	/* ret val */
      || unw_set_reg (&c, UNW_REG_EH + 1, ip))
    panic ("failed to redirect to resumption_point\n");

  if (verbose)
    {
      unw_word_t bsp;
      if (unw_get_reg (&c, UNW_IA64_BSP, &bsp) < 0)
	panic ("unw_get_reg() failed\n");
      printf ("  bsp=%lx, old ip=%lx, new ip=%p\n", bsp,
	      ip, &resumption_point_label);
    }

  ret = unw_resume (&c);
  panic ("unw_resume() returned (ret=%d)!!\n", ret);
  return 0;
}
Пример #8
0
void
siglongjmp (sigjmp_buf env, int val)
{
  unw_word_t *wp = (unw_word_t *) env;
  extern int _UI_siglongjmp_cont;
  extern int _UI_longjmp_cont;
  unw_context_t uc;
  unw_cursor_t c;
  unw_word_t sp;
  int *cont;

  if (unw_getcontext (&uc) < 0 || unw_init_local (&c, &uc) < 0)
    abort ();

  do
    {
      if (unw_get_reg (&c, UNW_REG_SP, &sp) < 0)
	abort ();
#ifdef __FreeBSD__
      if (sp != wp[JB_SP] + sizeof(unw_word_t))
#else
      if (sp != wp[JB_SP])
#endif
	continue;

      if (!bsp_match (&c, wp))
	continue;

      /* found the right frame: */

      /* default to resuming without restoring signal-mask */
      cont = &_UI_longjmp_cont;

      /* Order of evaluation is important here: if unw_resume()
	 restores signal mask, we must set it up appropriately, even
	 if wp[JB_MASK_SAVED] is FALSE.  */
      if (!resume_restores_sigmask (&c, wp) && wp[JB_MASK_SAVED])
	{
	  /* sigmask was saved */
	  if (UNW_NUM_EH_REGS < 4 || _NSIG >= 16 * sizeof (unw_word_t))
	    /* signal mask doesn't fit into EH arguments and we can't
	       put it on the stack without overwriting something
	       else... */
	    abort ();
	  else
	    if (unw_set_reg (&c, UNW_REG_EH + 2, wp[JB_MASK]) < 0
		|| (_NSIG > 8 * sizeof (unw_word_t)
		    && unw_set_reg (&c, UNW_REG_EH + 3, wp[JB_MASK + 1]) < 0))
	      abort ();
	  cont = &_UI_siglongjmp_cont;
	}

      if (unw_set_reg (&c, UNW_REG_EH + 0, wp[JB_RP]) < 0
	  || unw_set_reg (&c, UNW_REG_EH + 1, val) < 0
	  || unw_set_reg (&c, UNW_REG_IP, (unw_word_t) (uintptr_t) cont))
	abort ();

      unw_resume (&c);

      abort ();
    }
  while (unw_step (&c) > 0);

  abort ();
}
Пример #9
0
void
handler (int sig)
#endif
{
  unw_word_t ip;
  sigset_t mask, oldmask;
  unw_context_t uc;
  unw_cursor_t c;
  char foo;
  int ret;

#if UNW_TARGET_IA64
  if (verbose)
    printf ("bsp = %llx\n", (unsigned long long) get_bsp ());
#endif

  if (verbose)
    printf ("got signal %d\n", sig);

  if (sig == SIGUSR1)
    {
      ++got_usr1;
      sigusr1_sp = &foo;

      sigemptyset (&mask);
      sigaddset (&mask, SIGUSR2);
      sigprocmask (SIG_BLOCK, &mask, &oldmask);
      kill (getpid (), SIGUSR2);	/* pend SIGUSR2 */

      signal (SIGUSR1, SIG_IGN);

      if ((ret = unw_getcontext (&uc)) < 0)
	panic ("unw_getcontext() failed: ret=%d\n", ret);
#if UNW_TARGET_X86_64
      /* unw_getcontext() doesn't save signal mask to avoid a syscall */
      uc.uc_sigmask = oldmask; 
#endif
      if ((ret = unw_init_local (&c, &uc)) < 0)
	panic ("unw_init_local() failed: ret=%d\n", ret);

      if ((ret = unw_step (&c)) < 0)		/* step to signal trampoline */
	panic ("unw_step(1) failed: ret=%d\n", ret);

      if ((ret = unw_step (&c)) < 0)		/* step to kill() */
	panic ("unw_step(2) failed: ret=%d\n", ret);

      if ((ret = unw_get_reg (&c, UNW_REG_IP, &ip)) < 0)
	panic ("unw_get_reg(IP) failed: ret=%d\n", ret);
      if (verbose)
	printf ("resuming at 0x%lx, with SIGUSR2 pending\n",
		(unsigned long) ip);
      unw_resume (&c);
    }
  else if (sig == SIGUSR2)
    {
      ++got_usr2;
      if (got_usr1)
	{
	  if (verbose)
	    printf ("OK: stack still at %p\n", &foo);
	}
      signal (SIGUSR2, SIG_IGN);
    }
  else
    panic ("Got unexpected signal %d\n", sig);
}
Пример #10
0
static _Unwind_Reason_Code
unwind_phase2(unw_context_t *uc, struct _Unwind_Exception *exception_object, bool resume) {
  // See comment at the start of unwind_phase1 regarding VRS integrity.
  unw_cursor_t cursor2;
  unw_init_local(&cursor2, uc);

  _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)\n", exception_object);
  int frame_count = 0;

  // Walk each frame until we reach where search phase said to stop.
  while (true) {
    // Ask libuwind to get next frame (skip over first which is
    // _Unwind_RaiseException or _Unwind_Resume).
    //
    // Resume only ever makes sense for 1 frame.
    _Unwind_State state =
        resume ? _US_UNWIND_FRAME_RESUME : _US_UNWIND_FRAME_STARTING;
    if (resume && frame_count == 1) {
      // On a resume, first unwind the _Unwind_Resume() frame. The next frame
      // is now the landing pad for the cleanup from a previous execution of
      // phase2. To continue unwindingly correctly, replace VRS[15] with the
      // IP of the frame that the previous run of phase2 installed the context
      // for. After this, continue unwinding as if normal.
      //
      // See #7.4.6 for details.
      unw_set_reg(&cursor2, UNW_REG_IP, exception_object->unwinder_cache.reserved2);
      resume = false;
    }
    int stepResult = unw_step(&cursor2);
    if (stepResult == 0) {
      _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached "
                            "bottom => _URC_END_OF_STACK\n",
                            exception_object);
      return _URC_END_OF_STACK;
    } else if (stepResult < 0) {
      _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step failed => "
                            "_URC_FATAL_PHASE1_ERROR\n",
                            exception_object);
      return _URC_FATAL_PHASE2_ERROR;
    }

    // Get info about this frame.
    unw_word_t sp;
    unw_proc_info_t frameInfo;
    unw_get_reg(&cursor2, UNW_REG_SP, &sp);
    if (unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS) {
      _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_get_proc_info "
                            "failed => _URC_FATAL_PHASE1_ERROR\n",
                            exception_object);
      return _URC_FATAL_PHASE2_ERROR;
    }

    // When tracing, print state information.
    if (_LIBUNWIND_TRACING_UNWINDING) {
      char functionName[512];
      unw_word_t offset;
      if ((unw_get_proc_name(&cursor2, functionName, 512, &offset) !=
           UNW_ESUCCESS) || (frameInfo.start_ip + offset > frameInfo.end_ip))
        strcpy(functionName, ".anonymous.");
      _LIBUNWIND_TRACE_UNWINDING(
          "unwind_phase2(ex_ojb=%p): start_ip=0x%llX, func=%s, sp=0x%llX, "
          "lsda=0x%llX, personality=0x%llX\n",
          exception_object, frameInfo.start_ip, functionName, sp,
          frameInfo.lsda, frameInfo.handler);
    }

    // If there is a personality routine, tell it we are unwinding.
    if (frameInfo.handler != 0) {
      __personality_routine p =
          (__personality_routine)(long)(frameInfo.handler);
      struct _Unwind_Context *context = (struct _Unwind_Context *)(&cursor2);
#ifdef __arm__
      exception_object->pr_cache.fnstart = frameInfo.start_ip;
      exception_object->pr_cache.ehtp = (_Unwind_EHT_Header *)frameInfo.unwind_info;
      exception_object->pr_cache.additional = frameInfo.flags;
      _Unwind_Reason_Code personalityResult =
          (*p)(state, exception_object, context);
#else
      _Unwind_Action action = _UA_CLEANUP_PHASE;
      if (sp == exception_object->private_2) {
        // Tell personality this was the frame it marked in phase 1.
        action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME);
      }
       _Unwind_Reason_Code personalityResult =
          (*p)(1, action, exception_object->exception_class, exception_object,
               context);
#endif
      switch (personalityResult) {
      case _URC_CONTINUE_UNWIND:
        // Continue unwinding
        _LIBUNWIND_TRACE_UNWINDING(
            "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n",
            exception_object);
#ifdef __arm__
        if (sp == exception_object->barrier_cache.sp) {
#else
        if (sp == exception_object->private_2) {
#endif
          // Phase 1 said we would stop at this frame, but we did not...
          _LIBUNWIND_ABORT("during phase1 personality function said it would "
                           "stop here, but now in phase2 it did not stop here");
        }
        break;
      case _URC_INSTALL_CONTEXT:
        _LIBUNWIND_TRACE_UNWINDING(
            "unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT\n",
            exception_object);
        // Personality routine says to transfer control to landing pad.
        // We may get control back if landing pad calls _Unwind_Resume().
        if (_LIBUNWIND_TRACING_UNWINDING) {
          unw_word_t pc;
          unw_get_reg(&cursor2, UNW_REG_IP, &pc);
          unw_get_reg(&cursor2, UNW_REG_SP, &sp);
          _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering  "
                                     "user code with ip=0x%llX, sp=0x%llX\n",
                                    exception_object, pc, sp);
        }

#ifdef __arm__
        // #7.4.1 says we need to preserve pc for when _Unwind_Resume is called
        // back, to find this same frame.
        unw_word_t pc;
        unw_get_reg(&cursor2, UNW_REG_IP, &pc);
        exception_object->unwinder_cache.reserved2 = (uint32_t)pc;
#endif
        unw_resume(&cursor2);
        // unw_resume() only returns if there was an error.
        return _URC_FATAL_PHASE2_ERROR;
#ifdef __arm__
      // # 7.4.3
      case _URC_FAILURE:
        abort();
#endif
      default:
        // Personality routine returned an unknown result code.
        _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d",
                      personalityResult);
        return _URC_FATAL_PHASE2_ERROR;
      }
    }
    frame_count++;
  }

  // Clean up phase did not resume at the frame that the search phase
  // said it would...
  return _URC_FATAL_PHASE2_ERROR;
}

#ifndef __arm__
static _Unwind_Reason_Code
unwind_phase2_forced(unw_context_t *uc,
                     struct _Unwind_Exception *exception_object,
                     _Unwind_Stop_Fn stop, void *stop_parameter) {
  unw_cursor_t cursor2;
  unw_init_local(&cursor2, uc);

  // Walk each frame until we reach where search phase said to stop
  while (unw_step(&cursor2) > 0) {

    // Update info about this frame.
    unw_proc_info_t frameInfo;
    if (unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS) {
      _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): unw_step "
                                 "failed => _URC_END_OF_STACK\n",
                                 exception_object);
      return _URC_FATAL_PHASE2_ERROR;
    }

    // When tracing, print state information.
    if (_LIBUNWIND_TRACING_UNWINDING) {
      char functionName[512];
      unw_word_t offset;
      if ((unw_get_proc_name(&cursor2, functionName, 512, &offset) !=
           UNW_ESUCCESS) || (frameInfo.start_ip + offset > frameInfo.end_ip))
        strcpy(functionName, ".anonymous.");
      _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p):  "
                                 "start_ip=0x%llX, func=%s, lsda=0x%llX, "
                                 " personality=0x%llX\n",
                                 exception_object, frameInfo.start_ip,
                                 functionName, frameInfo.lsda,
                                 frameInfo.handler);
    }

    // Call stop function at each frame.
    _Unwind_Action action =
        (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE);
    _Unwind_Reason_Code stopResult =
        (*stop)(1, action, exception_object->exception_class, exception_object,
                (struct _Unwind_Context *)(&cursor2), stop_parameter);
    _LIBUNWIND_TRACE_UNWINDING(
        "unwind_phase2_forced(ex_ojb=%p): stop function returned %d\n",
        exception_object, stopResult);
    if (stopResult != _URC_NO_REASON) {
      _LIBUNWIND_TRACE_UNWINDING(
          "unwind_phase2_forced(ex_ojb=%p): stopped by stop function\n",
          exception_object);
      return _URC_FATAL_PHASE2_ERROR;
    }

    // If there is a personality routine, tell it we are unwinding.
    if (frameInfo.handler != 0) {
      __personality_routine p =
          (__personality_routine)(long)(frameInfo.handler);
      _LIBUNWIND_TRACE_UNWINDING(
          "unwind_phase2_forced(ex_ojb=%p): calling personality function %p\n",
          exception_object, p);
      _Unwind_Reason_Code personalityResult =
          (*p)(1, action, exception_object->exception_class, exception_object,
               (struct _Unwind_Context *)(&cursor2));
      switch (personalityResult) {
      case _URC_CONTINUE_UNWIND:
        _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
                                "personality  returned _URC_CONTINUE_UNWIND\n",
                                 exception_object);
        // Destructors called, continue unwinding
        break;
      case _URC_INSTALL_CONTEXT:
        _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
                                  "personality returned _URC_INSTALL_CONTEXT\n",
                                   exception_object);
        // We may get control back if landing pad calls _Unwind_Resume().
        unw_resume(&cursor2);
        break;
      default:
        // Personality routine returned an unknown result code.
        _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
                                   "personality returned %d, "
                                   "_URC_FATAL_PHASE2_ERROR\n",
                                   exception_object, personalityResult);
        return _URC_FATAL_PHASE2_ERROR;
      }
    }
  }

  // Call stop function one last time and tell it we've reached the end
  // of the stack.
  _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop "
                        "function with _UA_END_OF_STACK\n",
                        exception_object);
  _Unwind_Action lastAction =
      (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK);
  (*stop)(1, lastAction, exception_object->exception_class, exception_object,
          (struct _Unwind_Context *)(&cursor2), stop_parameter);

  // Clean up phase did not resume at the frame that the search phase said it
  // would.
  return _URC_FATAL_PHASE2_ERROR;
}
Пример #11
0
static _Unwind_Reason_Code
unwind_phase2_forced(unw_context_t *uc,
                     _Unwind_Exception *exception_object,
                     _Unwind_Stop_Fn stop, void *stop_parameter) {
    unw_cursor_t cursor2;
    unw_init_local(&cursor2, uc);

    // Walk each frame until we reach where search phase said to stop
    while (unw_step(&cursor2) > 0) {

        // Update info about this frame.
        unw_proc_info_t frameInfo;
        if (unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS) {
            _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): unw_step "
                                       "failed => _URC_END_OF_STACK\n",
                                       exception_object);
            return _URC_FATAL_PHASE2_ERROR;
        }

        // When tracing, print state information.
        if (_LIBUNWIND_TRACING_UNWINDING) {
            char functionName[512];
            unw_word_t offset;
            if ((unw_get_proc_name(&cursor2, functionName, 512, &offset) !=
                    UNW_ESUCCESS) || (frameInfo.start_ip + offset > frameInfo.end_ip))
                strcpy(functionName, ".anonymous.");
            _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p):  "
                                       "start_ip=0x%llX, func=%s, lsda=0x%llX, "
                                       " personality=0x%llX\n",
                                       exception_object, frameInfo.start_ip,
                                       functionName, frameInfo.lsda,
                                       frameInfo.handler);
        }

        // Call stop function at each frame.
        _Unwind_Action action =
            (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE);
        _Unwind_Reason_Code stopResult =
            (*stop)(1, action, exception_object->exception_class, exception_object,
                    (struct _Unwind_Context *)(&cursor2), stop_parameter);
        _LIBUNWIND_TRACE_UNWINDING(
            "unwind_phase2_forced(ex_ojb=%p): stop function returned %d\n",
            exception_object, stopResult);
        if (stopResult != _URC_NO_REASON) {
            _LIBUNWIND_TRACE_UNWINDING(
                "unwind_phase2_forced(ex_ojb=%p): stopped by stop function\n",
                exception_object);
            return _URC_FATAL_PHASE2_ERROR;
        }

        // If there is a personality routine, tell it we are unwinding.
        if (frameInfo.handler != 0) {
            __personality_routine p =
                (__personality_routine)(long)(frameInfo.handler);
            _LIBUNWIND_TRACE_UNWINDING(
                "unwind_phase2_forced(ex_ojb=%p): calling personality function %p\n",
                exception_object, p);
            _Unwind_Reason_Code personalityResult =
                (*p)(1, action, exception_object->exception_class, exception_object,
                     (struct _Unwind_Context *)(&cursor2));
            switch (personalityResult) {
            case _URC_CONTINUE_UNWIND:
                _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
                                           "personality  returned _URC_CONTINUE_UNWIND\n",
                                           exception_object);
                // Destructors called, continue unwinding
                break;
            case _URC_INSTALL_CONTEXT:
                _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
                                           "personality returned _URC_INSTALL_CONTEXT\n",
                                           exception_object);
                // We may get control back if landing pad calls _Unwind_Resume().
                unw_resume(&cursor2);
                break;
            default:
                // Personality routine returned an unknown result code.
                _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
                                           "personality returned %d, "
                                           "_URC_FATAL_PHASE2_ERROR\n",
                                           exception_object, personalityResult);
                return _URC_FATAL_PHASE2_ERROR;
            }
        }
    }

    // Call stop function one last time and tell it we've reached the end
    // of the stack.
    _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop "
                               "function with _UA_END_OF_STACK\n",
                               exception_object);
    _Unwind_Action lastAction =
        (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK);
    (*stop)(1, lastAction, exception_object->exception_class, exception_object,
            (struct _Unwind_Context *)(&cursor2), stop_parameter);

    // Clean up phase did not resume at the frame that the search phase said it
    // would.
    return _URC_FATAL_PHASE2_ERROR;
}
Пример #12
0
static _Unwind_Reason_Code
unwind_phase2(unw_context_t *uc, _Unwind_Exception *exception_object) {
    unw_cursor_t cursor2;
    unw_init_local(&cursor2, uc);

    _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)\n", exception_object);

    // Walk each frame until we reach where search phase said to stop.
    while (true) {

        // Ask libuwind to get next frame (skip over first which is
        // _Unwind_RaiseException).
        int stepResult = unw_step(&cursor2);
        if (stepResult == 0) {
            _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached "
                                       "bottom => _URC_END_OF_STACK\n",
                                       exception_object);
            return _URC_END_OF_STACK;
        } else if (stepResult < 0) {
            _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step failed => "
                                       "_URC_FATAL_PHASE1_ERROR\n",
                                       exception_object);
            return _URC_FATAL_PHASE2_ERROR;
        }

        // Get info about this frame.
        unw_word_t sp;
        unw_proc_info_t frameInfo;
        unw_get_reg(&cursor2, UNW_REG_SP, &sp);
        if (unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS) {
            _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_get_proc_info "
                                       "failed => _URC_FATAL_PHASE1_ERROR\n",
                                       exception_object);
            return _URC_FATAL_PHASE2_ERROR;
        }

        // When tracing, print state information.
        if (_LIBUNWIND_TRACING_UNWINDING) {
            char functionName[512];
            unw_word_t offset;
            if ((unw_get_proc_name(&cursor2, functionName, 512, &offset) !=
                    UNW_ESUCCESS) || (frameInfo.start_ip + offset > frameInfo.end_ip))
                strcpy(functionName, ".anonymous.");
            _LIBUNWIND_TRACE_UNWINDING(
                "unwind_phase2(ex_ojb=%p): start_ip=0x%llX, func=%s, sp=0x%llX, "
                "lsda=0x%llX, personality=0x%llX\n",
                exception_object, frameInfo.start_ip, functionName, sp,
                frameInfo.lsda, frameInfo.handler);
        }

        // If there is a personality routine, tell it we are unwinding.
        if (frameInfo.handler != 0) {
            __personality_routine p =
                (__personality_routine)(long)(frameInfo.handler);
            _Unwind_Action action = _UA_CLEANUP_PHASE;
            if (sp == exception_object->private_2) {
                // Tell personality this was the frame it marked in phase 1.
                action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME);
            }
            _Unwind_Reason_Code personalityResult =
                (*p)(1, action, exception_object->exception_class, exception_object,
                     (struct _Unwind_Context *)(&cursor2));
            switch (personalityResult) {
            case _URC_CONTINUE_UNWIND:
                // Continue unwinding
                _LIBUNWIND_TRACE_UNWINDING(
                    "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n",
                    exception_object);
                if (sp == exception_object->private_2) {
                    // Phase 1 said we would stop at this frame, but we did not...
                    _LIBUNWIND_ABORT("during phase1 personality function said it would "
                                     "stop here, but now in phase2 it did not stop here");
                }
                break;
            case _URC_INSTALL_CONTEXT:
                _LIBUNWIND_TRACE_UNWINDING(
                    "unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT\n",
                    exception_object);
                // Personality routine says to transfer control to landing pad.
                // We may get control back if landing pad calls _Unwind_Resume().
                if (_LIBUNWIND_TRACING_UNWINDING) {
                    unw_word_t pc;
                    unw_get_reg(&cursor2, UNW_REG_IP, &pc);
                    unw_get_reg(&cursor2, UNW_REG_SP, &sp);
                    _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering  "
                                               "user code with ip=0x%llX, sp=0x%llX\n",
                                               exception_object, pc, sp);
                }
                unw_resume(&cursor2);
                // unw_resume() only returns if there was an error.
                return _URC_FATAL_PHASE2_ERROR;
            default:
                // Personality routine returned an unknown result code.
                _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d",
                                     personalityResult);
                return _URC_FATAL_PHASE2_ERROR;
            }
        }
    }

    // Clean up phase did not resume at the frame that the search phase
    // said it would...
    return _URC_FATAL_PHASE2_ERROR;
}