MuBacktrace* get_backtrace(int skip) { MuBacktrace* trace, **out; void* buffer[100]; int num_frames; int i; char** symbols; num_frames = backtrace(buffer, sizeof(buffer) / sizeof(*buffer)); symbols = backtrace_symbols(buffer, num_frames); out = &trace; for (i = skip; i < num_frames; i++) { *out = calloc(1, sizeof(MuBacktrace)); fill_backtrace(*out, symbols[i]); out = &(*out)->up; } *out = NULL; return trace; }
int main(int argc, char *argv[]) { bool need_exit = false; ptrace_context ptrace_ctx; program_params params; struct itimerval itv; struct proc_timer proc_time; calltree_node *root = NULL; g_progname = argv[0]; if (!parse_args(¶ms, argc, argv)) usage(); print_message("Reading symbols (list of function)"); init_fndescr(params.pid); if (params.just_print_symbols) { print_symbols(); free_fndescr(); exit(0); } if (!reset_process_time(&proc_time, params.pid, params.prof_method)) { free_fndescr(); errx(2, "Failed to retrieve process time"); } print_message("Attaching to process: %d", params.pid); memset(&ptrace_ctx, 0, sizeof(ptrace_ctx)); if (!trace_init(params.pid, &ptrace_ctx)) err(1, "Failed to initialize unwind internals"); signal(SIGCHLD, on_sigchld); if (ptrace(PTRACE_ATTACH, params.pid, 0, 0) == -1) { int saved_errno = errno; warn("ptrace(PTRACE_ATTACH) failed"); if (saved_errno == EPERM) { printf("You have to see NOTES section of `man crxprof' for workarounds.\n"); } exit(2); } if (do_wait(&ptrace_ctx, true) != WR_STOPPED) err(1, "Error occured while stopping the process"); if (ptrace(PTRACE_CONT, params.pid, 0, 0) < 0) err(1, "Error occured while stopping the process 2"); /* interval timer for snapshots */ itv.it_interval.tv_sec = 0; itv.it_interval.tv_usec = params.us_sleep; itv.it_value = itv.it_interval; signal(SIGALRM, on_sigalarm); if (setitimer(ITIMER_REAL, &itv, NULL) == -1) err(1, "setitimer failed"); print_message("Starting profile (interval %dms)", params.us_sleep / 1000); print_message("Press ^C once to show profile, twice to quit"); signal(SIGINT, on_sigint); /* drop first meter since it contains our preparations */ (void)get_process_dt(&proc_time); while(!need_exit) { waitres_t wres = WR_NOTHING; sleep(1); if (timer_alarmed) { uint64_t proc_dt = get_process_dt(&proc_time); bool need_prof = (params.prof_method == PROF_REALTIME); if (params.prof_method == PROF_CPUTIME) { char st = get_procstate(&ptrace_ctx); if (st == 'R') need_prof = true; } if (need_prof) { kill(params.pid, SIGSTOP); wres = do_wait(&ptrace_ctx, true); if (wres == WR_STOPPED) { int signo_cont = (ptrace_ctx.stop_signal == SIGSTOP) ? 0 : ptrace_ctx.stop_signal; if (!get_backtrace(&ptrace_ctx)) err(2, "failed to get backtrace of process"); /* continue tracee ASAP */ if (ptrace_verbose(PTRACE_CONT, params.pid, 0, signo_cont) < 0) err(1, "ptrace(PTRACE_CONT) failed"); ptrace_ctx.nsnaps++; if (fill_backtrace(proc_dt, &ptrace_ctx.stk, &root)) ptrace_ctx.nsnaps_accounted++; } } } if (wres != WR_FINISHED && wres != WR_NEED_DETACH) { wres = discard_wait(&ptrace_ctx); } if (sigint_caught_twice) { need_exit = true; } else if (sigint_caught || wres == WR_FINISHED || wres == WR_NEED_DETACH) { if (root) { print_message("%" PRIu64 " snapshot interrputs got (%" PRIu64 " dropped)", ptrace_ctx.nsnaps, ptrace_ctx.nsnaps - ptrace_ctx.nsnaps_accounted); visualize_profile(root, ¶ms.vprops); if (params.dumpfile) dump_profile(root, params.dumpfile); } else print_message("No symbolic snapshot caught yet!"); sigint_caught = false; } if (wres == WR_FINISHED || wres == WR_NEED_DETACH) { if (wres == WR_NEED_DETACH) (void)ptrace_verbose(PTRACE_DETACH, params.pid, 0, ptrace_ctx.stop_signal); need_exit = true; } } free_fndescr(); trace_free(&ptrace_ctx); if (root) calltree_destroy(root); return 0; }