Compare commits

...

16 Commits

Author SHA1 Message Date
Matteo Cypriani 150a89bb40 README.md: improve markup 2016-11-02 01:16:55 +01:00
Thomas Preud'homme 6dbd036eea Rename README to accomodate gogs 2016-11-01 21:25:14 +00:00
Thomas Preud'homme f0aa8400b7 Ignore VDSO object
Do not try to load symbols from VDSO as it does not correspond to any
file on disk.
2014-02-28 23:27:45 +08:00
Thomas Preud'homme d75a8ea2a1 Makefile cleaning
Use $^ instead of explicitely listing .c files in recipe.
2012-10-22 11:22:05 +02:00
Thomas Preud'homme fe2590b471 Honour *FLAGS
Honour CPPFLAGS and LDFLAGS in addition to CFLAGS
2012-10-22 11:21:13 +02:00
Thomas Preud'homme 8ade3d5cb9 New release: pstack 1.3.1 2011-10-05 22:57:10 +02:00
Thomas Preud'homme 8a440f169b Error out if no object file header
Quit the program if object file header can't be read or is smaller than
expected.
2011-10-05 22:56:37 +02:00
Thomas Preud'homme a8f2e34c5f Make struct used by PTRACE_GETREGS arch-dependant
Structure used by ptrace in PTRACE_GETREGS mode is unfortunetely
arch-dependant. Although pt_regs seems portable, it's only designed to
represent the way registers are stored on the stack during system call.
The right struct to use is defined in sys/user.h and is
user_regs_struct on x86-{32,64} and user_regs on armel.
2011-10-05 17:38:17 +02:00
Thomas Preud'homme 1cede92011 Compile with -g -O2 by default
Change default CFLAGS (CFLAGS not overriden and no CFLAGS in
environment) to add debugging symbol and optimize the generated code.
2011-10-05 17:38:17 +02:00
Thomas Preud'homme c86ed77fb2 Don't include .*ignore files in archives
* Remove .cvsignore
* Exclude .gitignore and .gitattribute itself from archives produced
  with git archive
2011-10-03 22:51:02 +02:00
Thomas Preud'homme 3ec09496b9 Rewrite archive and cvstag make rules for git
* Rename cvstag to gittag
* Adapt archive and gittag make rules to git
2011-10-03 22:51:02 +02:00
Thomas Preud'homme 27599168da Support DESTDIR and PREFIX variables in Makefile
* Add support for DESTDIR and PREFIX variables in Makefile.
  PREFIX defaults to /usr and DESTDIR is not defined by default.
* Redefine MANDIR and BINDIR in function of PREFIX and DESTDIR. Note
  that DESTDIR for overriden variables (variables defined via make
  VAR=value construct)
2011-10-03 21:47:55 +02:00
Thomas Preud'homme ee32fa3624 Respect CFLAGS from the environment 2011-10-03 19:36:33 +02:00
Thomas Preud'homme d0e37451f5 Remove distribution specific variables in Makefile
Remove everything related to RPM_OPT_FLAGS variable in Makefile.
2011-10-03 19:35:16 +02:00
Thomas Preud'homme b455f99538 Add -Wextra flags to CFLAGS and fix warnings 2011-10-03 19:32:16 +02:00
Thomas Preud'homme 6f25ab2494 Fix incorrect ptrace failure tests in crawl() 2011-10-02 23:50:22 +02:00
7 changed files with 89 additions and 55 deletions

View File

@ -1 +0,0 @@
pstack

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
.gitignore export-ignore
.gitattributes export-ignore

View File

