view usr/src/lib/libctf/common/ctf_convert.c @ 25635:ce2b70e7aab0

[illumos-gate merge] commit 0a554e9f2c0d440dc40a97fae2d18f1d428ca786 13404 man page spelling errors commit 9f76c6ed5b6ee0cc0bf631daca15ac3dc5fc70c4 13400 zfs-tests: implicit conversion from 'enum dmu_objset_type' to 'enum lzc_dataset_type' commit ef96fc31fc4f4306719704352d5c3e33573c039f 13399 zfs: error: implicit conversion from 'boolean_t' to 'ds_hold_flags_t' commit 56870e8c76c2675bcef1fcee5d519585ce9c768e 13393 cheetah: case value '47616' not in enumerated type commit 8247326397b1a16f37e70cf13f5b7a4f50d06712 13403 zfs: symbol 'g_zfs' is multiply-defined commit 436b964b19ef06803ad9165542d80d9d731d6486 13402 zpool: symbol 'g_zfs' is multiply-defined commit 99308ed0417a2b8ab73c5856a8a5345ce2a7aea7 13396 PoolsExecption typo in resource pools javadoc commit 1575b751c16622553e958c1e5c45e59c86b15c6e 13392 px: case value '3' not in enumerated type commit 9b0429a10eec9313ec782d8421272aff70adbfdc 13339 Add support for Hygon Dhyana Family 18h processor commit d20422bd742384b77102bb3bd09e0dc4b7372e50 13351 loader: vbe_find_mode_xydm() is using wrong safety and iteration is buggy commit 174b8e455f9a6974e69fa4e28792580acde0892d 13311 uptime(1) dazed and confused for a minute after boot commit f816551bb187d104fbf2757703d7a5d2189a3a18 13401 eeprom: 'lv' may be used uninitialized in this function commit 5e96da73c99d9d17ff5a58b793fff2ab6dcadf25 13391 fm: build errors with gcc 7 on SPARC commit 58b55f701e285559e4799354996fd284238ed0d4 13398 libstand: xdrproc_t should return bool commit c6a28d7650029501a356f7b75b2a10a5c4430cef 13394 fhc: case value '4294967295' not in enumerated type commit 58d4b16fe601073f2408de78e3db7e9bfa9abfd2 13355 remove topo module warning gags commit 1473b8d60e902819558a8b0e8a257eb0d754c3c3 13388 ZFS list bookmark not working on zvols commit 4bba12ca5cd6f92aaf0d4c0d19d05528110bc095 13368 libbe_py should support temporary BE activation commit a92282e44f968185a6bba094d1e5fece2da819cf 13376 fm: variable may be used uninitialized commit 8b1df8bf71b7b62e7e4d46fe6b457d4d6447b2b8 13367 beadm activate -t should not promote new BE datasets commit 9704bf7fb82e71b685e194a967937ff03843e73a 13317 Decrease contention on dn_struct_rwlock commit 88a08813800ed7ba7c927986421cee437f7f2233 13363 ctfconvert could support more granular ignore for missing debug data commit 3dd4cd56e7843e01a8ab147a0d102cd4f6d732c1 13342 ctfconvert could encode _Float128 for 32-bit objects commit 73197b540cc5f0434c409b68ca9e1a514a6ce91b 13336 ctfconvert should be able to unconditionally attempt conversion commit dd4422524768709a579a2a93a10c78a88a6b0ecb 13280 CTF: provide option to truncate and continue Conflicts & other fixes (with help from Jason King <jbk@joyent.com>): usr/src/lib/fm/topo/modules/common/ipmi/ipmi_enum.c usr/src/lib/libctf/common/ctf_convert.c usr/src/lib/libctf/common/ctf_lib.c usr/src/lib/libctf/common/libctf.h usr/src/lib/libproc/common/Psymtab.c usr/src/man/man1/ld.so.1.1 usr/src/man/man4/process.4
author Dan McDonald <danmcd@joyent.com>
date Mon, 04 Jan 2021 14:49:49 -0500
parents 90db1918a22e 790618c19823
children
line wrap: on
line source

/*
 * This file and its contents are supplied under the terms of the
 * Common Development and Distribution License ("CDDL"), version 1.0.
 * You may only use this file in accordance with the terms of version
 * 1.0 of the CDDL.
 *
 * A full copy of the text of the CDDL should have accompanied this
 * source.  A copy of the CDDL is also available via the Internet at
 * http://www.illumos.org/license/CDDL.
 */

/*
 * Copyright 2019 Joyent, Inc.
 * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
 */

