dt_link.c

来自「Sun Solaris 10 中的 DTrace 组件的源代码。请参看: htt」· C语言 代码 · 共 1,111 行 · 第 1/2 页

C
1,111
字号
/* * 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	"@(#)dt_link.c	1.7	05/01/07 SMI"#define	ELF_TARGET_ALL#include <elf.h>#include <sys/types.h>#include <sys/sysmacros.h>#include <unistd.h>#include <strings.h>#include <alloca.h>#include <limits.h>#include <stddef.h>#include <stdlib.h>#include <stdio.h>#include <fcntl.h>#include <errno.h>#include <wait.h>#include <assert.h>#include <dt_impl.h>#include <dt_provider.h>#include <dt_string.h>#define	ESHDR_NULL	0#define	ESHDR_SHSTRTAB	1#define	ESHDR_DOF	2#define	ESHDR_STRTAB	3#define	ESHDR_SYMTAB	4#define	ESHDR_REL	5#define	ESHDR_NUM	6#define	PWRITE_SCN(index, data) \	(lseek64(fd, (off64_t)elf_file.shdr[(index)].sh_offset, SEEK_SET) != \	(off64_t)elf_file.shdr[(index)].sh_offset || \	dt_write(dtp, fd, (data), elf_file.shdr[(index)].sh_size) != \	elf_file.shdr[(index)].sh_size)static const char DTRACE_SHSTRTAB32[] = "\0"".shstrtab\0"		/* 1 */".SUNW_dof\0"		/* 11 */".strtab\0"		/* 21 */".symtab\0"		/* 29 */#ifdef __sparc".rela.SUNW_dof";	/* 37 */#else".rel.SUNW_dof";	/* 37 */#endifstatic const char DTRACE_SHSTRTAB64[] = "\0"".shstrtab\0"		/* 1 */".SUNW_dof\0"		/* 11 */".strtab\0"		/* 21 */".symtab\0"		/* 29 */".rela.SUNW_dof";	/* 37 */static const char DOFSTR[] = "__SUNW_dof";static const char DOFLAZYSTR[] = "___SUNW_dof";typedef struct dof_elf32 {	uint32_t de_nrel;	/* relocation count */#ifdef __sparc	Elf32_Rela *de_rel;	/* array of relocations for sparc */#else	Elf32_Rel *de_rel;	/* array of relocations for x86 */#endif	uint32_t de_nsym;	/* symbol count */	Elf32_Sym *de_sym;	/* array of symbols */	uint32_t de_strlen;	/* size of of string table */	char *de_strtab;	/* string table */	uint32_t de_global;	/* index of the first global symbol */} dof_elf32_t;static intprepare_elf32(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf32_t *dep){	dof_sec_t *dofs, *s;	dof_relohdr_t *dofrh;	dof_relodesc_t *dofr;	char *strtab;	int i, j, nrel;	size_t strtabsz = 1;	uint32_t count = 0;	size_t base;	Elf32_Sym *sym;#ifdef __sparc	Elf32_Rela *rel;#else	Elf32_Rel *rel;#endif	/*LINTED*/	dofs = (dof_sec_t *)((char *)dof + dof->dofh_secoff);	/*	 * First compute the size of the string table and the number of	 * relocations present in the DOF.	 */	for (i = 0; i < dof->dofh_secnum; i++) {		if (dofs[i].dofs_type != DOF_SECT_URELHDR)			continue;		/*LINTED*/		dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset);		s = &dofs[dofrh->dofr_strtab];		strtab = (char *)dof + s->dofs_offset;		assert(strtab[0] == '\0');		strtabsz += s->dofs_size - 1;		s = &dofs[dofrh->dofr_relsec];		/*LINTED*/		dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset);		count += s->dofs_size / s->dofs_entsize;	}	dep->de_strlen = strtabsz;	dep->de_nrel = count;	dep->de_nsym = count + 1; /* the first symbol is always null */	if (dtp->dt_lazyload) {		dep->de_strlen += sizeof (DOFLAZYSTR);		dep->de_nsym++;	} else {		dep->de_strlen += sizeof (DOFSTR);		dep->de_nsym++;	}	if ((dep->de_rel = calloc(dep->de_nrel,	    sizeof (dep->de_rel[0]))) == NULL) {		return (dt_set_errno(dtp, EDT_NOMEM));	}	if ((dep->de_sym = calloc(dep->de_nsym, sizeof (Elf32_Sym))) == NULL) {		free(dep->de_rel);		return (dt_set_errno(dtp, EDT_NOMEM));	}	if ((dep->de_strtab = calloc(dep->de_strlen, 1)) == NULL) {		free(dep->de_rel);		free(dep->de_sym);		return (dt_set_errno(dtp, EDT_NOMEM));	}	count = 0;	strtabsz = 1;	dep->de_strtab[0] = '\0';	rel = dep->de_rel;	sym = dep->de_sym;	dep->de_global = 1;	/*	 * The first symbol table entry must be zeroed and is always ignored.	 */	bzero(sym, sizeof (Elf32_Sym));	sym++;	/*	 * Take a second pass through the DOF sections filling in the	 * memory we allocated.	 */	for (i = 0; i < dof->dofh_secnum; i++) {		if (dofs[i].dofs_type != DOF_SECT_URELHDR)			continue;		/*LINTED*/		dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset);		s = &dofs[dofrh->dofr_strtab];		strtab = (char *)dof + s->dofs_offset;		bcopy(strtab + 1, dep->de_strtab + strtabsz, s->dofs_size);		base = strtabsz;		strtabsz += s->dofs_size - 1;		s = &dofs[dofrh->dofr_relsec];		/*LINTED*/		dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset);		nrel = s->dofs_size / s->dofs_entsize;		s = &dofs[dofrh->dofr_tgtsec];		for (j = 0; j < nrel; j++) {#if defined(__i386) || defined(__amd64)			rel->r_offset = s->dofs_offset +			    dofr[j].dofr_offset;			rel->r_info = ELF32_R_INFO(count + dep->de_global,			    R_386_32);#elif defined(__sparc)			/*			 * Add 4 bytes to hit the low half of this 64-bit			 * big-endian address.			 */			rel->r_offset = s->dofs_offset +			    dofr[j].dofr_offset + 4;			rel->r_info = ELF32_R_INFO(count + dep->de_global,			    R_SPARC_32);#else#error unknown ISA#endif			sym->st_name = base + dofr[j].dofr_name - 1;			sym->st_value = 0;			sym->st_size = 0;			sym->st_info = ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE);			sym->st_other = 0;			sym->st_shndx = SHN_UNDEF;			rel++;			sym++;			count++;		}	}	/*	 * Add a symbol for the DOF itself. We use a different symbol for	 * lazily and actively loaded DOF to make them easy to distinguish.	 */	sym->st_name = strtabsz;	sym->st_value = 0;	sym->st_size = dof->dofh_filesz;	sym->st_info = ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT);	sym->st_other = 0;	sym->st_shndx = ESHDR_DOF;	sym++;	if (dtp->dt_lazyload) {		bcopy(DOFLAZYSTR, dep->de_strtab + strtabsz,		    sizeof (DOFLAZYSTR));		strtabsz += sizeof (DOFLAZYSTR);	} else {		bcopy(DOFSTR, dep->de_strtab + strtabsz, sizeof (DOFSTR));		strtabsz += sizeof (DOFSTR);	}	assert(count == dep->de_nrel);	assert(strtabsz == dep->de_strlen);	return (0);}typedef struct dof_elf64 {	uint32_t de_nrel;	Elf64_Rela *de_rel;	uint32_t de_nsym;	Elf64_Sym *de_sym;	uint32_t de_strlen;	char *de_strtab;	uint32_t de_global;} dof_elf64_t;static intprepare_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf64_t *dep){	dof_sec_t *dofs, *s;	dof_relohdr_t *dofrh;	dof_relodesc_t *dofr;	char *strtab;	int i, j, nrel;	size_t strtabsz = 1;	uint32_t count = 0;	size_t base;	Elf64_Sym *sym;	Elf64_Rela *rel;	/*LINTED*/	dofs = (dof_sec_t *)((char *)dof + dof->dofh_secoff);	/*	 * First compute the size of the string table and the number of	 * relocations present in the DOF.	 */	for (i = 0; i < dof->dofh_secnum; i++) {		if (dofs[i].dofs_type != DOF_SECT_URELHDR)			continue;		/*LINTED*/		dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset);		s = &dofs[dofrh->dofr_strtab];		strtab = (char *)dof + s->dofs_offset;		assert(strtab[0] == '\0');		strtabsz += s->dofs_size - 1;		s = &dofs[dofrh->dofr_relsec];		/*LINTED*/		dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset);		count += s->dofs_size / s->dofs_entsize;	}	dep->de_strlen = strtabsz;	dep->de_nrel = count;	dep->de_nsym = count + 1; /* the first symbol is always null */	if (dtp->dt_lazyload) {		dep->de_strlen += sizeof (DOFLAZYSTR);		dep->de_nsym++;	} else {		dep->de_strlen += sizeof (DOFSTR);		dep->de_nsym++;	}	if ((dep->de_rel = calloc(dep->de_nrel,	    sizeof (dep->de_rel[0]))) == NULL) {		return (dt_set_errno(dtp, EDT_NOMEM));	}	if ((dep->de_sym = calloc(dep->de_nsym, sizeof (Elf64_Sym))) == NULL) {		free(dep->de_rel);		return (dt_set_errno(dtp, EDT_NOMEM));	}	if ((dep->de_strtab = calloc(dep->de_strlen, 1)) == NULL) {		free(dep->de_rel);		free(dep->de_sym);		return (dt_set_errno(dtp, EDT_NOMEM));	}	count = 0;	strtabsz = 1;	dep->de_strtab[0] = '\0';	rel = dep->de_rel;	sym = dep->de_sym;	dep->de_global = 1;	/*	 * The first symbol table entry must be zeroed and is always ignored.	 */	bzero(sym, sizeof (Elf64_Sym));	sym++;	/*	 * Take a second pass through the DOF sections filling in the	 * memory we allocated.	 */	for (i = 0; i < dof->dofh_secnum; i++) {		if (dofs[i].dofs_type != DOF_SECT_URELHDR)			continue;		/*LINTED*/		dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset);		s = &dofs[dofrh->dofr_strtab];		strtab = (char *)dof + s->dofs_offset;		bcopy(strtab + 1, dep->de_strtab + strtabsz, s->dofs_size);		base = strtabsz;		strtabsz += s->dofs_size - 1;		s = &dofs[dofrh->dofr_relsec];		/*LINTED*/		dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset);		nrel = s->dofs_size / s->dofs_entsize;		s = &dofs[dofrh->dofr_tgtsec];		for (j = 0; j < nrel; j++) {#if defined(__i386) || defined(__amd64)			rel->r_offset = s->dofs_offset +			    dofr[j].dofr_offset;			rel->r_info = ELF64_R_INFO(count + dep->de_global,			    R_AMD64_64);#elif defined(__sparc)			rel->r_offset = s->dofs_offset +			    dofr[j].dofr_offset;			rel->r_info = ELF64_R_INFO(count + dep->de_global,			    R_SPARC_64);#else#error unknown ISA#endif			sym->st_name = base + dofr[j].dofr_name - 1;			sym->st_value = 0;			sym->st_size = 0;			sym->st_info = ELF64_ST_INFO(STB_GLOBAL, STT_NOTYPE);			sym->st_other = 0;			sym->st_shndx = SHN_UNDEF;			rel++;			sym++;			count++;		}	}	/*	 * Add a symbol for the DOF itself. We use a different symbol for	 * lazily and actively loaded DOF to make them easy to distinguish.	 */	sym->st_name = strtabsz;	sym->st_value = 0;	sym->st_size = dof->dofh_filesz;	sym->st_info = ELF64_ST_INFO(STB_GLOBAL, STT_OBJECT);	sym->st_other = 0;	sym->st_shndx = ESHDR_DOF;	sym++;	if (dtp->dt_lazyload) {		bcopy(DOFLAZYSTR, dep->de_strtab + strtabsz,		    sizeof (DOFLAZYSTR));		strtabsz += sizeof (DOFLAZYSTR);	} else {		bcopy(DOFSTR, dep->de_strtab + strtabsz, sizeof (DOFSTR));		strtabsz += sizeof (DOFSTR);	}	assert(count == dep->de_nrel);	assert(strtabsz == dep->de_strlen);	return (0);}/* * Write out an ELF32 file prologue consisting of a header, section headers, * and a section header string table.  The DOF data will follow this prologue * and complete the contents of the given ELF file. */static intdump_elf32(dtrace_hdl_t *dtp, const dof_hdr_t *dof, int fd){	struct {		Elf32_Ehdr ehdr;		Elf32_Shdr shdr[ESHDR_NUM];	} elf_file;	Elf32_Shdr *shp;	Elf32_Off off;	dof_elf32_t de;	int ret = 0;	uint_t nshdr;	if (prepare_elf32(dtp, dof, &de) != 0)		return (-1); /* errno is set for us */	/*	 * If there are no relocations, we only need enough sections for	 * the shstrtab and the DOF.	 */	nshdr = de.de_nrel == 0 ? ESHDR_SYMTAB + 1 : ESHDR_NUM;	bzero(&elf_file, sizeof (elf_file));	elf_file.ehdr.e_ident[EI_MAG0] = ELFMAG0;	elf_file.ehdr.e_ident[EI_MAG1] = ELFMAG1;	elf_file.ehdr.e_ident[EI_MAG2] = ELFMAG2;	elf_file.ehdr.e_ident[EI_MAG3] = ELFMAG3;	elf_file.ehdr.e_ident[EI_VERSION] = EV_CURRENT;	elf_file.ehdr.e_ident[EI_CLASS] = ELFCLASS32;#if defined(_BIG_ENDIAN)	elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2MSB;#elif defined(_LITTLE_ENDIAN)	elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2LSB;#endif	elf_file.ehdr.e_type = ET_REL;#if defined(__sparc)	elf_file.ehdr.e_machine = EM_SPARC;#elif defined(__i386) || defined(__amd64)	elf_file.ehdr.e_machine = EM_386;#endif	elf_file.ehdr.e_version = EV_CURRENT;	elf_file.ehdr.e_shoff = sizeof (Elf32_Ehdr);	elf_file.ehdr.e_ehsize = sizeof (Elf32_Ehdr);	elf_file.ehdr.e_phentsize = sizeof (Elf32_Phdr);	elf_file.ehdr.e_shentsize = sizeof (Elf32_Shdr);	elf_file.ehdr.e_shnum = nshdr;	elf_file.ehdr.e_shstrndx = ESHDR_SHSTRTAB;	off = sizeof (elf_file) + nshdr * sizeof (Elf32_Shdr);	shp = &elf_file.shdr[ESHDR_SHSTRTAB];	shp->sh_name = 1; /* DTRACE_SHSTRTAB32[1] = ".shstrtab" */	shp->sh_type = SHT_STRTAB;	shp->sh_offset = off;	shp->sh_size = sizeof (DTRACE_SHSTRTAB32);	shp->sh_addralign = sizeof (char);	off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8);	shp = &elf_file.shdr[ESHDR_DOF];	shp->sh_name = 11; /* DTRACE_SHSTRTAB32[11] = ".SUNW_dof" */	shp->sh_flags = SHF_ALLOC;	shp->sh_type = SHT_SUNW_dof;	shp->sh_offset = off;	shp->sh_size = dof->dofh_filesz;	shp->sh_addralign = 8;	off = shp->sh_offset + shp->sh_size;	shp = &elf_file.shdr[ESHDR_STRTAB];	shp->sh_name = 21; /* DTRACE_SHSTRTAB32[21] = ".strtab" */	shp->sh_flags = SHF_ALLOC;	shp->sh_type = SHT_STRTAB;	shp->sh_offset = off;	shp->sh_size = de.de_strlen;	shp->sh_addralign = sizeof (char);	off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 4);	shp = &elf_file.shdr[ESHDR_SYMTAB];	shp->sh_name = 29; /* DTRACE_SHSTRTAB32[29] = ".symtab" */	shp->sh_flags = SHF_ALLOC;	shp->sh_type = SHT_SYMTAB;	shp->sh_entsize = sizeof (Elf32_Sym);	shp->sh_link = ESHDR_STRTAB;	shp->sh_offset = off;	shp->sh_info = de.de_global;	shp->sh_size = de.de_nsym * sizeof (Elf32_Sym);	shp->sh_addralign = 4;	off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 4);	if (de.de_nrel == 0) {		if (dt_write(dtp, fd, &elf_file,		    sizeof (elf_file)) != sizeof (elf_file) ||		    PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB32) ||		    PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) ||		    PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) ||		    PWRITE_SCN(ESHDR_DOF, dof)) {			ret = dt_set_errno(dtp, errno);		}	} else {		shp = &elf_file.shdr[ESHDR_REL];		shp->sh_name = 37; /* DTRACE_SHSTRTAB32[37] = ".rel.SUNW_dof" */		shp->sh_flags = SHF_ALLOC;#ifdef __sparc		shp->sh_type = SHT_RELA;#else		shp->sh_type = SHT_REL;#endif		shp->sh_entsize = sizeof (de.de_rel[0]);		shp->sh_link = ESHDR_SYMTAB;		shp->sh_info = ESHDR_DOF;		shp->sh_offset = off;		shp->sh_size = de.de_nrel * sizeof (de.de_rel[0]);		shp->sh_addralign = 4;		if (dt_write(dtp, fd, &elf_file,		    sizeof (elf_file)) != sizeof (elf_file) ||		    PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB32) ||		    PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) ||		    PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) ||		    PWRITE_SCN(ESHDR_REL, de.de_rel) ||		    PWRITE_SCN(ESHDR_DOF, dof)) {			ret = dt_set_errno(dtp, errno);		}	}	free(de.de_strtab);	free(de.de_sym);	free(de.de_rel);	return (ret);

⌨️ 快捷键说明

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