Exemple #1
0
/*
 * Attempt to dlopen the decompression library and locate the symbols of
 * interest that we will need to call.  This information in cached so
 * that multiple calls to ctf_bufopen() do not need to reopen the library.
 */
void *
ctf_zopen(int *errp)
{
#if defined(sun)
	ctf_dprintf("decompressing CTF data using %s\n", _libctf_zlib);

	if (zlib.z_dlp != NULL)
		return (zlib.z_dlp); /* library is already loaded */

	if (access(_libctf_zlib, R_OK) == -1)
		return (ctf_set_open_errno(errp, ECTF_ZMISSING));

	if ((zlib.z_dlp = dlopen(_libctf_zlib, RTLD_LAZY | RTLD_LOCAL)) == NULL)
		return (ctf_set_open_errno(errp, ECTF_ZINIT));

	zlib.z_uncompress = (int (*)(uchar_t *, ulong_t *, const uchar_t *, ulong_t)) dlsym(zlib.z_dlp, "uncompress");
	zlib.z_error = (const char *(*)(int)) dlsym(zlib.z_dlp, "zError");

	if (zlib.z_uncompress == NULL || zlib.z_error == NULL) {
		(void) dlclose(zlib.z_dlp);
		bzero(&zlib, sizeof (zlib));
		return (ctf_set_open_errno(errp, ECTF_ZINIT));
	}
#else
	zlib.z_uncompress = uncompress;
	zlib.z_error = zError;

	/* Dummy return variable as 'no error' */
	zlib.z_dlp = (void *) (uintptr_t) 1;
#endif

	return (zlib.z_dlp);
}
Exemple #2
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);
}
/*
 * Decode the specified CTF buffer and optional symbol table and create a new
 * CTF container representing the symbolic debugging information.  This code
 * can be used directly by the debugger, or it can be used as the engine for
 * ctf_fdopen() or ctf_open(), below.
 */
