示例#1
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;
}
示例#2
0
static _Unwind_Reason_Code
unwind_phase2(struct _Unwind_Exception *exception_object) {
  _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)\n", exception_object);

  // walk each frame until we reach where search phase said to stop
  _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
  while (true) {
    _LIBUNWIND_TRACE_UNWINDING("unwind_phase2s(ex_ojb=%p): context=%p\n",
                              exception_object, c);

    // check for no more frames
    if (c == NULL) {
      _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached "
                                "bottom => _URC_END_OF_STACK\n",
                                 exception_object);
      return _URC_END_OF_STACK;
    }

    // if there is a personality routine, tell it we are unwinding
    if (c->personality != NULL) {
      _Unwind_Action action = _UA_CLEANUP_PHASE;
      if ((uintptr_t) c == exception_object->private_2)
        action = (_Unwind_Action)(
            _UA_CLEANUP_PHASE |
            _UA_HANDLER_FRAME); // tell personality this was the frame it marked
                                // in phase 1
      _Unwind_Reason_Code personalityResult =
          (*c->personality)(1, action, exception_object->exception_class,
                            exception_object, (struct _Unwind_Context *)c);
      switch (personalityResult) {
      case _URC_CONTINUE_UNWIND:
        // continue unwinding
        _LIBUNWIND_TRACE_UNWINDING(
            "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n",
            exception_object);
        if ((uintptr_t) c == 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 if phase2 it did not stop here");
        }
        break;
      case _URC_INSTALL_CONTEXT:
        _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): "
                                  "_URC_INSTALL_CONTEXT, will resume at "
                                  "landing pad %p\n",
                                  exception_object, c->jbuf[1]);
        // personality routine says to transfer control to landing pad
        // we may get control back if landing pad calls _Unwind_Resume()
        __Unwind_SjLj_SetTopOfFunctionStack(c);
        __builtin_longjmp(c->jbuf, 1);
        // unw_resume() only returns if there was an error
        return _URC_FATAL_PHASE2_ERROR;
      default:
        // something went wrong
        _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d",
                      personalityResult);
        return _URC_FATAL_PHASE2_ERROR;
      }
    }
    c = c->prev;
  }

  // clean up phase did not resume at the frame that the search phase said it
  // would
  return _URC_FATAL_PHASE2_ERROR;
}
示例#3
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;
}