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

📄 psymtab.c

📁 Sun Solaris 10 中的 DTrace 组件的源代码。请参看: http://www.sun.com/software/solaris/observability.jsp
💻 C
📖 第 1 页 / 共 5 页
字号:
	(void) mutex_unlock(&sort_mtx);	free(syms);}/* * Build the symbol table for the given mapped file. */voidPbuild_file_symtab(struct ps_prochandle *P, file_info_t *fptr){	char objectfile[PATH_MAX];	uint_t i;	GElf_Ehdr ehdr;	GElf_Sym s;	Elf_Data *shdata;	Elf_Scn *scn;	Elf *elf;	struct {		GElf_Shdr c_shdr;		Elf_Data *c_data;		const char *c_name;	} *cp, *cache = NULL, *dyn = NULL, *plt = NULL, *ctf = NULL;	if (fptr->file_init)		return;	/* We've already processed this file */	/*	 * Mark the file_info struct as having the symbol table initialized	 * even if we fail below.  We tried once; we don't try again.	 */	fptr->file_init = 1;	if (elf_version(EV_CURRENT) == EV_NONE) {		dprintf("libproc ELF version is more recent than libelf\n");		return;	}	if (P->state == PS_DEAD || P->state == PS_IDLE) {		/*		 * If we're a not live, we can't open files from the /proc		 * object directory; we have only the mapping and file names		 * to guide us.  We prefer the file_lname, but need to handle		 * the case of it being NULL in order to bootstrap: we first		 * come here during rd_new() when the only information we have		 * is interpreter name associated with the AT_BASE mapping.		 */		(void) snprintf(objectfile, sizeof (objectfile), "%s",		    fptr->file_lname ? fptr->file_lname : fptr->file_pname);	} else {		(void) snprintf(objectfile, sizeof (objectfile),		    "/proc/%d/object/%s", (int)P->pid, fptr->file_pname);	}	/*	 * Open the object file, create the elf file, and then get the elf	 * header and .shstrtab data buffer so we can process sections by	 * name. If anything goes wrong try to fake up an elf file from	 * the in-core elf image.	 */	if ((fptr->file_fd = open(objectfile, O_RDONLY)) < 0) {		dprintf("Pbuild_file_symtab: failed to open %s: %s\n",		    objectfile, strerror(errno));		if ((elf = fake_elf(P, fptr)) == NULL ||		    elf_kind(elf) != ELF_K_ELF ||		    gelf_getehdr(elf, &ehdr) == NULL ||		    (scn = elf_getscn(elf, ehdr.e_shstrndx)) == NULL ||		    (shdata = elf_getdata(scn, NULL)) == NULL) {			dprintf("failed to fake up ELF file\n");			return;		}	} else if ((elf = elf_begin(fptr->file_fd, ELF_C_READ, NULL)) == NULL ||	    elf_kind(elf) != ELF_K_ELF ||	    gelf_getehdr(elf, &ehdr) == NULL ||	    (scn = elf_getscn(elf, ehdr.e_shstrndx)) == NULL ||	    (shdata = elf_getdata(scn, NULL)) == NULL) {		dprintf("failed to process ELF file %s: %s\n",		    objectfile, elf_errmsg(elf_errno()));		if ((elf = fake_elf(P, fptr)) == NULL ||		    elf_kind(elf) != ELF_K_ELF ||		    gelf_getehdr(elf, &ehdr) == NULL ||		    (scn = elf_getscn(elf, ehdr.e_shstrndx)) == NULL ||		    (shdata = elf_getdata(scn, NULL)) == NULL) {			dprintf("failed to fake up ELF file\n");			goto bad;		}	} else if (file_differs(P, elf, fptr)) {		Elf *newelf;		/*		 * Before we get too excited about this elf file, we'll check		 * its checksum value against the value we have in memory. If		 * they don't agree, we try to fake up a new elf file and		 * proceed with that instead.		 */		dprintf("ELF file %s (%lx) doesn't match in-core image\n",		    fptr->file_pname,		    (ulong_t)fptr->file_map->map_pmap.pr_vaddr);		if ((newelf = fake_elf(P, fptr)) == NULL ||		    elf_kind(newelf) != ELF_K_ELF ||		    gelf_getehdr(newelf, &ehdr) == NULL ||		    (scn = elf_getscn(newelf, ehdr.e_shstrndx)) == NULL ||		    (shdata = elf_getdata(scn, NULL)) == NULL) {			dprintf("failed to fake up ELF file\n");		} else {			(void) elf_end(elf);			elf = newelf;			dprintf("switched to faked up ELF file\n");		}	}	if ((cache = malloc(ehdr.e_shnum * sizeof (*cache))) == NULL) {		dprintf("failed to malloc section cache for %s\n", objectfile);		goto bad;	}	dprintf("processing ELF file %s\n", objectfile);	fptr->file_class = ehdr.e_ident[EI_CLASS];	fptr->file_etype = ehdr.e_type;	fptr->file_elf = elf;	/*	 * Iterate through each section, caching its section header, data	 * pointer, and name.  We use this for handling sh_link values below.	 */	for (cp = cache + 1, scn = NULL; scn = elf_nextscn(elf, scn); cp++) {		if (gelf_getshdr(scn, &cp->c_shdr) == NULL)			goto bad; /* Failed to get section header */		if ((cp->c_data = elf_getdata(scn, NULL)) == NULL)			goto bad; /* Failed to get section data */		if (cp->c_shdr.sh_name >= shdata->d_size)			goto bad; /* Corrupt section name */		cp->c_name = (const char *)shdata->d_buf + cp->c_shdr.sh_name;	}	/*	 * Now iterate through the section cache in order to locate info	 * for the .symtab, .dynsym, .dynamic, .plt, and .SUNW_ctf sections:	 */	for (i = 1, cp = cache + 1; i < ehdr.e_shnum; i++, cp++) {		GElf_Shdr *shp = &cp->c_shdr;		if (shp->sh_type == SHT_SYMTAB || shp->sh_type == SHT_DYNSYM) {			sym_tbl_t *symp = shp->sh_type == SHT_SYMTAB ?			    &fptr->file_symtab : &fptr->file_dynsym;			/*			 * It's possible that the we already got the symbol			 * table from the core file itself. Either the file			 * differs in which case our faked up elf file will			 * only contain the dynsym (not the symtab) or the			 * file matches in which case we'll just be replacing			 * the symbol table we pulled out of the core file			 * with an equivalent one. In either case, this			 * check isn't essential, but it's a good idea.			 */			if (symp->sym_data == NULL) {				symp->sym_data = cp->c_data;				symp->sym_symn = shp->sh_size / shp->sh_entsize;				symp->sym_strs =				    cache[shp->sh_link].c_data->d_buf;				symp->sym_strsz =				    cache[shp->sh_link].c_data->d_size;				symp->sym_hdr = cp->c_shdr;				symp->sym_strhdr = cache[shp->sh_link].c_shdr;			}		} else if (shp->sh_type == SHT_DYNAMIC) {			dyn = cp;		} else if (strcmp(cp->c_name, ".plt") == 0) {			plt = cp;		} else if (strcmp(cp->c_name, ".SUNW_ctf") == 0) {			/*			 * Skip over bogus CTF sections so they don't come back			 * to haunt us later.			 */			if (shp->sh_link == 0 ||			    shp->sh_link > ehdr.e_shnum ||			    (cache[shp->sh_link].c_shdr.sh_type != SHT_DYNSYM &&			    cache[shp->sh_link].c_shdr.sh_type != SHT_SYMTAB)) {				dprintf("Bad sh_link %d for "				    "CTF\n", shp->sh_link);				continue;			}			ctf = cp;		}	}	/*	 * At this point, we've found all the symbol tables we're ever going	 * to find: the ones in the loop above and possibly the symtab that	 * was included in the core file. Before we perform any lookups, we	 * create sorted versions to optimize for lookups.	 */	optimize_symtab(&fptr->file_symtab);	optimize_symtab(&fptr->file_dynsym);	/*	 * Fill in the base address of the text mapping for shared libraries.	 * This allows us to translate symbols before librtld_db is ready.	 */	if (fptr->file_etype == ET_DYN) {		fptr->file_dyn_base = fptr->file_map->map_pmap.pr_vaddr -		    fptr->file_map->map_pmap.pr_offset;		dprintf("setting file_dyn_base for %s to %p\n",		    objectfile, (void *)fptr->file_dyn_base);	}	/*	 * Record the CTF section information in the file info structure.	 */	if (ctf != NULL) {		fptr->file_ctf_off = ctf->c_shdr.sh_offset;		fptr->file_ctf_size = ctf->c_shdr.sh_size;		if (ctf->c_shdr.sh_link != 0 &&		    cache[ctf->c_shdr.sh_link].c_shdr.sh_type == SHT_DYNSYM)			fptr->file_ctf_dyn = 1;	}	if (fptr->file_lo == NULL)		goto done; /* Nothing else to do if no load object info */	/*	 * If the object is a shared library and we have a different rl_base	 * value, reset file_dyn_base according to librtld_db's information.	 */	if (fptr->file_etype == ET_DYN &&	    fptr->file_lo->rl_base != fptr->file_dyn_base) {		dprintf("resetting file_dyn_base for %s to %p\n",		    objectfile, (void *)fptr->file_lo->rl_base);		fptr->file_dyn_base = fptr->file_lo->rl_base;	}	/*	 * Fill in the PLT information for this file if a PLT symbol is found.	 */	if (sym_by_name(&fptr->file_dynsym, "_PROCEDURE_LINKAGE_TABLE_", &s,	    NULL) != NULL) {		fptr->file_plt_base = s.st_value + fptr->file_dyn_base;		fptr->file_plt_size = (plt != NULL) ? plt->c_shdr.sh_size : 0;		/*		 * Bring the load object up to date; it is the only way the		 * user has to access the PLT data. The PLT information in the		 * rd_loadobj_t is not set in the call to map_iter() (the		 * callback for rd_loadobj_iter) where we set file_lo.		 */		fptr->file_lo->rl_plt_base = fptr->file_plt_base;		fptr->file_lo->rl_plt_size = fptr->file_plt_size;		dprintf("PLT found at %p, size = %lu\n",		    (void *)fptr->file_plt_base, (ulong_t)fptr->file_plt_size);	}	/*	 * Fill in the PLT information.	 */	if (dyn != NULL) {		uintptr_t dynaddr = dyn->c_shdr.sh_addr + fptr->file_dyn_base;		size_t ndyn = dyn->c_shdr.sh_size / dyn->c_shdr.sh_entsize;		GElf_Dyn d;		for (i = 0; i < ndyn; i++) {			if (gelf_getdyn(dyn->c_data, i, &d) != NULL &&			    d.d_tag == DT_JMPREL) {				fptr->file_jmp_rel =				    d.d_un.d_ptr + fptr->file_dyn_base;				break;			}		}		dprintf("_DYNAMIC found at %p, %lu entries, DT_JMPREL = %p\n",		    (void *)dynaddr, (ulong_t)ndyn, (void *)fptr->file_jmp_rel);	}done:	free(cache);	return;bad:	if (cache != NULL)		free(cache);	(void) elf_end(elf);	fptr->file_elf = NULL;	if (fptr->file_elfmem != NULL) {		free(fptr->file_elfmem);		fptr->file_elfmem = NULL;	}	(void) close(fptr->file_fd);	fptr->file_fd = -1;}/* * Given a process virtual address, return the map_info_t containing it. * If none found, return NULL. */map_info_t *Paddr2mptr(struct ps_prochandle *P, uintptr_t addr){	int lo = 0;	int hi = P->map_count - 1;	int mid;	map_info_t *mp;	while (lo <= hi) {		mid = (lo + hi) / 2;		mp = &P->mappings[mid];		/* check that addr is in [vaddr, vaddr + size) */		if ((addr - mp->map_pmap.pr_vaddr) < mp->map_pmap.pr_size)			return (mp);		if (addr < mp->map_pmap.pr_vaddr)			hi = mid - 1;		else			lo = mid + 1;	}	return (NULL);}/* * Return the map_info_t for the executable file. * If not found, return NULL. */static map_info_t *exec_map(struct ps_prochandle *P){	uint_t i;	map_info_t *mptr;	map_info_t *mold = NULL;	file_info_t *fptr;	uintptr_t base;	for (i = 0, mptr = P->mappings; i < P->map_count; i++, mptr++) {		if (mptr->map_pmap.pr_mapname[0] == '\0')			continue;		if (strcmp(mptr->map_pmap.pr_mapname, "a.out") == 0) {			if ((fptr = mptr->map_file) != NULL &&			    fptr->file_lo != NULL) {				base = fptr->file_lo->rl_base;				if (base >= mptr->map_pmap.pr_vaddr &&				    base < mptr->map_pmap.pr_vaddr +				    mptr->map_pmap.pr_size)	/* text space */					return (mptr);				mold = mptr;	/* must be the data */				continue;			}			/* This is a poor way to test for text space */			if (!(mptr->map_pmap.pr_mflags & MA_EXEC) ||			    (mptr->map_pmap.pr_mflags & MA_WRITE)) {				mold = mptr;				continue;			}			return (mptr);		}	}	return (mold);}/* * Given a shared object name, return the map_info_t for it.  If no matching * object is found, return NULL.  Normally, the link maps contain the full * object pathname, e.g. /usr/lib/libc.so.1.  We allow the object name to * take one of the following forms: * * 1. An exact match (i.e. a full pathname): "/usr/lib/libc.so.1" * 2. An exact basename match: "libc.so.1" * 3. An initial basename match up to a '.' suffix: "libc.so" or "libc" * 4. The literal string "a.out" is an alias for the executable mapping * * The third case is a convenience for callers and may not be necessary. * * As the exact same object name may be loaded on different link maps (see * dlmopen(3DL)), we also allow the caller to resolve the object name by * specifying a particular link map id.  If lmid is PR_LMID_EVERY, the * first matching name will be returned, regardless of the link map id. */static map_info_t *object_to_map(struct ps_prochandle *P, Lmid_t lmid, const char *objname){	map_info_t *mp;	file_info_t *fp;	size_t objlen;	uint_t i;	/*	 * First pass: look for exact matches of the entire pathname or	 * basename (cases 1 and 2 above):	 */	for (i = 0, mp = P->mappings; i < P->map_count; i++, mp++) {		if (mp->map_pmap.pr_mapname[0] == '\0' ||		    (fp = mp->map_file) == NULL || fp->file_lname == NULL)			continue;		if (lmid != PR_LMID_EVERY &&		    (fp->file_lo == NULL || lmid != fp->file_lo->rl_lmident))			continue;		/*		 * If we match, return the primary text mapping; otherwise		 * just return the mapping we matched.		 */		if (strcmp(fp->file_lname, objname) == 0 ||		    strcmp(fp->file_lbase, objname) == 0)			return (fp->file_map ? fp->file_map : mp);	}	objlen = strlen(objname);	/*	 * Second pass: look for partial matches (case 3 above):	 */	for (i = 0, mp = P->mappings; i < P->map_count; i++, mp++) {		if (mp->map_pmap.pr_mapname[0] == '\0' ||		    (fp = mp->map_file) == NULL || fp->file_lname == NULL)			continue;		if (lmid != PR_LMID_EVERY &&		    (fp->file_lo == NULL || lmid != fp->file_lo->rl_lmident))			continue;		/*		 * If we match, return the primary text mapping; otherwise		 * just return the mapping we matched.		 */		if (strncmp(fp->file_lbase, objname, objlen) == 0 &&		    fp->file_lbase[objlen] == '.')			return (fp->file_map ? fp->file_map : mp);	}	/*	 * One last check: we allow "a.out" to always alias the executable,	 * assuming this name was not in use for something else.	 */	if ((lmid == PR_LMID_EVERY || lmid == LM_ID_BASE) &&	    (strcmp(objname, "a.out") == 0))		return (P->map_exec);	return (NULL);}static map_info_t *object_name_to_map(struct ps_prochandle *P, Lmid_t lmid, const char *name){	map_info_t *mptr;	if (!P->info_valid)		Pupdate_maps(P);	if (P->map_exec == NULL && ((mptr = Paddr2mptr(P,	    Pgetauxval(P, AT_ENTRY))) != NULL || (mptr = exec_map(P)) != NULL))		P->map_exec = mptr;	if (P->map_ldso == NULL && (mptr = Paddr2mptr(P,	    Pgetauxval(P, AT_BASE))) != NULL)		P->map_ldso = mptr;	if (name == PR_OBJ_EXEC)		mptr = P->map_exec;	else if (name == PR_OBJ_LDSO)		mptr = P->map_ldso;	else if (Prd_agent(P) != NULL || P->state == PS_IDLE)		mptr = object_to_map(P, lmid, name);	else		mptr = NULL;	return (mptr);}/* * When two symbols are found by address, decide which one is to be preferred. */static GElf_Sym *sym_prefer(GElf_Sym *sym1, char *name1, GElf_Sym *sym2, char *name2){	/*	 * Prefer the non-NULL symbol.	 */	if (sym1 == NULL)		return (sym2);	if (sym2 == NULL)		return (sym1);	/*	 * Defer to the sort ordering...	 */	return (byaddr_cmp_common(sym1, name1, sym2, name2) <= 0 ? sym1 : sym2);}/* * Look up a symbol by address in the 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -