Please consider a donation to the Higher Intellect project. See https://preterhuman.net/donate.php or the Donate to Higher Intellect page for more info. |
Trace-objlist.shar
Jump to navigation
Jump to search
#! /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