bool BacktraceOffline::Unwind(size_t num_ignore_frames, ucontext_t* context) {
  if (context == nullptr) {
    BACK_LOGW("The context is needed for offline backtracing.");
    return false;
  }
  context_ = context;

  unw_addr_space_t addr_space = unw_create_addr_space(&accessors, 0);
  unw_cursor_t cursor;
  int ret = unw_init_remote(&cursor, addr_space, this);
  if (ret != 0) {
    BACK_LOGW("unw_init_remote failed %d", ret);
    unw_destroy_addr_space(addr_space);
    return false;
  }
  size_t num_frames = 0;
  do {
    unw_word_t pc;
    ret = unw_get_reg(&cursor, UNW_REG_IP, &pc);
    if (ret < 0) {
      BACK_LOGW("Failed to read IP %d", ret);
      break;
    }
    unw_word_t sp;
    ret = unw_get_reg(&cursor, UNW_REG_SP, &sp);
    if (ret < 0) {
      BACK_LOGW("Failed to read SP %d", ret);
      break;
    }

    if (num_ignore_frames == 0) {
      frames_.resize(num_frames + 1);
      backtrace_frame_data_t* frame = &frames_[num_frames];
      frame->num = num_frames;
      frame->pc = static_cast<uintptr_t>(pc);
      frame->sp = static_cast<uintptr_t>(sp);
      frame->stack_size = 0;

      if (num_frames > 0) {
        backtrace_frame_data_t* prev = &frames_[num_frames - 1];
        prev->stack_size = frame->sp - prev->sp;
      }
      frame->func_name = GetFunctionName(frame->pc, &frame->func_offset);
      FillInMap(frame->pc, &frame->map);
      num_frames++;
    } else {
      num_ignore_frames--;
    }
    ret = unw_step(&cursor);
  } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES);

  unw_destroy_addr_space(addr_space);
  context_ = nullptr;
  return true;
}
Exemple #2
0
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) */
}
UnwindPtrace::~UnwindPtrace() {
  if (upt_info_) {
    _UPT_destroy(upt_info_);
    upt_info_ = NULL;
  }
  if (addr_space_) {
    unw_destroy_addr_space(addr_space_);
    addr_space_ = NULL;
  }
}
Exemple #4
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;
}
Exemple #5
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;
  }
}
/*++
Function:
    PAL_VirtualUnwindOutOfProc

    Unwind the stack given the context for a "remote" target using the
    provided read memory callback.

    Assumes the IP is in the module of the base address provided (coreclr).

Parameters:
    context - the start context in the target
    contextPointers - the context of the next frame
    baseAddress - base address of the module to find the unwind info
    readMemoryCallback - reads memory from the target
--*/
BOOL
PALAPI
PAL_VirtualUnwindOutOfProc(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextPointers, SIZE_T baseAddress, UnwindReadMemoryCallback readMemoryCallback)
{
    unw_addr_space_t addrSpace = 0;
    unw_cursor_t cursor;
    libunwindInfo info;
    BOOL result = FALSE;
    int st;

    info.BaseAddress = baseAddress;
    info.Context = context;
    info.ReadMemory = readMemoryCallback;

    addrSpace = unw_create_addr_space(&unwind_accessors, 0);

    st = unw_init_remote(&cursor, addrSpace, &info);
    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, NULL, contextPointers);
    }
    result = TRUE;

