#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
# Makefile
# main.c
# test-prog.c
# This archive created: Thu Nov 2 15:24:45 2000
export PATH; PATH=/bin:$PATH
if test -f 'Makefile'
then
echo shar: will not over-write existing file "'Makefile'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile'
X
XCC=cc
XCFLAGS=-n32 -g -fullwarn
XLDLIBS=
X
XSHELL=/bin/sh
Xall: trace-objlist test-prog
X
Xtrace-objlist: main.o
X $(CC) $(CFLAGS) main.o $(LDLIBS) -o trace-objlist
X
Xmain.o: main.c
X $(CC) $(CFLAGS) -c main.c
X
Xtest-prog:test-prog.c
X $(CC) $(CFLAGS) test-prog.c -o test-prog
X
Xshar:
X shar -p X Makefile main.c test-prog.c >trace-objlist.shar
X
Xclean clobber:
X -rm -f *.o
X -rm -f trace-objlist
X -rm -f core
X -rm -f trace-objlist.shar
X -rm -f test-prog
X
X#$Revision: 1.5 $
SHAR_EOF
fi # end of overwriting check
if test -f 'main.c'
then
echo shar: will not over-write existing file "'main.c'"
else
sed 's/^X//' << \SHAR_EOF > 'main.c'
X/*
X Given a process id, print the list of DSOs attached (and the count).
X
X
X Because the execution and link addresses of an a.out
X are identical, we can take all addresses as offsets
X of the basic elf header (from elf_header_base_address,
X which we find in the program header).
X
X This is written for n32 apps only, at present.
X
X For use by anyone.
X Original version, Oct 18,2000
X [email protected]
X Revised and improved by Bruno Stefanizzi, [email protected]
X
X This version only handles n32 apps.
X Handling o32 and 64 apps is straightforward, but
X is not done ...
X
X $Revision: 1.17 $
X $Date: 2000/11/02 23:24:32 $
X*/
X
X
X
X#include <sys/types.h>
X#include <sys/signal.h>
X#include <sys/fault.h>
X#include <sys/syscall.h>
X#include <sys/procfs.h>
X
X#include <stdio.h>
X#include <stdlib.h>
X#include <stddef.h>
X#include <unistd.h>
X#include <fcntl.h>
X#include <elf.h>
X#include <string.h>
X#include <errno.h>
X#include <objlist.h>
X#include <dirent.h>
X
X
Xtypedef unsigned long ADDR;
Xtypedef unsigned long OFFSET;
X
X#define ELF_SYM Elf32_Sym
X#define ELF_DYN Elf32_Dyn
X#define ELF_EHDR Elf32_Ehdr
X#define ELF_PHDR Elf32_Phdr
X#define OBJ_INFO Elf32_Obj_Info
X
Xextern int errno;
X
Xchar *magic_symbol = "__rld_obj_head";
Xint fd;
X
X#define streq(a,b) (strcmp((a),(b)) == 0)
X
Xstatic int find_program_in_proc(char *pid_str, DIR *dirp);
Xstatic void open_proc_dir(DIR **dirp);
XADDR find_symbol(char *name, int in_fd);
Xvoid print_obj_list (char *name,ADDR, int in_fd);
Xvoid read_program_headers(OFFSET offset,int in_fd);
Xvoid read_victim_mem(char * buf,OFFSET offset,int len, int in_fd);
Xchar * read_victim_string(OFFSET straddr,int in_fd);
Xint get_fd_on_executable(int fd);
Xstatic void print_piocmap(int fd);
X
X
X/* We seek/read in the victim's virtual address directly
X That is, offset == virtual address
X*/
X#define ADJ_ADDR(a) ((a))
XADDR elf_header_base_address;
X
Xstruct symbol_list_s {
X ADDR symbols;
X ADDR strings;
X long symcount;
X long stringsize;
X};
X
Xstruct symbol_list_s symbol_base;
X
Xstatic int print_short_form = 0;
Xstatic int print_piocmap_regions = 0;
Xstatic int print_headers = 1;
X
Xchar *progname = "";
Xint
Xmain(int argc, char **argv)
X{
X char pfile[256];
X char *pid_str;
X int pid_num;
X ADDR addr;
X int localfd;
X DIR *dirp = NULL;
X int i;
X
X progname = argv[0];
X if(argc < 2) {
X printf("Usage: %s [-p] [-s] [-h] process-pid or process-name\n",
X progname);
X printf("default: print long form, one line per active DSO\n");
X printf("-s means short form, one line per active DSO\n");
X printf("-p means print piocmap regions list\n");
X printf("-h means suppress column headers\n");
X exit(1);
X }
X
X for( i = 1; i < argc; ++i) {
X if(streq(argv[i],"--")) {
X /* next arg is id/name */
X ++i;
X break;
X }
X if(streq(argv[i],"-p")) {
X print_piocmap_regions = 1;
X continue;
X }
X if(streq(argv[i],"-s")) {
X print_short_form = 1;
X continue;
X }
X if(streq(argv[i],"-h")) {
X print_headers = 0;
X continue;
X }
X /* Done with - options */
X break;
X }
X
X pid_str = argv[i];
X pid_num = atoi(pid_str);
X
X if (pid_num == 0) {
X open_proc_dir(&dirp);
X fd = find_program_in_proc(pid_str, dirp);
X }
X else {
X sprintf(pfile, "/proc/%s", pid_str);
X fd = open(pfile, O_RDONLY);
X }
X if (fd < 0) {
X fprintf(stderr, "Can't open %s\n", pfile);
X exit(1);
X }
X if(print_piocmap_regions) {
X print_piocmap(fd);
X }
X localfd = get_fd_on_executable(fd);
X
X /* This reads using the file id, and sets elf_header_base_address,
X which we need for the second read_program_headers
X call. For this one it is an elf file, so
X the offset of the elf header is zero.
X */
X read_program_headers(/*base=*/0,localfd);
X
X /* We do not need or want the *file* fd any more */
X close(localfd);
X
X /*
X We have the virtual address
X of the elf header itself now so that we
X can read the elf header in the process.
X */
X read_program_headers(elf_header_base_address,fd);
X /* Now find the elf symbol address for
X the magic symbol.
X */
X addr = find_symbol(magic_symbol, fd);
X
X print_obj_list(magic_symbol,addr,fd);
X
X
X
X close(fd);
X return 0;
X}
X
Xstatic void open_proc_dir(DIR **dirp)
X{
X if (!*dirp) {
X if ((*dirp = opendir("/proc")) == NULL) {
X perror("/proc");
X exit(1);
X }
X }
X rewinddir(*dirp);
X}
X
Xstatic int find_program_in_proc(char *proc_name, DIR *dirp)
X{
X struct dirent *dent;
X int fd = -1;
X struct prpsinfo info;
X char pfile[1024];
X
X while ((dent = readdir(dirp)) != NULL) {
X if (strcmp(dent->d_name, ".") != 0
X && strcmp(dent->d_name, "..") != 0
X && strcmp(dent->d_name, "pinfo") != 0) {
X sprintf(pfile, "/proc/%s", dent->d_name);
X fd = open(pfile, O_RDONLY);
X if (fd>0) {
X ioctl(fd, PIOCPSINFO, &info);
X if (strcmp(proc_name, info.pr_fname) == 0) {
X return fd;
X }
X else
X close(fd);
X }
X }
X }
X return fd;
X}
X
Xstatic void
Xprint_piocmap(int fd)
X{
X int nmaps;
X struct prmap_sgi maps[2048];
X register prmap_sgi_t *map;
X prmap_sgi_arg_t maparg;
X int i;
X
X maparg.pr_vaddr = (caddr_t)maps;
X maparg.pr_size = sizeof maps;
X
X nmaps = ioctl(fd, PIOCMAP_SGI,&maparg);
X if(nmaps == -1) {
X printf("PIOCMAP_SGI ioctl failed\n");
X }
X if(print_headers) {
X printf("PIOCMAP_SGI output\n");
X printf(" vaddr offset size mflags \n");
X }
X for (map = maps, i = 0; i < nmaps; ++i,++map) {
X printf("[%d] 0x%08llx 0x%08llx 0x%08llx 0x%08llx\n",
X i,
X (unsigned long long)(map)->pr_vaddr,
X (unsigned long long)(map)->pr_off,
X (unsigned long long)(map)->pr_size,
X (unsigned long long)(map)->pr_mflags);
X }
X
X}
X
X/*
X in_fd is open on the process, the zero byte of the
X open fd should be the process elf header, so
X follow the elf header to the data.
X
X The program header has (using example elfdump output):
X
X Program header 4 type PT_DYNAMIC (2), offset 0x1c8 456
X vaddr 0x100001c8 268435912, paddr 0x100001c8 268435912
X filesz 0x100 256
X memsz 0x100 256, flags 0x4 PF_R, align 0x4 4
X
X so we can get the following things from the dynamic section,:
X
X[1] DT_STRTAB 0x100002dc
X[2] DT_SYMTAB 0x10000664
X[3] DT_STRSZ 0x1c0
X[4] DT_MIPS_SYMTABNO 0x10
X
X And then we can search the table (linear search)
X to find the name.
X
X
X*/
XADDR
Xfind_symbol(char *name, int in_fd)
X{
X
X int i;
X
X
X
X for(i = 0; i <symbol_base.symcount; ++i) {
X ELF_SYM sym;
X
X char *dynsym_name;
X
X
X ADDR straddr;
X ADDR symaddr = symbol_base.symbols
X + sizeof(ELF_SYM)*i;
X
X read_victim_mem((char*)&sym,
X ADJ_ADDR(symaddr),sizeof(sym),in_fd);
X
X straddr = sym.st_name + symbol_base.strings;
X
X dynsym_name = read_victim_string(ADJ_ADDR(straddr),in_fd);
X
X if(strcmp(name,dynsym_name) == 0) {
X /* FOUND! */
X return (ADDR)sym.st_value;
X }
X }
X
X printf("Could not find %s\n",name);
X exit(1);
X /* NOTREACHED */
X}
X
X
X
X/*ARGSUSED*/
Xvoid
Xprint_obj_list (char *name,ADDR addr, int in_fd)
X{
X int count = 0;
X unsigned bufsize = 2000;
X char *buf = malloc(bufsize);
X
X ADDR victim_addr;
X
X int nmaps;
X struct prmap_sgi maps[2048];
X register prmap_sgi_t *map;
X prmap_sgi_arg_t maparg;
X int i;
X
X maparg.pr_vaddr = (caddr_t)maps;
X maparg.pr_size = sizeof maps;
X
X {
X nmaps = ioctl(in_fd, PIOCMAP_SGI,&maparg);
X if(nmaps == -1) {
X printf("PIOCMAP_SGI ioctl failed\n");
X }
X }
X
X if(!buf) {
X printf("Unable to malloc basic buffer\n");
X exit(1);
X }
X read_victim_mem((char *)&victim_addr,ADJ_ADDR(addr),
X sizeof(victim_addr),in_fd);
X if(print_headers) {
X if(print_short_form) {
X printf(
X" vaddr QSaddr size(KBytes)\n");
X } else {
X printf(
X" Kbytes\n");
X printf(
X" vaddr QSaddr Phys rsdnt Tot Priv Shrd\n");
X
X }
X }
X for(; ; ) {
X OBJ_INFO oi;
X if(victim_addr == 0) {
X break;
X }
X read_victim_mem((char *)&oi,ADJ_ADDR(victim_addr),
X sizeof(oi),in_fd);
X
X if(oi.oi_pathname_len > (bufsize-1)) {
X bufsize = (unsigned)oi.oi_pathname_len+10;
X free(buf);
X buf = malloc(bufsize);
X if(buf == 0) {
X printf("Un able to re-malloc %ld bytes buf\n",
X (long)bufsize);
X exit(2);
X }
X }
X read_victim_mem((char *)buf,ADJ_ADDR(oi.oi_pathname),
X (int)oi.oi_pathname_len,
X in_fd);
X buf[oi.oi_pathname_len] = 0;
X {
X for (map = maps, i = 0, i = nmaps; i-- > 0; ++map) {
X if ((unsigned long long)map->pr_vaddr
X == (unsigned long long)oi.oi_ehdr)
X {
X /* Print entries for each
X DSO, one per DSO (not one per memory region).
X */
X unsigned long weightSize, resSize, totalSize, privSize;
X unsigned long refCount = map->pr_mflags >> MA_REFCNT_SHIFT;
X unsigned long pgsize = getpagesize()/1024;
X privSize = ((map->pr_mflags & MA_PHYS) ||
X (map->pr_mflags & MA_SHMEM)) ?
X 0 : (map->pr_psize * pgsize) / refCount;
X weightSize = map->pr_wsize;
X weightSize *= pgsize; /* use 1KB resolution */
X weightSize /= MA_WSIZE_FRAC;
X weightSize /= refCount;
X resSize = (map->pr_vsize * pgsize) / refCount;
X totalSize = (map->pr_size + 1023) / 1024;
X
X if(print_short_form) {
X printf("[%2d] %-24s 0x%08llx 0x%08llx %6d\n",
X count,
X buf,
X (unsigned long long)map->pr_vaddr,
X (unsigned long long)oi.oi_orig_ehdr,
X totalSize);
X } else {
X printf("[%2d] %-24s 0x%08llx 0x%08llx "
X "%4d %4d %4d %4d %4d\n",
X count,
X buf,
X (unsigned long long)map->pr_vaddr,
X (unsigned long long)oi.oi_orig_ehdr,
X weightSize,
X resSize,
X totalSize,
X privSize,
X weightSize-privSize);
X }
X
X break;
X }
X }
X }
X ++count;
X
X victim_addr = oi.oi_next;
X }
X if(print_headers) {
X printf("Number of list entries: %d\n",count);
X }
X
X return;
X}
Xvoid
Xread_victim_mem(char * buf,OFFSET offset,int len, int in_fd)
X{
X int res;
X
X
X res = lseek(in_fd,offset,SEEK_SET);
X if(res < 0) {
X printf("Seek to 0x%llx %lld failed\n",
X (unsigned long long)offset,
X (long long)offset);
X exit(2);
X }
X
X
X res = read(in_fd,buf,len);
X if(res != len) {
X int myerr = errno;
X printf("Unable to read %d bytes at offset"
X " 0x%llx %lld (%d %s)\n",
X len,(unsigned long long)offset,
X (long long)offset,
X myerr,strerror(myerr));
X exit(2);
X }
X
X}
X
X
X/*
X Read an entire string (slowly, performance
X does not matter).
X Return pointer to static mem of the string.
X
X At all times we ensure our static return buffer
X is NUL terminated.
X
X*/
Xchar *
Xread_victim_string(OFFSET straddr,int in_fd)
X{
X
X#define LBUFSIZ 32000
X static char buf[LBUFSIZ+1];
X int i;
X
X buf[0] = 0;
X for(i = 0; i < LBUFSIZ; ++i) {
X buf[i+1] = 0;
X read_victim_mem(buf+i,straddr+i,1,in_fd);
X if(buf[i] == 0) {
X /* found NUL, have read entire string */
X return buf;
X }
X }
X printf("INCOMPLETE string!, addr 0x%llx\n",(long long)straddr);
X return buf;
X
X
X#undef LBUFSIZ
X}
X
X/*
X We are at 0 in the area, having opened but not read.
X
X*/
Xvoid
Xread_program_headers(OFFSET elf_header_off,int in_fd)
X{
X
X ELF_EHDR ehdr;
X OFFSET phdr_offset;
X int phdr_count;
X int entsize;
X int i;
X OFFSET dynamic_offset;
X int dynamic_count;
X
X read_victim_mem((char*)&ehdr,/* offset */elf_header_off,
X sizeof(ehdr), in_fd);
X
X
X if( ehdr.e_ident[0] != 0x7f ||
X ehdr.e_ident[1] != 'E' ||
X ehdr.e_ident[2] != 'L' ||
X ehdr.e_ident[3] != 'F' ) {
X
X printf("did not find elf header!\n");
X exit(2);
X }
X /* should also check to see is n32, here */
X /* FIXME */
X
X phdr_offset = ehdr.e_phoff;
X entsize = ehdr.e_phentsize;
X phdr_count = ehdr.e_phnum;
X
X
X for(i = 0; i < phdr_count; ++i) {
X ELF_PHDR phdr;
X read_victim_mem((char *)&phdr,
X elf_header_off+
X phdr_offset + i*entsize,
X sizeof(phdr),in_fd);
X
X if(phdr.p_offset == 0) {
X elf_header_base_address = phdr.p_vaddr;
X break;
X }
X }
X if(i == phdr_count) {
X printf("Never found base address!\n");
X exit(2);
X }
X
X for(i = 0; i < phdr_count; ++i) {
X ELF_PHDR phdr;
X read_victim_mem((char *)&phdr,
X elf_header_off +
X phdr_offset + i*entsize,
X sizeof(phdr),in_fd);
X
X if(phdr.p_type == PT_DYNAMIC) {
X dynamic_offset = phdr.p_offset;
X dynamic_count = (int)(phdr.p_filesz/sizeof(ELF_DYN));
X break;
X }
X }
X if(i == phdr_count) {
X printf("Never found dynamic info!\n");
X exit(2);
X }
X
X
X for(i = 0; i <dynamic_count; ++i) {
X ELF_DYN dyn;
X
X read_victim_mem((char *)&dyn,
X elf_header_off +
X dynamic_offset+i*sizeof(dyn),
X sizeof(dyn),in_fd);
X
X switch(dyn.d_tag) {
X case DT_STRTAB:
X symbol_base.strings = dyn.d_un.d_ptr;
X break;
X case DT_SYMTAB:
X symbol_base.symbols = dyn.d_un.d_ptr;
X break;
X case DT_STRSZ:
X symbol_base.stringsize = (int)dyn.d_un.d_val;
X break;
X case DT_MIPS_SYMTABNO:
X symbol_base.symcount = (int)dyn.d_un.d_val;
X break;
X }
X }
X
X
X if(symbol_base.symcount == 0 ||
X symbol_base.stringsize == 0 ||
X symbol_base.symbols == 0 ||
X symbol_base.strings ==0) {
X printf("Did not find all dyamic entries we need!\n");
X exit(3);
X }
X
X
X}
X
X/*
X Get open fd on the executable *file*.
X*/
Xint
Xget_fd_on_executable(int fd)
X{
X int res;
X
X /* Passing 3rd arg 0 means open fd on the executable file. */
X
X res = ioctl(fd, PIOCOPENM,0);
X if(res < 0) {
X printf("Could not open fd on executable!\n");
X }
X return res;
X}
SHAR_EOF
fi # end of overwriting check
if test -f 'test-prog.c'
then
echo shar: will not over-write existing file "'test-prog.c'"
else
sed 's/^X//' << \SHAR_EOF > 'test-prog.c'
X/*
X $Revision: 1.3 $
X $Date: 2000/10/18 18:57:41 $
X*/
X#include <unistd.h>
Xint main()
X{
X sleep(1000);
X return 0;
X}
SHAR_EOF
fi # end of overwriting check
# End of shell archive
exit 0