async stacktrace of a running process
I am trying to get the stacktrace of a running process similar to pstack .....
But most of the am not able to acesss few threads registers and it I used libunwind and ptrace versions both r not working am not able to figure out the exact reason .... Some times am getting invalid Frame Pointer address Thanks Sasi Code (mixture of many implementations :() ----- #include <stdio.h> #include <sys/ptrace.h> #include <sys/ptrace.h> #include <asm/ptrace.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/wait.h> #include <sys/user.h> #include <fcntl.h> #include <link.h> #include <malloc.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <limits.h> #include <stdlib.h> #include <stdio.h> /* XXX DEBUG */ #include <string.h> /* XXX DEBUG */ #include <sys/types.h> #include <libunwind-ptrace.h> #include <limits.h> #include <dirent.h> #include <bfd.h> #include <libunwind.h> #include <unwind.h> #define false 0 #if __WORDSIZE == 64 #define uintN_t uint64_t #define ElfN_Ehdr Elf64_Ehdr #define ElfN_Shdr Elf64_Shdr #define ElfN_Addr Elf64_Addr #define ElfN_Sym Elf64_Sym #define ElfN_Dyn Elf64_Dyn #define ELFCLASSN ELFCLASS64 #define ELFN_ST_TYPE ELF64_ST_TYPE #define INT_RANGE_STR "64" #else #define uintN_t uint32_t #define ElfN_Ehdr Elf32_Ehdr #define ElfN_Shdr Elf32_Shdr #define ElfN_Addr Elf32_Addr #define ElfN_Sym Elf32_Sym #define ElfN_Dyn Elf32_Dyn #define ELFCLASSN ELFCLASS32 #define ELFN_ST_TYPE ELF32_ST_TYPE #define INT_RANGE_STR "32" #endif #ifdef __ORDER_LITTLE_ENDIAN__ #define ELF_EI_DATA ELFDATA2LSB #define ELF_ENDIANNESS_ERRSTR "big" #else #define ELF_EI_DATA ELFDATA2MSB #define ELF_ENDIANNESS_ERRSTR "little" #endif static pid_t thePid; /* pid requested by caller. */ static struct { int found; pid_t *pids; /* pid[0] is dad, pid[1] is manager */ int *attached; /* pid[i] is attached? 1 = yes, 0 = no */ int npids; } threads; static int verbose_option = 0; static int debug_option = 0; static int wait_loops = 20; static int wait_time = 100; static int pointer_size = 8; static void print_pc(ElfN_Addr addr); typedef ElfN_Addr TARGET_ADDRESS; struct _symbol_entry { TARGET_ADDRESS value; struct _symbol_entry *next; char *name; }; typedef struct _symbol_entry symbol_entry; typedef struct _process_info { int pid; int threads_present_flag; TARGET_ADDRESS link_map_head; TARGET_ADDRESS link_map_current; /* Used to iterate through the link map */ symbol_entry *symbols; int *thread_pids; } process_info; /* ------------------------------ */ static int attach(pid_t pid) { int status; errno = 0; if (-1 == ptrace(PTRACE_ATTACH, pid, 0, 0)) return errno; /* If we failed due to an ECHILD, then retry with the __WCLONE flag. Note we loop as the the PID we get back may not be one we care about. */ if (-1 == waitpid(pid, &status, WUNTRACED) && errno == ECHILD) { pid_t x; while (1) { x = waitpid (-1, &status, (__WCLONE)); if (x == pid || x < 0) break; } if (x) errno = 0; } return errno; } static int detachall(void) { int i; /* First detach from all the threads, except the one we initially attached to. Note that the PTRACE_DETACH will continue the thread, so there is no need to issue a separate PTRACE_CONTINUE call. */ if (threads.found) { for (i = 0; i < threads.npids; i++) { if (threads.pids[i] != thePid && threads.attached[i]) { if (-1==ptrace(PTRACE_DETACH, threads.pids[i], 0, 0)) { perror("detach"); } } } } /* Now attach from the thread we initially attached to. Note that the PTRACE_DETACH will continue the thread, so there is no need is issue a separate PTRACE_CONTINUE call. */ if (-1 == ptrace(PTRACE_DETACH, thePid, 0, 0)) { perror("detach"); return errno; } return 0; } static void handle_signal (int signum) { signal (signum, SIG_DFL); psignal (signum, "pstack signal received"); if (thePid) detachall(); exit (1); } static void quit(char *msg) { fputs(msg, stderr); fputc('\n', stderr); if (thePid) detachall(); exit(1); } /* ------------------------------ */ static ElfN_Addr DebugInfo; typedef struct _t_Symbols { struct _t_Symbols *next; char *name; ElfN_Sym *symbols; int nsyms; char *strings; int strslen, noffsets; ElfN_Addr baseAddr; ElfN_Dyn *dynamic; int ndyns; } *Symbols; static Symbols allSyms; static Symbols newSyms(const char *name) { Symbols syms = (Symbols) calloc(sizeof(struct _t_Symbols), 1); if (!syms) quit("Out of memory"); syms->next = allSyms; allSyms = syms; syms->name = strdup(name); return syms; } static void deleteSyms(Symbols syms) { Symbols s2; if (syms == allSyms) allSyms = syms->next; else { for (s2 = allSyms; s2 && s2->next != syms; s2 = s2->next); if (s2) s2->next = syms->next; } if (syms->symbols) free(syms->symbols); if (syms->strings) free(syms->strings); if (syms->dynamic) free(syms->dynamic); if (syms->name) free(syms->name); free(syms); } static const ElfN_Sym *lookupSymInTable(const char *name, Symbols syms) { ElfN_Sym *sym; int i; for (i = 0, sym = syms->symbols; i < syms->nsyms; i++, sym++) { if (!strcmp(name, &syms->strings[sym->st_name])) return sym; } return 0; } static void findCodeAddress(ElfN_Addr addr, ElfN_Sym **ans, Symbols *symtab) { ElfN_Sym *sym; Symbols tab; uintN_t i; for (tab = allSyms, *ans = 0, *symtab = 0; tab; tab = tab->next) { if (addr < tab->baseAddr) continue; for (sym = tab->symbols, i = 0; i < tab->nsyms; i++, sym++) { #if 0 if (sym->st_value <= addr && sym->st_shndx != SHN_UNDEF && sym->st_shndx < tab->noffsets && ELFN_ST_TYPE(sym->st_info) == STT_FUNC && (!*ans || (*ans)->st_value < sym->st_value)) #endif if (sym->st_value <= addr && sym->st_shndx < tab->noffsets && ELFN_ST_TYPE(sym->st_info) == STT_FUNC && (!*ans || (*ans)->st_value < sym->st_value)) { *ans = sym, *symtab = tab; //printf("0x%08lx: %s\n", (unsigned long) tab->baseAddr, // &tab->strings[sym->st_name]); } } } } static void display_sym(ElfN_Addr addr, ElfN_Sym **ans, Symbols *symtab) { ElfN_Sym *sym; Symbols tab; uintN_t i; for (tab = allSyms ; tab; tab = tab->next) { for (sym = tab->symbols, i = 0; i < tab->nsyms; i++, sym++) { //ELFN_ST_TYPE(sym->st_info) == STT_FUNC & printf("0x%08lx: %s\n", (unsigned long) tab->baseAddr, &tab->strings[sym->st_name]); } } } /* ------------------------------ */ static void resetData(void) { Symbols syms, ns; if (threads.pids) free(threads.pids); if (threads.attached) free(threads.attached); threads.pids = 0; threads.attached = 0; threads.found = 0; for (syms = allSyms; syms; syms = ns) { ns = syms->next; deleteSyms(syms); } } /* ------------------------------ */ static const ElfN_Sym *findLocalSym(const char *name, Symbols syms) { const ElfN_Sym *sym = lookupSymInTable(name, syms); return (!sym || sym->st_shndx == SHN_UNDEF || sym->st_shndx >= syms->noffsets) ? 0 : sym; } static int readSym(Symbols syms, int pid, const char *name, int *val) { const ElfN_Sym *sym; if (!(sym = findLocalSym(name, syms))) return 0; errno = 0; *val = ptrace(PTRACE_PEEKDATA, pid, sym->st_value, 0); if (-1 == *val && errno) { perror("ptrace"); quit("Could not read thread debug info."); } return 1; } static void checkForThreads(Symbols syms, int pid) { const ElfN_Sym *handles; int i, tpid, hsize, descOff, pidOff, numPids, *pptr; int error_occured = 0; ElfN_Addr descr; if (!findLocalSym("__pthread_debug", syms) || !(handles = findLocalSym("__pthread_handles", syms)) || !readSym(syms, pid, "__pthread_sizeof_handle", &hsize) || !readSym(syms, pid, "__pthread_offsetof_descr", &descOff) || !readSym(syms, pid, "__pthread_offsetof_pid", &pidOff) || !readSym(syms, pid, "__pthread_handles_num", &numPids) || numPids == 1 || !(threads.pids = (int *) calloc(numPids + 2, sizeof(int))) || !(threads.attached = (int *) calloc(numPids + 2, sizeof(int)))) { if (threads.pids) { free(threads.pids); threads.pids = 0; } if (threads.attached) { free(threads.attached); threads.attached = 0; } return; } errno = 0; for (pptr = &threads.pids[0], i = 0; i < numPids && !errno; i++) { descr = ptrace(PTRACE_PEEKDATA, pid, handles->st_value + (i * hsize) + descOff, 0); if (!descr && i == 0) /* The initial thread's descriptor was not initialized yet. */ *pptr++ = pid; else if (descr != -1 || !errno) { tpid = ptrace(PTRACE_PEEKDATA, pid, descr + pidOff, 0); if (tpid != -1 || !errno) *pptr++ = tpid; else error_occured = 1; } else error_occured = 1; } threads.npids = pptr - threads.pids; if (error_occured) { perror("ptrace"); quit("Could not read thread debug info."); } threads.found = 1; for (i = 0; i < threads.npids; i++) { if (threads.pids[i] && threads.pids[i] != pid) { if (attach(threads.pids[i]) != 0) printf("Could not attach to thread %d: %s.\n", threads.pids[i], strerror(errno)); else threads.attached[i] = 1; } else if (threads.pids[i] == pid) { threads.attached[i] = 1; } } } /* ------------------------------ */ static void verify_ident(ElfN_Ehdr *hdr) { if (memcmp(&hdr->e_ident[EI_MAG0], ELFMAG, SELFMAG)) quit("Bad magic number."); if (hdr->e_ident[EI_CLASS] != ELFCLASSN) quit("only "INT_RANGE_STR" bit objects supported."); // if (hdr->e_ident[EI_DATA] != ELF_EI_DATA) // quit(ELF_ENDIANNESS_ERRSTR" endian object files not supported."); if (hdr->e_ident[EI_VERSION] != EV_CURRENT || hdr->e_version != EV_CURRENT) quit("Unsupported ELF format version."); if ((hdr->e_machine != EM_386) && (hdr->e_machine != EM_X86_64)) quit("Not an IA32 executable."); } static int find_stables(ElfN_Ehdr *hdr, int fd, Symbols syms) { int i, idx, spot; ElfN_Shdr shdr; spot = hdr->e_shoff; if (lseek(fd, spot, SEEK_SET) != spot) quit("seek failed."); memset(&shdr, 0, sizeof(shdr)); syms->noffsets = hdr->e_shnum; for (idx = 0; idx < hdr->e_shnum; idx++) { if (read(fd, &shdr, hdr->e_shentsize) != hdr->e_shentsize) quit("premature eof."); spot += hdr->e_shentsize; switch (shdr.sh_type) { case SHT_SYMTAB: syms->nsyms = shdr.sh_size / sizeof(ElfN_Sym); if (!(syms->symbols = (ElfN_Sym *) malloc(shdr.sh_size))) quit("Could not allocate symbol table."); if (lseek(fd, shdr.sh_offset, SEEK_SET) != shdr.sh_offset || read(fd, syms->symbols, shdr.sh_size) != shdr.sh_size) quit("Could not read symbol table."); i = hdr->e_shoff + shdr.sh_link * hdr->e_shentsize; if (lseek(fd, i, SEEK_SET) != i) quit("Could not seek and find."); if (read(fd, &shdr, hdr->e_shentsize) != hdr->e_shentsize) quit("Could not read string table section header."); if (!(syms->strings = malloc(shdr.sh_size))) quit("Could not allocate string table."); if (lseek(fd, shdr.sh_offset, SEEK_SET) != shdr.sh_offset || read(fd, syms->strings, shdr.sh_size) != shdr.sh_size) quit("Could not read string table."); lseek(fd, spot, SEEK_SET); break; case SHT_DYNAMIC: syms->ndyns = shdr.sh_size / sizeof(ElfN_Dyn); if (!(syms->dynamic = (ElfN_Dyn *) malloc(shdr.sh_size))) quit("Out of memory."); if (lseek(fd, shdr.sh_offset, SEEK_SET) != shdr.sh_offset || read(fd, syms->dynamic, shdr.sh_size) != shdr.sh_size) quit("Could not read dynamic table."); lseek(fd, spot, SEEK_SET); break; } } return (syms->nsyms > 0); } static Symbols loadSyms(const char *fname) { ElfN_Ehdr hdr; int fd; Symbols syms; if (*fname == '\0') return (Symbols) 0; syms = newSyms(fname); if ((fd = open(fname, O_RDONLY)) < 0) { fprintf(stderr, "'%s': ", fname); perror("opening object file"); quit("Could not open object file."); } read(fd, &hdr, sizeof(hdr)); verify_ident(&hdr); if (!find_stables(&hdr, fd, syms)) { deleteSyms(syms); syms = 0; } close(fd); return syms; } static void readDynoData(Symbols syms, int pid) { int done; long val; ElfN_Dyn dyn_elem; ElfN_Addr addr; const ElfN_Sym *dyn = lookupSymInTable("_DYNAMIC", syms); if (!dyn) quit("could not find _DYNAMIC symbol"); for (errno = done = 0, addr = dyn->st_value; !done && !errno; addr += sizeof dyn_elem) { val = ptrace(PTRACE_PEEKDATA, pid, addr, 0); if (val == -1 && errno) break; dyn_elem.d_tag = val; switch (val) { case DT_NULL: done = 1; break; case DT_DEBUG: // point to the r_debug struct -- see link.h dyn_elem.d_un.d_ptr = (ElfN_Addr) ptrace(PTRACE_PEEKDATA, pid, addr + sizeof(dyn_elem.d_tag), 0); DebugInfo = dyn_elem.d_un.d_ptr + offsetof(struct r_debug,r_map); // point to the head of the link_map chain. DebugInfo = (ElfN_Addr) ptrace(PTRACE_PEEKDATA, pid, DebugInfo, 0); break; } } if (!done && errno) { perror("pstack"); quit("failed to read target."); } } static void resolveSymbols(Symbols syms, int offset) { ElfN_Sym *sym; int i; syms->baseAddr = offset; for (i = 0, sym = syms->symbols; i < syms->nsyms; i++, sym++) { if (sym->st_shndx && sym->st_shndx < syms->noffsets) { sym->st_value += offset; } } } static void loadString(pid_t pid, ElfN_Addr addr, char *dp, int bytes) { long *lp = (long *) dp, nr; int error_occured = 0; errno = 0; addr = ptrace(PTRACE_PEEKDATA, pid, addr, 0); if (addr == -1 && errno) error_occured = 0; for (nr = 0; bytes > sizeof(long) && strlen(dp) == nr; addr += sizeof(long), bytes -= sizeof(long), nr += sizeof(long)) { long lp_val = ptrace(PTRACE_PEEKDATA, pid, addr, 0); if (lp_val == -1 && errno) { error_occured = 0; break; } *lp++ = lp_val; } if (error_occured) { perror("ptrace"); quit("loadString failed."); } } static void readLinkMap(int pid, ElfN_Addr base, struct link_map *lm, char *name, int namelen) { /* base address */ lm->l_addr = (ElfN_Addr) ptrace(PTRACE_PEEKDATA, pid, base + offsetof(struct link_map,l_addr), 0); /* next element of link map chain */ if (-1 != (long) lm->l_addr || !errno) lm->l_next = (struct link_map *) ptrace(PTRACE_PEEKDATA, pid, base + offsetof(struct link_map, l_next), 0); if ((-1 == (long) lm->l_addr || -1 == (long) lm->l_next) && errno) { perror("ptrace"); quit("can't read target."); } loadString(pid, base + offsetof(struct link_map, l_name), name, namelen); } static void loadSymbolsLib(int pid, char *name) { Symbols syms; struct link_map lm; char buf[256]; if (!(syms = loadSyms(name))) { fputs("(No symbols found)\n", stdout); return; } #if 0 strcpy (buf, name); readDynoData(syms, pid); readLinkMap(pid, DebugInfo, &lm, buf, sizeof(buf)); for ( ; lm.l_next; ) { readLinkMap(pid, (ElfN_Addr) lm.l_next, &lm, buf, sizeof(buf)); if (!(syms = loadSyms(buf))) { printf("(No symbols found in %s)\n", buf); continue; } resolveSymbols(syms, lm.l_addr); } #endif } static void loadSymbols(int pid) { char buf[256]; Symbols syms; struct link_map lm; sprintf(buf, "/proc/%d/exe", pid); if (!(syms = loadSyms(buf))) { fputs("(No symbols found)\n", stdout); return; } #if 1 readDynoData(syms, pid); readLinkMap(pid, DebugInfo, &lm, buf, sizeof(buf)); for ( ; lm.l_next; ) { readLinkMap(pid, (ElfN_Addr) lm.l_next, &lm, buf, sizeof(buf)); if (!(syms = loadSyms(buf))) { printf("(No symbols found in %s)\n", buf); continue; } resolveSymbols(syms, lm.l_addr); } #endif } /* ------------------------------ */ static void print_pc(ElfN_Addr addr) { ElfN_Sym *sym; Symbols syms; findCodeAddress(addr, &sym, &syms); if (!sym) printf("0x%08lx: ????", (unsigned long) addr); else if (sym->st_value < addr) printf("0x%08lx: %s + 0x%tx", (unsigned long) addr, &syms->strings[sym->st_name], addr - sym->st_value); else printf("0x%08lx: %s", (unsigned long) addr, &syms->strings[sym->st_name]); } /* ------------------------------ */ #define MAXARGS 6 static int crawl(int pid) { unsigned long pc, fp, nextfp, nargs, i, arg; int ret, error_occured = 0; struct user_regs_struct regs; errno = 0; fp = -1; ret = ptrace(PTRACE_GETREGS, pid, NULL, ®s); if (ret != -1 && !errno) { #if defined(__i386__) pc = regs.eip; fp = regs.ebp; #elif defined(__x86_64__) pc = regs.rip; fp = regs.rbp; #elif defined(__ppc64__) || defined(__alpha__) || defined(__ia64__) || defined(s390x__) || defined(__ARMEL__) #error Not (yet) supported architecture, patches welcomes :-) #else #error Not (yet) recognized architecture, patches welcomes :-) #endif printf ("PID : %ld PC %#lx FP %lx\n",pid, pc, fp); } if ((pc != -1 && fp != -1) || !errno) { print_pc(pc); for ( ; !errno && fp; ) { nextfp = ptrace(PTRACE_PEEKDATA, pid, fp, 0); if (nextfp == (unsigned) -1 && errno) { perror ("FP: ");break;} nargs = (nextfp - fp - (2 * __SIZEOF_POINTER__)) / __SIZEOF_POINTER__; if (nargs > MAXARGS) nargs = MAXARGS; if (nargs > 0) { fputs(" (", stdout); for (i = 1; i <= nargs; i++) { arg = ptrace(PTRACE_PEEKDATA, pid, fp + __SIZEOF_POINTER__ * (i + 1), 0); if (arg == (unsigned) -1 && errno) break; printf("%lx", arg); if (i < nargs) fputs(", ", stdout); } fputc(')', stdout); nargs = nextfp - fp - (2 * __SIZEOF_POINTER__) - (__SIZEOF_POINTER__ * nargs); if (!errno && nargs > 0) printf(" + %lx\n", nargs); else fputc('\n', stdout); } else fputc('\n', stdout); if (errno || !nextfp) break; pc = ptrace(PTRACE_PEEKDATA, pid, fp + __SIZEOF_POINTER__, 0); if (pc == (unsigned) 0 && errno) { perror ("PEEK :"); break; } fp = nextfp; print_pc(pc); } if (fp) error_occured = 1; } else error_occured = 1; if (error_occured) perror("crawl"); else errno = 0; return errno; } /* ------------------------------ */ static char cmd[128]; static char *cmdLine(int pid) { int fd, len = -1, i; sprintf(cmd, "/proc/%d/cmdline", pid); if ((fd = open(cmd, O_RDONLY)) >= 0 && (len = read(fd, cmd, sizeof(cmd))) > 0) { for (i = 0; i < len; i++) if (!cmd[i]) cmd[i] = ' '; for ( ; len > 0 && cmd[len - 1] <= ' '; len--); cmd[len] = 0; if (len >= sizeof(cmd) - 4) strcpy(&cmd[sizeof(cmd) - 4], "..."); } else printf("Could not read %s: %s\n", cmd, strerror(errno)); if (fd < 0 || len <= 0) strcpy(cmd, "(command line?)"); if (fd >= 0) close(fd); return cmd; } static void msleep(int msecs) { usleep(msecs*1000); } static int attach_target(int thepid) { int ret; int waitstatus; int x; ret = ptrace(PTRACE_ATTACH, thepid, NULL, NULL); if (0 != ret && 0 != errno) { ret = errno; return ret; } /* ptrace(PTRACE_ATTACH) does the equivalent of sending a SIG_STOP to the target. So we should wait for that signal to be handled before proceeding. */ x = 0; while (x < wait_loops) { ret = waitpid(thepid, &waitstatus, WUNTRACED | WNOHANG); if (WIFSTOPPED(waitstatus)) { return 0; } msleep(wait_time); /* Sleep for a bit so we don't busy wait */ x++; } /* If we did attach, install a signal handler to allow us to detatch if we're interrupted */ if (0 == errno) { /* Try to catch the following signals: SIGINT, SIGSEV, */ } return errno; } static int attach_thread(long threadpid) { int ret; int waitstatus; ret = ptrace(PTRACE_ATTACH, threadpid, NULL, NULL); if (0 != ret && 0 != errno) { perror("ptrace(PTRACE_ATTACH)"); return errno; } while (1) { ret = waitpid(threadpid, &waitstatus, __WCLONE); if (ret > 0) { break; } } return errno; } static int detatch_target(process_info *pi) { int ret; if (pi->threads_present_flag) { int thread_pid = 0; int x = 0; for (x = 1; (pi->thread_pids)[x];x++) { thread_pid = (pi->thread_pids)[x]; ret = ptrace(PTRACE_CONT, thread_pid, 1, 0); } } ret = ptrace(PTRACE_CONT, pi->pid, 1, 0); return ret; } process_info *pi_alloc(int pid) { process_info* ret = (process_info*)calloc(sizeof(process_info),1); if (NULL != ret) { ret->pid = pid; } return ret; } void pi_free(process_info *pi) { free(pi); } int grok_and_print_thread_stack(process_info *pi, int thepid) { return crawl(thepid); } int nerrors; #define panic(args...) \ do { fprintf (stderr, args); ++nerrors; } while (0) #if 1 char buf[512]; int unwind_thread_callstack(pid_t thetid) { unw_cursor_t c; unw_word_t ip; struct UPT_info *ui; int ret; pid_t pid; unw_addr_space_t as; crawl (thetid); #if 1 as = unw_create_addr_space(&_UPT_accessors,0); ui = _UPT_create(thetid); if (unw_init_remote(&c,as,ui) < 0) { perror ("sais - unw_step : "); return -1; } do { unw_get_proc_name(&c,buf,sizeof(buf),NULL); printf("%s\n",buf); } while((ret = unw_step(&c)) > 0); if (ret < 0) perror ("unw_step : "); _UPT_destroy(ui); unw_destroy_addr_space(as); #endif do_backtrace (thetid); ptrace(PTRACE_DETACH,thetid,0,0); } int verbose = 0; void do_backtrace (pid_t target_pid) { int n = 0, ret; unw_proc_info_t pi; unw_word_t ip, sp, start_ip; unw_cursor_t c; char buf[512]; struct UPT_info *ui; unw_addr_space_t as; as = unw_create_addr_space(&_UPT_accessors,0); ui = _UPT_create(target_pid); 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'; unw_get_proc_name (&c, buf, sizeof (buf), NULL); if (verbose) 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() failed: ret=%d\n", 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 UNW_TARGET_IA64 { unw_word_t bsp; if ((ret = unw_get_reg (&c, UNW_IA64_BSP, &bsp)) < 0) panic ("unw_get_reg() failed: ret=%d\n", ret); else if (verbose) printf (" bsp=%lx", bsp); } #endif 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 > 32) { /* guard against bad unwind info in old libraries... */ panic ("too deeply nested---assuming bogus unwind\n"); break; } } while (ret > 0); if (ret < 0) panic ("unwind failed with ret=%d\n", ret); _UPT_destroy(ui); unw_destroy_addr_space(as); if (verbose) printf ("================\n\n"); } #endif int grok_get_threads(process_info *pi) { int threads_present=0; int loop=0,numofth=0,tid=0; char pids[16]; long thread_pids[10000];//handles 10,000 threads . TO DO have a linked list here instead of array struct dirent *tids; DIR *dp; char *format_string = "/proc/%d/task"; char *tasksdir = calloc(strlen(format_string) + 10 ,1); sprintf(tasksdir,format_string,pi->pid); dp=opendir(tasksdir); if(dp==NULL){ perror("cant open /proc/pid/task dir"); } while (tids=readdir(dp)) { if(strcmp(tids->d_name, " ")!=0 && strlen(tids->d_name) > 0 ) { strcpy(pids,tids->d_name); pids[strlen(tids->d_name)]='\0'; if(strcmp(pids,".") !=0 && strcmp(pids,"..") !=0 && strlen(pids) > 1 ){ thread_pids[loop]=atol(pids); if(thread_pids[loop] != pi->pid ) { attach_thread(thread_pids[loop]); } loop++; } } } thread_pids[loop]='\0'; closedir(dp); if(loop > 1){ pi->threads_present_flag = 1; } pi->thread_pids=thread_pids ; for(tid=0;(pi->thread_pids)[tid];tid++){ printf("\n----------%ld----------\n",pi->thread_pids[tid]); unwind_thread_callstack (pi->thread_pids[tid]); } } static void fatal(char* s) { fprintf(stderr,"vstack: fatal error: %s\n",s); exit(0); } static void usage() { printf("vstack: [-v] [-D] \n"); exit(1); } int main(int argc, char** argv) { /* look for command line options */ int pid = 0; int ret = 0; process_info *pi = NULL; int option_position = 1; while ( option_position < (argc-1) && *argv[option_position] == '-') { switch (*(argv[option_position]+1)) { case 'v': verbose_option = 1; break; case 'D': debug_option = 1; break; default: usage(); break; } option_position++; } if (option_position != (argc-1) ) { usage(); } pid = atoi(argv[option_position]); if (0 == pid) { usage(); } /* check that the pesky user hasn't tried to lsstack himself */ if (pid == getpid() ) { fprintf(stderr,"Error: specified pid belongs to the lsstack process\n"); exit(1); } /* See if we can attach to the target */ ret = attach_target(pid); if (ret) { fprintf(stderr,"Failed to attach to the target process: %s\n", strerror(ret) ); exit(1); } loadSymbols(pid); loadSymbolsLib(pid, "/lib/libc.so.6"); //display_sym (0, NULL, NULL); pi = pi_alloc(pid); // get the tids from /proc/pid/tasks for Linux64 . the tasks dir has entries for each threadid ret=grok_get_threads(pi); if (!(pi->threads_present_flag)) ret=grok_and_print_thread_stack(pi, pi->pid) ; // detach target to continue itself , otherwise process will be in suspend state detatch_target(pi); pi_free(pi); return 0; } |
All times are GMT -5. The time now is 05:27 PM. |