示例#1
0
文件: S52utils.c 项目: sduclos/S52
void              _dump_crash_report(unsigne pid)
// shortened code from android's debuggerd
// to get a backtrace on ARM
{
    unw_addr_space_t as;
    struct UPT_info *ui;
    unw_cursor_t     cursor;

    as = unw_create_addr_space(&_UPT_accessors, 0);
    ui = _UPT_create(pid);

    int ret = unw_init_remote(&cursor, as, ui);
    if (ret < 0) {
        PRINTF("WARNING: unw_init_remote() failed [pid %i]\n", pid);
        _UPT_destroy(ui);
        return;
    }

    PRINTF("DEBUG: backtrace of the remote process (pid %d) using libunwind-ptrace:\n", pid);

    do {
        unw_word_t ip, sp, offp;
        char buf[512];

        unw_get_reg(&cursor, UNW_REG_IP, &ip);
        unw_get_reg(&cursor, UNW_REG_SP, &sp);
        unw_get_proc_name(&cursor, buf, sizeof (buf), &offp);

        PRINTF("DEBUG:   ip: %10p, sp: %10p   %s\n", (void*) ip, (void*) sp, buf);

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

    _UPT_destroy (ui);
}
示例#2
0
文件: proc.c 项目: mer-tools/ltrace
static void
destroy_unwind(struct Process *proc)
{
#if defined(HAVE_LIBUNWIND)
	_UPT_destroy(proc->unwind_priv);
	unw_destroy_addr_space(proc->unwind_as);
#endif /* defined(HAVE_LIBUNWIND) */
}
示例#3
0
int backtrace_ptrace(int pid, int *tids, int *index, int nr_tids)
{
#if !defined (NO_LIBUNWIND_PTRACE)
    int i, count, rc = 0;
    int *threads = NULL;

    count = get_threads(pid, &threads);
    if (!count || threads == NULL)
        return -1;

    if (tids != NULL) {
        if (adjust_threads(threads, count, tids, index, nr_tids) < 0)
            return -1;

        free(threads);
        count = nr_tids;
        threads = tids;
    }

    if (attach_process(pid) < 0)
        return -1;

    for (i = 0; i < count; ++i) {
        void *upt_info;

        printf("--------------------  thread %d (%d)  --------------------\n",
               (index != NULL ? index[i] : i+1), threads[i]);

        if (threads[i] != pid && attach_thread(threads[i]) < 0) {
            rc = -1;
            break;
        }

        upt_info = _UPT_create(threads[i]);

        if (backtrace_thread(&_UPT_accessors, upt_info) < 0)
            rc = -1;

        _UPT_destroy(upt_info);

        if (threads[i] != pid && detach_thread(threads[i]))
            rc = -1;
        if (rc < 0)
            break;
    }

    free(threads);

    if (detach_process(pid) < 0)
        return -1;

    return rc;

#else
    return -1;
#endif /* NO_LIBUNWIND_PTRACE */
}
UnwindPtrace::~UnwindPtrace() {
  if (upt_info_) {
    _UPT_destroy(upt_info_);
    upt_info_ = NULL;
  }
  if (addr_space_) {
    unw_destroy_addr_space(addr_space_);
    addr_space_ = NULL;
  }
}
示例#5
0
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;
}
示例#6
0
UnwindPtrace::~UnwindPtrace() {
  if (upt_info_) {
    _UPT_destroy(upt_info_);
    upt_info_ = NULL;
  }
  if (addr_space_) {
    // Remove the map from the address space before destroying it.
    // It will be freed in the UnwindMap destructor.
    unw_map_set(addr_space_, NULL);

    unw_destroy_addr_space(addr_space_);
    addr_space_ = NULL;
  }
}
示例#7
0
BOOL PAL_VirtualUnwindOutOfProc(CONTEXT *context, 
                                KNONVOLATILE_CONTEXT_POINTERS *contextPointers, 
                                DWORD pid, 
                                ReadMemoryWordCallback readMemCallback)
{
    // This function can be executed only by one thread at a time. 
    // The reason for this is that we need to pass context and read mem function to libunwind callbacks
    // but "arg" is already used by the pointer returned from _UPT_create(). 
    // So we resort to using global variables and a lock.
    struct Lock 
    {
        CRITICAL_SECTION cs;
        Lock()
        {        
            // ctor of a static variable is a thread-safe way to initialize critical section exactly once (clang,gcc)
            InitializeCriticalSection(&cs);
        }
    };
    struct LockHolder
    {
        CRITICAL_SECTION *cs;
        LockHolder(CRITICAL_SECTION *cs)
        {
            this->cs = cs;
            EnterCriticalSection(cs);
        }

        ~LockHolder()
        {
            LeaveCriticalSection(cs);
            cs = NULL;
        }
    };    
    static Lock lock;
    LockHolder lockHolder(&lock.cs);

    int st;
    unw_context_t unwContext;
    unw_cursor_t cursor;
    unw_addr_space_t addrSpace = 0;
    void *libunwindUptPtr = NULL;
    BOOL result = FALSE;

    LibunwindCallbacksInfo.Context = context;
    LibunwindCallbacksInfo.readMemCallback = readMemCallback;
    WinContextToUnwindContext(context, &unwContext);
    addrSpace = unw_create_addr_space(&unwind_accessors, 0);
    libunwindUptPtr = _UPT_create(pid);
    st = unw_init_remote(&cursor, addrSpace, libunwindUptPtr);
    if (st < 0)
    {
        result = FALSE;
        goto Exit;
    }

    st = unw_step(&cursor);
    if (st < 0)
    {
        result = FALSE;
        goto Exit;
    }

    UnwindContextToWinContext(&cursor, context);

    if (contextPointers != NULL)
    {
        GetContextPointers(&cursor, &unwContext, contextPointers);
    }
    result = TRUE;

Exit:
    if (libunwindUptPtr != nullptr) 
    {
        _UPT_destroy(libunwindUptPtr);
    }
    if (addrSpace != 0) 
    {
        unw_destroy_addr_space(addrSpace);
    }    
    return result;
}
示例#8
0
static void print_stack_trace(pid_t pid, int * count)
{
	void *		    pinfo = NULL;
	unw_addr_space_t    aspace = NULL;
	unw_cursor_t	    cursor;
	unw_word_t	    ip, sp;

	char		    nbuf[256];
	unw_word_t	    off;

	int ret;

	if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
		fprintf(stderr,
			"Failed to attach to process %llu: %s\n",
			(unsigned long long)pid, strerror(errno));
		return;
	}

	/* Wait until the attach is complete. */
	waitpid(pid, NULL, 0);

	if (((pinfo = _UPT_create(pid)) == NULL) ||
	    ((aspace = unw_create_addr_space(&_UPT_accessors, 0)) == NULL)) {
		/* Probably out of memory. */
		fprintf(stderr,
			"Unable to initialize stack unwind for process %llu\n",
			(unsigned long long)pid);
		goto cleanup;
	}

	if ((ret = unw_init_remote(&cursor, aspace, pinfo))) {
		fprintf(stderr,
			"Unable to unwind stack for process %llu: %s\n",
			(unsigned long long)pid, unw_strerror(ret));
		goto cleanup;
	}

	if (*count > 0) {
		printf("\n");
	}

	if (procname(pid, nbuf, sizeof(nbuf))) {
		printf("Stack trace for process %llu (%s):\n",
			(unsigned long long)pid, nbuf);
	} else {
		printf("Stack trace for process %llu:\n",
			(unsigned long long)pid);
	}

	while (unw_step(&cursor) > 0) {
		ip = sp = off = 0;
		unw_get_reg(&cursor, UNW_REG_IP, &ip);
		unw_get_reg(&cursor, UNW_REG_SP, &sp);

		ret = unw_get_proc_name(&cursor, nbuf, sizeof(nbuf), &off);
		if (ret != 0 && ret != -UNW_ENOMEM) {
			snprintf(nbuf, sizeof(nbuf), "<unknown symbol>");
		}
		printf("    %s + %#llx [ip=%#llx] [sp=%#llx]\n",
			nbuf, (long long)off, (long long)ip,
			(long long)sp);
	}

	(*count)++;