exit:
    if (addrSpace != 0)
    {
        unw_destroy_addr_space(addrSpace);
    }
    return result;
}
Exemple #7
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);
}
Exemple #8
0
bool DestroyUnwindAddressSpaceCallback::execute_real()
{
  unw_destroy_addr_space(as_);
  return true;
}
Exemple #9
0
void bt_finish(struct bt_data *btd)
{
	_UPT_destroy(btd->ui);
	unw_destroy_addr_space(btd->as);
	free(btd);
}
Exemple #10
0
int
main(int argc , char **argv)
{
  unw_addr_space_t as;
  unw_cursor_t cursor;
  struct UCD_info *ui;
  unw_word_t ip, sp, off;
  char buf[512], name[256];
  int line;
  int depth = 0;
  int ret;
  bool pybt_done = false;
#define TEST_NAME_LEN 256 

  install_signal_handler();

  if (argc != 3) {
    fprintf(stderr, "Usage: %s <binary> <corefile>", argv[0]);
    exit(1);
  }

  as = unw_create_addr_space(&_UCD_accessors, 0);
  if (!as) {
    fprintf(stderr, "unw_create_addr_space() failed");
    exit(1);
  }

  ui = _UCD_create(argv[2]);
  if (!ui) {
    fprintf(stderr,"_UCD_create('%s') failed", argv[1]);
    exit(1);
  }
  ret = unw_init_remote(&cursor, as, ui);
  if (ret < 0) {
    fprintf(stderr,"unw_init_remote() failed: ret=%d\n", ret);
    exit(1);
  }

  read_elfnotes(argv[2], ui);

  while (unw_step(&cursor) > 0) {
    // Avoid going too deep
    if (depth++ > MAX_STACK_DEPTH) {
      exit(1);
    }
    unw_get_reg(&cursor, UNW_REG_IP, &ip);
    unw_get_reg(&cursor, UNW_REG_SP, &sp);


    if (unw_get_proc_name(&cursor, name, sizeof (name), &off) == 0) {
      if (off) {
        snprintf(buf, sizeof (buf), "<%s+0x%lx>", name, (long) off);
      } else {
        snprintf(buf, sizeof (buf), "<%s>", name);
      }
    }

    /* Check for Python backtrace */
    if (!strncmp(name,"PyEval_EvalFrameEx", 18) && !pybt_done) {
      pybacktrace(cursor);
      pybt_done = true;
    }
    rw_get_file_and_line((long)ip, name, argv[1], 256, &line);
    printf("%016lx %s <%s:%d> (sp=%016lx)\n",
            (long) ip, buf, basename(name), line, (long) sp);

  }
  _UCD_destroy(ui);
  unw_destroy_addr_space(as);

  return 0;
}
Exemple #11
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 #12
0
static int backtrace_thread(unw_accessors_t *accessors, void *arg)
{
    unw_addr_space_t addr_space;
    unw_cursor_t cursor;
    int rc = 0, n = 0;

    if ((addr_space = unw_create_addr_space(accessors, 0)) == NULL) {
        fprintf(stderr, "failed to create address space for unwinding\n");
        return -1;
    }

    if ((rc = unw_init_remote(&cursor, addr_space, arg)) < 0) {
        fprintf(stderr, "failed to init cursor for unwinding: rc=%d\n", rc);
        return -1;
    }

    do {
        unw_word_t ip, sp = -1, off;
        static char buf[512];
        size_t len;

        if ((rc = unw_get_reg(&cursor, UNW_REG_IP, &ip)) < 0) {
            fprintf(stderr, "failed to get IP: rc=%d\n", rc);
            break;
        }

        buf[0] = '\0';
        unw_get_proc_name(&cursor, buf, sizeof(buf), &off);

        if (buf[0] == '\0') {
            buf[0] = '?';
            buf[1] = '\0';
            len = 1;
        } else {
            len = strlen(buf);
        }

        if (len >= sizeof(buf) - 32)
            len = sizeof(buf) - 32;

        if (!ip)
            break;

        if (off) {
            sprintf(buf + len, " + 0x%lx", (unsigned long)off);
        }
        if (!opt_show_rsp) {
            printf(" %016lx  %s\n", (long)ip, buf);
        } else {
            unw_get_reg(&cursor, UNW_REG_SP, &sp);
            printf(" %016lx  %016lx  %s\n", (long)ip, (long)sp, buf);
        }

        if ((rc = unw_step(&cursor)) < 0) {
            if (!opt_show_rsp)
                printf(" ????????????????  <stack breaks here>\n");
            else
                printf(" ????????????????  ????????????????  <stack breaks here>\n");

            if (opt_verbose) {
                fprintf(stderr, "unwind step failed: n=%d rc=%d\n", n, rc);
            }
            break;
        }

        if (++n == 64 && rc) {
            puts(" ????????????????  <stack is too long>\n");
            break;
        }
    } while (rc > 0);

    unw_destroy_addr_space(addr_space);

    return rc;
}
Exemple #13
0
struct sr_core_stacktrace *
sr_parse_coredump(const char *core_file,
                   const char *exe_file,
                   char **error_msg)
{
    struct sr_core_stacktrace *stacktrace = NULL;

    /* Initialize error_msg to 'no error'. */
    if (error_msg)
        *error_msg = NULL;

    struct core_handle *ch = open_coredump(core_file, exe_file, error_msg);
    if (*error_msg)
        return NULL;

    unw_addr_space_t as;
    struct UCD_info *ui;
    as = unw_create_addr_space(&_UCD_accessors, 0);
    if (!as)
    {
        set_error("Failed to create address space");
        goto fail_destroy_handle;
    }

    ui = _UCD_create(core_file);
    if (!ui)
    {
        set_error("Failed to set up core dump accessors for '%s'", core_file);
        goto fail_destroy_as;
    }

    struct exe_mapping_data *s;
    for (s = ch->segments; s != NULL; s = s->next)
    {
        if (_UCD_add_backing_file_at_vaddr(ui, s->start, s->filename) < 0)
        {
            /* Sometimes produces:
             * >_UCD_add_backing_file_at_segment:
             * Error reading from '/usr/lib/modules/3.6.9-2.fc17.x86_64/vdso/vdso.so'
             * Ignore errors for now & fail later.
             */
            warn("Can't add backing file '%s' at addr 0x%jx", s->filename,
                 (uintmax_t)s->start);
            /* goto fail_destroy_ui; */
        }
    }

    stacktrace = sr_core_stacktrace_new();

    int tnum, nthreads = _UCD_get_num_threads(ui);
    for (tnum = 0; tnum < nthreads; ++tnum)
    {
        struct sr_core_thread *trace = unwind_thread(ui, as, ch->dwfl, tnum, error_msg);
        if (trace)
        {
            stacktrace->threads = sr_core_thread_append(stacktrace->threads, trace);
        }
        else
        {
            sr_core_stacktrace_free(stacktrace);
            stacktrace = NULL;
            break;
        }
    }

    stacktrace->executable = realpath(exe_file, NULL);
    stacktrace->signal = get_signal_number_libunwind(ui);
    /* FIXME: is this the best we can do? */
    stacktrace->crash_thread = stacktrace->threads;

    _UCD_destroy(ui);
fail_destroy_as:
    unw_destroy_addr_space(as);
fail_destroy_handle:
    core_handle_free(ch);

    return stacktrace;
}
Exemple #14
0
int
main(int ac, char** av)
{
  const char* outputFile = 0;
  const char* symbolFile = 0;
  int commandStart = 1;
  bool mainThreadOnly = false;

  for (int i = 1; i < ac; ++i) {
    if (strcmp(av[i], "-o") == 0) {
      if (i + 1 < ac) {
        outputFile = av[++i];
      } else {
        usage(av[0]);
        return -1;
      }
    } else if (strcmp(av[i], "-s") == 0) {
      if (i + 1 < ac) {
        symbolFile = av[++i];
      } else {
        usage(av[0]);
        return -1;
      }
    } else if (strcmp(av[i], "--main-thread-only") == 0) {
      mainThreadOnly = true;
    } else {
      commandStart = i;
      break;
    }
  }

  if (commandStart == ac) {
    usage(av[0]);
    return -1;
  }

  const char* command = av[commandStart];

  pid_t process = fork();
  if (process == 0) { // child
    execv(command, av + commandStart);
  } else if (process < 0) { // error
    fprintf(stderr, "unable to fork\n");
    return -1;
  } else { // parent
    struct sigaction action;
    action.sa_sigaction = handleSignal;
    action.sa_flags = SA_SIGINFO;

    sigaction(SIGCHLD, &action, 0);
    sigaction(SIGINT, &action, 0);

    timespec interval = { 0, 1000000L };

    Context context(process);

    space = unw_create_addr_space(&_UPT_accessors, __LITTLE_ENDIAN);

    while (not done) {
      sample(&context, mainThreadOnly);

      timespec remainder;
      do {
        if (nanosleep(&interval, &remainder)) {
          if (errno != EINTR) {
            fprintf(stderr, "nanosleep errno %s\n", strerror(errno));
            done = true;
          }
        } else {
          break;
        }
      } while ((not done) and (remainder.tv_sec or remainder.tv_nsec));
    }

    unw_destroy_addr_space(space);

    FILE* out = stdout;
    if (outputFile) {
      out = fopen(outputFile, "wb");
      if (out == 0) {
        fprintf(stderr, "unable to open %s\n", outputFile);
        return -1;
      }
    }

    SymbolTable* symbols = loadElfSymbols(command);

    if (symbolFile) {
      symbols = append(symbols, loadTextSymbols(symbolFile));
    }

    dump(&context, symbols, out);

    symbolTableDispose(symbols);

    if (outputFile) {
      fclose(out);
    }
  }

  return 0;
}
Exemple #15
0
void
trace_free(ptrace_context *ctx) {
    _UPT_destroy(ctx->unwind_rctx);
    unw_destroy_addr_space(ctx->addr_space);
    free(ctx->cmdline);
}
Exemple #16
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;
}
Exemple #17
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;
}
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;
}