/*
 * Main conversion entry points. This has been designed such that there can be
 * any number of different conversion backends. Currently we only have one that
 * understands DWARFv2 and DWARFv4. Each backend should be placed in
 * the ctf_converters list and each will be tried in turn.
 */

#include <libctf_impl.h>
#include <assert.h>
#include <gelf.h>
#include <sys/list.h>

static ctf_convert_f ctf_converters[] = {
	ctf_dwarf_convert
};

#define	NCONVERTS	(sizeof (ctf_converters) / sizeof (ctf_convert_f))

ctf_hsc_ret_t
ctf_has_c_source(Elf *elf, char *errmsg, size_t errlen)
{
	ctf_hsc_ret_t ret = CHR_NO_C_SOURCE;
	Elf_Scn *scn, *strscn;
	Elf_Data *data, *strdata;
	GElf_Shdr shdr;
	ulong_t i;

	scn = NULL;
	while ((scn = elf_nextscn(elf, scn)) != NULL) {
		if (gelf_getshdr(scn, &shdr) == NULL) {
			(void) snprintf(errmsg, errlen,
			    "failed to get section header: %s",
			    elf_errmsg(elf_errno()));
			return (CHR_ERROR);
		}

		if (shdr.sh_type == SHT_SYMTAB)
			break;
	}

	if (scn == NULL) {
		ctf_dprintf("Could not find symbol table section\n");
		return (CHR_NO_C_SOURCE);
	}

	if ((strscn = elf_getscn(elf, shdr.sh_link)) == NULL) {
		(void) snprintf(errmsg, errlen, "failed to get str section: %s",
		    elf_errmsg(elf_errno()));
		return (CHR_ERROR);
	}

	if ((data = elf_getdata(scn, NULL)) == NULL) {
		(void) snprintf(errmsg, errlen, "failed to read section: %s",
		    elf_errmsg(elf_errno()));
		return (CHR_ERROR);
	}

	if ((strdata = elf_getdata(strscn, NULL)) == NULL) {
		(void) snprintf(errmsg, errlen,
		    "failed to read string table: %s", elf_errmsg(elf_errno()));
		return (CHR_ERROR);
	}

	ctf_dprintf("Walking string table looking for .c files\n");

	for (i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) {
		GElf_Sym sym;
		const char *file;
		size_t len;

		if (gelf_getsym(data, i, &sym) == NULL) {
			(void) snprintf(errmsg, errlen,
			    "failed to read sym %lu: %s",
			    i, elf_errmsg(elf_errno()));
			return (CHR_ERROR);
		}

		file = (const char *)((uintptr_t)strdata->d_buf + sym.st_name);

		if (GELF_ST_TYPE(sym.st_info) != STT_FILE) {
			ctf_dprintf("'%s'\n", file);
			continue;
		}

		ctf_dprintf("'%s'; is a file\n", file);

		len = strlen(file);
		if (len >= 2 && strncmp(".c", &file[len - 2], 2) == 0) {
			ret = CHR_HAS_C_SOURCE;
			ctf_dprintf("Found .c file - '%s'\n", file);
			break;
		}
	}

	return (ret);
}

ctf_file_t *
ctf_elfconvert(ctf_convert_t *cch, int fd, Elf *elf, int *errp, char *errbuf,
    size_t errlen)
{
	int err, i;
	ctf_file_t *fp = NULL;
	boolean_t no_c_src = B_FALSE;

	if (errp == NULL)
		errp = &err;

	if (elf == NULL) {
		*errp = EINVAL;
		return (NULL);
	}

	if (elf_kind(elf) != ELF_K_ELF) {
		*errp = ECTF_FMT;
		return (NULL);
	}

	switch (ctf_has_c_source(elf, errbuf, errlen)) {
	case CHR_ERROR:
		*errp = ECTF_ELF;
		return (NULL);

	case CHR_NO_C_SOURCE:
		if ((cch->cch_flags & CTF_FORCE_CONVERSION) == 0) {
			*errp = ECTF_CONVNOCSRC;
			return (NULL);
		}
		no_c_src = B_TRUE;
		break;

	default:
		break;
	}

	for (i = 0; i < NCONVERTS; i++) {
		fp = NULL;
		err = ctf_converters[i](cch, fd, elf, &fp, errbuf, errlen);

		if (err != ECTF_CONVNODEBUG)
			break;
	}

	if (err != 0) {
		assert(fp == NULL);
		/*
		 * If no C source was found but we attempted conversion anyway
		 * due to CTF_FORCE_CONVERSION, and none of the converters
		 * was able to process the object, return ECTF_CONVNOCSRC.
		 */
		if (no_c_src && err == ECTF_CONVNODEBUG)
			*errp = ECTF_CONVNOCSRC;
		else
			*errp = err;
		return (NULL);
	}

	if (cch->cch_label != NULL) {
		if (ctf_add_label(fp, cch->cch_label, fp->ctf_typemax, 0) ==
		    CTF_ERR) {
			*errp = ctf_errno(fp);
			ctf_close(fp);
			return (NULL);
		}
		if (ctf_update(fp) == CTF_ERR) {
			*errp = ctf_errno(fp);
			ctf_close(fp);
			return (NULL);
		}
	}

	return (fp);
}