cleanup:
	if (aspace) {
		unw_destroy_addr_space(aspace);
	}

	if (pinfo) {
		_UPT_destroy(pinfo);
	}

	ptrace(PTRACE_DETACH, pid, NULL, NULL);
}
示例#9
0
bool UPTDestroyCallback::execute_real()
{
  _UPT_destroy(handle_);
  return true;
}
示例#10
0
void bt_finish(struct bt_data *btd)
{
	_UPT_destroy(btd->ui);
	unw_destroy_addr_space(btd->as);
	free(btd);
}
示例#11
0
int
main(int argc, char **argv) {
    int status, pid, pending_sig, optind = 1, state = 1;

    as = unw_create_addr_space(&_UPT_accessors, 0);
    if (!as)
        panic ("unw_create_addr_space() failed");

    if (argc == 1) {
        static char *args[] = {"self", "/bin/ls", "/usr", NULL};

        /* automated test case */
        argv = args;
    }
    else if (argc > 1)
        while (argv[optind][0] == '-') {
            if (strcmp(argv[optind], "-v") == 0)
                ++optind, verbose = 1;
            else if (strcmp(argv[optind], "-i") == 0)
                ++optind, trace_mode = INSTRUCTION;    /* backtrace at each insn */
            else if (strcmp(argv[optind], "-s") == 0)
                ++optind, trace_mode = SYSCALL;    /* backtrace at each syscall */
            else if (strcmp(argv[optind], "-t") == 0)
                /* Execute until raise(SIGUSR1), then backtrace at each insn
                   until raise(SIGUSR2).  */
                ++optind, trace_mode = TRIGGER;
            else if (strcmp(argv[optind], "-c") == 0)
                /* Enable caching of unwind-info.  */
                ++optind, unw_set_caching_policy(as, UNW_CACHE_GLOBAL);
            else if (strcmp(argv[optind], "-n") == 0)
                /* Don't look-up and print symbol names.  */
                ++optind, print_names = 0;
            else
                fprintf(stderr, "unrecognized option: %s\n", argv[optind++]);
            if (optind >= argc)
                break;
        }

    target_pid = fork();
    if (!target_pid) {
        /* child */

        if (!verbose)
            dup2(open("/dev/null", O_WRONLY), 1);

        ptrace(PTRACE_TRACEME, 0, 0, 0);

        if ((argc > 1) && (optind == argc)) {
            fprintf(stderr, "Need to specify a command line for the child\n");
            exit(-1);
        }
        execve(argv[optind], argv + optind, environ);
        _exit(-1);
    }
    atexit(target_pid_kill);

    ui = _UPT_create(target_pid);

    while (nerrors <= nerrors_max) {
        pid = wait4(-1, &status, 0, NULL);
        if (pid == -1) {
            if (errno == EINTR)
                continue;

            panic ("wait4() failed (errno=%d)\n", errno);
        }
        pending_sig = 0;
        if (WIFSIGNALED (status) || WIFEXITED (status)
            || (WIFSTOPPED (status) && WSTOPSIG (status) != SIGTRAP)) {
            if (WIFEXITED (status)) {
                if (WEXITSTATUS (status) != 0)
                    panic ("child's exit status %d\n", WEXITSTATUS(status));
                break;
            }
            else if (WIFSIGNALED (status)) {
                if (!killed)
                    panic ("child terminated by signal %d\n", WTERMSIG(status));
                break;
            }
            else {
                pending_sig = WSTOPSIG (status);
                /* Avoid deadlock:  */
                if (WSTOPSIG (status) == SIGKILL)
                    break;
                if (trace_mode == TRIGGER) {
                    if (WSTOPSIG (status) == SIGUSR1)
                        state = 0;
                    else if (WSTOPSIG (status) == SIGUSR2)
                        state = 1;
                }
                if (WSTOPSIG (status) != SIGUSR1 && WSTOPSIG (status) != SIGUSR2) {
                    static int count = 0;

                    if (count++ > 100) {
                        panic ("Too many child unexpected signals (now %d)\n",
                               WSTOPSIG(status));
                        killed = 1;
                    }
                }
            }
        }

        switch (trace_mode) {
            case TRIGGER:
                if (state)
                    ptrace(PTRACE_CONT, target_pid, 0, 0);
                else {
                    do_backtrace();
                    if (ptrace(PTRACE_SINGLESTEP, target_pid, 0, pending_sig) < 0) {
                        panic ("ptrace(PTRACE_SINGLESTEP) failed (errno=%d)\n", errno);
                        killed = 1;
                    }
                }
                break;

            case SYSCALL:
                if (!state)
                    do_backtrace();
                state ^= 1;
                ptrace(PTRACE_SYSCALL, target_pid, 0, pending_sig);
                break;

            case INSTRUCTION:
                do_backtrace();
                ptrace(PTRACE_SINGLESTEP, target_pid, 0, pending_sig);
                break;
        }
        if (killed)
            kill(target_pid, SIGKILL);
    }

    _UPT_destroy(ui);
    unw_destroy_addr_space(as);

    if (nerrors) {
        printf("FAILURE: detected %d errors\n", nerrors);
        exit(-1);
    }
    if (verbose)
        printf("SUCCESS\n");

    return 0;
}
示例#12
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;
}
示例#13
0
int backtrace_ptrace(int pid, int *tids, int *index, int nr_tids)
{
#if !defined (NO_LIBUNWIND_PTRACE)
    int i, count, rc = 0;
    int *threads = NULL;

    count = get_threads(pid, &threads);
    if (!count || threads == NULL)
        return -1;

    if (tids != NULL) {
        if (adjust_threads(threads, count, tids, index, nr_tids) < 0)
            return -1;

        free(threads);
        count = nr_tids;
        threads = tids;
    }

    if (attach_process(pid) < 0)
        return -1;

    for (i = 0; i < count; ++i) {
        void *upt_info;
        int x;
        char comm[16];
        char end_pad[25] = "------------------------";

        x = get_thread_comm(threads[i], comm, sizeof(comm));

        if (x > 0 && x <= sizeof(end_pad))
        {
            end_pad[sizeof(end_pad) - x] = '\0';
            printf("-------------- thread %d (%d) (%s) %s\n", (index != NULL ? index[i] : i + 1), threads[i], comm, end_pad);
        }

        if (threads[i] != pid && attach_thread(threads[i]) < 0) {
            rc = -1;
            break;
        }

        upt_info = _UPT_create(threads[i]);

        if (backtrace_thread(&_UPT_accessors, upt_info) < 0)
            rc = -1;

        _UPT_destroy(upt_info);

        if (threads[i] != pid && detach_thread(threads[i]))
            rc = -1;
        if (rc < 0)
            break;
    }

    free(threads);

    if (detach_process(pid) < 0)
        return -1;

    return rc;

#else
    return -1;
#endif /* NO_LIBUNWIND_PTRACE */
}
示例#14
0
文件: trace.c 项目: dkrotx/crxprof
void
trace_free(ptrace_context *ctx) {
    _UPT_destroy(ctx->unwind_rctx);
    unw_destroy_addr_space(ctx->addr_space);
    free(ctx->cmdline);
}
size_t StackCorkscrewLibunwind::Unwind (pid_t ppid, pid_t tid, size_t ignoreDepth, size_t maxDepth)
{
  assert (ppid > 0);

  assert (tid >= ppid);

  (void) ignoreDepth;

  m_frames.clear ();

  if (maxDepth == 0)
  {
    return 0;
  }

  static unw_addr_space_t addr_space;

  (void) addr_space;

#if UNWIND_SUPPORTED && UNWIND_REMOTE_SUPPORTED

  addr_space = unw_create_addr_space (&_UPT_accessors, 0);

  if (!addr_space)
  {
    fprintf (stderr, "unw_create_addr_space failed.\n");

    fflush (stderr);

    return 0;
  }

#endif

#if UNWIND_MAP_SUPPORTED && UNWIND_FUNCTION_NAME

  unw_map_cursor_t map_cursor;

  if (unw_map_cursor_create (&map_cursor, tid) < 0)
  {
    fprintf (stderr, "Failed to create map cursor.\n");

    fflush (stderr);

    return 0;
  }

  unw_map_set (addr_space, &map_cursor);

#endif

#if UNWIND_REMOTE_SUPPORTED

  struct UPT_info* upt_info = reinterpret_cast<struct UPT_info*> (_UPT_create (tid));

  if (!upt_info)
  {
    fprintf (stderr, "Failed to create upt info.\n");

    fflush (stderr);

    return 0;
  }

  unw_cursor_t cursor;

  {
    int error = unw_init_remote (&cursor, addr_space, upt_info);

    if (error < 0)
    {
      fprintf (stderr, "unw_init_remote failed (%d)\n", error);

      fflush (stderr);

      return 0;
    }
  }

#endif

  bool shouldContinue = false;

  size_t numFrames = 0;

  do
  {
    //
    // Evaluate instruction pointer / program counter address.
    //

#if UNWIND_REMOTE_SUPPORTED

    uint64_t pc = 0;

    {
      unw_word_t unwound_pc;

      int error = unw_get_reg (&cursor, UNW_REG_IP, &unwound_pc);

      if (error < 0)
      {
        fprintf (stderr, "Failed to read IP (%d)\n", error);

        fflush (stderr);

        break;
      }

      pc = unwound_pc;
    }

#if UNWIND_STACK_POINTER

    uint64_t sp = 0;

    {
      unw_word_t unwound_sp;

      int error = unw_get_reg (&cursor, UNW_REG_SP, &unwound_sp);

      if (error < 0)
      {
        fprintf (stderr, "Failed to read SP (%d)\n", error);

        fflush (stderr);

        break;
      }

      sp = unwound_sp;
    }

#endif

    if (ignoreDepth == 0)
    {
      const char *function = "??";

#if UNWIND_FUNCTION_NAME

      uintptr_t offset = 0;

      char buffer [128];

      unw_word_t value;

      const int result = unw_get_proc_name_by_ip (addr_space, pc, buffer, sizeof (buffer), &value, upt_info);

      if (result >= 0 && buffer [0] != '\0')
      {
        function = buffer;

        offset = static_cast<uintptr_t>(value);
      }

#endif

      StackFrame frame;

      frame.m_level = numFrames;

      frame.m_pc = pc;

#if UNWIND_STACK_POINTER

      frame.m_sp = sp;

#endif

      strncpy (frame.m_function, function, sizeof (frame.m_function));

      m_frames.push_back (frame);

      numFrames++;
    }
    else
    {
      ignoreDepth--;
    }

    shouldContinue = (unw_step (&cursor) > 0);

#endif
  }
  while (shouldContinue && numFrames < maxDepth);

#if UNWIND_REMOTE_SUPPORTED

  _UPT_destroy (upt_info);

#endif

#if UNWIND_MAP_SUPPORTED && UNWIND_FUNCTION_NAME

  unw_map_cursor_destroy (&map_cursor);

  unw_map_cursor_clear (&map_cursor);

#endif

  return m_frames.size ();
}