Exemple #1
0
/*
 * ut_dump_backtrace -- dump stacktrace to error log using libunwind
 */
void
ut_dump_backtrace(void)
{
	unw_context_t context;
	unw_proc_info_t pip;

	pip.unwind_info = NULL;
	int ret = unw_getcontext(&context);
	if (ret) {
		ERR("unw_getcontext: %s [%d]", unw_strerror(ret), ret);
		return;
	}

	unw_cursor_t cursor;
	ret = unw_init_local(&cursor, &context);
	if (ret) {
		ERR("unw_init_local: %s [%d]", unw_strerror(ret), ret);
		return;
	}

	ret = unw_step(&cursor);

	char procname[PROCNAMELEN];
	unsigned i = 0;

	while (ret > 0) {
		ret = unw_get_proc_info(&cursor, &pip);
		if (ret) {
			ERR("unw_get_proc_info: %s [%d]", unw_strerror(ret),
					ret);
			break;
		}

		unw_word_t off;
		ret = unw_get_proc_name(&cursor, procname, PROCNAMELEN, &off);
		if (ret && ret != -UNW_ENOMEM) {
			if (ret != -UNW_EUNSPEC) {
				ERR("unw_get_proc_name: %s [%d]",
					unw_strerror(ret), ret);
			}

			strcpy(procname, "?");
		}

		void *ptr = (void *)(pip.start_ip + off);
		Dl_info dlinfo;
		const char *fname = "?";

		if (dladdr(ptr, &dlinfo) && dlinfo.dli_fname &&
				*dlinfo.dli_fname)
			fname = dlinfo.dli_fname;

		ERR("%u: %s (%s%s+0x%lx) [%p]", i++, fname, procname,
				ret == -UNW_ENOMEM ? "..." : "", off, ptr);

		ret = unw_step(&cursor);
		if (ret < 0)
			ERR("unw_step: %s [%d]", unw_strerror(ret), ret);
	}
}
Exemple #2
0
// Find LSDA and start address for a function at address controlPC
bool FindProcInfo(UIntNative controlPC, UIntNative* startAddress, UIntNative* lsda)
{
#ifndef CAN_LINK_SHARED_LIBUNWIND
    return false;
#else // CAN_LINK_SHARED_LIBUNWIND
    unw_context_t unwContext;
    unw_cursor_t cursor;
    REGDISPLAY regDisplay;
    memset(&regDisplay, 0, sizeof(REGDISPLAY));

    regDisplay.SetIP((PCODE)controlPC);

    if (!InitializeUnwindContextAndCursor(&regDisplay, &cursor, &unwContext))
    {
        return false;
    }

    unw_proc_info_t procInfo;
    int st = unw_get_proc_info(&cursor, &procInfo);
    if (st < 0)
    {
        return false;
    }

    assert((procInfo.start_ip <= controlPC) && (controlPC < procInfo.end_ip));

    *lsda = procInfo.lsda;
    *startAddress = procInfo.start_ip;

    return true;
#endif // CAN_LINK_SHARED_LIBUNWIND
}
Exemple #3
0
void collectStackRoots(TraceStack *stack) {
    unw_cursor_t cursor;
    unw_context_t uc;
    unw_word_t ip, sp, bp;

    // force callee-save registers onto the stack:
    // Actually, I feel like this is pretty brittle:
    // collectStackRoots itself is allowed to save the callee-save registers
    // on its own stack.
    jmp_buf registers __attribute__((aligned(sizeof(void*))));
#ifdef VALGRIND
    memset(&registers, 0, sizeof(registers));
    memset(&cursor, 0, sizeof(cursor));
    memset(&uc, 0, sizeof(uc));
    memset(&ip, 0, sizeof(ip));
    memset(&sp, 0, sizeof(sp));
    memset(&bp, 0, sizeof(bp));
#endif
    setjmp(registers);

    assert(sizeof(registers) % 8 == 0);
    //void* stack_bottom = __builtin_frame_address(0);
    collectRoots(&registers, &registers + 1, stack);

    unw_getcontext(&uc);
    unw_init_local(&cursor, &uc);

    TraceStackGCVisitor visitor(stack);

    int code;
    while (true) {
        int code = unw_step(&cursor);
        assert(code > 0 && "something broke unwinding!");

        unw_get_reg(&cursor, UNW_REG_IP, &ip);
        unw_get_reg(&cursor, UNW_REG_SP, &sp);
        unw_get_reg(&cursor, UNW_TDEP_BP, &bp);

        void* cur_sp = (void*)sp;
        void* cur_bp = (void*)bp;

        //std::string name = g.func_addr_registry.getFuncNameAtAddress((void*)ip, true);
        //if (VERBOSITY()) printf("ip = %lx (%s), stack = [%p, %p)\n", (long) ip, name.c_str(), cur_sp, cur_bp);

        unw_proc_info_t pip;
        unw_get_proc_info(&cursor, &pip);

        if (pip.start_ip == (uintptr_t)&__libc_start_main) {
            break;
        }

        if (pip.start_ip == (intptr_t)interpretFunction) {
            // TODO Do we still need to crawl the interpreter itself?
            gatherInterpreterRootsForFrame(&visitor, cur_bp);
        }

        collectRoots(cur_sp, (char*)cur_bp, stack);
    }
}
Exemple #4
0
PROTECTED unsigned long
_Unwind_GetRegionStart (struct _Unwind_Context *context)
{
  unw_proc_info_t pi;

  pi.start_ip = 0;
  unw_get_proc_info (&context->cursor, &pi);
  return pi.start_ip;
}
Exemple #5
0
PROTECTED unsigned long
_Unwind_GetDataRelBase (struct _Unwind_Context *context)
{
  unw_proc_info_t pi;

  pi.gp = 0;
  unw_get_proc_info (&context->cursor, &pi);
  return pi.gp;
}
Exemple #6
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");
}
Exemple #7
0
//
// Called by personality handler during phase 2 to find the start of the function
//
EXPORT uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context* context)
{
	unw_cursor_t* cursor = (unw_cursor_t*)context;
	unw_proc_info_t frameInfo;
	uintptr_t result = 0;
	if ( unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS ) 
		result = frameInfo.start_ip;
	DEBUG_PRINT_API("_Unwind_GetRegionStart(context=%p) => 0x%lX\n", context, result);
	return result;
}
Exemple #8
0
/// Called by personality handler during phase 2 to find the start of the
/// function.
_LIBUNWIND_EXPORT uintptr_t
_Unwind_GetRegionStart(struct _Unwind_Context *context) {
  unw_cursor_t *cursor = (unw_cursor_t *)context;
  unw_proc_info_t frameInfo;
  uintptr_t result = 0;
  if (unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS)
    result = (uintptr_t)frameInfo.start_ip;
  _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%" PRIXPTR "\n",
                             context, result);
  return result;
}
Exemple #9
0
//
// Called by personality handler during phase 2 to get LSDA for current frame
//
EXPORT uintptr_t _Unwind_GetLanguageSpecificData(struct _Unwind_Context* context)
{
	unw_cursor_t* cursor = (unw_cursor_t*)context;
	unw_proc_info_t frameInfo;
	uintptr_t result = 0;
	if ( unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS ) 
		result = frameInfo.lsda;
	DEBUG_PRINT_API("_Unwind_GetLanguageSpecificData(context=%p) => 0x%lX\n", context, result);
	if ( result != 0 ) {
		if ( *((uint8_t*)result) != 0xFF ) 
			DEBUG_MESSAGE("lsda at 0x%lX does not start with 0xFF\n", result);
	}
	return result;
}
Exemple #10
0
/// Called by personality handler during phase 2 to get LSDA for current frame.
_LIBUNWIND_EXPORT uintptr_t
_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {
  unw_cursor_t *cursor = (unw_cursor_t *)context;
  unw_proc_info_t frameInfo;
  uintptr_t result = 0;
  if (unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS)
    result = (uintptr_t)frameInfo.lsda;
  _LIBUNWIND_TRACE_API("_Unwind_GetLanguageSpecificData(context=%p)"
                             "=> 0x%" PRIXPTR "\n", context, result);
  if (result != 0) {
    if (*((uint8_t *)result) != 0xFF)
      _LIBUNWIND_DEBUG_LOG("lsda at 0x%" PRIXPTR " does not start with 0xFF\n", result);
  }
  return result;
}
/// Scans unwind information to find the function that contains the
/// specified code address "pc".
_LIBUNWIND_EXPORT void *_Unwind_FindEnclosingFunction(void *pc) {
  _LIBUNWIND_TRACE_API("_Unwind_FindEnclosingFunction(pc=%p)\n", pc);
  // This is slow, but works.
  // We create an unwind cursor then alter the IP to be pc
  unw_cursor_t cursor;
  unw_context_t uc;
  unw_proc_info_t info;
  unw_getcontext(&uc);
  unw_init_local(&cursor, &uc);
  unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(long) pc);
  if (unw_get_proc_info(&cursor, &info) == UNW_ESUCCESS)
    return (void *)(long) info.start_ip;
  else
    return NULL;
}
Exemple #12
0
void
fill_in_backtrace(FaultData* fdp)
{
    unw_context_t uc;
    unw_cursor_t c;
    int i, boff;

    memset(&uc, 0, sizeof(uc));
    memset(&c, 0, sizeof(c));
    if (unw_getcontext(&uc) < 0) {
        abort();
    }

    if (unw_init_local(&c, &uc) < 0) {
        abort();
    }

    // Skip the signal handler, and the signal trampoline
    for (i = 0; i < SKIP_FRAME_COUNT; i++) {
        if (unw_step(&c) <= 0) {
            break;
        }
    }

    memset(fdp->frame, 0, sizeof(fdp->frame));
    fdp->frame_count = 0;
    boff = 0;

    do {
        char fn[256];
        unw_word_t off, ip;
        Dl_info dli;
        unw_proc_info_t pi;

        unw_get_reg (&c, UNW_REG_IP, &ip);
        fdp->frame[fdp->frame_count].addr = (uintptr_t) ip;
        fdp->frame[fdp->frame_count].procname = (uintptr_t) &fdp->backtrace_buf[boff];
        unw_get_proc_name(&c, (char *) fdp->frame[fdp->frame_count].procname, sizeof(fdp->backtrace_buf) - boff, &off);
        unw_get_proc_info(&c, &pi);
        boff += strlen((char *) fdp->frame[fdp->frame_count].procname) + 1;
        fdp->frame[fdp->frame_count].libname = (uintptr_t) &fdp->backtrace_buf[boff];
        dladdr((void *)(uintptr_t) ip, &dli);
        strcpy((char *) (uintptr_t) fdp->frame[fdp->frame_count].libname, dli.dli_fname);
        boff += strlen((char *) fdp->frame[fdp->frame_count].libname) + 1;
        fdp->frame_count++;

    } while (unw_step(&c) > 0);
}
Exemple #13
0
G_GNUC_UNUSED static void
print_ctx (MonoContext *ctx)
{
	char name[256];
	unw_word_t off, ip, sp;
	unw_proc_info_t pi;
	int res;

	unw_get_proc_name (&ctx->cursor, name, 256, &off);
	unw_get_proc_info(&ctx->cursor, &pi);
	res = unw_get_reg (&ctx->cursor, UNW_IA64_IP, &ip);
	g_assert (res == 0);
	res = unw_get_reg (&ctx->cursor, UNW_IA64_SP, &sp);
	g_assert (res == 0);

	printf ("%s:%lx [%lx-%lx] SP: %lx\n", name, ip - pi.start_ip, pi.start_ip, pi.end_ip, sp);
}
Exemple #14
0
void zmq::print_backtrace (void)
{
    static zmq::mutex_t mtx;
    mtx.lock ();
    Dl_info dl_info;
    unw_cursor_t cursor;
    unw_context_t ctx;
    unsigned frame_n = 0;

    unw_getcontext (&ctx);
    unw_init_local (&cursor, &ctx);

    while (unw_step (&cursor) > 0) {
        unw_word_t offset;
        unw_proc_info_t p_info;
        const char *file_name;
        char *demangled_name;
        char func_name[256] = "";
        void *addr;
        int rc;

        if (unw_get_proc_info (&cursor, &p_info))
            break;

        addr = (void *)(p_info.start_ip + offset);

        if (dladdr (addr, &dl_info) && dl_info.dli_fname)
            file_name = dl_info.dli_fname;
        else
            file_name = "?";

        rc = unw_get_proc_name (&cursor, func_name, 256, &offset);
        if (rc == -UNW_ENOINFO)
            strcpy(func_name, "?");

        demangled_name = abi::__cxa_demangle (func_name, NULL, NULL, &rc);

        printf ("#%u  %p in %s (%s+0x%lx)\n", frame_n++, addr, file_name,
                rc ? func_name : demangled_name, (unsigned long) offset);
        free (demangled_name);
    }
    puts ("");
    
    fflush (stdout);
    mtx.unlock ();
}
Exemple #15
0
void unwindExc(Box* exc_obj) {
    unw_cursor_t cursor;
    unw_context_t uc;
    unw_word_t ip, sp;

    unw_getcontext(&uc);
    unw_init_local(&cursor, &uc);

    int code;
    unw_proc_info_t pip;

    while (unw_step(&cursor) > 0) {
        unw_get_reg(&cursor, UNW_REG_IP, &ip);
        unw_get_reg(&cursor, UNW_REG_SP, &sp);
        printf("ip = %lx, sp = %lx\n", (long)ip, (long)sp);

        code = unw_get_proc_info(&cursor, &pip);
        RELEASE_ASSERT(code == 0, "");

        // printf("%lx %lx %lx %lx %lx %lx %d %d %p\n", pip.start_ip, pip.end_ip, pip.lsda, pip.handler, pip.gp,
        // pip.flags, pip.format, pip.unwind_info_size, pip.unwind_info);

        assert((pip.lsda == 0) == (pip.handler == 0));
        assert(pip.flags == 0);

        if (pip.handler == 0) {
            if (VERBOSITY())
                printf("Skipping frame without handler\n");

            continue;
        }

        printf("%lx %lx %lx\n", pip.lsda, pip.handler, pip.flags);
        // assert(pip.handler == (uintptr_t)__gxx_personality_v0 || pip.handler == (uintptr_t)__py_personality_v0);

        // auto handler_fn = (int (*)(int, int, uint64_t, void*, void*))pip.handler;
        ////handler_fn(1, 1 /* _UA_SEARCH_PHASE */, 0 /* exc_class */, NULL, NULL);
        // handler_fn(2, 2 /* _UA_SEARCH_PHASE */, 0 /* exc_class */, NULL, NULL);
        unw_set_reg(&cursor, UNW_REG_IP, 1);

        // TODO testing:
        // unw_resume(&cursor);
    }

    abort();
}
/// Find dwarf unwind info for an address 'pc' in some function.
_LIBUNWIND_EXPORT const void *_Unwind_Find_FDE(const void *pc,
                                               struct dwarf_eh_bases *bases) {
  // This is slow, but works.
  // We create an unwind cursor then alter the IP to be pc
  unw_cursor_t cursor;
  unw_context_t uc;
  unw_proc_info_t info;
  unw_getcontext(&uc);
  unw_init_local(&cursor, &uc);
  unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(long) pc);
  unw_get_proc_info(&cursor, &info);
  bases->tbase = (uintptr_t)info.extra;
  bases->dbase = 0; // dbase not used on Mac OS X
  bases->func = (uintptr_t)info.start_ip;
  _LIBUNWIND_TRACE_API("_Unwind_Find_FDE(pc=%p) => %p\n", pc,
                  (void *)(long) info.unwind_info);
  return (void *)(long) info.unwind_info;
}
Exemple #17
0
static std::vector<const LineInfo*> getTracebackEntries() {
    std::vector<const LineInfo*> entries;

    unw_cursor_t cursor;
    unw_context_t uc;
    unw_word_t ip, bp;

    unw_getcontext(&uc);
    unw_init_local(&cursor, &uc);

    int code;
    unw_proc_info_t pip;

    while (unw_step(&cursor) > 0) {
        unw_get_reg(&cursor, UNW_REG_IP, &ip);

        const LineInfo* line = getLineInfoFor((uint64_t)ip);
        if (line) {
            entries.push_back(line);
        } else {
            unw_get_reg(&cursor, UNW_TDEP_BP, &bp);

            unw_proc_info_t pip;
            code = unw_get_proc_info(&cursor, &pip);
            RELEASE_ASSERT(code == 0, "%d", code);

            if (pip.start_ip == (intptr_t)interpretFunction) {
                line = getLineInfoForInterpretedFrame((void*)bp);
                assert(line);
                entries.push_back(line);
            }
        }
    }
    std::reverse(entries.begin(), entries.end());

    return entries;
}
void
debug_backtrace_capture(struct debug_stack_frame *backtrace,
                        unsigned start_frame,
                        unsigned nr_frames)
{
   unw_cursor_t cursor;
   unw_context_t context;
   unw_proc_info_t pip;
   unsigned i = 0;

   pip.unwind_info = NULL;

   unw_getcontext(&context);
   unw_init_local(&cursor, &context);

   while ((start_frame > 0) && (unw_step(&cursor) > 0))
      start_frame--;

   while ((i < nr_frames) && (unw_step(&cursor) > 0)) {
      unw_word_t ip;

      unw_get_reg(&cursor, UNW_REG_IP, &ip);
      unw_get_proc_info(&cursor, &pip);

      backtrace[i].start_ip = pip.start_ip;
      backtrace[i].off      = ip - pip.start_ip;
      backtrace[i].procname = symbol_name_cached(&cursor, &pip);

      i++;
   }

   while (i < nr_frames) {
      backtrace[i].start_ip = 0;
      i++;
   }
}
Exemple #19
0
int
main(int argc UNUSED, char **argv)
{
  unw_addr_space_t as;
  struct UCD_info *ui;
  unw_cursor_t c;
  int ret;

#define TEST_FRAMES 4
#define TEST_NAME_LEN 32
  int testcase = 0;
  int test_cur = 0;
  long test_start_ips[TEST_FRAMES];
  char test_names[TEST_FRAMES][TEST_NAME_LEN];

  install_sigsegv_handler();

  const char *progname = strrchr(argv[0], '/');
  if (progname)
    progname++;
  else
    progname = argv[0];

  if (!argv[1])
    error_msg_and_die("Usage: %s COREDUMP [VADDR:BINARY_FILE]...", progname);

  msg_prefix = progname;

  as = unw_create_addr_space(&_UCD_accessors, 0);
  if (!as)
    error_msg_and_die("unw_create_addr_space() failed");

  ui = _UCD_create(argv[1]);
  if (!ui)
    error_msg_and_die("_UCD_create('%s') failed", argv[1]);
  ret = unw_init_remote(&c, as, ui);
  if (ret < 0)
    error_msg_and_die("unw_init_remote() failed: ret=%d\n", ret);

  argv += 2;

  /* Enable checks for the crasher test program? */
  if (*argv && !strcmp(*argv, "-testcase"))
  {
    testcase = 1;
    logmode = LOGMODE_NONE;
    argv++;
  }

  while (*argv)
    {
      char *colon;
      unsigned long vaddr = strtoul(*argv, &colon, 16);
      if (*colon != ':')
        error_msg_and_die("Bad format: '%s'", *argv);
      if (_UCD_add_backing_file_at_vaddr(ui, vaddr, colon + 1) < 0)
        error_msg_and_die("Can't add backing file '%s'", colon + 1);
      argv++;
    }

  for (;;)
    {
      unw_word_t ip;
      ret = unw_get_reg(&c, UNW_REG_IP, &ip);
      if (ret < 0)
        error_msg_and_die("unw_get_reg(UNW_REG_IP) failed: ret=%d\n", ret);

      unw_proc_info_t pi;
      ret = unw_get_proc_info(&c, &pi);
      if (ret < 0)
        error_msg_and_die("unw_get_proc_info(ip=0x%lx) failed: ret=%d\n", (long) ip, ret);

      if (!testcase)
        printf("\tip=0x%08lx proc=%08lx-%08lx handler=0x%08lx lsda=0x%08lx\n",
				(long) ip,
				(long) pi.start_ip, (long) pi.end_ip,
				(long) pi.handler, (long) pi.lsda);

      if (testcase && test_cur < TEST_FRAMES)
        {
           unw_word_t off;

           test_start_ips[test_cur] = (long) pi.start_ip;
           if (unw_get_proc_name(&c, test_names[test_cur], sizeof(test_names[0]), &off) != 0)
           {
             test_names[test_cur][0] = '\0';
           }
           test_cur++;
        }

      log("step");
      ret = unw_step(&c);
      log("step done:%d", ret);
      if (ret < 0)
    	error_msg_and_die("FAILURE: unw_step() returned %d", ret);
      if (ret == 0)
        break;
    }
  log("stepping ended");

  /* Check that the second and third frames are equal, but distinct of the
   * others */
  if (testcase &&
       (test_cur != 4
       || test_start_ips[1] != test_start_ips[2]
       || test_start_ips[0] == test_start_ips[1]
       || test_start_ips[2] == test_start_ips[3]
       )
     )
    {
      fprintf(stderr, "FAILURE: start IPs incorrect\n");
      return -1;
    }

  if (testcase &&
       (  strcmp(test_names[0], "a")
       || strcmp(test_names[1], "b")
       || strcmp(test_names[2], "b")
       || strcmp(test_names[3], "main")
       )
     )
    {
      fprintf(stderr, "FAILURE: procedure names are missing/incorrect\n");
      return -1;
    }

  _UCD_destroy(ui);
  unw_destroy_addr_space(as);

  return 0;
}
Exemple #20
0
PROTECTED _Unwind_Reason_Code
_Unwind_RaiseException (struct _Unwind_Exception *exception_object)
{
  uint64_t exception_class = exception_object->exception_class;
  _Unwind_Personality_Fn personality;
  struct _Unwind_Context context;
  _Unwind_Reason_Code reason;
  unw_proc_info_t pi;
  unw_context_t uc;
  unw_word_t ip;
  int ret;

  if (_Unwind_InitContext (&context, &uc) < 0)
    return _URC_FATAL_PHASE1_ERROR;

  Debug (1, "(exception_object=%p)\n", exception_object);

  /* Phase 1 (search phase) */

  while (1)
    {
      if ((ret = unw_step (&context.cursor)) <= 0)
	{
	  if (ret == 0)
	    {
	      Debug (1, "no handler found\n");
	      return _URC_END_OF_STACK;
	    }
	  else
	    return _URC_FATAL_PHASE1_ERROR;
	}

      if (unw_get_proc_info (&context.cursor, &pi) < 0)
	return _URC_FATAL_PHASE1_ERROR;

      personality = (_Unwind_Personality_Fn) (uintptr_t) pi.handler;
      if (personality)
	{
	  reason = (*personality) (_U_VERSION, _UA_SEARCH_PHASE,
				   exception_class, exception_object,
				   &context);
	  if (reason != _URC_CONTINUE_UNWIND)
	    {
	      if (reason == _URC_HANDLER_FOUND)
		break;
	      else
		{
		  Debug (1, "personality returned %d\n", reason);
		  return _URC_FATAL_PHASE1_ERROR;
		}
	    }
	}
    }

  /* Exceptions are associated with IP-ranges.  If a given exception
     is handled at a particular IP, it will _always_ be handled at
     that IP.  If this weren't true, we'd have to track the tuple
     (IP,SP,BSP) to uniquely identify the stack frame that's handling
     the exception.  */
  if (unw_get_reg (&context.cursor, UNW_REG_IP, &ip) < 0)
    return _URC_FATAL_PHASE1_ERROR;
  exception_object->private_1 = 0;	/* clear "stop" pointer */
  exception_object->private_2 = ip;	/* save frame marker */

  Debug (1, "found handler for IP=%lx; entering cleanup phase\n", (long) ip);

  /* Reset the cursor to the first frame: */
  if (unw_init_local (&context.cursor, &uc) < 0)
    return _URC_FATAL_PHASE1_ERROR;

  return _Unwind_Phase2 (exception_object, &context);
}
/// Walk every frame and call trace function at each one.  If trace function
/// returns anything other than _URC_NO_REASON, then walk is terminated.
_LIBUNWIND_EXPORT _Unwind_Reason_Code
_Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) {
  unw_cursor_t cursor;
  unw_context_t uc;
  unw_getcontext(&uc);
  unw_init_local(&cursor, &uc);

  _LIBUNWIND_TRACE_API("_Unwind_Backtrace(callback=%p)\n", callback);

  // walk each frame
  while (true) {
    _Unwind_Reason_Code result;

    // ask libuwind to get next frame (skip over first frame which is
    // _Unwind_Backtrace())
    if (unw_step(&cursor) <= 0) {
      _LIBUNWIND_TRACE_UNWINDING(" _backtrace: ended because cursor reached "
                                 "bottom of stack, returning %d\n",
                                 _URC_END_OF_STACK);
      return _URC_END_OF_STACK;
    }

#if LIBCXXABI_ARM_EHABI
    // Get the information for this frame.
    unw_proc_info_t frameInfo;
    if (unw_get_proc_info(&cursor, &frameInfo) != UNW_ESUCCESS) {
      return _URC_END_OF_STACK;
    }

    struct _Unwind_Context *context = (struct _Unwind_Context *)&cursor;
    const uint32_t* unwindInfo = (uint32_t *) frameInfo.unwind_info;
    if ((*unwindInfo & 0x80000000) == 0) {
      // 6.2: Generic Model
      // EHT entry is a prel31 pointing to the PR, followed by data understood
      // only by the personality routine. Since EHABI doesn't guarantee the
      // location or availability of the unwind opcodes in the generic model,
      // we have to call personality functions with (_US_VIRTUAL_UNWIND_FRAME |
      // _US_FORCE_UNWIND) state.

      // Create a mock exception object for force unwinding.
      _Unwind_Exception ex;
      ex.exception_class = 0x434C4E47554E5700; // CLNGUNW\0
      ex.pr_cache.fnstart = frameInfo.start_ip;
      ex.pr_cache.ehtp = (_Unwind_EHT_Header *) unwindInfo;
      ex.pr_cache.additional= frameInfo.flags;

      // Get and call the personality function to unwind the frame.
      __personality_routine pr = (__personality_routine) readPrel31(unwindInfo);
      if (pr(_US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND, &ex, context) !=
              _URC_CONTINUE_UNWIND) {
        return _URC_END_OF_STACK;
      }
    } else {
      size_t off, len;
      unwindInfo = decode_eht_entry(unwindInfo, &off, &len);
      if (unwindInfo == NULL) {
        return _URC_FAILURE;
      }

      result = _Unwind_VRS_Interpret(context, unwindInfo, off, len);
      if (result != _URC_CONTINUE_UNWIND) {
        return _URC_END_OF_STACK;
      }
    }
#endif // LIBCXXABI_ARM_EHABI

    // debugging
    if (_LIBUNWIND_TRACING_UNWINDING) {
      char functionName[512];
      unw_proc_info_t frame;
      unw_word_t offset;
      unw_get_proc_name(&cursor, functionName, 512, &offset);
      unw_get_proc_info(&cursor, &frame);
      _LIBUNWIND_TRACE_UNWINDING(
          " _backtrace: start_ip=0x%llX, func=%s, lsda=0x%llX, context=%p\n",
          (long long)frame.start_ip, functionName,
          (long long)frame.lsda, &cursor);
    }

    // call trace function with this frame
    result = (*callback)((struct _Unwind_Context *)(&cursor), ref);
    if (result != _URC_NO_REASON) {
      _LIBUNWIND_TRACE_UNWINDING(" _backtrace: ended because callback "
                                 "returned %d\n",
                                 result);
      return result;
    }
  }
}
Exemple #22
0
// The stack-unwinding loop.
static inline void unwind_loop(ExcInfo* exc_data) {
    // NB. https://monoinfinito.wordpress.com/series/exception-handling-in-c/ is a very useful resource
    // as are http://www.airs.com/blog/archives/460 and http://www.airs.com/blog/archives/464
    unw_cursor_t cursor;
    unw_context_t uc; // exists only to initialize cursor
#ifndef NDEBUG
    // poison stack memory. have had problems with these structures being insufficiently initialized.
    memset(&uc, 0xef, sizeof uc);
    memset(&cursor, 0xef, sizeof cursor);
#endif
    unw_getcontext(&uc);
    unw_init_local(&cursor, &uc);

    auto unwind_session = getActivePythonUnwindSession();

    while (unw_step(&cursor) > 0) {
        unw_proc_info_t pip;

        static StatCounter frames_unwound("num_frames_unwound_cxx");
        frames_unwound.log();

        // NB. unw_get_proc_info is slow; a significant chunk of all time spent unwinding is spent here.
        check(unw_get_proc_info(&cursor, &pip));

        assert((pip.lsda == 0) == (pip.handler == 0));
        assert(pip.flags == 0);

        if (VERBOSITY("cxx_unwind") >= 4) {
            print_frame(&cursor, &pip);
        }

        // let the PythonUnwindSession know that we're in a new frame,
        // giving it a chance to possibly add a traceback entry for
        // it.
        unwindingThroughFrame(unwind_session, &cursor);

        // Skip frames without handlers
        if (pip.handler == 0) {
            continue;
        }

        RELEASE_ASSERT(pip.handler == (uintptr_t)__gxx_personality_v0,
                       "personality function other than __gxx_personality_v0; "
                       "don't know how to unwind through non-C++ functions");

        // Don't call __gxx_personality_v0; we perform dispatch ourselves.
        // 1. parse LSDA header
        lsda_info_t info;
        parse_lsda_header(&pip, &info);

        call_site_entry_t entry;
        {
            // 2. Find our current IP in the call site table.
            unw_word_t ip;
            unw_get_reg(&cursor, UNW_REG_IP, &ip);
            // ip points to the instruction *after* the instruction that caused the error - which is generally (always?)
            // a call instruction - UNLESS we're in a signal frame, in which case it points at the instruction that
            // caused the error. For now, we assume we're never in a signal frame. So, we decrement it by one.
            //
            // TODO: double-check that we never hit a signal frame.
            --ip;

            bool found = find_call_site_entry(&info, (const uint8_t*)ip, &entry);
            // If we didn't find an entry, an exception happened somewhere exceptions should never happen; terminate
            // immediately.
            if (!found) {
                panic();
            }
        }

        // 3. Figure out what to do based on the call site entry.
        if (!entry.landing_pad) {
            // No landing pad means no exception handling or cleanup; keep unwinding!
            continue;
        }
        // After this point we are guaranteed to resume something rather than unwinding further.

        if (VERBOSITY("cxx_unwind") >= 4) {
            print_lsda(&info);
        }

        int64_t switch_value = determine_action(&info, &entry);
        if (switch_value != CLEANUP_ACTION) {
            // we're transfering control to a non-cleanup landing pad.
            // i.e. a catch block.  thus ends our unwind session.
            endPythonUnwindSession(unwind_session);
#if STAT_TIMERS
            pyston::StatTimer::finishOverride();
#endif
        }
        static_assert(THREADING_USE_GIL, "have to make the unwind session usage in this file thread safe!");
        // there is a python unwinding implementation detail leaked
        // here - that the unwind session can be ended but its
        // exception storage is still around.
        //
        // this manifests itself as this short window here where we've
        // (possibly) ended the unwind session above but we still need
        // to pass exc_data (which is the exceptionStorage for this
        // unwind session) to resume().
        //
        // the only way this could bite us is if we somehow clobber
        // the PythonUnwindSession's storage, or cause a GC to occur, before
        // transfering control to the landing pad in resume().
        //
        resume(&cursor, entry.landing_pad, switch_value, exc_data);
    }

    // Hit end of stack! return & let unwindException determine what to do.
}
void
do_backtrace(void) {
    unw_word_t ip, sp, start_ip = 0, off;
    int n = 0, ret;
    unw_proc_info_t pi;
    unw_cursor_t c;
    char buf[512];
    size_t len;

    ret = unw_init_remote(&c, as, ui);
    if (ret < 0)
        panic ("unw_init_remote() failed: ret=%d\n", ret);

    do {
        if ((ret = unw_get_reg(&c, UNW_REG_IP, &ip)) < 0
            || (ret = unw_get_reg(&c, UNW_REG_SP, &sp)) < 0)
            panic ("unw_get_reg/unw_get_proc_name() failed: ret=%d\n", ret);

        if (n == 0)
            start_ip = ip;

        buf[0] = '\0';
        if (print_names)
            unw_get_proc_name(&c, buf, sizeof(buf), &off);

        if (verbose) {
            if (off) {
                len = strlen(buf);
                if (len >= sizeof(buf) - 32)
                    len = sizeof(buf) - 32;
                sprintf(buf + len, "+0x%lx", (unsigned long) off);
            }
            printf("%016lx %-32s (sp=%016lx)\n", (long) ip, buf, (long) sp);
        }

        if ((ret = unw_get_proc_info(&c, &pi)) < 0)
            panic ("unw_get_proc_info(ip=0x%lx) failed: ret=%d\n", (long) ip, ret);
        else if (verbose)
            printf("\tproc=%016lx-%016lx\n\thandler=%lx lsda=%lx",
                   (long) pi.start_ip, (long) pi.end_ip,
                   (long) pi.handler, (long) pi.lsda);

        if (verbose)
            printf("\n");

        ret = unw_step(&c);
        if (ret < 0) {
            unw_get_reg(&c, UNW_REG_IP, &ip);
            panic ("FAILURE: unw_step() returned %d for ip=%lx (start ip=%lx)\n",
                   ret, (long) ip, (long) start_ip);
        }

        if (++n > 64) {
            /* guard against bad unwind info in old libraries... */
            panic ("too deeply nested---assuming bogus unwind (start ip=%lx)\n",
                   (long) start_ip);
            break;
        }
        if (nerrors > nerrors_max) {
            panic ("Too many errors (%d)!\n", nerrors);
            break;
        }
    }
    while (ret > 0);

    if (ret < 0)
        panic ("unwind failed with ret=%d\n", ret);

    if (verbose)
        printf("================\n\n");
}
Exemple #24
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;
}
Exemple #25
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;
}
Exemple #26
0
static _Unwind_Reason_Code
unwind_phase1(unw_context_t *uc, struct _Unwind_Exception *exception_object) {
  // EHABI #7.3 discusses preserving the VRS in a "temporary VRS" during
  // phase 1 and then restoring it to the "primary VRS" for phase 2. The
  // effect is phase 2 doesn't see any of the VRS manipulations from phase 1.
  // In this implementation, the phases don't share the VRS backing store.
  // Instead, they are passed the original |uc| and they create a new VRS
  // from scratch thus achieving the same effect.
  unw_cursor_t cursor1;
  unw_init_local(&cursor1, uc);

  // Walk each frame looking for a place to stop.
  for (bool handlerNotFound = true; handlerNotFound;) {

    // Ask libuwind to get next frame (skip over first which is
    // _Unwind_RaiseException).
    int stepResult = unw_step(&cursor1);
    if (stepResult == 0) {
      _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(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_phase1(ex_ojb=%p): unw_step failed => "
                            "_URC_FATAL_PHASE1_ERROR\n",
                            exception_object);
      return _URC_FATAL_PHASE1_ERROR;
    }

    // See if frame has code to run (has personality routine).
    unw_proc_info_t frameInfo;
    unw_word_t sp;
    if (unw_get_proc_info(&cursor1, &frameInfo) != UNW_ESUCCESS) {
      _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_get_proc_info "
                            "failed => _URC_FATAL_PHASE1_ERROR\n",
                            exception_object);
      return _URC_FATAL_PHASE1_ERROR;
    }

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

    // If there is a personality routine, ask it if it will want to stop at
    // this frame.
    if (frameInfo.handler != 0) {
      __personality_routine p =
          (__personality_routine)(long)(frameInfo.handler);
      _LIBUNWIND_TRACE_UNWINDING(
          "unwind_phase1(ex_ojb=%p): calling personality function %p\n",
          exception_object, p);
      struct _Unwind_Context *context = (struct _Unwind_Context *)(&cursor1);
#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)(_US_VIRTUAL_UNWIND_FRAME, exception_object, context);
#else
      _Unwind_Reason_Code personalityResult =
          (*p)(1, _UA_SEARCH_PHASE, exception_object->exception_class,
               exception_object, context);
#endif
      switch (personalityResult) {
      case _URC_HANDLER_FOUND:
        // found a catch clause or locals that need destructing in this frame
        // stop search and remember stack pointer at the frame
        handlerNotFound = false;
#ifndef __arm__
        unw_get_reg(&cursor1, UNW_REG_SP, &sp);
        exception_object->private_2 = (uintptr_t)sp;
#else
        // p should have initialized barrier_cache. #7.3.5
#endif
        _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): "
                                   "_URC_HANDLER_FOUND \n",
                                   exception_object);
        return _URC_NO_REASON;

      case _URC_CONTINUE_UNWIND:
        _LIBUNWIND_TRACE_UNWINDING(
            "unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND\n",
            exception_object);
        // continue unwinding
        break;

#ifdef __arm__
      // # 7.3.3
      case _URC_FAILURE:
        return _URC_FAILURE;
#endif

      default:
        // something went wrong
        _LIBUNWIND_TRACE_UNWINDING(
            "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR\n",
            exception_object);
        return _URC_FATAL_PHASE1_ERROR;
      }
    }
  }
  return _URC_NO_REASON;
}
Exemple #27
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;
}
Exemple #28
0
static void chpl_stack_unwind(void){
  // This is just a prototype using libunwind
  unw_cursor_t cursor;
  unw_context_t uc;
  unw_word_t wordValue;
  char buffer[128];
  unsigned int line;

#ifdef __linux__
  unw_proc_info_t info;
  // Get the exec path and name for the precise line printing
  char process_name[128];

  line = readlink("/proc/self/exe", process_name, sizeof(process_name));
  // It unlikely to happen but this means that the process name is too big 
  // for our buffer. In this case, we truncate the name
  if(line == sizeof(process_name))
    line = sizeof(process_name)-1;
  process_name[line] = '\0';
#endif

  // Check if we need to print the stack trace (default = yes)
  if(! chpl_get_rt_env_bool("UNWIND", true)) {
    return;
  }

  line = 0;
  unw_getcontext(&uc);
  unw_init_local(&cursor, &uc);

  if(chpl_sizeSymTable > 0)
    fprintf(stderr,"Stacktrace\n\n");

  // This loop does the effective stack unwind, see libunwind documentation
  while (unw_step(&cursor) > 0) {
    unw_get_proc_name(&cursor, buffer, sizeof(buffer), &wordValue);
    // Since this stack trace is printed out a program exit, we do not believe
    // it is performance sensitive. Additionally, this initial implementation
    // favors simplicity over performance.
    //
    // If it becomes necessary to improve performance, this code could use be
    // faster using one of these two strategies:
    // 1) Use a hashtable or map to find entries in chpl_funSymTable, or
    // 2) Emit chpl_funSymTable in sorted order and use binary search on it
    for(int t = 0; t < chpl_sizeSymTable; t+=2 ){
      if (!strcmp(chpl_funSymTable[t], buffer)){
#ifdef __linux__
        // Maybe we can get a more precise line number
        unw_get_proc_info(&cursor, &info);
        line = chpl_unwind_getLineNum(process_name,
                                      (void *)(info.start_ip + wordValue));
        // We wasn't able to obtain the line number, let's use the procedure
        // line number
        if(line == 0)
          line = chpl_filenumSymTable[t+1];
#else
        line = chpl_filenumSymTable[t+1];
#endif
        fprintf(stderr,"%s() at %s:%d\n",
                  chpl_funSymTable[t+1],
                  chpl_lookupFilename(chpl_filenumSymTable[t]),
                  line);
        break;
      }
    }
  }
}
Exemple #29
0
        /* Benefit from maps being sorted by address */
        if (addr < mapsList[i].start) {
            break;
        }
    }
    return NULL;
}

