예제 #1
0
void
ctf_dtd_delete(ctf_file_t *fp, ctf_dtdef_t *dtd)
{
	ulong_t h = dtd->dtd_type & (fp->ctf_dthashlen - 1);
	ctf_dtdef_t *p, **q = &fp->ctf_dthash[h];
	ctf_dmdef_t *dmd, *nmd;
	size_t len;

	for (p = *q; p != NULL; p = p->dtd_hash) {
		if (p != dtd)
			q = &p->dtd_hash;
		else
			break;
	}

	if (p != NULL)
		*q = p->dtd_hash;

	switch (CTF_INFO_KIND(dtd->dtd_data.ctt_info)) {
	case CTF_K_STRUCT:
	case CTF_K_UNION:
	case CTF_K_ENUM:
		for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members);
		    dmd != NULL; dmd = nmd) {
			if (dmd->dmd_name != NULL) {
				len = strlen(dmd->dmd_name) + 1;
				ctf_free(dmd->dmd_name, len);
				fp->ctf_dtstrlen -= len;
			}
			nmd = ctf_list_next(dmd);
			ctf_free(dmd, sizeof (ctf_dmdef_t));
		}
		break;
	case CTF_K_FUNCTION:
		ctf_free(dtd->dtd_u.dtu_argv, sizeof (ctf_id_t) *
		    CTF_INFO_VLEN(dtd->dtd_data.ctt_info));
		break;
	}

	if (dtd->dtd_name) {
		len = strlen(dtd->dtd_name) + 1;
		ctf_free(dtd->dtd_name, len);
		fp->ctf_dtstrlen -= len;
	}

	ctf_list_delete(&fp->ctf_dtdefs, dtd);
	ctf_free(dtd, sizeof (ctf_dtdef_t));
}
예제 #2
0
static int
membadd(const char *name, ctf_id_t type, ulong_t offset, void *arg)
{
	ctf_bundle_t *ctb = arg;
	ctf_dmdef_t *dmd;
	char *s = NULL;

	if ((dmd = ctf_alloc(sizeof (ctf_dmdef_t))) == NULL)
		return (ctf_set_errno(ctb->ctb_file, EAGAIN));

	if (name != NULL && (s = ctf_strdup(name)) == NULL) {
		ctf_free(dmd, sizeof (ctf_dmdef_t));
		return (ctf_set_errno(ctb->ctb_file, EAGAIN));
	}

	/*
	 * For now, dmd_type is copied as the src_fp's type; it is reset to an
	 * equivalent dst_fp type by a final loop in ctf_add_type(), below.
	 */
	dmd->dmd_name = s;
	dmd->dmd_type = type;
	dmd->dmd_offset = offset;
	dmd->dmd_value = -1;

	ctf_list_append(&ctb->ctb_dtd->dtd_u.dtu_members, dmd);

	if (s != NULL)
		ctb->ctb_file->ctf_dtstrlen += strlen(s) + 1;

	ctb->ctb_file->ctf_flags |= LCTF_DIRTY;
	return (0);
}
예제 #3
0
/*
 * Set the parent name.  It is an error to call this routine without calling
 * ctf_import() at some point.
 */
