⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 psymtab.c

📁 Sun Solaris 10 中的 DTrace 组件的源代码。请参看: http://www.sun.com/software/solaris/observability.jsp
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * 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 + -