1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2015 Joyent, Inc. 14 */ 15 16 /* 17 * Main conversion entry points. This has been designed such that there can be 18 * any number of different conversion backends. Currently we only have one that 19 * understands DWARFv2 (and bits of DWARFv4). Each backend should be placed in 20 * the ctf_converters list and each will be tried in turn. 21 */ 22 23 #include <libctf_impl.h> 24 #include <gelf.h> 25 26 ctf_convert_f ctf_converters[] = { 27 ctf_dwarf_convert 28 }; 29 30 #define NCONVERTS (sizeof (ctf_converters) / sizeof (ctf_convert_f)) 31 32 typedef enum ctf_convert_source { 33 CTFCONV_SOURCE_NONE = 0x0, 34 CTFCONV_SOURCE_UNKNOWN = 0x01, 35 CTFCONV_SOURCE_C = 0x02, 36 CTFCONV_SOURCE_S = 0x04 37 } ctf_convert_source_t; 38 39 static void 40 ctf_convert_ftypes(Elf *elf, ctf_convert_source_t *types) 41 { 42 int i; 43 Elf_Scn *scn = NULL, *strscn; 44 *types = CTFCONV_SOURCE_NONE; 45 GElf_Shdr shdr; 46 Elf_Data *data, *strdata; 47 48 while ((scn = elf_nextscn(elf, scn)) != NULL) { 49 50 if (gelf_getshdr(scn, &shdr) == NULL) 51 return; 52 53 if (shdr.sh_type == SHT_SYMTAB) 54 break; 55 } 56 57 if (scn == NULL) 58 return; 59 60 if ((strscn = elf_getscn(elf, shdr.sh_link)) == NULL) 61 return; 62 63 if ((data = elf_getdata(scn, NULL)) == NULL) 64 return; 65 66 if ((strdata = elf_getdata(strscn, NULL)) == NULL) 67 return; 68 69 for (i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) { 70 GElf_Sym sym; 71 const char *file; 72 size_t len; 73 74 if (gelf_getsym(data, i, &sym) == NULL) 75 return; 76 77 if (GELF_ST_TYPE(sym.st_info) != STT_FILE) 78 continue; 79 80 file = (const char *)((uintptr_t)strdata->d_buf + sym.st_name); 81 len = strlen(file); 82 if (len < 2 || file[len - 2] != '.') { 83 *types |= CTFCONV_SOURCE_UNKNOWN; 84 continue; 85 } 86 87 switch (file[len - 1]) { 88 case 'c': 89 *types |= CTFCONV_SOURCE_C; 90 break; 91 case 'h': 92 /* We traditionally ignore header files... */ 93 break; 94 case 's': 95 *types |= CTFCONV_SOURCE_S; 96 break; 97 default: 98 *types |= CTFCONV_SOURCE_UNKNOWN; 99 break; 100 } 101 } 102 } 103 104 static ctf_file_t * 105 ctf_elfconvert(int fd, Elf *elf, const char *label, uint_t nthrs, uint_t flags, 106 int *errp, char *errbuf, size_t errlen) 107 { 108 int err, i; 109 ctf_file_t *fp = NULL; 110 boolean_t notsup = B_TRUE; 111 ctf_convert_source_t type; 112 113 if (errp == NULL) 114 errp = &err; 115 116 if (elf == NULL) { 117 *errp = EINVAL; 118 return (NULL); 119 } 120 121 if (flags & ~CTF_CONVERT_F_IGNNONC) { 122 *errp = EINVAL; 123 return (NULL); 124 } 125 126 if (elf_kind(elf) != ELF_K_ELF) { 127 *errp = ECTF_FMT; 128 return (NULL); 129 } 130 131 ctf_convert_ftypes(elf, &type); 132 ctf_dprintf("got types: %d\n", type); 133 if (flags & CTF_CONVERT_F_IGNNONC) { 134 if (type == CTFCONV_SOURCE_NONE || 135 (type & CTFCONV_SOURCE_UNKNOWN)) { 136 *errp = ECTF_CONVNOCSRC; 137 return (NULL); 138 } 139 } 140 141 for (i = 0; i < NCONVERTS; i++) { 142 ctf_conv_status_t cs; 143 144 fp = NULL; 145 cs = ctf_converters[i](fd, elf, nthrs, errp, &fp, errbuf, 146 errlen); 147 if (cs == CTF_CONV_SUCCESS) { 148 notsup = B_FALSE; 149 break; 150 } 151 if (cs == CTF_CONV_ERROR) { 152 fp = NULL; 153 notsup = B_FALSE; 154 break; 155 } 156 } 157 158 if (notsup == B_TRUE) { 159 if ((flags & CTF_CONVERT_F_IGNNONC) != 0 && 160 (type & CTFCONV_SOURCE_C) == 0) { 161 *errp = ECTF_CONVNOCSRC; 162 return (NULL); 163 } 164 *errp = ECTF_NOCONVBKEND; 165 return (NULL); 166 } 167 168 /* 169 * Succsesful conversion. 170 */ 171 if (fp != NULL) { 172 if (label == NULL) 173 label = ""; 174 if (ctf_add_label(fp, label, fp->ctf_typemax, 0) == CTF_ERR) { 175 *errp = ctf_errno(fp); 176 ctf_close(fp); 177 return (NULL); 178 } 179 if (ctf_update(fp) == CTF_ERR) { 180 *errp = ctf_errno(fp); 181 ctf_close(fp); 182 return (NULL); 183 } 184 } 185 186 return (fp); 187 } 188 189 ctf_file_t * 190 ctf_fdconvert(int fd, const char *label, uint_t nthrs, uint_t flags, int *errp, 191 char *errbuf, size_t errlen) 192 { 193 int err; 194 Elf *elf; 195 ctf_file_t *fp; 196 197 if (errp == NULL) 198 errp = &err; 199 200 elf = elf_begin(fd, ELF_C_READ, NULL); 201 if (elf == NULL) { 202 *errp = ECTF_FMT; 203 return (NULL); 204 } 205 206 fp = ctf_elfconvert(fd, elf, label, nthrs, flags, errp, errbuf, errlen); 207 208 (void) elf_end(elf); 209 return (fp); 210 }