@ -15,33 +15,37 @@
#
VERSION = $(shell awk 'END { print $$1 }' VERSION)
CFLAGS = -Wall -DVERSION=\"$(VERSION)\" $(RPM_OPT_FLAGS)
CFLAGS ?= -Wall -Wextra -g -O2
CPPFLAGS += -DVERSION=\"$(VERSION)\"
# Note: assignments are ignored for variable overriden on command line VAR=value
# so DESTDIR is ignored for overriden variables
PREFIX ?= /usr
BINDIR ?= $(PREFIX)/bin
BINDIR := $(DESTDIR)$(BINDIR)
MANDIR ?= $(PREFIX)/share/man
MANDIR := $(DESTDIR)$(MANDIR)
ifeq ($(RPM_OPT_FLAGS),)
CFLAGS += -g
LDFLAGS += -g
endif
pstack : pstack.c
$(CC) $(CFLAGS) -o pstack pstack.c
$(CC) $(CPPFLAGS) $(CFLAGS) -o pstack $^ $(LDFLAGS)
clean:
rm -f pstack
install : pstack
mkdir -p $(BINDIR)
install -m 755 pstack $(BINDIR)
mkdir -p $(MANDIR)/man1
install -m 644 man1/pstack.1 $(MANDIR)/man1
mkdir -p "$(BINDIR)"
install -m 755 pstack "$(BINDIR)"
mkdir -p "$(MANDIR)/man1"
install -m 644 man1/pstack.1 "$(MANDIR)/man1"
cvstag:
cvs tag -F $(CVSTAG) .
gittag:
git tag -s pstack-$(VERSION)
archive: cvstag
@rm -rf /tmp/pstack-$(VERSION) /tmp/pstack
@cd /tmp; cvs export -r$(CVSTAG) pstack; mv pstack pstack-$(VERSION)
@cd /tmp; tar czSpf pstack-$(VERSION).tar.gz pstack-$(VERSION)
@rm -rf /tmp/pstack-$(VERSION)
archive: gittag
@rm -rf /tmp/pstack-$(VERSION).tar.gz
@git archive -o /tmp/pstack-$(VERSION).tar --prefix=pstack-$(VERSION)/ pstack-$(VERSION)
@cd /tmp; gzip -9 pstack-$(VERSION).tar
@cp /tmp/pstack-$(VERSION).tar.gz .
@echo " "
@echo ""
@echo "The final archive is ./pstack-$(VERSION).tar.gz."

View File

@ -1,4 +1,4 @@
pstack - print stack trace of running processes
# pstack - print stack trace of running processes
pstack dumps a stack trace for a process, given the pid of that
process. If the process named is part of a thread group, then all the threads
@ -6,8 +6,9 @@ inthe group are traced. See the man page for more information.
This program was inspired by the 'pstack' program available on Solaris.
SUPPORTED PLATFORMS:
This program runs on 32 bit x86 machines, using ELF binaries
## Supported Platforms
This program runs on 32 bit x86 machines, using ELF binaries
generated from GNU compilers. If threads are being used, it depends
on a debuggable version of the pthreads library to find the threads in
the thread group. If anyone wants to port this to other
@ -15,22 +16,20 @@ architectures, please let me know about questions you may have, or
achievements you have made. I'd like to incorporate such changes into
my version of the code.
FEATURES:
symbolic address dumping
thread group support
## Features
BUILD:
make
* symbolic address dumping
* thread group support
INSTALL:
make install
## Build, install, uninstall
UNINSTALL:
make uninstall
make
make install
make uninstall
NOTE: you must be root to [un]install. pstack will run fine from any
**Note:** you must be root to [un]install. pstack will run fine from any
directory, install just puts the binary and man page in 'normal'
places (/usr/local/...)
places (`/usr/local/...`)
USAGE:
pstack pid [...]

View File

@ -2,3 +2,4 @@
1.1 25/Feb/2002
1.2 12/Nov/2003
1.3 02/Oct/2011
1.3.1 03/Oct/2011

View File

@ -1,3 +1,17 @@
** pstack 1.3.1 **
Thomas Preud'homme (6):
Fix incorrect ptrace failure tests in crawl()
Add -Wextra flags to CFLAGS and fix warnings
Remove distribution specific variables in Makefile
Respect CFLAGS from the environment
Support DESTDIR and PREFIX variables in Makefile
Rewrite archive and cvstag make rules for git
Don't include .*ignore files in archives
Compile with -g -O2 by default
Make struct used by PTRACE_GETREGS arch-dependant
Error out if no object file header
** pstack 1.3 **
Baruch Even (1):
@ -15,4 +29,3 @@ Thomas Preud'homme (12):
Add support for armel architecture
Include <endian.h> as fallback for endianness
Do not call perror in crawl() if no ptrace error

View File