void
ctf_parent_name_set(ctf_file_t *fp, const char *name)
{
	if(fp->ctf_dynparname != NULL)
		ctf_free(fp->ctf_dynparname, strlen(fp->ctf_dynparname) + 1);

	fp->ctf_dynparname = ctf_strdup(name);
	fp->ctf_parname = fp->ctf_dynparname;
}
예제 #4
0
ctf_id_t
ctf_add_function(ctf_file_t *fp, uint_t flag,
    const ctf_funcinfo_t *ctc, const ctf_id_t *argv)
{
	ctf_dtdef_t *dtd;
	ctf_id_t type;
	uint_t vlen;
	int i;
	ctf_id_t *vdat = NULL;
	ctf_file_t *fpd;

	if (ctc == NULL || (ctc->ctc_flags & ~CTF_FUNC_VARARG) != 0 ||
	    (ctc->ctc_argc != 0 && argv == NULL))
		return (ctf_set_errno(fp, EINVAL));

	vlen = ctc->ctc_argc;
	if (ctc->ctc_flags & CTF_FUNC_VARARG)
		vlen++; /* add trailing zero to indicate varargs (see below) */

	if (vlen > CTF_MAX_VLEN)
		return (ctf_set_errno(fp, EOVERFLOW));

	fpd = fp;
	if (ctf_lookup_by_id(&fpd, ctc->ctc_return) == NULL &&
	    ctf_dtd_lookup(fp, ctc->ctc_return) == NULL)
		return (ctf_set_errno(fp, ECTF_BADID));

	for (i = 0; i < ctc->ctc_argc; i++) {
		fpd = fp;
		if (ctf_lookup_by_id(&fpd, argv[i]) == NULL &&
		    ctf_dtd_lookup(fp, argv[i]) == NULL)
			return (ctf_set_errno(fp, ECTF_BADID));
	}

	if (vlen != 0 && (vdat = ctf_alloc(sizeof (ctf_id_t) * vlen)) == NULL)
		return (ctf_set_errno(fp, EAGAIN));

	if ((type = ctf_add_generic(fp, flag, NULL, &dtd)) == CTF_ERR) {
		ctf_free(vdat, sizeof (ctf_id_t) * vlen);
		return (CTF_ERR); /* errno is set for us */
	}

	dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_FUNCTION, flag, vlen);
	dtd->dtd_data.ctt_type = (ushort_t)ctc->ctc_return;

	ctf_ref_inc(fp, ctc->ctc_return);
	for (i = 0; i < ctc->ctc_argc; i++)
		ctf_ref_inc(fp, argv[i]);

	bcopy(argv, vdat, sizeof (ctf_id_t) * ctc->ctc_argc);
	if (ctc->ctc_flags & CTF_FUNC_VARARG)
		vdat[vlen - 1] = 0; /* add trailing zero to indicate varargs */
	dtd->dtd_u.dtu_argv = vdat;

	return (type);
}
예제 #5
0
int
ctf_add_enumerator(ctf_file_t *fp, ctf_id_t enid, const char *name, int value)
{
	ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, enid);
	ctf_dmdef_t *dmd;

	uint_t kind, vlen, root;
	char *s;

	if (name == NULL)
		return (ctf_set_errno(fp, EINVAL));

	if (!(fp->ctf_flags & LCTF_RDWR))
		return (ctf_set_errno(fp, ECTF_RDONLY));

	if (dtd == NULL)
		return (ctf_set_errno(fp, ECTF_BADID));

	kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info);
	root = CTF_INFO_ISROOT(dtd->dtd_data.ctt_info);
	vlen = CTF_INFO_VLEN(dtd->dtd_data.ctt_info);

	if (kind != CTF_K_ENUM)
		return (ctf_set_errno(fp, ECTF_NOTENUM));

	if (vlen == CTF_MAX_VLEN)
		return (ctf_set_errno(fp, ECTF_DTFULL));

	for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members);
	    dmd != NULL; dmd = ctf_list_next(dmd)) {
		if (strcmp(dmd->dmd_name, name) == 0)
			return (ctf_set_errno(fp, ECTF_DUPMEMBER));
	}

	if ((dmd = ctf_alloc(sizeof (ctf_dmdef_t))) == NULL)
		return (ctf_set_errno(fp, EAGAIN));

	if ((s = ctf_strdup(name)) == NULL) {
		ctf_free(dmd, sizeof (ctf_dmdef_t));
		return (ctf_set_errno(fp, EAGAIN));
	}

	dmd->dmd_name = s;
	dmd->dmd_type = CTF_ERR;
	dmd->dmd_offset = 0;
	dmd->dmd_value = value;

	dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, root, vlen + 1);
	ctf_list_append(&dtd->dtd_u.dtu_members, dmd);

	fp->ctf_dtstrlen += strlen(s) + 1;
	fp->ctf_flags |= LCTF_DIRTY;

	return (0);
}
예제 #6
0
void
ctf_decl_fini(ctf_decl_t *cd)
{
	ctf_decl_node_t *cdp, *ndp;
	int i;

	for (i = CTF_PREC_BASE; i < CTF_PREC_MAX; i++) {
		for (cdp = ctf_list_next(&cd->cd_nodes[i]);
		    cdp != NULL; cdp = ndp) {
			ndp = ctf_list_next(cdp);
			ctf_free(cdp, sizeof (ctf_decl_node_t));
		}
	}
}
예제 #7
0
static ctf_id_t
ctf_add_generic(ctf_file_t *fp, uint_t flag, const char *name, ctf_dtdef_t **rp)
{
	ctf_dtdef_t *dtd;
	ctf_id_t type;
	char *s = NULL;

	if (flag != CTF_ADD_NONROOT && flag != CTF_ADD_ROOT)
		return (ctf_set_errno(fp, EINVAL));

	if (!(fp->ctf_flags & LCTF_RDWR))
		return (ctf_set_errno(fp, ECTF_RDONLY));

	if (CTF_INDEX_TO_TYPE(fp->ctf_dtnextid, 1) > CTF_MAX_TYPE)
		return (ctf_set_errno(fp, ECTF_FULL));

	if ((dtd = ctf_alloc(sizeof (ctf_dtdef_t))) == NULL)
		return (ctf_set_errno(fp, EAGAIN));

	if (name != NULL && (s = ctf_strdup(name)) == NULL) {
		ctf_free(dtd, sizeof (ctf_dtdef_t));
		return (ctf_set_errno(fp, EAGAIN));
	}

	type = fp->ctf_dtnextid++;
	type = CTF_INDEX_TO_TYPE(type, (fp->ctf_flags & LCTF_CHILD));

	bzero(dtd, sizeof (ctf_dtdef_t));
	dtd->dtd_name = s;
	dtd->dtd_type = type;

	if (s != NULL)
		fp->ctf_dtstrlen += strlen(s) + 1;

	ctf_dtd_insert(fp, dtd);
	fp->ctf_flags |= LCTF_DIRTY;

	*rp = dtd;
	return (type);
}
예제 #8
0
/*
 * To create an empty CTF container, we just declare a zeroed header and call
 * ctf_bufopen() on it.  If ctf_bufopen succeeds, we mark the new container r/w
 * and initialize the dynamic members.  We set dtstrlen to 1 to reserve the
 * first byte of the string table for a \0 byte, and we start assigning type
 * IDs at 1 because type ID 0 is used as a sentinel.
 */
