📄 psymtab.c
字号:
/* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only. * See the file usr/src/LICENSING.NOTICE in this distribution or * http://www.opensolaris.org/license/ for details. */#pragma ident "@(#)Psymtab.c 1.33 05/01/21 SMI"#include <stdio.h>#include <stdlib.h>#include <stddef.h>#include <unistd.h>#include <ctype.h>#include <fcntl.h>#include <string.h>#include <strings.h>#include <memory.h>#include <errno.h>#include <dirent.h>#include <signal.h>#include <limits.h>#include <libgen.h>#include <zone.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/systeminfo.h>#include <sys/sysmacros.h>#include "libproc.h"#include "Pcontrol.h"#include "Putil.h"static file_info_t *build_map_symtab(struct ps_prochandle *, map_info_t *);static map_info_t *exec_map(struct ps_prochandle *);static map_info_t *object_to_map(struct ps_prochandle *, Lmid_t, const char *);static map_info_t *object_name_to_map(struct ps_prochandle *, Lmid_t, const char *);static GElf_Sym *sym_by_name(sym_tbl_t *, const char *, GElf_Sym *, uint_t *);static int read_ehdr32(struct ps_prochandle *, Elf32_Ehdr *, uintptr_t);#ifdef _LP64static int read_ehdr64(struct ps_prochandle *, Elf64_Ehdr *, uintptr_t);#endif#define DATA_TYPES \ ((1 << STT_OBJECT) | (1 << STT_FUNC) | \ (1 << STT_COMMON) | (1 << STT_TLS))#define IS_DATA_TYPE(tp) (((1 << (tp)) & DATA_TYPES) != 0)#define MA_RWX (MA_READ | MA_WRITE | MA_EXEC)typedef enum { PRO_NATURAL, PRO_BYADDR, PRO_BYNAME} pr_order_t;static intaddr_cmp(const void *aa, const void *bb){ uintptr_t a = *((uintptr_t *)aa); uintptr_t b = *((uintptr_t *)bb); if (a > b) return (1); if (a < b) return (-1); return (0);}/* * Allocation function for a new file_info_t */static file_info_t *file_info_new(struct ps_prochandle *P, map_info_t *mptr){ file_info_t *fptr; map_info_t *mp; uintptr_t a, addr, *addrs, last = 0; uint_t i, j, naddrs = 0, unordered = 0; if ((fptr = calloc(1, sizeof (file_info_t))) == NULL) return (NULL); list_link(fptr, &P->file_head); (void) strcpy(fptr->file_pname, mptr->map_pmap.pr_mapname); mptr->map_file = fptr; fptr->file_ref = 1; fptr->file_fd = -1; P->num_files++; /* * To figure out which map_info_t instances correspond to the mappings * for this load object, we look at the in-memory ELF image in the * base mapping (usually the program text). We examine the program * headers to find the addresses at the beginning and end of each * section and store them in a list which we then sort. Finally, we * walk down the list of addresses and the list of map_info_t * instances in lock step to correctly find the mappings that * correspond to this load object. */ if (P->status.pr_dmodel == PR_MODEL_ILP32) { Elf32_Ehdr ehdr; Elf32_Phdr phdr; if (read_ehdr32(P, &ehdr, mptr->map_pmap.pr_vaddr) != 0) return (fptr); addrs = malloc(sizeof (uintptr_t) * ehdr.e_phnum * 2); a = mptr->map_pmap.pr_vaddr + ehdr.e_phoff; for (i = 0; i < ehdr.e_phnum; i++, a += ehdr.e_phentsize) { if (Pread(P, &phdr, sizeof (phdr), a) != sizeof (phdr)) goto out; if (phdr.p_type != PT_LOAD || phdr.p_memsz == 0) continue; addr = phdr.p_vaddr; if (ehdr.e_type == ET_DYN) addr += mptr->map_pmap.pr_vaddr; if (last > addr) unordered = 1; addrs[naddrs++] = addr; addrs[naddrs++] = last = addr + phdr.p_memsz - 1; }#ifdef _LP64 } else { Elf64_Ehdr ehdr; Elf64_Phdr phdr; if (read_ehdr64(P, &ehdr, mptr->map_pmap.pr_vaddr) != 0) return (fptr); addrs = malloc(sizeof (uintptr_t) * ehdr.e_phnum * 2); a = mptr->map_pmap.pr_vaddr + ehdr.e_phoff; for (i = 0; i < ehdr.e_phnum; i++, a += ehdr.e_phentsize) { if (Pread(P, &phdr, sizeof (phdr), a) != sizeof (phdr)) goto out; if (phdr.p_type != PT_LOAD || phdr.p_memsz == 0) continue; addr = phdr.p_vaddr; if (ehdr.e_type == ET_DYN) addr += mptr->map_pmap.pr_vaddr; if (last > addr) unordered = 1; addrs[naddrs++] = addr; addrs[naddrs++] = last = addr + phdr.p_memsz - 1; }#endif } if (unordered) qsort(addrs, naddrs, sizeof (uintptr_t), addr_cmp); i = j = 0; mp = P->mappings; while (j < P->map_count && i < naddrs) { addr = addrs[i]; if (addr >= mp->map_pmap.pr_vaddr && addr < mp->map_pmap.pr_vaddr + mp->map_pmap.pr_size && mp->map_file == NULL) { mp->map_file = fptr; fptr->file_ref++; } if (addr < mp->map_pmap.pr_vaddr + mp->map_pmap.pr_size) { i++; } else { mp++; j++; } }out: free(addrs); return (fptr);}/* * Deallocation function for a file_info_t */static voidfile_info_free(struct ps_prochandle *P, file_info_t *fptr){ if (--fptr->file_ref == 0) { list_unlink(fptr); if (fptr->file_symtab.sym_elf) { (void) elf_end(fptr->file_symtab.sym_elf); free(fptr->file_symtab.sym_elfmem); } if (fptr->file_symtab.sym_byname) free(fptr->file_symtab.sym_byname); if (fptr->file_symtab.sym_byaddr) free(fptr->file_symtab.sym_byaddr); if (fptr->file_dynsym.sym_elf) { (void) elf_end(fptr->file_dynsym.sym_elf); free(fptr->file_dynsym.sym_elfmem); } if (fptr->file_dynsym.sym_byname) free(fptr->file_dynsym.sym_byname); if (fptr->file_dynsym.sym_byaddr) free(fptr->file_dynsym.sym_byaddr); if (fptr->file_lo) free(fptr->file_lo); if (fptr->file_lname) free(fptr->file_lname); if (fptr->file_elf) (void) elf_end(fptr->file_elf); if (fptr->file_elfmem != NULL) free(fptr->file_elfmem); if (fptr->file_fd >= 0) (void) close(fptr->file_fd); if (fptr->file_ctfp) { ctf_close(fptr->file_ctfp); free(fptr->file_ctf_buf); } free(fptr); P->num_files--; }}/* * Deallocation function for a map_info_t */static voidmap_info_free(struct ps_prochandle *P, map_info_t *mptr){ file_info_t *fptr; if ((fptr = mptr->map_file) != NULL) { if (fptr->file_map == mptr) fptr->file_map = NULL; file_info_free(P, fptr); } if (P->execname && mptr == P->map_exec) { free(P->execname); P->execname = NULL; } if (P->auxv && (mptr == P->map_exec || mptr == P->map_ldso)) { free(P->auxv); P->auxv = NULL; P->nauxv = 0; } if (mptr == P->map_exec) P->map_exec = NULL; if (mptr == P->map_ldso) P->map_ldso = NULL;}/* * Call-back function for librtld_db to iterate through all of its shared * libraries. We use this to get the load object names for the mappings. */static intmap_iter(const rd_loadobj_t *lop, void *cd){ char buf[PATH_MAX]; struct ps_prochandle *P = cd; map_info_t *mptr; file_info_t *fptr; dprintf("encountered rd object at %p\n", (void *)lop->rl_base); if ((mptr = Paddr2mptr(P, lop->rl_base)) == NULL) return (1); /* Base address does not match any mapping */ if ((fptr = mptr->map_file) == NULL && (fptr = file_info_new(P, mptr)) == NULL) return (1); /* Failed to allocate a new file_info_t */ if ((fptr->file_lo == NULL) && (fptr->file_lo = malloc(sizeof (rd_loadobj_t))) == NULL) { file_info_free(P, fptr); return (1); /* Failed to allocate rd_loadobj_t */ } fptr->file_map = mptr; *fptr->file_lo = *lop; fptr->file_lo->rl_plt_base = fptr->file_plt_base; fptr->file_lo->rl_plt_size = fptr->file_plt_size; if (fptr->file_lname) { free(fptr->file_lname); fptr->file_lname = NULL; } if (Pread_string(P, buf, sizeof (buf), lop->rl_nameaddr) > 0) { if ((fptr->file_lname = strdup(buf)) != NULL) fptr->file_lbase = basename(fptr->file_lname); } dprintf("loaded rd object %s lmid %lx\n", fptr->file_lname ? fptr->file_lname : "<NULL>", lop->rl_lmident); return (1);}static voidmap_set(struct ps_prochandle *P, map_info_t *mptr, const char *lname){ file_info_t *fptr; if ((fptr = mptr->map_file) == NULL && (fptr = file_info_new(P, mptr)) == NULL) return; /* Failed to allocate a new file_info_t */ fptr->file_map = mptr; if ((fptr->file_lo == NULL) && (fptr->file_lo = malloc(sizeof (rd_loadobj_t))) == NULL) { file_info_free(P, fptr); return; /* Failed to allocate rd_loadobj_t */ } (void) memset(fptr->file_lo, 0, sizeof (rd_loadobj_t)); fptr->file_lo->rl_base = mptr->map_pmap.pr_vaddr; fptr->file_lo->rl_bend = mptr->map_pmap.pr_vaddr + mptr->map_pmap.pr_size; fptr->file_lo->rl_plt_base = fptr->file_plt_base; fptr->file_lo->rl_plt_size = fptr->file_plt_size; if (fptr->file_lname) { free(fptr->file_lname); fptr->file_lname = NULL; } if ((fptr->file_lname = strdup(lname)) != NULL) fptr->file_lbase = basename(fptr->file_lname);}static voidload_static_maps(struct ps_prochandle *P){ map_info_t *mptr; /* * Construct the map for the a.out. */ if ((mptr = object_name_to_map(P, PR_LMID_EVERY, PR_OBJ_EXEC)) != NULL) map_set(P, mptr, "a.out"); /* * If the dynamic linker exists for this process, * construct the map for it. */ if (Pgetauxval(P, AT_BASE) != -1L && (mptr = object_name_to_map(P, PR_LMID_EVERY, PR_OBJ_LDSO)) != NULL) map_set(P, mptr, "ld.so.1");}/* * Go through all the address space mappings, validating or updating * the information already gathered, or gathering new information. * * This function is only called when we suspect that the mappings have changed * because this is the first time we're calling it or because of rtld activity. */voidPupdate_maps(struct ps_prochandle *P){ char mapfile[64]; int mapfd; struct stat statb; prmap_t *Pmap = NULL; prmap_t *pmap; ssize_t nmap; int i; uint_t oldmapcount; map_info_t *newmap, *newp; map_info_t *mptr; if (P->info_valid) return; Preadauxvec(P); (void) sprintf(mapfile, "/proc/%d/map", (int)P->pid); if ((mapfd = open(mapfile, O_RDONLY)) < 0 || fstat(mapfd, &statb) != 0 || statb.st_size < sizeof (prmap_t) || (Pmap = malloc(statb.st_size)) == NULL || (nmap = pread(mapfd, Pmap, statb.st_size, 0L)) <= 0 || (nmap /= sizeof (prmap_t)) == 0) { if (Pmap != NULL) free(Pmap); if (mapfd >= 0) (void) close(mapfd); Preset_maps(P); /* utter failure; destroy tables */ return; } (void) close(mapfd); if ((newmap = calloc(1, nmap * sizeof (map_info_t))) == NULL) return; /* * We try to merge any file information we may have for existing * mappings, to avoid having to rebuild the file info. */ mptr = P->mappings; pmap = Pmap; newp = newmap; oldmapcount = P->map_count; for (i = 0; i < nmap; i++, pmap++, newp++) { if (oldmapcount == 0) { /* * We've exhausted all the old mappings. Every new * mapping should be added. */ newp->map_pmap = *pmap; } else if (pmap->pr_vaddr == mptr->map_pmap.pr_vaddr && pmap->pr_size == mptr->map_pmap.pr_size && pmap->pr_offset == mptr->map_pmap.pr_offset && (pmap->pr_mflags & ~(MA_BREAK | MA_STACK)) == (mptr->map_pmap.pr_mflags & ~(MA_BREAK | MA_STACK)) && pmap->pr_pagesize == mptr->map_pmap.pr_pagesize && pmap->pr_shmid == mptr->map_pmap.pr_shmid && strcmp(pmap->pr_mapname, mptr->map_pmap.pr_mapname) == 0) { /* * This mapping matches exactly. Copy over the old * mapping, taking care to get the latest flags. */ *newp = *mptr; if (P->map_exec == mptr) P->map_exec = newp; if (P->map_ldso == mptr) P->map_ldso = newp; newp->map_pmap.pr_mflags = pmap->pr_mflags; oldmapcount--; mptr++; } else if (pmap->pr_vaddr + pmap->pr_size > mptr->map_pmap.pr_vaddr) { /* * The old mapping doesn't exist any more, remove it * from the list. */ map_info_free(P, mptr); oldmapcount--; i--; newp--; pmap--; mptr++; } else { /* * This is a new mapping, add it directly. */ newp->map_pmap = *pmap; } } /* * Free any old maps */ while (oldmapcount) { map_info_free(P, mptr); oldmapcount--; mptr++; } free(Pmap); if (P->mappings != NULL) free(P->mappings); P->mappings = newmap; P->map_count = nmap; P->info_valid = 1; /* * Consult librtld_db to get the load object * names for all of the shared libraries. */ if (P->rap != NULL) (void) rd_loadobj_iter(P->rap, map_iter, P);}/* * Update all of the mappings and rtld_db as if by Pupdate_maps(), and then * forcibly cache all of the symbol tables associated with all object files. */voidPupdate_syms(struct ps_prochandle *P){ file_info_t *fptr = list_next(&P->file_head); int i; Pupdate_maps(P); for (i = 0; i < P->num_files; i++, fptr = list_next(fptr)) { Pbuild_file_symtab(P, fptr); (void) Pbuild_file_ctf(P, fptr); }}/* * Return the librtld_db agent handle for the victim process. * The handle will become invalid at the next successful exec() and the * client (caller of proc_rd_agent()) must not use it beyond that point. * If the process is already dead, we've already tried our best to * create the agent during core file initialization. */rd_agent_t *Prd_agent(struct ps_prochandle *P){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -