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 2019 Joyent, Inc. 14 * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. 15 */ 16 17 /* 18 * Main conversion entry points. This has been designed such that there can be 19 * any number of different conversion backends. Currently we only have one that 20 * understands DWARFv2 and DWARFv4. Each backend should be placed in 21 * the ctf_converters list and each will be tried in turn. 22 */ 23 24 #include <libctf_impl.h> 25 #include <assert.h> 26 #include <gelf.h> 27 28 static ctf_convert_f ctf_converters[] = { 29 ctf_dwarf_convert 30 }; 31 32 #define NCONVERTS (sizeof (ctf_converters) / sizeof (ctf_convert_f)) 33 34 ctf_hsc_ret_t 35 ctf_has_c_source(Elf *elf, char *errmsg, size_t errlen) 36 { 37 ctf_hsc_ret_t ret = CHR_NO_C_SOURCE; 38 Elf_Scn *scn, *strscn; 39 Elf_Data *data, *strdata; 40 GElf_Shdr shdr; 41 ulong_t i; 42 43 scn = NULL; 44 while ((scn = elf_nextscn(elf, scn)) != NULL) { 45 if (gelf_getshdr(scn, &shdr) == NULL) { 46 (void) snprintf(errmsg, errlen, 47 "failed to get section header: %s", 48 elf_errmsg(elf_errno())); 49 return (CHR_ERROR); 50 } 51 52 if (shdr.sh_type == SHT_SYMTAB) 53 break; 54 } 55 56 if (scn == NULL) 57 return (CHR_NO_C_SOURCE); 58 59 if ((strscn = elf_getscn(elf, shdr.sh_link)) == NULL) { 60 (void) snprintf(errmsg, errlen, "failed to get str section: %s", 61 elf_errmsg(elf_errno())); 62 return (CHR_ERROR); 63 } 64 65 if ((data = elf_getdata(scn, NULL)) == NULL) { 66 (void) snprintf(errmsg, errlen, "failed to read section: %s", 67 elf_errmsg(elf_errno())); 68 return (CHR_ERROR); 69 } 70 71 if ((strdata = elf_getdata(strscn, NULL)) == NULL) { 72 (void) snprintf(errmsg, errlen, 73 "failed to read string table: %s", elf_errmsg(elf_errno())); 74 return (CHR_ERROR); 75 } 76 77 for (i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) { 78 GElf_Sym sym; 79 const char *file; 80 size_t len; 81 82 if (gelf_getsym(data, i, &sym) == NULL) { 83 (void) snprintf(errmsg, errlen, 84 "failed to read sym %lu: %s", 85 i, elf_errmsg(elf_errno())); 86 return (CHR_ERROR); 87 } 88 89 if (GELF_ST_TYPE(sym.st_info) != STT_FILE) 90 continue; 91 92 file = (const char *)((uintptr_t)strdata->d_buf + sym.st_name); 93 len = strlen(file); 94 if (len >= 2 && strncmp(".c", &file[len - 2], 2) == 0) { 95 ret = CHR_HAS_C_SOURCE; 96 break; 97 } 98 } 99 100 return (ret); 101 } 102 103 static ctf_file_t * 104 ctf_elfconvert(ctf_convert_t *cch, int fd, Elf *elf, int *errp, char *errbuf, 105 size_t errlen) 106 { 107 int err, i; 108 ctf_file_t *fp = NULL; 109 110 if (errp == NULL) 111 errp = &err; 112 113 if (elf == NULL) { 114 *errp = EINVAL; 115 return (NULL); 116 } 117 118 if (elf_kind(elf) != ELF_K_ELF) { 119 *errp = ECTF_FMT; 120 return (NULL); 121 } 122 123 switch (ctf_has_c_source(elf, errbuf, errlen)) { 124 case CHR_ERROR: 125 *errp = ECTF_ELF; 126 return (NULL); 127 128 case CHR_NO_C_SOURCE: 129 *errp = ECTF_CONVNOCSRC; 130 return (NULL); 131 132 default: 133 break; 134 } 135 136 for (i = 0; i < NCONVERTS; i++) { 137 fp = NULL; 138 err = ctf_converters[i](cch, fd, elf, &fp, errbuf, errlen); 139 140 if (err != ECTF_CONVNODEBUG) 141 break; 142 } 143 144 if (err != 0) { 145 assert(fp == NULL); 146 *errp = err; 147 return (NULL); 148 } 149 150 if (cch->cch_label != NULL) { 151 if (ctf_add_label(fp, cch->cch_label, fp->ctf_typemax, 0) == 152 CTF_ERR) { 153 *errp = ctf_errno(fp); 154 ctf_close(fp); 155 return (NULL); 156 } 157 if (ctf_update(fp) == CTF_ERR) { 158 *errp = ctf_errno(fp); 159 ctf_close(fp); 160 return (NULL); 161 } 162 } 163 164 return (fp); 165 } 166 167 ctf_convert_t * 168 ctf_convert_init(int *errp) 169 { 170 struct ctf_convert_handle *cch; 171 int err; 172 173 if (errp == NULL) 174 errp = &err; 175 *errp = 0; 176 177 cch = ctf_alloc(sizeof (struct ctf_convert_handle)); 178 if (cch == NULL) { 179 *errp = ENOMEM; 180 return (NULL); 181 } 182 183 cch->cch_label = NULL; 184 cch->cch_flags = 0; 185 cch->cch_nthreads = CTF_CONVERT_DEFAULT_NTHREADS; 186 cch->cch_batchsize = CTF_CONVERT_DEFAULT_BATCHSIZE; 187 cch->cch_warncb = NULL; 188 cch->cch_warncb_arg = NULL; 189 190 return (cch); 191 } 192 193 void 194 ctf_convert_fini(ctf_convert_t *cch) 195 { 196 if (cch->cch_label != NULL) { 197 size_t len = strlen(cch->cch_label) + 1; 198 ctf_free(cch->cch_label, len); 199 } 200 ctf_free(cch, sizeof (struct ctf_convert_handle)); 201 } 202 203 int 204 ctf_convert_set_nthreads(ctf_convert_t *cch, uint_t nthrs) 205 { 206 if (nthrs == 0) 207 return (EINVAL); 208 cch->cch_nthreads = nthrs; 209 return (0); 210 } 211 212 int 213 ctf_convert_set_batchsize(ctf_convert_t *cch, uint_t bsize) 214 { 215 if (bsize == 0) 216 return (EINVAL); 217 cch->cch_batchsize = bsize; 218 return (0); 219 } 220 221 int 222 ctf_convert_set_flags(ctf_convert_t *cch, uint_t flags) 223 { 224 if ((flags & ~CTF_CONVERT_ALL_FLAGS) != 0) 225 return (EINVAL); 226 cch->cch_flags = flags; 227 return (0); 228 } 229 230 int 231 ctf_convert_set_label(ctf_convert_t *cch, const char *label) 232 { 233 char *dup; 234 235 if (label == NULL) 236 return (EINVAL); 237 238 dup = ctf_strdup(label); 239 if (dup == NULL) 240 return (ENOMEM); 241 242 if (cch->cch_label != NULL) { 243 size_t len = strlen(cch->cch_label) + 1; 244 ctf_free(cch->cch_label, len); 245 } 246 247 cch->cch_label = dup; 248 return (0); 249 } 250 251 int 252 ctf_convert_set_warncb(ctf_convert_t *cch, ctf_convert_warn_f cb, void *arg) 253 { 254 cch->cch_warncb = cb; 255 cch->cch_warncb_arg = arg; 256 return (0); 257 } 258 259 ctf_file_t * 260 ctf_fdconvert(ctf_convert_t *cch, int fd, int *errp, 261 char *errbuf, size_t errlen) 262 { 263 int err; 264 Elf *elf; 265 ctf_file_t *fp; 266 267 if (errp == NULL) 268 errp = &err; 269 270 elf = elf_begin(fd, ELF_C_READ, NULL); 271 if (elf == NULL) { 272 *errp = ECTF_FMT; 273 return (NULL); 274 } 275 276 fp = ctf_elfconvert(cch, fd, elf, errp, errbuf, errlen); 277 278 (void) elf_end(elf); 279 return (fp); 280 } 281