ctf_file_t *
ctf_create(int *errp)
{
	static const ctf_header_t hdr = { .cth_preamble = {
		.ctp_magic = CTF_MAGIC,
		.ctp_version = CTF_VERSION,
		.ctp_flags = 0
	} };

	const ulong_t hashlen = 128;
	ctf_dtdef_t **hash = ctf_alloc(hashlen * sizeof (ctf_dtdef_t *));
	ctf_sect_t cts;
	ctf_file_t *fp;

	if (hash == NULL)
		return (ctf_set_open_errno(errp, EAGAIN));

	cts.cts_name = __UNCONST(_CTF_SECTION);
	cts.cts_type = SHT_PROGBITS;
	cts.cts_flags = 0;
	cts.cts_data = __UNCONST(&hdr);
	cts.cts_size = sizeof (hdr);
	cts.cts_entsize = 1;
	cts.cts_offset = 0;

	if ((fp = ctf_bufopen(&cts, NULL, NULL, errp)) == NULL) {
		ctf_free(hash, hashlen * sizeof (ctf_dtdef_t *));
		return (NULL);
	}

	fp->ctf_flags |= LCTF_RDWR;
	fp->ctf_dthashlen = hashlen;
	bzero(hash, hashlen * sizeof (ctf_dtdef_t *));
	fp->ctf_dthash = hash;
	fp->ctf_dtstrlen = sizeof (_CTF_STRTAB_TEMPLATE);
	fp->ctf_dtnextid = 1;
	fp->ctf_dtoldid = 0;

	return (fp);
}
예제 #9
0
/*
 * Close the specified CTF container and free associated data structures.  Note
 * that ctf_close() is a reference counted operation: if the specified file is
 * the parent of other active containers, its reference count will be greater
 * than one and it will be freed later when no active children exist.
 */