ctf_file_t *
ctf_bufopen(const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
    const ctf_sect_t *strsect, int *errp)
{
	const ctf_preamble_t *pp;
	ctf_header_t hp;
	ctf_file_t *fp;
	void *buf, *base;
	size_t size, hdrsz;
	int err;

	if (ctfsect == NULL || ((symsect == NULL) != (strsect == NULL)))
		return (ctf_set_open_errno(errp, EINVAL));

	if (symsect != NULL && symsect->cts_entsize != sizeof (struct nlist) &&
	    symsect->cts_entsize != sizeof (struct nlist_64))
		return (ctf_set_open_errno(errp, ECTF_SYMTAB));

	if (symsect != NULL && symsect->cts_data == NULL)
		return (ctf_set_open_errno(errp, ECTF_SYMBAD));

	if (strsect != NULL && strsect->cts_data == NULL)
		return (ctf_set_open_errno(errp, ECTF_STRBAD));

	if (ctfsect->cts_size < sizeof (ctf_preamble_t))
		return (ctf_set_open_errno(errp, ECTF_NOCTFBUF));

	pp = (const ctf_preamble_t *)ctfsect->cts_data;

	ctf_dprintf("ctf_bufopen: magic=0x%x version=%u\n",
	    pp->ctp_magic, pp->ctp_version);

	/*
	 * Validate each part of the CTF header (either V1 or V2).
	 * First, we validate the preamble (common to all versions).  At that
	 * point, we know specific header version, and can validate the
	 * version-specific parts including section offsets and alignments.
	 */
	if (pp->ctp_magic != CTF_MAGIC)
		return (ctf_set_open_errno(errp, ECTF_NOCTFBUF));

	if (pp->ctp_version == CTF_VERSION_2) {
		if (ctfsect->cts_size < sizeof (ctf_header_t))
			return (ctf_set_open_errno(errp, ECTF_NOCTFBUF));

		bcopy(ctfsect->cts_data, &hp, sizeof (hp));
		hdrsz = sizeof (ctf_header_t);

	} else if (pp->ctp_version == CTF_VERSION_1) {
		const ctf_header_v1_t *h1p =
		    (const ctf_header_v1_t *)ctfsect->cts_data;

		if (ctfsect->cts_size < sizeof (ctf_header_v1_t))
			return (ctf_set_open_errno(errp, ECTF_NOCTFBUF));

		bzero(&hp, sizeof (hp));
		hp.cth_preamble = h1p->cth_preamble;
		hp.cth_objtoff = h1p->cth_objtoff;
		hp.cth_funcoff = h1p->cth_funcoff;
		hp.cth_typeoff = h1p->cth_typeoff;
		hp.cth_stroff = h1p->cth_stroff;
		hp.cth_strlen = h1p->cth_strlen;

		hdrsz = sizeof (ctf_header_v1_t);
	} else
		return (ctf_set_open_errno(errp, ECTF_CTFVERS));

	size = hp.cth_stroff + hp.cth_strlen;

	ctf_dprintf("ctf_bufopen: uncompressed size=%lu\n", (ulong_t)size);

	if (hp.cth_lbloff > size || hp.cth_objtoff > size ||
	    hp.cth_funcoff > size || hp.cth_typeoff > size ||
	    hp.cth_stroff > size)
		return (ctf_set_open_errno(errp, ECTF_CORRUPT));

	if (hp.cth_lbloff > hp.cth_objtoff ||
	    hp.cth_objtoff > hp.cth_funcoff ||
	    hp.cth_funcoff > hp.cth_typeoff ||
	    hp.cth_typeoff > hp.cth_stroff)
		return (ctf_set_open_errno(errp, ECTF_CORRUPT));

	if ((hp.cth_lbloff & 3) || (hp.cth_objtoff & 1) ||
	    (hp.cth_funcoff & 1) || (hp.cth_typeoff & 3))
		return (ctf_set_open_errno(errp, ECTF_CORRUPT));

	/*
	 * Once everything is determined to be valid, attempt to decompress
	 * the CTF data buffer if it is compressed.  Otherwise we just put
	 * the data section's buffer pointer into ctf_buf, below.
	 */
	if (hp.cth_flags & CTF_F_COMPRESS) {
		size_t srclen, dstlen;
		const void *src;
		int rc = Z_OK;

		if (ctf_zopen(errp) == NULL)
			return (NULL); /* errp is set for us */

		if ((base = ctf_data_alloc(size + hdrsz)) == MAP_FAILED)
			return (ctf_set_open_errno(errp, ECTF_ZALLOC));

		bcopy(ctfsect->cts_data, base, hdrsz);
		((ctf_preamble_t *)base)->ctp_flags &= ~CTF_F_COMPRESS;
		buf = (uchar_t *)base + hdrsz;

		src = (uchar_t *)ctfsect->cts_data + hdrsz;
		srclen = ctfsect->cts_size - hdrsz;
		dstlen = size;

		if ((rc = z_uncompress(buf, &dstlen, src, srclen)) != Z_OK) {
			ctf_dprintf("zlib inflate err: %s\n", z_strerror(rc));
			ctf_data_free(base, size + hdrsz);
			return (ctf_set_open_errno(errp, ECTF_DECOMPRESS));
		}

		if (dstlen != size) {
			ctf_dprintf("zlib inflate short -- got %lu of %lu "
			    "bytes\n", (ulong_t)dstlen, (ulong_t)size);
			ctf_data_free(base, size + hdrsz);
			return (ctf_set_open_errno(errp, ECTF_CORRUPT));
		}

		ctf_data_protect(base, size + hdrsz);

	} else {
		base = (void *)ctfsect->cts_data;
		buf = (uchar_t *)base + hdrsz;
	}

	/*
	 * Once we have uncompressed and validated the CTF data buffer, we can
	 * proceed with allocating a ctf_file_t and initializing it.
	 */
	if ((fp = ctf_alloc(sizeof (ctf_file_t))) == NULL)
		return (ctf_set_open_errno(errp, EAGAIN));

	bzero(fp, sizeof (ctf_file_t));
	fp->ctf_version = hp.cth_version;
	fp->ctf_fileops = &ctf_fileops[hp.cth_version];
	bcopy(ctfsect, &fp->ctf_data, sizeof (ctf_sect_t));

	if (symsect != NULL) {
		bcopy(symsect, &fp->ctf_symtab, sizeof (ctf_sect_t));
		bcopy(strsect, &fp->ctf_strtab, sizeof (ctf_sect_t));
	}

	if (fp->ctf_data.cts_name != NULL)
		fp->ctf_data.cts_name = ctf_strdup(fp->ctf_data.cts_name);
	if (fp->ctf_symtab.cts_name != NULL)
		fp->ctf_symtab.cts_name = ctf_strdup(fp->ctf_symtab.cts_name);
	if (fp->ctf_strtab.cts_name != NULL)
		fp->ctf_strtab.cts_name = ctf_strdup(fp->ctf_strtab.cts_name);

	if (fp->ctf_data.cts_name == NULL)
		fp->ctf_data.cts_name = _CTF_NULLSTR;
	if (fp->ctf_symtab.cts_name == NULL)
		fp->ctf_symtab.cts_name = _CTF_NULLSTR;
	if (fp->ctf_strtab.cts_name == NULL)
		fp->ctf_strtab.cts_name = _CTF_NULLSTR;

	fp->ctf_str[CTF_STRTAB_0].cts_strs = (const char *)buf + hp.cth_stroff;
	fp->ctf_str[CTF_STRTAB_0].cts_len = hp.cth_strlen;

	if (strsect != NULL) {
		fp->ctf_str[CTF_STRTAB_1].cts_strs = strsect->cts_data;
		fp->ctf_str[CTF_STRTAB_1].cts_len = strsect->cts_size;
	}

	fp->ctf_base = base;
	fp->ctf_buf = buf;
	fp->ctf_size = size + hdrsz;

	/*
	 * If we have a parent container name and label, store the relocated
	 * string pointers in the CTF container for easy access later.
	 */
	if (hp.cth_parlabel != 0)
		fp->ctf_parlabel = ctf_strptr(fp, hp.cth_parlabel);
	if (hp.cth_parname != 0)
		fp->ctf_parname = ctf_strptr(fp, hp.cth_parname);

	ctf_dprintf("ctf_bufopen: parent name %s (label %s)\n",
	    fp->ctf_parname ? fp->ctf_parname : "<NULL>",
	    fp->ctf_parlabel ? fp->ctf_parlabel : "<NULL>");

	/*
	 * If we have a symbol table section, allocate and initialize
	 * the symtab translation table, pointed to by ctf_sxlate.
	 */
	if (symsect != NULL) {
		fp->ctf_nsyms = symsect->cts_size / symsect->cts_entsize;
		fp->ctf_sxlate = ctf_alloc(fp->ctf_nsyms * sizeof (uint_t));

		if (fp->ctf_sxlate == NULL) {
			(void) ctf_set_open_errno(errp, EAGAIN);
			goto bad;
		}

		if ((err = init_symtab(fp, &hp, symsect, strsect)) != 0) {
			(void) ctf_set_open_errno(errp, err);
			goto bad;
		}
	}

	if ((err = init_types(fp, &hp)) != 0) {
		(void) ctf_set_open_errno(errp, err);
		goto bad;
	}

	/*
	 * Initialize the ctf_lookup_by_name top-level dictionary.  We keep an
	 * array of type name prefixes and the corresponding ctf_hash to use.
	 * NOTE: This code must be kept in sync with the code in ctf_update().
	 */
	fp->ctf_lookups[0].ctl_prefix = "struct";
	fp->ctf_lookups[0].ctl_len = strlen(fp->ctf_lookups[0].ctl_prefix);
	fp->ctf_lookups[0].ctl_hash = &fp->ctf_structs;
	fp->ctf_lookups[1].ctl_prefix = "union";
	fp->ctf_lookups[1].ctl_len = strlen(fp->ctf_lookups[1].ctl_prefix);
	fp->ctf_lookups[1].ctl_hash = &fp->ctf_unions;
	fp->ctf_lookups[2].ctl_prefix = "enum";
	fp->ctf_lookups[2].ctl_len = strlen(fp->ctf_lookups[2].ctl_prefix);
	fp->ctf_lookups[2].ctl_hash = &fp->ctf_enums;
	fp->ctf_lookups[3].ctl_prefix = _CTF_NULLSTR;
	fp->ctf_lookups[3].ctl_len = strlen(fp->ctf_lookups[3].ctl_prefix);
	fp->ctf_lookups[3].ctl_hash = &fp->ctf_names;
	fp->ctf_lookups[4].ctl_prefix = NULL;
	fp->ctf_lookups[4].ctl_len = 0;
	fp->ctf_lookups[4].ctl_hash = NULL;

	if (symsect != NULL) {
		if (symsect->cts_entsize == sizeof (struct nlist_64))
			(void) ctf_setmodel(fp, CTF_MODEL_LP64);
		else if (symsect->cts_entsize == sizeof (struct nlist))
			(void) ctf_setmodel(fp, CTF_MODEL_ILP32);
		else if (symsect->cts_entsize == sizeof (Elf64_Sym))
			(void) ctf_setmodel(fp, CTF_MODEL_LP64);
		else
			(void) ctf_setmodel(fp, CTF_MODEL_ILP32);
	} else
		(void) ctf_setmodel(fp, CTF_MODEL_NATIVE);

	fp->ctf_refcnt = 1;
	return (fp);

bad:
	ctf_close(fp);
	return (NULL);
}
Exemple #4
0
/*
 * Open the specified file descriptor and return a pointer to a CTF container.
 * The file can be either an ELF file or raw CTF file.  The caller is
 * responsible for closing the file descriptor when it is no longer needed.
 */
