893 lines
18 KiB
C
Executable File
893 lines
18 KiB
C
Executable File
#ident "@(#)pstack.c 1.2 95/06/27 SMI"
|
|
|
|
#include <stdio.h>
|
|
#include <fcntl.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include <libelf.h>
|
|
#include <link.h>
|
|
#include <elf.h>
|
|
|
|
#include "pcontrol.h"
|
|
#include "ramdata.h"
|
|
|
|
#if defined(i386)
|
|
# define MAX_ARGS 8 /* be generous here */
|
|
typedef struct {
|
|
greg_t fr_savfp;
|
|
greg_t fr_savpc;
|
|
greg_t fr_args[MAX_ARGS];
|
|
long fr_argc;
|
|
long fr_argv;
|
|
} frame_t;
|
|
#endif /* i386 */
|
|
|
|
typedef struct cache {
|
|
Elf32_Shdr * c_shdr;
|
|
Elf_Data * c_data;
|
|
char * c_name;
|
|
} Cache;
|
|
|
|
typedef struct sym_tbl {
|
|
Elf32_Sym * syms; /* start of table */
|
|
char * strs; /* ptr to strings */
|
|
int symn; /* number of entries */
|
|
} sym_tbl_t;
|
|
|
|
typedef struct map_info {
|
|
int mapfd; /* file descriptor for mapping */
|
|
Elf * elf; /* elf handle so we can close */
|
|
Elf32_Ehdr * ehdr; /* need the header for type */
|
|
sym_tbl_t symtab; /* symbol table */
|
|
sym_tbl_t dynsym; /* dynamic symbol table */
|
|
} map_info_t;
|
|
|
|
typedef struct proc_info {
|
|
int proc_fd; /* /proc fd */
|
|
int num_mappings; /* number of mappings */
|
|
prmap_t * mappings; /* extant mappings */
|
|
map_info_t * map_info; /* per mapping info */
|
|
} proc_info_t;
|
|
|
|
extern proc_info_t * get_proc_info(int pfd);
|
|
extern void destroy_proc_info(proc_info_t *);
|
|
extern char * find_sym_name(caddr_t addr,
|
|
proc_info_t *pip,
|
|
char *func_name,
|
|
u_int *size,
|
|
caddr_t *start);
|
|
|
|
#define TRUE 1
|
|
#define FALSE 0
|
|
|
|
static void alrm(int);
|
|
static pid_t getproc(char *, char **);
|
|
static int AllCallStacks(process_t *, pid_t, proc_info_t *);
|
|
static void CallStack(int, prstatus_t *, pid_t, proc_info_t *);
|
|
static int grabit(process_t *, pid_t);
|
|
|
|
#if defined(sparc)
|
|
|
|
static void PrintFirstFrame(prgregset_t, id_t, proc_info_t *, prstatus_t *);
|
|
static void PrintFrame(prgregset_t, id_t, int, proc_info_t *);
|
|
static int PrevFrame(int, prgregset_t);
|
|
|
|
#elif defined(i386)
|
|
|
|
static void PrintFirstFrame(prgreg_t, frame_t *, id_t, int, proc_info_t *);
|
|
static void PrintFrame(prgreg_t, frame_t *, id_t, int, proc_info_t *);
|
|
static int PrevFrame(int, frame_t *);
|
|
static long argcount(int, long);
|
|
|
|
#endif
|
|
|
|
main(argc, argv)
|
|
int argc;
|
|
char **argv;
|
|
{
|
|
int retc = 0;
|
|
int opt;
|
|
int errflg = FALSE;
|
|
register process_t *Pr = &Proc;
|
|
|
|
command = strrchr(argv[0], '/');
|
|
if (command++ == NULL)
|
|
command = argv[0];
|
|
|
|
#if 1
|
|
/* allow all accesses for setuid version */
|
|
(void) setuid((int)geteuid());
|
|
#endif
|
|
|
|
/* options */
|
|
while ((opt = getopt(argc, argv, "p:")) != EOF) {
|
|
switch (opt) {
|
|
case 'p': /* alternate /proc directory */
|
|
procdir = optarg;
|
|
break;
|
|
default:
|
|
errflg = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
argc -= optind;
|
|
argv += optind;
|
|
|
|
if (errflg || argc <= 0) {
|
|
(void) fprintf(stderr, "usage:\t%s pid ...\n", command);
|
|
(void) fprintf(stderr, " (show process call stack)\n");
|
|
exit(2);
|
|
}
|
|
|
|
if (!isprocdir(procdir)) {
|
|
(void) fprintf(stderr,
|
|
"%s: %s is not a PROC directory\n",
|
|
command, procdir);
|
|
exit(2);
|
|
}
|
|
|
|
/* catch alarms */
|
|
(void) sigset(SIGALRM, alrm);
|
|
|
|
while (--argc >= 0) {
|
|
int pfd;
|
|
pid_t pid;
|
|
char *pdir;
|
|
proc_info_t * proc;
|
|
|
|
/* get the specified pid and its /proc directory */
|
|
pid = getproc(*argv++, &pdir);
|
|
|
|
if (pid < 0 || (pfd = grabit(Pr, pid)) < 0) {
|
|
retc++;
|
|
continue;
|
|
}
|
|
|
|
pfd = Pr->pfd;
|
|
proc = get_proc_info(pfd);
|
|
|
|
if (AllCallStacks(Pr, pid, proc) != 0)
|
|
retc++;
|
|
|
|
(void) close(pfd);
|
|
destroy_proc_info(proc);
|
|
}
|
|
|
|
return retc;
|
|
}
|
|
|
|
static pid_t /* get process id and /proc directory */
|
|
getproc(path, pdirp) /* return pid on success, -1 on failure */
|
|
register char * path; /* number or /proc/nnn */
|
|
char ** pdirp; /* points to /proc directory on success */
|
|
{
|
|
register char * name;
|
|
register pid_t pid;
|
|
char *next;
|
|
|
|
if ((name = strrchr(path, '/')) != NULL) /* last component */
|
|
*name++ = '\0';
|
|
else {
|
|
name = path;
|
|
path = procdir;
|
|
}
|
|
|
|
pid = strtol(name, &next, 10);
|
|
if (isdigit(*name) && pid >= 0 && *next == '\0') {
|
|
if (strcmp(procdir, path) != 0
|
|
&& !isprocdir(path)) {
|
|
(void) fprintf(stderr,
|
|
"%s: %s is not a PROC directory\n",
|
|
command, path);
|
|
pid = -1;
|
|
}
|
|
} else {
|
|
(void) fprintf(stderr, "%s: invalid process id: %s\n",
|
|
command, name);
|
|
pid = -1;
|
|
}
|
|
|
|
if (pid >= 0)
|
|
*pdirp = path;
|
|
return pid;
|
|
}
|
|
|
|
static int
|
|
grabit(Pr, pid) /* take control of an existing process */
|
|
register process_t *Pr;
|
|
pid_t pid;
|
|
{
|
|
int gcode;
|
|
int Fflag = 0;
|
|
|
|
gcode = Pgrab(Pr, pid, Fflag);
|
|
|
|
if (gcode >= 0)
|
|
return gcode;
|
|
|
|
if (gcode == G_INTR)
|
|
return -1;
|
|
|
|
(void) fprintf(stderr, "%s: cannot grab %d", command, pid);
|
|
switch (gcode) {
|
|
case G_NOPROC:
|
|
(void) fprintf(stderr, ": No such process");
|
|
break;
|
|
case G_ZOMB:
|
|
(void) fprintf(stderr, ": Zombie process");
|
|
break;
|
|
case G_PERM:
|
|
(void) fprintf(stderr, ": Permission denied");
|
|
break;
|
|
case G_BUSY:
|
|
(void) fprintf(stderr, ": Process is traced");
|
|
break;
|
|
case G_SYS:
|
|
(void) fprintf(stderr, ": System process");
|
|
break;
|
|
case G_SELF:
|
|
(void) fprintf(stderr, ": Cannot dump self");
|
|
break;
|
|
}
|
|
(void) fputc('\n', stderr);
|
|
|
|
return -1;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static void
|
|
alrm(sig)
|
|
int sig;
|
|
{
|
|
timeout = TRUE;
|
|
}
|
|
|
|
static int
|
|
AllCallStacks(Pr, pid, proc)
|
|
process_t *Pr;
|
|
pid_t pid; /* process-id */
|
|
proc_info_t * proc;
|
|
{
|
|
int pfd = Pr->pfd; /* process file descriptor */
|
|
prstatus_t status;
|
|
|
|
if (Ioctl(pfd, PIOCSTATUS, (int)&status) != 0) {
|
|
perror("AllCallStacks(): PIOCSTATUS");
|
|
return -1;
|
|
}
|
|
(void) printf("%d:\t%.70s\n", pid, Pr->psinfo.pr_psargs);
|
|
if (status.pr_nlwp <= 1)
|
|
CallStack(pfd, &status, 0, proc);
|
|
else {
|
|
int nlwp = status.pr_nlwp;
|
|
id_t * lwpid = (id_t *)malloc((nlwp+1)*sizeof(id_t));
|
|
int lwpfd;
|
|
int i;
|
|
|
|
if (lwpid == NULL) {
|
|
perror("AllCallStacks(): malloc()");
|
|
return -1;
|
|
}
|
|
if (Ioctl(pfd, PIOCLWPIDS, (int)lwpid) != 0) {
|
|
perror("AllCallStacks(): PIOCLWPIDS");
|
|
free(lwpid);
|
|
return -1;
|
|
}
|
|
for (i = 0; i < nlwp; i++) {
|
|
if ((lwpfd = Ioctl(pfd, PIOCOPENLWP, (int)&lwpid[i])) < 0) {
|
|
perror("AllCallStacks(): PIOCOPENLWP");
|
|
break;
|
|
}
|
|
if (Ioctl(lwpfd, PIOCSTATUS, (int)&status) != 0) {
|
|
perror("AllCallStacks(): lwp PIOCSTATUS");
|
|
(void) close(lwpfd);
|
|
break;
|
|
}
|
|
(void) close(lwpfd);
|
|
CallStack(pfd, &status, lwpid[i], proc);
|
|
}
|
|
free(lwpid);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#if defined(sparc)
|
|
|
|
static void
|
|
CallStack(pfd, psp, lwpid, proc)
|
|
int pfd; /* process file descriptor */
|
|
prstatus_t * psp;
|
|
id_t lwpid; /* lwp-id */
|
|
proc_info_t * proc;
|
|
{
|
|
prgreg_t fp;
|
|
int nfp;
|
|
prgreg_t *prevfp;
|
|
u_int size;
|
|
int i;
|
|
int first = TRUE;
|
|
prgregset_t reg;
|
|
|
|
(void) memcpy(reg, psp->pr_reg, sizeof(reg));
|
|
|
|
if (psp->pr_flags & PR_ASLEEP) {
|
|
PrintFirstFrame(reg, lwpid, proc, psp);
|
|
first = FALSE;
|
|
reg[R_PC] = reg[R_O7];
|
|
reg[R_nPC] = reg[R_PC] + 4;
|
|
}
|
|
|
|
size = 16;
|
|
prevfp = malloc(size * sizeof(prgreg_t));
|
|
nfp = 0;
|
|
do {
|
|
/* prevent stack recursion from running on forever */
|
|
fp = reg[R_FP];
|
|
for (i = 0; i < nfp; i++) {
|
|
if (fp == prevfp[i]) {
|
|
free(prevfp);
|
|
return;
|
|
}
|
|
}
|
|
if (nfp == size) {
|
|
size *= 2;
|
|
prevfp = realloc(prevfp, size * sizeof(prgreg_t));
|
|
}
|
|
prevfp[nfp++] = fp;
|
|
|
|
PrintFrame(reg, lwpid, first, proc);
|
|
first = FALSE;
|
|
} while (PrevFrame(pfd, reg) == 0);
|
|
|
|
free(prevfp);
|
|
}
|
|
|
|
static void
|
|
PrintFirstFrame(reg, lwpid, proc, psp)
|
|
prgregset_t reg;
|
|
id_t lwpid;
|
|
proc_info_t * proc;
|
|
prstatus_t * psp;
|
|
{
|
|
char buff[255];
|
|
u_int size;
|
|
caddr_t start;
|
|
char *sname;
|
|
int match = TRUE;
|
|
int i;
|
|
|
|
if (lwpid)
|
|
printf("lwp#%d ----------\n", lwpid);
|
|
|
|
sname = sysname(psp->pr_syscall);
|
|
printf(" %.8x %-8s (", reg[R_PC], sname);
|
|
for (i = 0; i < psp->pr_nsysarg; i++) {
|
|
if (i != 0)
|
|
printf(", ");
|
|
printf("%x", psp->pr_sysarg[i]);
|
|
if (psp->pr_sysarg[i] != reg[R_O0+i])
|
|
match = FALSE;
|
|
}
|
|
printf(")\n");
|
|
|
|
sprintf(buff, "%.8x", reg[R_PC]);
|
|
start = (caddr_t)reg[R_PC];
|
|
strcpy(buff+8, " ????????");
|
|
find_sym_name((caddr_t)reg[R_PC], proc, buff+9, &size, &start);
|
|
if (match) {
|
|
register char *s = buff+9;
|
|
|
|
while (*s == '_')
|
|
s++;
|
|
if (strcmp(sname, s) != 0)
|
|
match = FALSE;
|
|
}
|
|
|
|
if (!match) {
|
|
printf((start != (caddr_t)reg[R_PC])?
|
|
" %-17s (%x, %x, %x, %x, %x, %x) + %x\n" :
|
|
" %-17s (%x, %x, %x, %x, %x, %x)\n",
|
|
buff,
|
|
reg[R_O0],
|
|
reg[R_O1],
|
|
reg[R_O2],
|
|
reg[R_O3],
|
|
reg[R_O4],
|
|
reg[R_O5],
|
|
(u_int)reg[R_PC] - (u_int)start);
|
|
}
|
|
}
|
|
|
|
static void
|
|
PrintFrame(reg, lwpid, first, proc)
|
|
prgregset_t reg;
|
|
id_t lwpid;
|
|
int first;
|
|
proc_info_t * proc;
|
|
{
|
|
char buff[255];
|
|
u_int size;
|
|
caddr_t start;
|
|
|
|
sprintf(buff, "%.8x", reg[R_PC]);
|
|
start = (caddr_t)reg[R_PC];
|
|
strcpy(buff+8, " ????????");
|
|
find_sym_name((caddr_t)reg[R_PC], proc, buff+9, &size, &start);
|
|
|
|
if (lwpid && first)
|
|
printf("lwp#%d ----------\n", lwpid);
|
|
printf((start != (caddr_t)reg[R_PC])?
|
|
" %-17s (%x, %x, %x, %x, %x, %x) + %x\n" :
|
|
" %-17s (%x, %x, %x, %x, %x, %x)\n",
|
|
buff,
|
|
reg[R_I0],
|
|
reg[R_I1],
|
|
reg[R_I2],
|
|
reg[R_I3],
|
|
reg[R_I4],
|
|
reg[R_I5],
|
|
(u_int)reg[R_PC] - (u_int)start);
|
|
}
|
|
|
|
static int
|
|
PrevFrame(pfd, reg)
|
|
int pfd;
|
|
prgregset_t reg;
|
|
{
|
|
long sp;
|
|
|
|
if ((sp = reg[R_I6]) == 0)
|
|
return -1;
|
|
reg[R_PC] = reg[R_I7];
|
|
reg[R_nPC] = reg[R_PC] + 4;
|
|
(void) memcpy(®[R_O0], ®[R_I0], 8*sizeof(prgreg_t));
|
|
if (lseek(pfd, sp, 0) != sp
|
|
|| read(pfd, (char *)®[R_L0], 16*sizeof(prgreg_t)) <= 0)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
#endif /* sparc */
|
|
|
|
#if defined(i386)
|
|
|
|
static void
|
|
CallStack(pfd, psp, lwpid, proc)
|
|
int pfd; /* process file descriptor */
|
|
prstatus_t * psp;
|
|
id_t lwpid; /* lwp-id */
|
|
proc_info_t * proc;
|
|
{
|
|
prgreg_t fp;
|
|
int nfp;
|
|
prgreg_t *prevfp;
|
|
u_int size;
|
|
int first = TRUE;
|
|
prgregset_t reg;
|
|
frame_t frame;
|
|
prgreg_t pc;
|
|
int i;
|
|
|
|
(void) memcpy(reg, psp->pr_reg, sizeof(reg));
|
|
|
|
if (psp->pr_flags & PR_ASLEEP) {
|
|
(void) memset((char *)&frame, 0, sizeof(frame));
|
|
frame.fr_savfp = reg[R_SP];
|
|
frame.fr_savpc = reg[R_PC];
|
|
for (i = 0; i < psp->pr_nsysarg && i < MAX_ARGS; i++)
|
|
frame.fr_args[i] = psp->pr_sysarg[i];
|
|
frame.fr_argc = psp->pr_nsysarg;
|
|
frame.fr_argv = NULL;
|
|
PrintFirstFrame(reg[R_PC], &frame, lwpid, psp->pr_syscall, proc);
|
|
first = FALSE;
|
|
if (pread(pfd, (char *)®[R_PC], sizeof(prgreg_t),
|
|
(long)reg[R_SP]) != sizeof(prgreg_t))
|
|
return;
|
|
reg[R_SP] += 4;
|
|
}
|
|
|
|
if (pread(pfd, (char *)&frame, sizeof(frame), (long)reg[R_FP])
|
|
!= sizeof(frame))
|
|
return;
|
|
frame.fr_argc = argcount(pfd, (long)frame.fr_savpc);
|
|
frame.fr_argv = (long)reg[R_FP] + 2 * sizeof(long);
|
|
|
|
size = 16;
|
|
prevfp = malloc(size * sizeof(prgreg_t));
|
|
nfp = 0;
|
|
pc = reg[R_PC];
|
|
do {
|
|
/* prevent stack recursion from running on forever */
|
|
fp = frame.fr_savfp;
|
|
for (i = 0; i < nfp; i++) {
|
|
if (fp == prevfp[i]) {
|
|
free(prevfp);
|
|
return;
|
|
}
|
|
}
|
|
if (nfp == size) {
|
|
size *= 2;
|
|
prevfp = realloc(prevfp, size * sizeof(prgreg_t));
|
|
}
|
|
prevfp[nfp++] = fp;
|
|
|
|
PrintFrame(pc, &frame, lwpid, first, proc);
|
|
first = FALSE;
|
|
pc = frame.fr_savpc;
|
|
} while (PrevFrame(pfd, &frame) == 0);
|
|
|
|
free(prevfp);
|
|
}
|
|
|
|
static void
|
|
PrintFirstFrame(pc, frame, lwpid, sys, proc)
|
|
prgreg_t pc;
|
|
frame_t *frame;
|
|
id_t lwpid;
|
|
int sys;
|
|
proc_info_t * proc;
|
|
{
|
|
char buff[255];
|
|
u_int size;
|
|
caddr_t start;
|
|
int i;
|
|
|
|
sprintf(buff, "%.8x ", pc);
|
|
start = (caddr_t)pc;
|
|
strcpy(buff+9, sysname(sys));
|
|
|
|
if (lwpid)
|
|
printf("lwp#%d ----------\n", lwpid);
|
|
|
|
printf(" %-17s (", buff);
|
|
for (i = 0; i < frame->fr_argc && i < MAX_ARGS; i++)
|
|
printf((i+1 == frame->fr_argc)? "%x" : "%x, ",
|
|
frame->fr_args[i]);
|
|
printf(")\n");
|
|
}
|
|
|
|
static void
|
|
PrintFrame(pc, frame, lwpid, first, proc)
|
|
prgreg_t pc;
|
|
frame_t *frame;
|
|
id_t lwpid;
|
|
int first;
|
|
proc_info_t * proc;
|
|
{
|
|
char buff[255];
|
|
u_int size;
|
|
caddr_t start;
|
|
int i;
|
|
|
|
sprintf(buff, "%.8x ", pc);
|
|
start = (caddr_t)pc;
|
|
strcpy(buff+9, "????????");
|
|
find_sym_name((caddr_t)pc, proc, buff+9, &size, &start);
|
|
|
|
if (lwpid && first)
|
|
printf("lwp#%d ----------\n", lwpid);
|
|
printf(" %-17s (", buff);
|
|
for (i = 0; i < frame->fr_argc && i < MAX_ARGS; i++)
|
|
printf((i+1 == frame->fr_argc)? "%x" : "%x, ",
|
|
frame->fr_args[i]);
|
|
if (i != frame->fr_argc)
|
|
printf("...");
|
|
putchar(')');
|
|
printf((start != (caddr_t)pc)?
|
|
" + %x\n" : "\n", (u_int)pc - (u_int)start);
|
|
}
|
|
|
|
static int
|
|
PrevFrame(pfd, frame)
|
|
int pfd;
|
|
frame_t *frame;
|
|
{
|
|
prgreg_t fp = frame->fr_savfp;
|
|
|
|
if (fp == 0
|
|
|| pread(pfd, (char *)frame, sizeof(*frame), (long)fp)
|
|
!= sizeof(*frame))
|
|
return -1;
|
|
frame->fr_argc = argcount(pfd, (long)frame->fr_savpc);
|
|
frame->fr_argv = (long)fp + 2 * sizeof(long);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Given the return PC, return the number of arguments.
|
|
*/
|
|
static long
|
|
argcount(int pfd, long pc)
|
|
{
|
|
unsigned char instr[6];
|
|
int count;
|
|
|
|
if (pread(pfd, (char *)instr, sizeof(instr), pc) != sizeof(instr)
|
|
|| instr[1] != 0xc4)
|
|
return 0;
|
|
|
|
switch (instr[0]) {
|
|
case 0x81: /* count is a longword */
|
|
count = instr[2]+(instr[3]<<8)+(instr[4]<<16)+(instr[5]<<24);
|
|
break;
|
|
case 0x83: /* count is a bytes */
|
|
count = instr[2];
|
|
break;
|
|
default:
|
|
count = 0;
|
|
break;
|
|
}
|
|
|
|
return count / sizeof(long);
|
|
}
|
|
|
|
#endif /* i386 */
|
|
|
|
|
|
/*
|
|
* Routines to generate a symbolic traceback from an ELF
|
|
* executable. It works w/ shared libraries as well.
|
|
* This is a first cut.
|
|
*/
|
|
|
|
/*
|
|
* Define our own standard error routine.
|
|
*/
|
|
static void
|
|
failure(const char * name)
|
|
{
|
|
(void) fprintf(stderr, "%s failed: %s\n", name,
|
|
elf_errmsg(elf_errno()));
|
|
exit(1);
|
|
}
|
|
|
|
void
|
|
destroy_proc_info(proc_info_t * ptr)
|
|
{
|
|
map_info_t * mptr = ptr->map_info;
|
|
int i;
|
|
|
|
if (ptr) {
|
|
for (i = ptr->num_mappings; i; i--, mptr++) {
|
|
if (mptr->mapfd > 0)
|
|
(void) close(mptr->mapfd);
|
|
if (mptr->elf)
|
|
elf_end(mptr->elf);
|
|
}
|
|
if (ptr->mappings)
|
|
free(ptr->mappings);
|
|
if (ptr->map_info)
|
|
free(ptr->map_info);
|
|
free(ptr);
|
|
}
|
|
}
|
|
|
|
proc_info_t *
|
|
get_proc_info(int fd)
|
|
{
|
|
int i, n;
|
|
|
|
map_info_t * map_info, * mptr;
|
|
|
|
proc_info_t * ptr = malloc(sizeof(*ptr));
|
|
|
|
if (ioctl(fd, PIOCNMAP, &n) < 0) {
|
|
perror("PIONCMAP ioctl");
|
|
return NULL;
|
|
}
|
|
|
|
ptr->num_mappings = n;
|
|
ptr->proc_fd = fd;
|
|
ptr->mappings = (prmap_t *) malloc(sizeof(prmap_t) * (n+1));
|
|
|
|
if (ioctl(fd, PIOCMAP, ptr->mappings) < 0) {
|
|
perror("PIOCMAP ioctl");
|
|
return NULL;
|
|
}
|
|
|
|
ptr->map_info = mptr = map_info =
|
|
(map_info_t *) malloc(sizeof(map_info_t) * (n+1));
|
|
|
|
memset(mptr, 0, sizeof(map_info_t) * (n+1));
|
|
|
|
for (i = 0; i < n ; i++) {
|
|
mptr = &map_info[i];
|
|
mptr->mapfd = 0;
|
|
}
|
|
|
|
return ptr;
|
|
}
|
|
|
|
static int
|
|
build_sym_tab(proc_info_t * ptr, int map_index)
|
|
{
|
|
int fd = ptr->proc_fd;
|
|
|
|
map_info_t * mptr = ptr->map_info + map_index;
|
|
prmap_t * pptr = ptr->mappings + map_index;
|
|
Elf32_Shdr * shdr;
|
|
Elf * elf;
|
|
Elf_Scn * scn;
|
|
Elf32_Ehdr * ehdr;
|
|
Elf_Data * data;
|
|
sym_tbl_t * which;
|
|
Cache * cache;
|
|
Cache * _cache;
|
|
char * names;
|
|
u_int cnt;
|
|
|
|
(void) elf_version(EV_CURRENT);
|
|
|
|
if (mptr->mapfd < 0) /* failed here before */
|
|
return -1;
|
|
|
|
if ((mptr->mapfd = ioctl(fd, PIOCOPENM, &pptr->pr_vaddr)) < 0) {
|
|
#ifdef DEBUG
|
|
perror("PIOCOPENM ioctl");
|
|
fprintf(stderr, "Cannot get fd for following mapping:\n");
|
|
fprintf(stderr, "\tpr_vaddr = 0x%x\n", pptr->pr_vaddr);
|
|
fprintf(stderr, "\tpr_size = %d\n", pptr->pr_size);
|
|
fprintf(stderr, "\tpr_pagesize = %d\n", pptr->pr_pagesize);
|
|
fprintf(stderr, "\tpr_off = %d\n", pptr->pr_off);
|
|
#endif
|
|
return -1;
|
|
}
|
|
|
|
if ((elf = elf_begin(mptr->mapfd, ELF_C_READ, NULL)) == NULL
|
|
|| elf_kind(elf) != ELF_K_ELF) {
|
|
#ifdef DEBUG
|
|
(void) fprintf(stderr, "file is not elf??\n");
|
|
#endif
|
|
(void) close(mptr->mapfd);
|
|
mptr->mapfd = -1;
|
|
return -1;
|
|
}
|
|
mptr->elf = elf;
|
|
|
|
if ((mptr->ehdr = ehdr = elf32_getehdr(elf)) == NULL)
|
|
failure("elf_getehdr");
|
|
|
|
/*
|
|
* Obtain the .shstrtab data buffer to provide the required section
|
|
* name strings.
|
|
*/
|
|
if ((scn = elf_getscn(elf, ehdr->e_shstrndx)) == NULL)
|
|
failure("elf_getscn");
|
|
|
|
if ((data = elf_getdata(scn, NULL)) == NULL)
|
|
failure("elf_getdata");
|
|
|
|
names = data->d_buf;
|
|
|
|
/*
|
|
* Fill in the cache descriptor with information for each section.
|
|
*/
|
|
|
|
cache = (Cache *)malloc(ehdr->e_shnum * sizeof (Cache));
|
|
|
|
_cache = cache;
|
|
_cache++;
|
|
|
|
for (scn = NULL; scn = elf_nextscn(elf, scn); _cache++) {
|
|
if ((_cache->c_shdr = elf32_getshdr(scn)) == NULL)
|
|
failure("elf32_getshdr");
|
|
|
|
if ((_cache->c_data = elf_getdata(scn, NULL)) == NULL)
|
|
failure("elf_getdata");
|
|
|
|
_cache->c_name = names + _cache->c_shdr->sh_name;
|
|
}
|
|
|
|
for (cnt = 1; cnt < ehdr->e_shnum; cnt++) {
|
|
_cache = &cache[cnt];
|
|
shdr = _cache->c_shdr;
|
|
|
|
if (shdr->sh_type == SHT_SYMTAB)
|
|
which = & mptr->symtab;
|
|
else if (shdr->sh_type == SHT_DYNSYM)
|
|
which = & mptr->dynsym;
|
|
else
|
|
continue;
|
|
|
|
/*
|
|
* Determine the symbol data and number.
|
|
*/
|
|
which->syms = (Elf32_Sym *)_cache->c_data->d_buf;
|
|
which->symn = shdr->sh_size / shdr->sh_entsize;
|
|
which->strs = (char *)cache[shdr->sh_link].c_data->d_buf;
|
|
}
|
|
|
|
free(cache);
|
|
|
|
return 0;
|
|
}
|
|
|
|
char *
|
|
find_sym_name(caddr_t addr, proc_info_t * proc, char * func_name, u_int * size, caddr_t * start)
|
|
{
|
|
int i;
|
|
int n = proc->num_mappings;
|
|
u_int offset;
|
|
|
|
prmap_t * ptr;
|
|
|
|
for (i = 0, ptr = proc->mappings; i < n; i++, ptr++) {
|
|
map_info_t * mptr;
|
|
Elf32_Sym * syms;
|
|
int symn;
|
|
char * strs;
|
|
int _cnt;
|
|
|
|
if (addr < ptr->pr_vaddr
|
|
|| addr >= (ptr->pr_vaddr + ptr->pr_size))
|
|
continue;
|
|
|
|
/* found it */
|
|
mptr = proc->map_info + i;
|
|
|
|
if (mptr->ehdr == NULL) {
|
|
if (build_sym_tab(proc, i)) {
|
|
#ifdef DEBUG
|
|
fprintf(stderr
|
|
"failed to build symbol table for address 0x%x\n",
|
|
addr);
|
|
#endif
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if (mptr->ehdr->e_type != ET_DYN)
|
|
offset = 0;
|
|
else {
|
|
offset = (u_int) proc->mappings[i].pr_vaddr
|
|
- (u_int) proc->mappings[i].pr_off;
|
|
addr -= (u_int)offset;
|
|
}
|
|
|
|
syms = mptr->symtab.syms;
|
|
symn = mptr->symtab.symn;
|
|
strs = mptr->symtab.strs;
|
|
|
|
for (_cnt = 0; _cnt < symn; _cnt++, syms++) {
|
|
if (ELF32_ST_TYPE(syms->st_info) != STT_FUNC
|
|
|| (u_int)addr < syms->st_value
|
|
|| (u_int)addr >= (syms->st_value+syms->st_size))
|
|
continue;
|
|
|
|
strcpy(func_name, (strs + syms->st_name));
|
|
*size = syms->st_size;
|
|
*start = (caddr_t)syms->st_value + offset;
|
|
return func_name;
|
|
}
|
|
|
|
syms = mptr->dynsym.syms;
|
|
symn = mptr->dynsym.symn;
|
|
strs = mptr->dynsym.strs;
|
|
|
|
for (_cnt = 0; _cnt < symn; _cnt++, syms++) {
|
|
if (ELF32_ST_TYPE(syms->st_info) != STT_FUNC
|
|
|| (u_int)addr < syms->st_value
|
|
|| (u_int)addr >= (syms->st_value+syms->st_size))
|
|
continue;
|
|
strcpy(func_name, (strs + syms->st_name));
|
|
*size = syms->st_size;
|
|
*start = (caddr_t)syms->st_value + offset;
|
|
return func_name;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
return NULL;
|
|
}
|