void
ctf_close(ctf_file_t *fp)
{
	ctf_dtdef_t *dtd, *ntd;

	if (fp == NULL)
		return; /* allow ctf_close(NULL) to simplify caller code */

	ctf_dprintf("ctf_close(%p) refcnt=%u\n", (void *)fp, fp->ctf_refcnt);

	if (fp->ctf_refcnt > 1) {
		fp->ctf_refcnt--;
		return;
	}

	if (fp->ctf_parent != NULL)
		ctf_close(fp->ctf_parent);

	for (dtd = ctf_list_next(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) {
		ntd = ctf_list_next(dtd);
		ctf_dtd_delete(fp, dtd);
	}

	ctf_free(fp->ctf_dthash, fp->ctf_dthashlen * sizeof (ctf_dtdef_t *));

	if (fp->ctf_flags & LCTF_MMAP) {
		if (fp->ctf_data.cts_data != NULL)
			ctf_sect_munmap(&fp->ctf_data);
		if (fp->ctf_symtab.cts_data != NULL)
			ctf_sect_munmap(&fp->ctf_symtab);
		if (fp->ctf_strtab.cts_data != NULL)
			ctf_sect_munmap(&fp->ctf_strtab);
	}

	if (fp->ctf_data.cts_name != _CTF_NULLSTR &&
	    fp->ctf_data.cts_name != NULL) {
		ctf_free((char *)fp->ctf_data.cts_name,
		    strlen(fp->ctf_data.cts_name) + 1);
	}

	if (fp->ctf_symtab.cts_name != _CTF_NULLSTR &&
	    fp->ctf_symtab.cts_name != NULL) {
		ctf_free((char *)fp->ctf_symtab.cts_name,
		    strlen(fp->ctf_symtab.cts_name) + 1);
	}

	if (fp->ctf_strtab.cts_name != _CTF_NULLSTR &&
	    fp->ctf_strtab.cts_name != NULL) {
		ctf_free((char *)fp->ctf_strtab.cts_name,
		    strlen(fp->ctf_strtab.cts_name) + 1);
	}

	if (fp->ctf_base != fp->ctf_data.cts_data && fp->ctf_base != NULL)
		ctf_data_free((void *)fp->ctf_base, fp->ctf_size);

	if (fp->ctf_sxlate != NULL)
		ctf_free(fp->ctf_sxlate, sizeof (uint_t) * fp->ctf_nsyms);

	if (fp->ctf_txlate != NULL) {
		ctf_free(fp->ctf_txlate,
		    sizeof (uint_t) * (fp->ctf_typemax + 1));
	}

	if (fp->ctf_ptrtab != NULL) {
		ctf_free(fp->ctf_ptrtab,
		    sizeof (ushort_t) * (fp->ctf_typemax + 1));
	}

	ctf_hash_destroy(&fp->ctf_structs);
	ctf_hash_destroy(&fp->ctf_unions);
	ctf_hash_destroy(&fp->ctf_enums);
	ctf_hash_destroy(&fp->ctf_names);

	ctf_free(fp, sizeof (ctf_file_t));
}
예제 #10
0
void
ctf_dtd_delete(ctf_file_t *fp, ctf_dtdef_t *dtd)
{
	ulong_t h = dtd->dtd_type & (fp->ctf_dthashlen - 1);
	ctf_dtdef_t *p, **q = &fp->ctf_dthash[h];
	ctf_dmdef_t *dmd, *nmd;
	size_t len;
	int kind, i;

	for (p = *q; p != NULL; p = p->dtd_hash) {
		if (p != dtd)
			q = &p->dtd_hash;
		else
			break;
	}

	if (p != NULL)
		*q = p->dtd_hash;

	kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info);
	switch (kind) {
	case CTF_K_STRUCT:
	case CTF_K_UNION:
	case CTF_K_ENUM:
		for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members);
		    dmd != NULL; dmd = nmd) {
			if (dmd->dmd_name != NULL) {
				len = strlen(dmd->dmd_name) + 1;
				ctf_free(dmd->dmd_name, len);
				fp->ctf_dtstrlen -= len;
			}
			if (kind != CTF_K_ENUM)
				ctf_ref_dec(fp, dmd->dmd_type);
			nmd = ctf_list_next(dmd);
			ctf_free(dmd, sizeof (ctf_dmdef_t));
		}
		break;
	case CTF_K_FUNCTION:
		ctf_ref_dec(fp, dtd->dtd_data.ctt_type);
		for (i = 0; i < CTF_INFO_VLEN(dtd->dtd_data.ctt_info); i++)
			if (dtd->dtd_u.dtu_argv[i] != 0)
				ctf_ref_dec(fp, dtd->dtd_u.dtu_argv[i]);
		ctf_free(dtd->dtd_u.dtu_argv, sizeof (ctf_id_t) *
		    CTF_INFO_VLEN(dtd->dtd_data.ctt_info));
		break;
	case CTF_K_ARRAY:
		ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_contents);
		ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_index);
		break;
	case CTF_K_TYPEDEF:
		ctf_ref_dec(fp, dtd->dtd_data.ctt_type);
		break;
	case CTF_K_POINTER:
	case CTF_K_VOLATILE:
	case CTF_K_CONST:
	case CTF_K_RESTRICT:
		ctf_ref_dec(fp, dtd->dtd_data.ctt_type);
		break;
	}

	if (dtd->dtd_name) {
		len = strlen(dtd->dtd_name) + 1;
		ctf_free(dtd->dtd_name, len);
		fp->ctf_dtstrlen -= len;
	}

	ctf_list_delete(&fp->ctf_dtdefs, dtd);
	ctf_free(dtd, sizeof (ctf_dtdef_t));
}
예제 #11
0
int
ctf_add_member(ctf_file_t *fp, ctf_id_t souid, const char *name, ctf_id_t type)
{
	ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, souid);
	ctf_dmdef_t *dmd;

	ssize_t msize, malign, ssize;
	uint_t kind, vlen, root;
	char *s = NULL;

	if (!(fp->ctf_flags & LCTF_RDWR))
		return (ctf_set_errno(fp, ECTF_RDONLY));

	if (dtd == NULL)
		return (ctf_set_errno(fp, ECTF_BADID));

	kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info);
	root = CTF_INFO_ISROOT(dtd->dtd_data.ctt_info);
	vlen = CTF_INFO_VLEN(dtd->dtd_data.ctt_info);

	if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
		return (ctf_set_errno(fp, ECTF_NOTSOU));

	if (vlen == CTF_MAX_VLEN)
		return (ctf_set_errno(fp, ECTF_DTFULL));

	if (name != NULL) {
		for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members);
		    dmd != NULL; dmd = ctf_list_next(dmd)) {
			if (dmd->dmd_name != NULL &&
			    strcmp(dmd->dmd_name, name) == 0)
				return (ctf_set_errno(fp, ECTF_DUPMEMBER));
		}
	}

	if ((msize = ctf_type_size(fp, type)) == CTF_ERR ||
	    (malign = ctf_type_align(fp, type)) == CTF_ERR)
		return (CTF_ERR); /* errno is set for us */

	if ((dmd = ctf_alloc(sizeof (ctf_dmdef_t))) == NULL)
		return (ctf_set_errno(fp, EAGAIN));

	if (name != NULL && (s = ctf_strdup(name)) == NULL) {
		ctf_free(dmd, sizeof (ctf_dmdef_t));
		return (ctf_set_errno(fp, EAGAIN));
	}

	dmd->dmd_name = s;
	dmd->dmd_type = type;
	dmd->dmd_value = -1;

	if (kind == CTF_K_STRUCT && vlen != 0) {
		ctf_dmdef_t *lmd = ctf_list_prev(&dtd->dtd_u.dtu_members);
		ctf_id_t ltype = ctf_type_resolve(fp, lmd->dmd_type);
		size_t off = lmd->dmd_offset;

		ctf_encoding_t linfo;
		ssize_t lsize;

		if (ctf_type_encoding(fp, ltype, &linfo) != CTF_ERR)
			off += linfo.cte_bits;
		else if ((lsize = ctf_type_size(fp, ltype)) != CTF_ERR)
			off += lsize * NBBY;

		/*
		 * Round up the offset of the end of the last member to the
		 * next byte boundary, convert 'off' to bytes, and then round
		 * it up again to the next multiple of the alignment required
		 * by the new member.  Finally, convert back to bits and store
		 * the result in dmd_offset.  Technically we could do more
		 * efficient packing if the new member is a bit-field, but
		 * we're the "compiler" and ANSI says we can do as we choose.
		 */
		off = roundup(off, NBBY) / NBBY;
		off = roundup(off, MAX(malign, 1));
		dmd->dmd_offset = off * NBBY;
		ssize = off + msize;
	} else {
		dmd->dmd_offset = 0;
		ssize = ctf_get_ctt_size(fp, &dtd->dtd_data, NULL, NULL);
		ssize = MAX(ssize, msize);
	}

	if (ssize > CTF_MAX_SIZE) {
		dtd->dtd_data.ctt_size = CTF_LSIZE_SENT;
		dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI(ssize);
		dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO(ssize);
	} else
		dtd->dtd_data.ctt_size = (ushort_t)ssize;

	dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, root, vlen + 1);
	ctf_list_append(&dtd->dtd_u.dtu_members, dmd);

	if (s != NULL)
		fp->ctf_dtstrlen += strlen(s) + 1;

	ctf_ref_inc(fp, type);
	fp->ctf_flags |= LCTF_DIRTY;
	return (0);
}
예제 #12
0
static int
ctf_write_elf(ctf_file_t *fp, Elf *src, Elf *dst, int flags)
{
	GElf_Ehdr sehdr, dehdr;
	Elf_Scn *sscn, *dscn;
	Elf_Data *sdata, *ddata;
	GElf_Shdr shdr;
	int symtab_idx = -1;
	off_t new_offset = 0;
	off_t ctfnameoff = 0;
	int compress = (flags & CTF_ELFWRITE_F_COMPRESS);
	int *secxlate = NULL;
	int srcidx, dstidx, pad, i;
	int curnmoff = 0;
	int changing = 0;
	int ret;
	size_t nshdr, nphdr, strndx;
	void *strdatabuf = NULL, *symdatabuf = NULL;
	size_t strdatasz = 0, symdatasz = 0;

	void *cdata = NULL;
	size_t elfsize, asize;

	if ((flags & ~(CTF_ELFWRITE_F_COMPRESS)) != 0) {
		ret = ctf_set_errno(fp, EINVAL);
		goto out;
	}

	if (gelf_newehdr(dst, gelf_getclass(src)) == 0) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}
	if (gelf_getehdr(src, &sehdr) == NULL) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}
	(void) memcpy(&dehdr, &sehdr, sizeof (GElf_Ehdr));
	if (gelf_update_ehdr(dst, &dehdr) == 0) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}

	/*
	 * Use libelf to get the number of sections and the string section to
	 * deal with ELF files that may have a large number of sections. We just
	 * always use this to make our live easier.
	 */
	if (elf_getphdrnum(src, &nphdr) != 0) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}
	if (elf_getshdrnum(src, &nshdr) != 0) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}
	if (elf_getshdrstrndx(src, &strndx) != 0) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}

	/*
	 * Neither the existing debug sections nor the SUNW_ctf sections (new or
	 * existing) are SHF_ALLOC'd, so they won't be in areas referenced by
	 * program headers.  As such, we can just blindly copy the program
	 * headers from the existing file to the new file.
	 */
	if (nphdr != 0) {
		(void) elf_flagelf(dst, ELF_C_SET, ELF_F_LAYOUT);
		if (gelf_newphdr(dst, nphdr) == 0) {
			ret = ctf_set_errno(fp, ECTF_ELF);
			goto out;
		}

		for (i = 0; i < nphdr; i++) {
			GElf_Phdr phdr;

			if (gelf_getphdr(src, i, &phdr) == NULL) {
				ret = ctf_set_errno(fp, ECTF_ELF);
				goto out;
			}
			if (gelf_update_phdr(dst, i, &phdr) == 0) {
				ret = ctf_set_errno(fp, ECTF_ELF);
				goto out;
			}
		}
	}

	secxlate = ctf_alloc(sizeof (int) * nshdr);
	for (srcidx = dstidx = 0; srcidx < nshdr; srcidx++) {
		Elf_Scn *scn = elf_getscn(src, srcidx);
		GElf_Shdr shdr;
		char *sname;

		if (gelf_getshdr(scn, &shdr) == NULL) {
			ret = ctf_set_errno(fp, ECTF_ELF);
			goto out;
		}
		sname = elf_strptr(src, strndx, shdr.sh_name);
		if (sname == NULL) {
			ret = ctf_set_errno(fp, ECTF_ELF);
			goto out;
		}

		if (strcmp(sname, CTF_ELF_SCN_NAME) == 0) {
			secxlate[srcidx] = -1;
		} else {
			secxlate[srcidx] = dstidx++;
			curnmoff += strlen(sname) + 1;
		}

		new_offset = (off_t)dehdr.e_phoff;
	}

	for (srcidx = 1; srcidx < nshdr; srcidx++) {
		char *sname;

		sscn = elf_getscn(src, srcidx);
		if (gelf_getshdr(sscn, &shdr) == NULL) {
			ret = ctf_set_errno(fp, ECTF_ELF);
			goto out;
		}

		if (secxlate[srcidx] == -1) {
			changing = 1;
			continue;
		}

		dscn = elf_newscn(dst);
		if (dscn == NULL) {
			ret = ctf_set_errno(fp, ECTF_ELF);
			goto out;
		}

		/*
		 * If this file has program headers, we need to explicitly lay
		 * out sections.  If none of the sections prior to this one have
		 * been removed, then we can just use the existing location.  If
		 * one or more sections have been changed, then we need to
		 * adjust this one to avoid holes.
		 */
		if (changing && nphdr != 0) {
			pad = new_offset % shdr.sh_addralign;

			if (pad != 0)
				new_offset += shdr.sh_addralign - pad;
			shdr.sh_offset = new_offset;
		}

		shdr.sh_link = secxlate[shdr.sh_link];

		if (shdr.sh_type == SHT_REL || shdr.sh_type == SHT_RELA)
			shdr.sh_info = secxlate[shdr.sh_info];

		sname = elf_strptr(src, strndx, shdr.sh_name);
		if (sname == NULL) {
			ret = ctf_set_errno(fp, ECTF_ELF);
			goto out;
		}
		if ((sdata = elf_getdata(sscn, NULL)) == NULL) {
			ret = ctf_set_errno(fp, ECTF_ELF);
			goto out;
		}
		if ((ddata = elf_newdata(dscn)) == NULL) {
			ret = ctf_set_errno(fp, ECTF_ELF);
			goto out;
		}
		bcopy(sdata, ddata, sizeof (Elf_Data));

		if (srcidx == strndx) {
			char seclen = strlen(CTF_ELF_SCN_NAME);

			strdatasz = ddata->d_size + shdr.sh_size +
			    seclen + 1;
			ddata->d_buf = strdatabuf = ctf_alloc(strdatasz);
			if (ddata->d_buf == NULL) {
				ret = ctf_set_errno(fp, ECTF_ELF);
				goto out;
			}
			bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size);
			(void) strcpy((caddr_t)ddata->d_buf + shdr.sh_size,
			    CTF_ELF_SCN_NAME);
			ctfnameoff = (off_t)shdr.sh_size;
			shdr.sh_size += seclen + 1;
			ddata->d_size += seclen + 1;

			if (nphdr != 0)
				changing = 1;
		}

		if (shdr.sh_type == SHT_SYMTAB && shdr.sh_entsize != 0) {
			int nsym = shdr.sh_size / shdr.sh_entsize;

			symtab_idx = secxlate[srcidx];

			symdatasz = shdr.sh_size;
			ddata->d_buf = symdatabuf = ctf_alloc(symdatasz);
			if (ddata->d_buf == NULL) {
				ret = ctf_set_errno(fp, ECTF_ELF);
				goto out;
			}
			(void) bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size);

			for (i = 0; i < nsym; i++) {
				GElf_Sym sym;
				short newscn;

				(void) gelf_getsym(ddata, i, &sym);

				if (sym.st_shndx >= SHN_LORESERVE)
					continue;

				if ((newscn = secxlate[sym.st_shndx]) !=
				    sym.st_shndx) {
					sym.st_shndx =
					    (newscn == -1 ? 1 : newscn);

					if (gelf_update_sym(ddata, i, &sym) ==
					    0) {
						ret = ctf_set_errno(fp,
						    ECTF_ELF);
						goto out;
					}
				}
			}
		}

		if (gelf_update_shdr(dscn, &shdr) == 0) {
			ret = ctf_set_errno(fp, ECTF_ELF);
			goto out;
		}

		new_offset = (off_t)shdr.sh_offset;
		if (shdr.sh_type != SHT_NOBITS)
			new_offset += shdr.sh_size;
	}

	if (symtab_idx == -1) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}

	/* Add the ctf section */
	if ((dscn = elf_newscn(dst)) == NULL) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}
	if (gelf_getshdr(dscn, &shdr) == NULL) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}
	shdr.sh_name = ctfnameoff;
	shdr.sh_type = SHT_PROGBITS;
	shdr.sh_size = fp->ctf_size;
	shdr.sh_link = symtab_idx;
	shdr.sh_addralign = 4;
	if (changing && nphdr != 0) {
		pad = new_offset % shdr.sh_addralign;

		if (pad)
			new_offset += shdr.sh_addralign - pad;

		shdr.sh_offset = new_offset;
		new_offset += shdr.sh_size;
	}

	if ((ddata = elf_newdata(dscn)) == NULL) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}

	if (compress != 0) {
		int err;

		if (ctf_zopen(&err) == NULL) {
			ret = ctf_set_errno(fp, err);
			goto out;
		}

		if ((err = ctf_compress(fp, &cdata, &asize, &elfsize)) != 0) {
			ret = ctf_set_errno(fp, err);
			goto out;
		}
		ddata->d_buf = cdata;
		ddata->d_size = elfsize;
	} else {
		ddata->d_buf = (void *)fp->ctf_base;
		ddata->d_size = fp->ctf_size;
	}
	ddata->d_align = shdr.sh_addralign;

	if (gelf_update_shdr(dscn, &shdr) == 0) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}

	/* update the section header location */
	if (nphdr != 0) {
		size_t align = gelf_fsize(dst, ELF_T_ADDR, 1, EV_CURRENT);
		size_t r = new_offset % align;

		if (r)
			new_offset += align - r;

		dehdr.e_shoff = new_offset;
	}

	/* commit to disk */
	if (sehdr.e_shstrndx == SHN_XINDEX)
		dehdr.e_shstrndx = SHN_XINDEX;
	else
		dehdr.e_shstrndx = secxlate[sehdr.e_shstrndx];
	if (gelf_update_ehdr(dst, &dehdr) == 0) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}
	if (elf_update(dst, ELF_C_WRITE) < 0) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}

	ret = 0;