#ifndef __ANDROID__
size_t arch_unwindStack(pid_t pid, funcs_t * funcs)
{
    size_t num_frames = 0, mapsCnt = 0;
    procMap_t *mapsList = arch_parsePidMaps(pid, &mapsCnt);
    defer {
        free(mapsList);
    };

    unw_addr_space_t as = unw_create_addr_space(&_UPT_accessors, __BYTE_ORDER);
    if (!as) {
        LOG_E("[pid='%d'] unw_create_addr_space failed", pid);
        return num_frames;
    }
    defer {
        unw_destroy_addr_space(as);
    };

    void *ui = _UPT_create(pid);
    if (ui == NULL) {
        LOG_E("[pid='%d'] _UPT_create failed", pid);
        return num_frames;
    }
    defer {
        _UPT_destroy(ui);
    };

    unw_cursor_t c;
    int ret = unw_init_remote(&c, as, ui);
    if (ret < 0) {
        LOG_E("[pid='%d'] unw_init_remote failed (%s)", pid, UNW_ER[-ret]);
        return num_frames;
    }

    for (num_frames = 0; unw_step(&c) > 0 && num_frames < _HF_MAX_FUNCS; num_frames++) {
        unw_word_t ip;
        char *mapName = NULL;
        ret = unw_get_reg(&c, UNW_REG_IP, &ip);
        if (ret < 0) {
            LOG_E("[pid='%d'] [%zd] failed to read IP (%s)", pid, num_frames, UNW_ER[-ret]);
            funcs[num_frames].pc = 0;
        } else {
            funcs[num_frames].pc = (void *)ip;
        }
        if (mapsCnt > 0 && (mapName = arch_searchMaps(ip, mapsCnt, mapsList)) != NULL) {
            memcpy(funcs[num_frames].mapName, mapName, sizeof(funcs[num_frames].mapName));
        } else {
            strncpy(funcs[num_frames].mapName, "UNKNOWN", sizeof(funcs[num_frames].mapName));
        }
    }

    return num_frames;
}

