LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   async stacktrace of a running process (https://www.linuxquestions.org/questions/linux-newbie-8/async-stacktrace-of-a-running-process-930166/)

Sasi19 02-19-2012 05:25 AM

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, &regs);
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.