out:
	if (strdatabuf != NULL)
		ctf_free(strdatabuf, strdatasz);
	if (symdatabuf != NULL)
		ctf_free(symdatabuf, symdatasz);
	if (cdata != NULL)
		ctf_data_free(cdata, fp->ctf_size);
	if (secxlate != NULL)
		ctf_free(secxlate, sizeof (int) * nshdr);

	return (ret);
}
예제 #13
0
/*
 * Close the specified CTF container and free associated data structures.  Note
 * that ctf_close() is a reference counted operation: if the specified file is
 * the parent of other active containers, its reference count will be greater
 * than one and it will be freed later when no active children exist.
 */
void
ctf_close(ctf_file_t *fp)
{
	ctf_dtdef_t *dtd, *ntd;
	ctf_dmdef_t *dmd, *nmd;

	if (fp == NULL)
		return; /* allow ctf_close(NULL) to simplify caller code */

	ctf_dprintf("ctf_close(%p) refcnt=%u\n", (void *)fp, fp->ctf_refcnt);

	if (fp->ctf_refcnt > 1) {
		fp->ctf_refcnt--;
		return;
	}

	for (dtd = ctf_list_next(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) {
		switch (CTF_INFO_KIND(dtd->dtd_data.ctt_info)) {
		case CTF_K_STRUCT:
		case CTF_K_UNION:
		case CTF_K_ENUM:
			for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members);
			    dmd != NULL; dmd = nmd) {
				if (dmd->dmd_name != NULL) {
					ctf_free(dmd->dmd_name,
					    strlen(dmd->dmd_name) + 1);
				}
				nmd = ctf_list_next(dmd);
				ctf_free(dmd, sizeof (ctf_dmdef_t));
			}
			break;
		case CTF_K_FUNCTION:
			ctf_free(dtd->dtd_u.dtu_argv, sizeof (ctf_id_t) *
			    CTF_INFO_VLEN(dtd->dtd_data.ctt_info));
			break;
		}

		if (dtd->dtd_name != NULL)
			ctf_free(dtd->dtd_name, strlen(dtd->dtd_name) + 1);

		ntd = ctf_list_next(dtd);
		ctf_free(dtd, sizeof (ctf_dtdef_t));
	}

	if (fp->ctf_parent != NULL)
		ctf_close(fp->ctf_parent);

	if (fp->ctf_flags & LCTF_MMAP) {
		if (fp->ctf_data.cts_data != NULL)
			ctf_sect_munmap(&fp->ctf_data);
		if (fp->ctf_symtab.cts_data != NULL)
			ctf_sect_munmap(&fp->ctf_symtab);
		if (fp->ctf_strtab.cts_data != NULL)
			ctf_sect_munmap(&fp->ctf_strtab);
	}

	if (fp->ctf_data.cts_name != _CTF_NULLSTR &&
	    fp->ctf_data.cts_name != NULL) {
		ctf_free((char *)fp->ctf_data.cts_name,
		    strlen(fp->ctf_data.cts_name) + 1);
	}

	if (fp->ctf_symtab.cts_name != _CTF_NULLSTR &&
	    fp->ctf_symtab.cts_name != NULL) {
		ctf_free((char *)fp->ctf_symtab.cts_name,
		    strlen(fp->ctf_symtab.cts_name) + 1);
	}

	if (fp->ctf_strtab.cts_name != _CTF_NULLSTR &&
	    fp->ctf_strtab.cts_name != NULL) {
		ctf_free((char *)fp->ctf_strtab.cts_name,
		    strlen(fp->ctf_strtab.cts_name) + 1);
	}

	if (fp->ctf_base != fp->ctf_data.cts_data && fp->ctf_base != NULL)
		ctf_data_free((void *)fp->ctf_base, fp->ctf_size);

	if (fp->ctf_sxlate != NULL)
		ctf_free(fp->ctf_sxlate, sizeof (uint_t) * fp->ctf_nsyms);

	if (fp->ctf_txlate != NULL) {
		ctf_free(fp->ctf_txlate,
		    sizeof (uint_t) * (fp->ctf_typemax + 1));
	}

	if (fp->ctf_ptrtab != NULL) {
		ctf_free(fp->ctf_ptrtab,
		    sizeof (ushort_t) * (fp->ctf_typemax + 1));
	}

	ctf_hash_destroy(&fp->ctf_structs);
	ctf_hash_destroy(&fp->ctf_unions);
	ctf_hash_destroy(&fp->ctf_enums);
	ctf_hash_destroy(&fp->ctf_names);

	ctf_free(fp, sizeof (ctf_file_t));
}
예제 #14
0
/*
 * Close the specified CTF container and free associated data structures.  Note
 * that ctf_close() is a reference counted operation: if the specified file is
 * the parent of other active containers, its reference count will be greater
 * than one and it will be freed later when no active children exist.
 */