#else                           /* !defined(__ANDROID__) */
size_t arch_unwindStack(pid_t pid, funcs_t * funcs)
{
    size_t num_frames = 0, mapsCnt = 0;
    procMap_t *mapsList = arch_parsePidMaps(pid, &mapsCnt);
    defer {
        free(mapsList);
    }

    unw_addr_space_t as = unw_create_addr_space(&_UPT_accessors, __BYTE_ORDER);
    if (!as) {
        LOG_E("[pid='%d'] unw_create_addr_space failed", pid);
        return num_frames;
    }
    defer {
        unw_destroy_addr_space(as);
    };

    struct UPT_info *ui = (struct UPT_info *)_UPT_create(pid);
    if (ui == NULL) {
        LOG_E("[pid='%d'] _UPT_create failed", pid);
        return num_frames;
    }
    defer {
        _UPT_destroy(ui);
    };

    unw_cursor_t cursor;
    int ret = unw_init_remote(&cursor, as, ui);
    if (ret < 0) {
        LOG_E("[pid='%d'] unw_init_remote failed (%s)", pid, UNW_ER[-ret]);
        return num_frames;
    }

    do {
        char *mapName = NULL;
        unw_word_t pc = 0, offset = 0;
        char buf[_HF_FUNC_NAME_SZ] = { 0 };

        ret = unw_get_reg(&cursor, UNW_REG_IP, &pc);
        if (ret < 0) {
            LOG_E("[pid='%d'] [%zd] failed to read IP (%s)", pid, num_frames, UNW_ER[-ret]);
            // We don't want to try to extract info from an arbitrary IP
            // TODO: Maybe abort completely (goto out))
            goto skip_frame_info;
        }

        unw_proc_info_t frameInfo;
        ret = unw_get_proc_info(&cursor, &frameInfo);
        if (ret < 0) {
            LOG_D("[pid='%d'] [%zd] unw_get_proc_info (%s)", pid, num_frames, UNW_ER[-ret]);
            // Not safe to keep parsing frameInfo
            goto skip_frame_info;
        }

        ret = unw_get_proc_name(&cursor, buf, sizeof(buf), &offset);
        if (ret < 0) {
            LOG_D("[pid='%d'] [%zd] unw_get_proc_name() failed (%s)", pid, num_frames,
                  UNW_ER[-ret]);
            buf[0] = '\0';
        }

 skip_frame_info:
        // Compared to bfd, line var plays the role of offset from func_name
        // Reports format is adjusted accordingly to reflect in saved file
        funcs[num_frames].line = offset;
        funcs[num_frames].pc = (void *)pc;
        memcpy(funcs[num_frames].func, buf, sizeof(funcs[num_frames].func));
        if (mapsCnt > 0 && (mapName = arch_searchMaps(pc, mapsCnt, mapsList)) != NULL) {
            memcpy(funcs[num_frames].mapName, mapName, sizeof(funcs[num_frames].mapName));
        } else {
            strncpy(funcs[num_frames].mapName, "UNKNOWN", sizeof(funcs[num_frames].mapName));
        }

        num_frames++;

        ret = unw_step(&cursor);
    } while (ret > 0 && num_frames < _HF_MAX_FUNCS);

    return num_frames;
}
Exemple #30
0
static _Unwind_Reason_Code
unwind_phase1(unw_context_t *uc, _Unwind_Exception *exception_object) {
    unw_cursor_t cursor1;
    unw_init_local(&cursor1, uc);

    // Walk each frame looking for a place to stop.
    for (bool handlerNotFound = true; handlerNotFound;) {

        // Ask libuwind to get next frame (skip over first which is
        // _Unwind_RaiseException).
        int stepResult = unw_step(&cursor1);
        if (stepResult == 0) {
            _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(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_phase1(ex_ojb=%p): unw_step failed => "
                                       "_URC_FATAL_PHASE1_ERROR\n",
                                       exception_object);
            return _URC_FATAL_PHASE1_ERROR;
        }

        // See if frame has code to run (has personality routine).
        unw_proc_info_t frameInfo;
        unw_word_t sp;
        if (unw_get_proc_info(&cursor1, &frameInfo) != UNW_ESUCCESS) {
            _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_get_proc_info "
                                       "failed => _URC_FATAL_PHASE1_ERROR\n",
                                       exception_object);
            return _URC_FATAL_PHASE1_ERROR;
        }

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

        // If there is a personality routine, ask it if it will want to stop at
        // this frame.
        if (frameInfo.handler != 0) {
            __personality_routine p =
                (__personality_routine)(long)(frameInfo.handler);
            _LIBUNWIND_TRACE_UNWINDING(
                "unwind_phase1(ex_ojb=%p): calling personality function %p\n",
                exception_object, p);
            _Unwind_Reason_Code personalityResult =
                (*p)(1, _UA_SEARCH_PHASE, exception_object->exception_class,
                     exception_object, (struct _Unwind_Context *)(&cursor1));
            switch (personalityResult) {
            case _URC_HANDLER_FOUND:
                // found a catch clause or locals that need destructing in this frame
                // stop search and remember stack pointer at the frame
                handlerNotFound = false;
                unw_get_reg(&cursor1, UNW_REG_SP, &sp);
                exception_object->private_2 = (uintptr_t)sp;
                _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): "
                                           "_URC_HANDLER_FOUND \n",
                                           exception_object);
                return _URC_NO_REASON;

            case _URC_CONTINUE_UNWIND:
                _LIBUNWIND_TRACE_UNWINDING(
                    "unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND\n",
                    exception_object);
                // continue unwinding
                break;

            default:
                // something went wrong
                _LIBUNWIND_TRACE_UNWINDING(
                    "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR\n",
                    exception_object);
                return _URC_FATAL_PHASE1_ERROR;
            }
        }
    }
    return _URC_NO_REASON;
}