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 */ 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 <assert.h> 25 #include <gelf.h> 26 27 ctf_convert_f ctf_converters[] = { 28 ctf_dwarf_convert 29 }; 30 31 #define NCONVERTS (sizeof (ctf_converters) / sizeof (ctf_convert_f)) 32 33 ctf_hsc_ret_t 34 ctf_has_c_source(Elf *elf, char *errmsg, size_t errlen) 35 { 36 ctf_hsc_ret_t ret = CHR_NO_C_SOURCE; 37 Elf_Scn *scn, *strscn; 38 Elf_Data *data, *strdata; 39 GElf_Shdr shdr; 40 ulong_t i; 41 42 scn = NULL; 43 while ((scn = elf_nextscn(elf, scn)) != NULL) { 44 if (gelf_getshdr(scn, &shdr) == NULL) { 45 (void) snprintf(errmsg, errlen, 46 "failed to get section header: %s", 47 elf_errmsg(elf_errno())); 48 return (CHR_ERROR); 49 } 50 51 if (shdr.sh_type == SHT_SYMTAB) 52 break; 53 } 54 55 if (scn == NULL) 56 return (CHR_NO_C_SOURCE); 57 58 if ((strscn = elf_getscn(elf, shdr.sh_link)) == NULL) { 59 (void) snprintf(errmsg, errlen, "failed to get str section: %s", 60 elf_errmsg(elf_errno())); 61 return (CHR_ERROR); 62 } 63 64 if ((data = elf_getdata(scn, NULL)) == NULL) { 65 (void) snprintf(errmsg, errlen, "failed to read section: %s", 66 elf_errmsg(elf_errno())); 67 return (CHR_ERROR); 68 } 69 70 if ((strdata = elf_getdata(strscn, NULL)) == NULL) { 71 (void) snprintf(errmsg, errlen, 72 "failed to read string table: %s", elf_errmsg(elf_errno())); 73 return (CHR_ERROR); 74 } 75 76 for (i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) { 77 GElf_Sym sym; 78 const char *file; 79 size_t len; 80 81 if (gelf_getsym(data, i, &sym) == NULL) { 82 (void) snprintf(errmsg, errlen, 83 "failed to read sym %lu: %s", 84 i, elf_errmsg(elf_errno())); 85 return (CHR_ERROR); 86 } 87 88 if (GELF_ST_TYPE(sym.st_info) != STT_FILE) 89 continue; 90 91 file = (const char *)((uintptr_t)strdata->d_buf + sym.st_name); 92 len = strlen(file); 93 if (len >= 2 && strncmp(".c", &file[len - 2], 2) == 0) { 94 ret = CHR_HAS_C_SOURCE; 95 break; 96 } 97 } 98 99 return (ret); 100 } 101 102 static ctf_file_t * 103 ctf_elfconvert(int fd, Elf *elf, const char *label, uint_t nthrs, uint_t flags, 104 int *errp, char *errbuf, size_t errlen) 105 { 106 int err, i; 107 ctf_file_t *fp = NULL; 108 109 if (errp == NULL) 110 errp = &err; 111 112 if (elf == NULL) { 113 *errp = EINVAL; 114 return (NULL); 115 } 116 117 if (flags & ~CTF_ALLOW_MISSING_DEBUG) { 118 *errp = EINVAL; 119 return (NULL); 120 } 121 122 if (elf_kind(elf) != ELF_K_ELF) { 123 *errp = ECTF_FMT; 124 return (NULL); 125 } 126 127 switch (ctf_has_c_source(elf, errbuf, errlen)) { 128 case CHR_ERROR: 129 *errp = ECTF_ELF; 130 return (NULL); 131 132 case CHR_NO_C_SOURCE: 133 *errp = ECTF_CONVNOCSRC; 134 return (NULL); 135 136 default: 137 break; 138 } 139 140 for (i = 0; i < NCONVERTS; i++) { 141 fp = NULL; 142 err = ctf_converters[i](fd, elf, nthrs, flags, 143 &fp, errbuf, errlen); 144 145 if (err != ECTF_CONVNODEBUG) 146 break; 147 } 148 149 if (err != 0) { 150 assert(fp == NULL); 151 *errp = err; 152 return (NULL); 153 } 154 155 if (label != NULL) { 156 if (ctf_add_label(fp, label, fp->ctf_typemax, 0) == CTF_ERR) { 157 *errp = ctf_errno(fp); 158 ctf_close(fp); 159 return (NULL); 160 } 161 if (ctf_update(fp) == CTF_ERR) { 162 *errp = ctf_errno(fp); 163 ctf_close(fp); 164 return (NULL); 165 } 166 } 167 168 return (fp); 169 } 170 171 ctf_file_t * 172 ctf_fdconvert(int fd, const char *label, uint_t nthrs, uint_t flags, int *errp, 173 char *errbuf, size_t errlen) 174 { 175 int err; 176 Elf *elf; 177 ctf_file_t *fp; 178 179 if (errp == NULL) 180 errp = &err; 181 182 elf = elf_begin(fd, ELF_C_READ, NULL); 183 if (elf == NULL) { 184 *errp = ECTF_FMT; 185 return (NULL); 186 } 187 188 fp = ctf_elfconvert(fd, elf, label, nthrs, flags, errp, errbuf, errlen); 189 190 (void) elf_end(elf); 191 return (fp); 192 }