@ -66,6 +66,7 @@
#define ElfN_Addr Elf64_Addr
#define ElfN_Sym Elf64_Sym
#define ElfN_Dyn Elf64_Dyn
#define ElfN_Off Elf64_Off
#define ELFCLASSN ELFCLASS64
#define ELFN_ST_TYPE ELF64_ST_TYPE
#define INT_RANGE_STR "64"
@ -76,6 +77,7 @@
#define ElfN_Addr Elf32_Addr
#define ElfN_Sym Elf32_Sym
#define ElfN_Dyn Elf32_Dyn
#define ElfN_Off Elf32_Off
#define ELFCLASSN ELFCLASS32
#define ELFN_ST_TYPE ELF32_ST_TYPE
#define INT_RANGE_STR "32"
@ -112,12 +114,16 @@
#endif /* x86-{32,64} */
#define NEXT_FRAME_POINTER_ADDR(fp) (fp)
#define NEXT_PROGRAM_COUNTER_ADDR(fp) ((fp) + __SIZEOF_POINTER__)
#define DECLARE_REGS_STRUCT(regs) struct user_regs_struct regs
#define VDSO_NAME "linux-vdso.so.1"
#elif defined(__ARMEL__) /* armel */
#define ELF_MACHINE EM_ARM
#define PROGRAM_COUNTER(regs) (regs.ARM_pc)
#define FRAME_POINTER(regs) (regs.ARM_fp)
#define NEXT_FRAME_POINTER_ADDR(fp) ((fp) - __SIZEOF_POINTER__)
#define NEXT_PROGRAM_COUNTER_ADDR(fp) (fp)
#define DECLARE_REGS_STRUCT(regs) struct user_regs regs
#define VDSO_NAME ""
#elif defined(__ppc64__) || defined(__alpha__) || defined(__ia64__) || defined(s390x__)
#error Not (yet) supported architecture, patches welcomes :-)
#else
@ -280,7 +286,7 @@ static void findCodeAddress(ElfN_Addr addr, ElfN_Sym **ans,
{
ElfN_Sym *sym;
Symbols tab;
uintN_t i;
int i;
for (tab = allSyms, *ans = 0, *symtab = 0; tab; tab = tab->next) {
if (addr < tab->baseAddr) continue;
@ -370,7 +376,7 @@ static void checkForThreads(Symbols syms, int pid)
if (!descr && i == 0)
/* The initial thread's descriptor was not initialized yet. */
*pptr++ = pid;
else if (descr != -1 || !errno) {
else if (descr != (ElfN_Addr) -1 || !errno) {
tpid = ptrace(PTRACE_PEEKDATA, pid, descr + pidOff, 0);
if (tpid != -1 || !errno)
*pptr++ = tpid;
@ -438,8 +444,8 @@ static int find_stables(ElfN_Ehdr *hdr, int fd, Symbols syms)
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)
if ((ElfN_Off) lseek(fd, shdr.sh_offset, SEEK_SET) != shdr.sh_offset ||
(uintN_t) 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;
@ -449,8 +455,8 @@ static int find_stables(ElfN_Ehdr *hdr, int fd, Symbols syms)
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)
if ((ElfN_Off) lseek(fd, shdr.sh_offset, SEEK_SET) != shdr.sh_offset ||
(uintN_t) read(fd, syms->strings, shdr.sh_size) != shdr.sh_size)
quit("Could not read string table.");
lseek(fd, spot, SEEK_SET);
break;
@ -458,8 +464,8 @@ static int find_stables(ElfN_Ehdr *hdr, int fd, Symbols syms)
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)
if ((ElfN_Off) lseek(fd, shdr.sh_offset, SEEK_SET) != shdr.sh_offset ||
(uintN_t) read(fd, syms->dynamic, shdr.sh_size) != shdr.sh_size)
quit("Could not read dynamic table.");
lseek(fd, spot, SEEK_SET);
break;
@ -477,6 +483,8 @@ static Symbols loadSyms(const char *fname)
if (*fname == '\0')
return (Symbols) 0;
if (!strcmp(VDSO_NAME, fname))
return (Symbols) 0;
syms = newSyms(fname);
if ((fd = open(fname, O_RDONLY)) < 0)
{
@ -484,7 +492,12 @@ static Symbols loadSyms(const char *fname)
perror("opening object file");
quit("Could not open object file.");
}
read(fd, &hdr, sizeof(hdr));
if (read(fd, &hdr, sizeof(hdr)) < (int) sizeof(hdr))
{
fprintf(stderr, "'%s': ", fname);
perror("reading object file ELF header");
quit("Could not read object file ELF header.");
}
verify_ident(&hdr);
if (!find_stables(&hdr, fd, syms)) {
deleteSyms(syms);
@ -542,16 +555,17 @@ static void resolveSymbols(Symbols syms, int offset)
}
}
static void loadString(pid_t pid, ElfN_Addr addr, char *dp, int bytes)
static void loadString(pid_t pid, ElfN_Addr addr, char *dp, unsigned int bytes)
{
long *lp = (long *) dp, nr;
long *lp = (long *) dp;
unsigned int nr;
int error_occured = 0;
memset(dp, 0, bytes);
errno = 0;
addr = ptrace(PTRACE_PEEKDATA, pid, addr, 0);
if (addr == -1 && errno)
if (addr == (ElfN_Addr) -1 && errno)
error_occured = 0;
for (nr = 0; bytes > sizeof(long) && strlen(dp) == nr;
@ -571,7 +585,7 @@ static void loadString(pid_t pid, ElfN_Addr addr, char *dp, int bytes)
}
static void readLinkMap(int pid, ElfN_Addr base,
struct link_map *lm, char *name, int namelen)
struct link_map *lm, char *name, unsigned int namelen)
{
/* base address */
lm->l_addr = (ElfN_Addr) ptrace(PTRACE_PEEKDATA, pid,
@ -640,12 +654,12 @@ static int crawl(int pid)
{
unsigned long pc, fp, nextfp, nargs, i, arg;
int ret, error_occured = 0;
struct pt_regs regs;
DECLARE_REGS_STRUCT(regs);
errno = 0;
ret = ptrace(PTRACE_GETREGS, pid, NULL, &regs);
if (ret != -1 && !errno) {
if (ret != -1) {
pc = PROGRAM_COUNTER(regs);
fp = FRAME_POINTER(regs);
}
@ -656,7 +670,7 @@ static int crawl(int pid)
print_pc(pc);
for ( ; !error_occured && fp; ) {
nextfp = ptrace(PTRACE_PEEKDATA, pid, NEXT_FRAME_POINTER_ADDR(fp), 0);
if (nextfp == (unsigned) -1 && errno) {
if (nextfp == (unsigned long) -1 && errno) {
error_occured = 1;
break;
}
@ -667,7 +681,7 @@ static int crawl(int pid)
fputs(" (", stdout);
for (i = 1; i <= nargs; i++) {
arg = ptrace(PTRACE_PEEKDATA, pid, ARG_NMBR(fp,i), 0);
if (arg == (unsigned) -1 && errno) {
if (arg == (unsigned long) -1 && errno) {
error_occured = 1;
break;
}
@ -682,7 +696,7 @@ static int crawl(int pid)
if (error_occured || !nextfp) break;
pc = ptrace(PTRACE_PEEKDATA, pid, NEXT_PROGRAM_COUNTER_ADDR(fp), 0);
if (pc == (unsigned) -1 && errno) {
if (pc == (unsigned long) -1 && errno) {
error_occured = 1;
break;
}
@ -710,7 +724,7 @@ static char *cmdLine(int pid)
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)
if ((unsigned int) 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?)");
@ -729,6 +743,7 @@ void usage(const char *argv0, const char *param)
int main(int argc, char **argv)
{
int i;
long thePidTmp;
const char *argv0 = argv[0];
/* Arrange to detach if we get an unexpected signal. This prevents
@ -741,10 +756,11 @@ int main(int argc, char **argv)
for (argc--, argv++; argc > 0; argc--, argv++) {
char *endptr = NULL;
thePid = strtol(*argv, &endptr, 0);
thePidTmp = strtol(*argv, &endptr, 0);
if (!*argv || *endptr || (errno == ERANGE &&
(thePid == LONG_MIN || thePid == LONG_MAX)))
(thePidTmp == LONG_MIN || thePidTmp == LONG_MAX)))
usage(argv0, *argv);
thePid = thePidTmp;
if (!thePid || thePid == getpid()) {
fprintf(stderr, "Invalid PID %d\n", thePid);
continue;