ctf_convert_t *
ctf_convert_init(int *errp)
{
	struct ctf_convert_handle *cch;
	int err;

	if (errp == NULL)
		errp = &err;
	*errp = 0;

	cch = ctf_alloc(sizeof (struct ctf_convert_handle));
	if (cch == NULL) {
		*errp = ENOMEM;
		return (NULL);
	}

	cch->cch_label = NULL;
	cch->cch_flags = 0;
	cch->cch_nthreads = CTF_CONVERT_DEFAULT_NTHREADS;
	cch->cch_batchsize = CTF_CONVERT_DEFAULT_BATCHSIZE;
	cch->cch_warncb = NULL;
	cch->cch_warncb_arg = NULL;
	list_create(&cch->cch_nodebug, sizeof (ctf_convert_filelist_t),
	    offsetof(ctf_convert_filelist_t, ccf_node));

	return (cch);
}

static void
ctf_convert_fini_filelist(ctf_convert_filelist_t *ccf)
{
	ctf_strfree(ccf->ccf_basename);
	ctf_free(ccf, sizeof (ctf_convert_filelist_t));
}

void
ctf_convert_fini(ctf_convert_t *cch)
{
	ctf_convert_filelist_t *ccf;

	ctf_strfree(cch->cch_label);
	while ((ccf = list_remove_head(&cch->cch_nodebug)) != NULL)
		ctf_convert_fini_filelist(ccf);
	list_destroy(&cch->cch_nodebug);

	ctf_free(cch, sizeof (struct ctf_convert_handle));
}

int
ctf_convert_set_nthreads(ctf_convert_t *cch, uint_t nthrs)
{
	if (nthrs == 0)
		return (EINVAL);
	cch->cch_nthreads = nthrs;
	return (0);
}

int
ctf_convert_set_batchsize(ctf_convert_t *cch, uint_t bsize)
{
	if (bsize == 0)
		return (EINVAL);
	cch->cch_batchsize = bsize;
	return (0);
}

int
ctf_convert_set_flags(ctf_convert_t *cch, uint_t flags)
{
	if ((flags & ~CTF_CONVERT_ALL_FLAGS) != 0)
		return (EINVAL);
	cch->cch_flags = flags;
	return (0);
}

int
ctf_convert_set_label(ctf_convert_t *cch, const char *label)
{
	char *dup;

	if (label == NULL)
		return (EINVAL);

	dup = ctf_strdup(label);
	if (dup == NULL)
		return (ENOMEM);

	ctf_strfree(cch->cch_label);
	cch->cch_label = dup;
	return (0);
}

int
ctf_convert_set_warncb(ctf_convert_t *cch, ctf_convert_warn_f cb, void *arg)
{
	cch->cch_warncb = cb;
	cch->cch_warncb_arg = arg;
	return (0);
}

int
ctf_convert_add_ignore(ctf_convert_t *cch, const char *basename)
{
	ctf_convert_filelist_t *ccf;

	if (strchr(basename, '/') != NULL)
		return (EINVAL);

	ccf = ctf_alloc(sizeof (ctf_convert_filelist_t));
	if (ccf == NULL)
		return (ENOMEM);

	ccf->ccf_basename = ctf_strdup(basename);
	if (ccf->ccf_basename == NULL) {
		ctf_free(ccf, sizeof (ctf_convert_filelist_t));
		return (ENOMEM);
	}
	list_insert_tail(&cch->cch_nodebug, ccf);

	return (0);
}

ctf_file_t *
ctf_fdconvert(ctf_convert_t *cch, int fd, int *errp,
    char *errbuf, size_t errlen)
{
	int err;
	Elf *elf;
	ctf_file_t *fp;

	if (errp == NULL)
		errp = &err;

	elf = elf_begin(fd, ELF_C_READ, NULL);
	if (elf == NULL) {
		*errp = ECTF_FMT;
		return (NULL);
	}

	fp = ctf_elfconvert(cch, fd, elf, errp, errbuf, errlen);

	(void) elf_end(elf);
	return (fp);
}