ctf_file_t *
ctf_fdopen(int fd, int *errp)
{
	ctf_sect_t ctfsect, symsect, strsect;
	ctf_file_t *fp = NULL;

	struct stat64 st;
	ssize_t nbytes;

	union {
		ctf_preamble_t ctf;
		Elf32_Ehdr e32;
		GElf_Ehdr e64;
	} hdr;

	bzero(&ctfsect, sizeof (ctf_sect_t));
	bzero(&symsect, sizeof (ctf_sect_t));
	bzero(&strsect, sizeof (ctf_sect_t));
	bzero(&hdr.ctf, sizeof (hdr));

	if (fstat64(fd, &st) == -1)
		return (ctf_set_open_errno(errp, errno));

	if ((nbytes = pread64(fd, &hdr.ctf, sizeof (hdr), 0)) <= 0)
		return (ctf_set_open_errno(errp, nbytes < 0? errno : ECTF_FMT));

	/*
	 * If we have read enough bytes to form a CTF header and the magic
	 * string matches, attempt to interpret the file as raw CTF.
	 */
	if (nbytes >= (ssize_t) sizeof (ctf_preamble_t) &&
	    hdr.ctf.ctp_magic == CTF_MAGIC) {
		if (hdr.ctf.ctp_version > CTF_VERSION)
			return (ctf_set_open_errno(errp, ECTF_CTFVERS));

		ctfsect.cts_data = mmap64(NULL, st.st_size, PROT_READ,
		    MAP_PRIVATE, fd, 0);

		if (ctfsect.cts_data == MAP_FAILED)
			return (ctf_set_open_errno(errp, errno));

		ctfsect.cts_name = _CTF_SECTION;
		ctfsect.cts_type = SHT_PROGBITS;
		ctfsect.cts_flags = SHF_ALLOC;
		ctfsect.cts_size = (size_t)st.st_size;
		ctfsect.cts_entsize = 1;
		ctfsect.cts_offset = 0;

		if ((fp = ctf_bufopen(&ctfsect, NULL, NULL, errp)) == NULL)
			ctf_sect_munmap(&ctfsect);

		return (fp);
	}

	/*
	 * If we have read enough bytes to form an ELF header and the magic
	 * string matches, attempt to interpret the file as an ELF file.  We
	 * do our own largefile ELF processing, and convert everything to
	 * GElf structures so that clients can operate on any data model.
	 */
	if (nbytes >= (ssize_t) sizeof (Elf32_Ehdr) &&
	    bcmp(&hdr.e32.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0) {
#ifdef	_BIG_ENDIAN
		uchar_t order = ELFDATA2MSB;
#else
		uchar_t order = ELFDATA2LSB;
#endif
		GElf_Half i, n;
		GElf_Shdr *sp;

		void *strs_map;
		size_t strs_mapsz;
		char *strs;

		if (hdr.e32.e_ident[EI_DATA] != order)
			return (ctf_set_open_errno(errp, ECTF_ENDIAN));
		if (hdr.e32.e_version != EV_CURRENT)
			return (ctf_set_open_errno(errp, ECTF_ELFVERS));

		if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS64) {
			if (nbytes < (ssize_t) sizeof (GElf_Ehdr))
				return (ctf_set_open_errno(errp, ECTF_FMT));
		} else {
			Elf32_Ehdr e32 = hdr.e32;
			ehdr_to_gelf(&e32, &hdr.e64);
		}

		if (hdr.e64.e_shstrndx >= hdr.e64.e_shnum)
			return (ctf_set_open_errno(errp, ECTF_CORRUPT));

		n = hdr.e64.e_shnum;
		nbytes = sizeof (GElf_Shdr) * n;

		if ((sp = malloc(nbytes)) == NULL)
			return (ctf_set_open_errno(errp, errno));

		/*
		 * Read in and convert to GElf the array of Shdr structures
		 * from e_shoff so we can locate sections of interest.
		 */
		if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS32) {
			Elf32_Shdr *sp32;

			nbytes = sizeof (Elf32_Shdr) * n;

			if ((sp32 = malloc(nbytes)) == NULL || pread64(fd,
			    sp32, nbytes, hdr.e64.e_shoff) != nbytes) {
				free(sp);
				return (ctf_set_open_errno(errp, errno));
			}

			for (i = 0; i < n; i++)
				shdr_to_gelf(&sp32[i], &sp[i]);

			free(sp32);

		} else if (pread64(fd, sp, nbytes, hdr.e64.e_shoff) != nbytes) {
			free(sp);
			return (ctf_set_open_errno(errp, errno));
		}

		/*
		 * Now mmap the section header strings section so that we can
		 * perform string comparison on the section names.
		 */
		strs_mapsz = sp[hdr.e64.e_shstrndx].sh_size +
		    (sp[hdr.e64.e_shstrndx].sh_offset & ~_PAGEMASK);

		strs_map = mmap64(NULL, strs_mapsz, PROT_READ, MAP_PRIVATE,
		    fd, sp[hdr.e64.e_shstrndx].sh_offset & _PAGEMASK);

		strs = (char *)strs_map +
		    (sp[hdr.e64.e_shstrndx].sh_offset & ~_PAGEMASK);

		if (strs_map == MAP_FAILED) {
			free(sp);
			return (ctf_set_open_errno(errp, ECTF_MMAP));
		}

		/*
		 * Iterate over the section header array looking for the CTF
		 * section and symbol table.  The strtab is linked to symtab.
		 */
		for (i = 0; i < n; i++) {
			const GElf_Shdr *shp = &sp[i];
			const GElf_Shdr *lhp = &sp[shp->sh_link];

			if (shp->sh_link >= hdr.e64.e_shnum)
				continue; /* corrupt sh_link field */

			if (shp->sh_name >= sp[hdr.e64.e_shstrndx].sh_size ||
			    lhp->sh_name >= sp[hdr.e64.e_shstrndx].sh_size)
				continue; /* corrupt sh_name field */

			if (shp->sh_type == SHT_PROGBITS &&
			    strcmp(strs + shp->sh_name, _CTF_SECTION) == 0) {
				ctfsect.cts_name = strs + shp->sh_name;
				ctfsect.cts_type = shp->sh_type;
				ctfsect.cts_flags = shp->sh_flags;
				ctfsect.cts_size = shp->sh_size;
				ctfsect.cts_entsize = shp->sh_entsize;
				ctfsect.cts_offset = (off64_t)shp->sh_offset;

			} else if (shp->sh_type == SHT_SYMTAB) {
				symsect.cts_name = strs + shp->sh_name;
				symsect.cts_type = shp->sh_type;
				symsect.cts_flags = shp->sh_flags;
				symsect.cts_size = shp->sh_size;
				symsect.cts_entsize = shp->sh_entsize;
				symsect.cts_offset = (off64_t)shp->sh_offset;

				strsect.cts_name = strs + lhp->sh_name;
				strsect.cts_type = lhp->sh_type;
				strsect.cts_flags = lhp->sh_flags;
				strsect.cts_size = lhp->sh_size;
				strsect.cts_entsize = lhp->sh_entsize;
				strsect.cts_offset = (off64_t)lhp->sh_offset;
			}
		}

		free(sp); /* free section header array */

		if (ctfsect.cts_type == SHT_NULL) {
			(void) munmap(strs_map, strs_mapsz);
			return (ctf_set_open_errno(errp, ECTF_NOCTFDATA));
		}

		/*
		 * Now mmap the CTF data, symtab, and strtab sections and
		 * call ctf_bufopen() to do the rest of the work.
		 */
		if (ctf_sect_mmap(&ctfsect, fd) == MAP_FAILED) {
			(void) munmap(strs_map, strs_mapsz);
			return (ctf_set_open_errno(errp, ECTF_MMAP));
		}

		if (symsect.cts_type != SHT_NULL &&
		    strsect.cts_type != SHT_NULL) {
			if (ctf_sect_mmap(&symsect, fd) == MAP_FAILED ||
			    ctf_sect_mmap(&strsect, fd) == MAP_FAILED) {
				(void) ctf_set_open_errno(errp, ECTF_MMAP);
				goto bad; /* unmap all and abort */
			}
			fp = ctf_bufopen(&ctfsect, &symsect, &strsect, errp);
		} else
			fp = ctf_bufopen(&ctfsect, NULL, NULL, errp);
bad:
		if (fp == NULL) {
			ctf_sect_munmap(&ctfsect);
			ctf_sect_munmap(&symsect);
			ctf_sect_munmap(&strsect);
		} else
			fp->ctf_flags |= LCTF_MMAP;

		(void) munmap(strs_map, strs_mapsz);
		return (fp);
	}

	return (ctf_set_open_errno(errp, ECTF_FMT));
}