profile.c (2451B)
1 #define _GNU_SOURCE 2 3 #include <string.h> 4 #include <errno.h> 5 #include <stdio.h> 6 7 #include <sys/types.h> 8 #include <signal.h> 9 #include <unistd.h> 10 11 #include <sys/ptrace.h> 12 #include <sys/wait.h> 13 #include <sys/fcntl.h> 14 15 #include <pthread.h> 16 #include <libunwind.h> 17 #include <libunwind-ptrace.h> 18 19 #include "log.h" 20 #include "profile.h" 21 22 vec_t profile(pid_t tid) { 23 vec_t stack = vec_new(MAX_SYMLEN); 24 errno = 0; 25 ptrace(PTRACE_ATTACH, tid); 26 kill(tid, SIGSTOP); 27 waitpid(tid, NULL, 0); 28 void* ui = _UPT_create(tid); 29 unw_cursor_t c; 30 unw_addr_space_t as = unw_create_addr_space(&_UPT_accessors, 0); 31 unw_init_remote(&c, as, ui); 32 do { 33 unw_word_t offset; 34 char fname[MAX_SYMLEN] = {0}; 35 int resp = unw_get_proc_name(&c, fname, sizeof(fname), &offset); 36 vec_push(&stack, fname); 37 } while(unw_step(&c) > 0); 38 _UPT_resume(as, &c, ui); 39 _UPT_destroy(ui); 40 kill(tid, SIGSTOP); 41 waitpid(tid, NULL, 0); 42 ptrace(PTRACE_DETACH, tid, NULL, NULL); 43 return stack; 44 } 45 46 struct profile_node profile_node_new(char* name) { 47 struct profile_node out = { 48 .children = vec_new(sizeof(struct profile_node)), 49 .samples = 0, 50 .symbol = {0} 51 }; 52 strcpy(out.symbol, name); 53 return out; 54 } 55 56 struct profile_node profile_res_new() { 57 return profile_node_new(""); 58 } 59 60 int cmp_prof_node(void* _a, void* _b) { 61 struct profile_node* a = _a; 62 struct profile_node* b = _b; 63 return strcmp(a->symbol, b->symbol); 64 } 65 66 void profile_proc_stack(struct profile_node* prof_res, vec_t* stack) { 67 if (stack->vec_sz == 0) return; 68 struct profile_node* node = prof_res; 69 for (int i = stack->vec_sz-1; i > 0; i--) { 70 char* sym = vec_get(stack, i); 71 int index = vec_check(&node->children, sym, cmp_prof_node); 72 if (index == -1) { 73 struct profile_node new = profile_node_new(sym); 74 vec_push(&node->children, &new); 75 index = node->children.vec_sz - 1; 76 } 77 node = vec_get(&node->children, index); 78 node->samples += 1; 79 } 80 } 81 82 void profile_dump(struct profile_node* prof_res, int indent) { 83 struct profile_node* node = prof_res; 84 if (indent >= 0) { 85 for (int i = 0; i < indent; i++) printf(" "); 86 printf("%s (%d) \n", node->symbol, node->samples); 87 } 88 for (int i = 0; i < node->children.vec_sz; i++) { 89 profile_dump(vec_get(&node->children, i), indent+1); 90 } 91 }