LinuxQuestions.org
Visit Jeremy's Blog.
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie
User Name
Password
Linux - Newbie This Linux forum is for members that are new to Linux.
Just starting out and have a question? If it is not in the man pages or the how-to's this is the place!

Notices


Reply
  Search this Thread
Old 02-19-2012, 06:25 AM   #1
Sasi19
LQ Newbie
 
Registered: Feb 2012
Posts: 2

Rep: Reputation: Disabled
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;
}
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Async Stack trace of a running process Sasi19 Programming 0 02-16-2012 09:23 AM
[SOLVED] JRE dies with a stacktrace, pls hlp,tnx ButterflyMelissa Linux - Software 2 04-30-2011 07:26 AM
Get Process size and Thread count for a particular running process haseit Linux - Newbie 2 01-23-2009 12:09 AM
Shell Script : Kill a running process when another process starts ashmew2 Linux - General 3 08-20-2008 04:47 AM
async with udev ItsNotMe Linux - Newbie 1 04-19-2005 06:19 PM


All times are GMT -5. The time now is 02:46 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration