/* * 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 2015 Joyent, Inc. */ /* * 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 bits of DWARFv4). Each backend should be placed in * the ctf_converters list and each will be tried in turn. */ #include #include ctf_convert_f ctf_converters[] = { ctf_dwarf_convert }; #define NCONVERTS (sizeof (ctf_converters) / sizeof (ctf_convert_f)) typedef enum ctf_convert_source { CTFCONV_SOURCE_NONE = 0x0, CTFCONV_SOURCE_UNKNOWN = 0x01, CTFCONV_SOURCE_C = 0x02, CTFCONV_SOURCE_S = 0x04 } ctf_convert_source_t; static void ctf_convert_ftypes(Elf *elf, ctf_convert_source_t *types) { int i; Elf_Scn *scn = NULL, *strscn; *types = CTFCONV_SOURCE_NONE; GElf_Shdr shdr; Elf_Data *data, *strdata; while ((scn = elf_nextscn(elf, scn)) != NULL) { if (gelf_getshdr(scn, &shdr) == NULL) return; if (shdr.sh_type == SHT_SYMTAB) break; } if (scn == NULL) return; if ((strscn = elf_getscn(elf, shdr.sh_link)) == NULL) return; if ((data = elf_getdata(scn, NULL)) == NULL) return; if ((strdata = elf_getdata(strscn, NULL)) == NULL) return; 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) return; if (GELF_ST_TYPE(sym.st_info) != STT_FILE) continue; file = (const char *)((uintptr_t)strdata->d_buf + sym.st_name); len = strlen(file); if (len < 2 || file[len - 2] != '.') { *types |= CTFCONV_SOURCE_UNKNOWN; continue; } switch (file[len - 1]) { case 'c': *types |= CTFCONV_SOURCE_C; break; case 'h': /* We traditionally ignore header files... */ break; case 's': *types |= CTFCONV_SOURCE_S; break; default: *types |= CTFCONV_SOURCE_UNKNOWN; break; } } } static ctf_file_t * ctf_elfconvert(int fd, Elf *elf, const char *label, uint_t nthrs, uint_t flags, int *errp, char *errbuf, size_t errlen) { int err, i; ctf_file_t *fp = NULL; boolean_t notsup = B_TRUE; ctf_convert_source_t type; if (errp == NULL) errp = &err; if (elf == NULL) { *errp = EINVAL; return (NULL); } if (flags & ~CTF_CONVERT_F_IGNNONC) { *errp = EINVAL; return (NULL); } if (elf_kind(elf) != ELF_K_ELF) { *errp = ECTF_FMT; return (NULL); } ctf_convert_ftypes(elf, &type); ctf_dprintf("got types: %d\n", type); if (flags & CTF_CONVERT_F_IGNNONC) { if (type == CTFCONV_SOURCE_NONE || (type & CTFCONV_SOURCE_UNKNOWN)) { *errp = ECTF_CONVNOCSRC; return (NULL); } } for (i = 0; i < NCONVERTS; i++) { ctf_conv_status_t cs; fp = NULL; cs = ctf_converters[i](fd, elf, nthrs, errp, &fp, errbuf, errlen); if (cs == CTF_CONV_SUCCESS) { notsup = B_FALSE; break; } if (cs == CTF_CONV_ERROR) { fp = NULL; notsup = B_FALSE; break; } } if (notsup == B_TRUE) { if ((flags & CTF_CONVERT_F_IGNNONC) != 0 && (type & CTFCONV_SOURCE_C) == 0) { *errp = ECTF_CONVNOCSRC; return (NULL); } *errp = ECTF_NOCONVBKEND; return (NULL); } /* * Succsesful conversion. */ if (fp != NULL) { if (label == NULL) label = ""; if (ctf_add_label(fp, 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_file_t * ctf_fdconvert(int fd, const char *label, uint_t nthrs, uint_t flags, 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(fd, elf, label, nthrs, flags, errp, errbuf, errlen); (void) elf_end(elf); return (fp); }