void
ctf_close(ctf_file_t *fp)
{
	ctf_dtdef_t *dtd, *ntd;

	if (fp == NULL)
		return; /* allow ctf_close(NULL) to simplify caller code */

	ctf_dprintf("ctf_close(%p) refcnt=%u\n", (void *)fp, fp->ctf_refcnt);

	if (fp->ctf_refcnt > 1) {
		fp->ctf_refcnt--;
		return;
	}

	if (fp->ctf_parent != NULL)
		ctf_close(fp->ctf_parent);

	/*
	 * Note, to work properly with reference counting on the dynamic
	 * section, we must delete the list in reverse.
	 */
	for (dtd = ctf_list_prev(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) {
		ntd = ctf_list_prev(dtd);
		ctf_dtd_delete(fp, dtd);
	}

	ctf_free(fp->ctf_dthash, fp->ctf_dthashlen * sizeof (ctf_dtdef_t *));

	if (fp->ctf_flags & LCTF_MMAP) {
		if (fp->ctf_data.cts_data != NULL)
			ctf_sect_munmap(&fp->ctf_data);
		if (fp->ctf_symtab.cts_data != NULL)
			ctf_sect_munmap(&fp->ctf_symtab);
		if (fp->ctf_strtab.cts_data != NULL)
			ctf_sect_munmap(&fp->ctf_strtab);
	}

	if (fp->ctf_data.cts_name != _CTF_NULLSTR &&
	    fp->ctf_data.cts_name != NULL) {
		ctf_free(__UNCONST(fp->ctf_data.cts_name),
		    strlen(fp->ctf_data.cts_name) + 1);
	}

	if (fp->ctf_symtab.cts_name != _CTF_NULLSTR &&
	    fp->ctf_symtab.cts_name != NULL) {
		ctf_free(__UNCONST(fp->ctf_symtab.cts_name),
		    strlen(fp->ctf_symtab.cts_name) + 1);
	}

	if (fp->ctf_strtab.cts_name != _CTF_NULLSTR &&
	    fp->ctf_strtab.cts_name != NULL) {
		ctf_free(__UNCONST(fp->ctf_strtab.cts_name),
		    strlen(fp->ctf_strtab.cts_name) + 1);
	}

	if (fp->ctf_base != fp->ctf_data.cts_data && fp->ctf_base != NULL)
		ctf_data_free(__UNCONST(fp->ctf_base), fp->ctf_size);

	if (fp->ctf_sxlate != NULL)
		ctf_free(fp->ctf_sxlate, sizeof (uint_t) * fp->ctf_nsyms);

	if (fp->ctf_txlate != NULL) {
		ctf_free(fp->ctf_txlate,
		    sizeof (uint_t) * (fp->ctf_typemax + 1));
	}

	if (fp->ctf_ptrtab != NULL) {
		ctf_free(fp->ctf_ptrtab,
		    sizeof (ushort_t) * (fp->ctf_typemax + 1));
	}

	ctf_hash_destroy(&fp->ctf_structs);
	ctf_hash_destroy(&fp->ctf_unions);
	ctf_hash_destroy(&fp->ctf_enums);
	ctf_hash_destroy(&fp->ctf_names);

	ctf_free(fp, sizeof (ctf_file_t));
}